(linenum→info "unix/slp.c:2238")

glibc/2.7/nis/nis_table.c

    1: /* Copyright (c) 1997-1999, 2003, 2004, 2005, 2006, 2007
    2:    Free Software Foundation, Inc.
    3:    This file is part of the GNU C Library.
    4:    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997.
    5: 
    6:    The GNU C Library is free software; you can redistribute it and/or
    7:    modify it under the terms of the GNU Lesser General Public
    8:    License as published by the Free Software Foundation; either
    9:    version 2.1 of the License, or (at your option) any later version.
   10: 
   11:    The GNU C Library is distributed in the hope that it will be useful,
   12:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   13:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   14:    Lesser General Public License for more details.
   15: 
   16:    You should have received a copy of the GNU Lesser General Public
   17:    License along with the GNU C Library; if not, write to the Free
   18:    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   19:    02111-1307 USA.  */
   20: 
   21: #include <assert.h>
   22: #include <string.h>
   23: #include <rpcsvc/nis.h>
   24: 
   25: #include "nis_xdr.h"
   26: #include "nis_intern.h"
   27: #include "libnsl.h"
   28: 
   29: 
   30: struct ib_request *
   31: __create_ib_request (const_nis_name name, unsigned int flags)
   32: {
   33:   struct ib_request *ibreq = calloc (1, sizeof (struct ib_request));
   34:   nis_attr *search_val = NULL;
   35:   size_t search_len = 0;
   36:   size_t size = 0;
   37: 
   38:   if (ibreq == NULL)
   39:     return NULL;
   40: 
   41:   ibreq->ibr_flags = flags;
   42: 
   43:   char *cptr = strdupa (name);
   44: 
   45:   /* Not of "[key=value,key=value,...],foo.." format? */
   46:   if (cptr[0] != '[')
   47:     {
   48:       ibreq->ibr_name = strdup (cptr);
   49:       if (ibreq->ibr_name == NULL)
   50:         {
   51:           free (ibreq);
   52:           return NULL;
   53:         }
   54:       return ibreq;
   55:     }
   56: 
   57:   /* "[key=value,...],foo" format */
   58:   ibreq->ibr_name = strchr (cptr, ']');
   59:   if (ibreq->ibr_name == NULL || ibreq->ibr_name[1] != ',')
   60:     {
   61:       /* The object has not really been built yet so we use free.  */
   62:       free (ibreq);
   63:       return NULL;
   64:     }
   65: 
   66:   /* Check if we have an entry of "[key=value,],bar".  If, remove the "," */
   67:   if (ibreq->ibr_name[-1] == ',')
   68:     ibreq->ibr_name[-1] = '\0';
   69:   else
   70:     ibreq->ibr_name[0] = '\0';
   71:   ibreq->ibr_name += 2;
   72:   ibreq->ibr_name = strdup (ibreq->ibr_name);
   73:   if (ibreq->ibr_name == NULL)
   74:     {
   75:     free_null:
   76:       while (search_len-- > 0)
   77:         {
   78:           free (search_val[search_len].zattr_ndx);
   79:           free (search_val[search_len].zattr_val.zattr_val_val);
   80:         }
   81:       free (search_val);
   82:       nis_free_request (ibreq);
   83:       return NULL;
   84:     }
   85: 
   86:   ++cptr; /* Remove "[" */
   87: 
   88:   while (cptr != NULL && cptr[0] != '\0')
   89:     {
   90:       char *key = cptr;
   91:       char *val = strchr (cptr, '=');
   92: 
   93:       cptr = strchr (key, ',');
   94:       if (cptr != NULL)
   95:         *cptr++ = '\0';
   96: 
   97:       if (__builtin_expect (val == NULL, 0))
   98:         {
   99:           nis_free_request (ibreq);
  100:           return NULL;
  101:         }
  102:       *val++ = '\0';
  103:       if (search_len + 1 >= size)
  104:         {
  105:           size += 1;
  106:           nis_attr *newp = realloc (search_val, size * sizeof (nis_attr));
  107:           if (newp == NULL)
  108:             goto free_null;
  109:           search_val = newp;
  110:         }
  111:       search_val[search_len].zattr_ndx = strdup (key);
  112:       if (search_val[search_len].zattr_ndx == NULL)
  113:         goto free_null;
  114: 
  115:       search_val[search_len].zattr_val.zattr_val_len = strlen (val) + 1;
  116:       search_val[search_len].zattr_val.zattr_val_val = strdup (val);
  117:       if (search_val[search_len].zattr_val.zattr_val_val == NULL)
  118:         {
  119:           free (search_val[search_len].zattr_ndx);
  120:           goto free_null;
  121:         }
  122: 
  123:       ++search_len;
  124:     }
  125: 
  126:   ibreq->ibr_srch.ibr_srch_val = search_val;
  127:   ibreq->ibr_srch.ibr_srch_len = search_len;
  128: 
  129:   return ibreq;
  130: }
  131: libnsl_hidden_def (__create_ib_request)
  132: 
  133: static const struct timeval RPCTIMEOUT = {10, 0};
  134: 
  135: static char *
  136: get_tablepath (char *name, dir_binding *bptr)
  137: {
  138:   enum clnt_stat result;
  139:   nis_result res;
  140:   struct ns_request req;
  141: 
  142:   memset (&res, '\0', sizeof (res));
  143: 
  144:   req.ns_name = name;
  145:   req.ns_object.ns_object_len = 0;
  146:   req.ns_object.ns_object_val = NULL;
  147: 
  148:   result = clnt_call (bptr->clnt, NIS_LOOKUP, (xdrproc_t) _xdr_ns_request,
  149:                       (caddr_t) &req, (xdrproc_t) _xdr_nis_result,
  150:                       (caddr_t) &res, RPCTIMEOUT);
  151: 
  152:   const char *cptr;
  153:   if (result == RPC_SUCCESS && NIS_RES_STATUS (&res) == NIS_SUCCESS
  154:       && __type_of (NIS_RES_OBJECT (&res)) == NIS_TABLE_OBJ)
  155:     cptr = NIS_RES_OBJECT (&res)->TA_data.ta_path;
  156:   else
  157:     cptr = "";
  158: 
  159:   char *str = strdup (cptr);
  160: 
  161:   if (result == RPC_SUCCESS)
  162:     xdr_free ((xdrproc_t) _xdr_nis_result, (char *) &res);
  163: 
  164:   return str;
  165: }
  166: 
  167: 
  168: nis_error
  169: __follow_path (char **tablepath, char **tableptr, struct ib_request *ibreq,
  170:                dir_binding *bptr)
  171: {
  172:   if (*tablepath == NULL)
  173:     {
  174:       *tablepath = get_tablepath (ibreq->ibr_name, bptr);
  175:       if (*tablepath == NULL)
  176:         return NIS_NOMEMORY;
  177: 
  178:       *tableptr = *tablepath;
  179:     }
  180:   if (*tableptr == NULL)
  181:     return NIS_NOTFOUND;
  182: 
  183:   char *newname = strsep (tableptr, ":");
  184:   if (newname[0] == '\0')
  185:     return NIS_NOTFOUND;
  186: 
  187:   newname = strdup (newname);
  188:   if (newname == NULL)
  189:     return NIS_NOMEMORY;
  190: 
  191:   free (ibreq->ibr_name);
  192:   ibreq->ibr_name = newname;
  193: 
  194:   return NIS_SUCCESS;
  195: }
  196: libnsl_hidden_def (__follow_path)
  197: 
  198: 
  199: nis_result *
  200: nis_list (const_nis_name name, unsigned int flags,
  201:           int (*callback) (const_nis_name name,
  202:                            const nis_object *object,
  203:                            const void *userdata),
  204:           const void *userdata)
  205: {
  206:   nis_result *res = malloc (sizeof (nis_result));
  207:   ib_request *ibreq;
  208:   int status;
  209:   enum clnt_stat clnt_status;
  210:   int count_links = 0;          /* We will only follow NIS_MAXLINKS links! */
  211:   int done = 0;
  212:   nis_name *names;
  213:   nis_name namebuf[2] = {NULL, NULL};
  214:   int name_nr = 0;
  215:   nis_cb *cb = NULL;
  216:   char *tableptr;
  217:   char *tablepath = NULL;
  218:   int first_try = 0; /* Do we try the old binding at first ? */
  219:   nis_result *allres = NULL;
  220: 
  221:   if (res == NULL)
  222:     return NULL;
  223: 
  224:   if (name == NULL)
  225:     {
  226:       status = NIS_BADNAME;
  227:     err_out:
  228:       nis_freeresult (allres);
  229:       memset (res, '\0', sizeof (nis_result));
  230:       NIS_RES_STATUS (res) = status;
  231:       return res;
  232:     }
  233: 
  234:   ibreq = __create_ib_request (name, flags);
  235:   if (ibreq == NULL)
  236:     {
  237:       status = NIS_BADNAME;
  238:       goto err_out;
  239:     }
  240: 
  241:   if ((flags & EXPAND_NAME)
  242:       && ibreq->ibr_name[strlen (ibreq->ibr_name) - 1] != '.')
  243:     {
  244:       names = nis_getnames (ibreq->ibr_name);
  245:       free (ibreq->ibr_name);
  246:       ibreq->ibr_name = NULL;
  247:       if (names == NULL)
  248:         {
  249:           nis_free_request (ibreq);
  250:           status = NIS_BADNAME;
  251:           goto err_out;
  252:         }
  253:       ibreq->ibr_name = strdup (names[name_nr]);
  254:       if (ibreq->ibr_name == NULL)
  255:         {
  256:           nis_freenames (names);
  257:           nis_free_request (ibreq);
  258:           status = NIS_NOMEMORY;
  259:           goto err_out;
  260:         }
  261:     }
  262:   else
  263:     {
  264:       names = namebuf;
  265:       names[name_nr] = ibreq->ibr_name;
  266:     }
  267: 
  268:   cb = NULL;
  269: 
  270:   while (!done)
  271:     {
  272:       dir_binding bptr;
  273:       directory_obj *dir = NULL;
  274: 
  275:       memset (res, '\0', sizeof (nis_result));
  276: 
  277:       status = __nisfind_server (ibreq->ibr_name,
  278:                                  ibreq->ibr_srch.ibr_srch_val != NULL,
  279:                                  &dir, &bptr, flags & ~MASTER_ONLY);
  280:       if (status != NIS_SUCCESS)
  281:         {
  282:           NIS_RES_STATUS (res) = status;
  283:           goto fail3;
  284:         }
  285: 
  286:       while (__nisbind_connect (&bptr) != NIS_SUCCESS)
  287:         if (__builtin_expect (__nisbind_next (&bptr) != NIS_SUCCESS, 0))
  288:           {
  289:             NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE;
  290:             goto fail;
  291:           }
  292: 
  293:       if (callback != NULL)
  294:         {
  295:           assert (cb == NULL);
  296:           cb = __nis_create_callback (callback, userdata, flags);
  297:           ibreq->ibr_cbhost.ibr_cbhost_len = 1;
  298:           ibreq->ibr_cbhost.ibr_cbhost_val = cb->serv;
  299:         }
  300: 
  301:     again:
  302:       clnt_status = clnt_call (bptr.clnt, NIS_IBLIST,
  303:                                (xdrproc_t) _xdr_ib_request, (caddr_t) ibreq,
  304:                                (xdrproc_t) _xdr_nis_result,
  305:                                (caddr_t) res, RPCTIMEOUT);
  306: 
  307:       if (__builtin_expect (clnt_status != RPC_SUCCESS, 0))
  308:         NIS_RES_STATUS (res) = NIS_RPCERROR;
  309:       else
  310:         switch (NIS_RES_STATUS (res))
  311:           { /* start switch */
  312:           case NIS_PARTIAL:
  313:           case NIS_SUCCESS:
  314:           case NIS_S_SUCCESS:
  315:             if (__type_of (NIS_RES_OBJECT (res)) == NIS_LINK_OBJ
  316:                 && (flags & FOLLOW_LINKS))    /* We are following links.  */
  317:               {
  318:                 free (ibreq->ibr_name);
  319:                 ibreq->ibr_name = NULL;
  320:                 /* If we hit the link limit, bail.  */
  321:                 if (__builtin_expect (count_links > NIS_MAXLINKS, 0))
  322:                   {
  323:                     NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
  324:                     ++done;
  325:                     break;
  326:                   }
  327:                 ++count_links;
  328:                 ibreq->ibr_name =
  329:                   strdup (NIS_RES_OBJECT (res)->LI_data.li_name);
  330:                 if (ibreq->ibr_name == NULL)
  331:                   {
  332:                     NIS_RES_STATUS (res) = NIS_NOMEMORY;
  333:                   fail:
  334:                     __nisbind_destroy (&bptr);
  335:                     nis_free_directory (dir);
  336:                   fail3:
  337:                     free (tablepath);
  338:                     if (cb)
  339:                       {
  340:                         __nis_destroy_callback (cb);
  341:                         ibreq->ibr_cbhost.ibr_cbhost_len = 0;
  342:                         ibreq->ibr_cbhost.ibr_cbhost_val = NULL;
  343:                       }
  344:                     if (names != namebuf)
  345:                       nis_freenames (names);
  346:                     nis_free_request (ibreq);
  347:                     nis_freeresult (allres);
  348:                     return res;
  349:                   }
  350:                 if (NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len)
  351:                   if (ibreq->ibr_srch.ibr_srch_len == 0)
  352:                     {
  353:                       ibreq->ibr_srch.ibr_srch_len =
  354:                         NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len;
  355:                       ibreq->ibr_srch.ibr_srch_val =
  356:                         NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_val;
  357:                     }
  358:                 /* The following is a non-obvious optimization.  A
  359:                    nis_freeresult call would call xdr_free as the
  360:                    following code.  But it also would unnecessarily
  361:                    free the result structure.  We avoid this here
  362:                    along with the necessary tests.  */
  363:                 xdr_free ((xdrproc_t) _xdr_nis_result, (char *)res);
  364:                 memset (res, '\0', sizeof (*res));
  365:                 first_try = 1; /* Try at first the old binding */
  366:                 goto again;
  367:               }
  368:             else if ((flags & FOLLOW_PATH)
  369:                      && NIS_RES_STATUS (res) == NIS_PARTIAL)
  370:               {
  371:                 clnt_status = __follow_path (&tablepath, &tableptr, ibreq,
  372:                                              &bptr);
  373:                 if (clnt_status != NIS_SUCCESS)
  374:                   {
  375:                     if (clnt_status == NIS_NOMEMORY)
  376:                       NIS_RES_STATUS (res) = clnt_status;
  377:                     ++done;
  378:                   }
  379:                 else
  380:                   {
  381:                     /* The following is a non-obvious optimization.  A
  382:                        nis_freeresult call would call xdr_free as the
  383:                        following code.  But it also would unnecessarily
  384:                        free the result structure.  We avoid this here
  385:                        along with the necessary tests.  */
  386:                     xdr_free ((xdrproc_t) _xdr_nis_result, (char *) res);
  387:                     memset (res, '\0', sizeof (*res));
  388:                     first_try = 1;
  389:                     goto again;
  390:                   }
  391:               }
  392:             else if ((flags & (FOLLOW_PATH | ALL_RESULTS))
  393:                      == (FOLLOW_PATH | ALL_RESULTS))
  394:               {
  395:                 if (allres == NULL)
  396:                   {
  397:                     allres = res;
  398:                     res = malloc (sizeof (nis_result));
  399:                     if (res == NULL)
  400:                       {
  401:                         res = allres;
  402:                         allres = NULL;
  403:                         NIS_RES_STATUS (res) = NIS_NOMEMORY;
  404:                         goto fail;
  405:                       }
  406:                     NIS_RES_STATUS (res) = NIS_RES_STATUS (allres);
  407:                   }
  408:                 else
  409:                   {
  410:                     nis_object *objects_val
  411:                       = realloc (NIS_RES_OBJECT (allres),
  412:                                  (NIS_RES_NUMOBJ (allres)
  413:                                   + NIS_RES_NUMOBJ (res))
  414:                                  * sizeof (nis_object));
  415:                     if (objects_val == NULL)
  416:                       {
  417:                         NIS_RES_STATUS (res) = NIS_NOMEMORY;
  418:                         goto fail;
  419:                       }
  420:                     NIS_RES_OBJECT (allres) = objects_val;
  421:                     memcpy (NIS_RES_OBJECT (allres) + NIS_RES_NUMOBJ (allres),
  422:                             NIS_RES_OBJECT (res),
  423:                             NIS_RES_NUMOBJ (res) * sizeof (nis_object));
  424:                     NIS_RES_NUMOBJ (allres) += NIS_RES_NUMOBJ (res);
  425:                     NIS_RES_NUMOBJ (res) = 0;
  426:                     free (NIS_RES_OBJECT (res));
  427:                     NIS_RES_OBJECT (res) = NULL;
  428:                     NIS_RES_STATUS (allres) = NIS_RES_STATUS (res);
  429:                     xdr_free ((xdrproc_t) _xdr_nis_result, (char *) res);
  430:                   }
  431:                 clnt_status = __follow_path (&tablepath, &tableptr, ibreq,
  432:                                              &bptr);
  433:                 if (clnt_status != NIS_SUCCESS)
  434:                   {
  435:                     /* Prepare for the nis_freeresult call.  */
  436:                     memset (res, '\0', sizeof (*res));
  437: 
  438:                     if (clnt_status == NIS_NOMEMORY)
  439:                       NIS_RES_STATUS (allres) = clnt_status;
  440:                     ++done;
  441:                   }
  442:               }
  443:             else
  444:               ++done;
  445:             break;
  446:           case NIS_CBRESULTS:
  447:             if (cb != NULL)
  448:               {
  449:                 __nis_do_callback (&bptr, &res->cookie, cb);
  450:                 NIS_RES_STATUS (res) = cb->result;
  451: 
  452:                 if (!(flags & ALL_RESULTS))
  453:                   ++done;
  454:                 else
  455:                   {
  456:                     clnt_status
  457:                       = __follow_path (&tablepath, &tableptr, ibreq, &bptr);
  458:                     if (clnt_status != NIS_SUCCESS)
  459:                       {
  460:                         if (clnt_status == NIS_NOMEMORY)
  461:                           NIS_RES_STATUS (res) = clnt_status;
  462:                         ++done;
  463:                       }
  464:                   }
  465:               }
  466:             break;
  467:           case NIS_SYSTEMERROR:
  468:           case NIS_NOSUCHNAME:
  469:           case NIS_NOT_ME:
  470:             /* If we had first tried the old binding, do nothing, but
  471:                get a new binding */
  472:             if (!first_try)
  473:               {
  474:                 if (__nisbind_next (&bptr) != NIS_SUCCESS)
  475:                   {
  476:                     ++done;
  477:                     break; /* No more servers to search */
  478:                   }
  479:                 while (__nisbind_connect (&bptr) != NIS_SUCCESS)
  480:                   {
  481:                     if (__nisbind_next (&bptr) != NIS_SUCCESS)
  482:                       {
  483:                         ++done;
  484:                         break; /* No more servers to search */
  485:                       }
  486:                   }
  487:                 goto again;
  488:               }
  489:             break;
  490:           default:
  491:             if (!first_try)
  492:               {
  493:                 /* Try the next domainname if we don't follow a link.  */
  494:                 free (ibreq->ibr_name);
  495:                 ibreq->ibr_name = NULL;
  496:                 if (__builtin_expect (count_links, 0))
  497:                   {
  498:                     NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
  499:                     ++done;
  500:                     break;
  501:                   }
  502:                 ++name_nr;
  503:                 if (names[name_nr] == NULL)
  504:                   {
  505:                     ++done;
  506:                     break;
  507:                   }
  508:                 ibreq->ibr_name = strdup (names[name_nr]);
  509:                 if (ibreq->ibr_name == NULL)
  510:                   {
  511:                     NIS_RES_STATUS (res) = NIS_NOMEMORY;
  512:                     goto fail;
  513:                   }
  514:                 first_try = 1; /* Try old binding at first */
  515:                 goto again;
  516:               }
  517:             break;
  518:           }
  519:       first_try = 0;
  520: 
  521:       if (cb)
  522:         {
  523:           __nis_destroy_callback (cb);
  524:           ibreq->ibr_cbhost.ibr_cbhost_len = 0;
  525:           ibreq->ibr_cbhost.ibr_cbhost_val = NULL;
  526:           cb = NULL;
  527:         }
  528: 
  529:       __nisbind_destroy (&bptr);
  530:       nis_free_directory (dir);
  531:     }
  532: 
  533:   free (tablepath);
  534: 
  535:   if (names != namebuf)
  536:     nis_freenames (names);
  537: 
  538:   nis_free_request (ibreq);
  539: 
  540:   if (allres)
  541:     {
  542:       nis_freeresult (res);
  543:       return allres;
  544:     }
  545: 
  546:   return res;
  547: }
  548: libnsl_hidden_def (nis_list)
  549: 
  550: nis_result *
  551: nis_add_entry (const_nis_name name, const nis_object *obj2, unsigned int flags)
  552: {
  553:   nis_result *res = calloc (1, sizeof (nis_result));
  554:   if (res == NULL)
  555:     return NULL;
  556: 
  557:   if (name == NULL)
  558:     {
  559:       NIS_RES_STATUS (res) = NIS_BADNAME;
  560:       return res;
  561:     }
  562: 
  563:   ib_request *ibreq = __create_ib_request (name, flags);
  564:   if (ibreq == NULL)
  565:     {
  566:       NIS_RES_STATUS (res) = NIS_BADNAME;
  567:       return res;
  568:     }
  569: 
  570:   nis_object obj;
  571:   memcpy (&obj, obj2, sizeof (nis_object));
  572: 
  573:   size_t namelen = strlen (name);
  574:   char buf1[namelen + 20];
  575:   char buf4[namelen + 20];
  576: 
  577:   if (obj.zo_name == NULL || strlen (obj.zo_name) == 0)
  578:     obj.zo_name = nis_leaf_of_r (name, buf1, sizeof (buf1));
  579: 
  580:   if (obj.zo_owner == NULL || strlen (obj.zo_owner) == 0)
  581:     obj.zo_owner = nis_local_principal ();
  582: 
  583:   if (obj.zo_group == NULL || strlen (obj.zo_group) == 0)
  584:     obj.zo_group = nis_local_group ();
  585: 
  586:   obj.zo_domain = nis_domain_of_r (name, buf4, sizeof (buf4));
  587: 
  588:   ibreq->ibr_obj.ibr_obj_val = nis_clone_object (&obj, NULL);
  589:   if (ibreq->ibr_obj.ibr_obj_val == NULL)
  590:     {
  591:       nis_free_request (