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

glibc/2.7/nis/ypclnt.c

    1: /* Copyright (C) 1996-2001, 2002, 2003, 2004, 2005, 2006
    2:    Free Software Foundation, Inc.
    3:    This file is part of the GNU C Library.
    4:    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996.
    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 <errno.h>
   22: #include <fcntl.h>
   23: #include <string.h>
   24: #include <unistd.h>
   25: #include <libintl.h>
   26: #include <rpc/rpc.h>
   27: #include <rpcsvc/nis.h>
   28: #include <rpcsvc/yp.h>
   29: #include <rpcsvc/ypclnt.h>
   30: #include <rpcsvc/ypupd.h>
   31: #include <sys/uio.h>
   32: #include <bits/libc-lock.h>
   33: 
   34: /* This should only be defined on systems with a BSD compatible ypbind */
   35: #ifndef BINDINGDIR
   36: # define BINDINGDIR "/var/yp/binding"
   37: #endif
   38: 
   39: struct dom_binding
   40:   {
   41:     struct dom_binding *dom_pnext;
   42:     char dom_domain[YPMAXDOMAIN + 1];
   43:     struct sockaddr_in dom_server_addr;
   44:     int dom_socket;
   45:     CLIENT *dom_client;
   46:   };
   47: typedef struct dom_binding dom_binding;
   48: 
   49: static const struct timeval RPCTIMEOUT = {25, 0};
   50: static const struct timeval UDPTIMEOUT = {5, 0};
   51: static int const MAXTRIES = 2;
   52: static char ypdomainname[NIS_MAXNAMELEN + 1];
   53: __libc_lock_define_initialized (static, ypbindlist_lock)
   54: static dom_binding *ypbindlist = NULL;
   55: 
   56: 
   57: static void
   58: yp_bind_client_create (const char *domain, dom_binding *ysd,
   59:                        struct ypbind_resp *ypbr)
   60: {
   61:   ysd->dom_server_addr.sin_family = AF_INET;
   62:   memcpy (&ysd->dom_server_addr.sin_port,
   63:           ypbr->ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
   64:           sizeof (ysd->dom_server_addr.sin_port));
   65:   memcpy (&ysd->dom_server_addr.sin_addr.s_addr,
   66:           ypbr->ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
   67:           sizeof (ysd->dom_server_addr.sin_addr.s_addr));
   68:   strncpy (ysd->dom_domain, domain, YPMAXDOMAIN);
   69:   ysd->dom_domain[YPMAXDOMAIN] = '\0';
   70: 
   71:   ysd->dom_socket = RPC_ANYSOCK;
   72:   ysd->dom_client = clntudp_create (&ysd->dom_server_addr, YPPROG, YPVERS,
   73:                                     UDPTIMEOUT, &ysd->dom_socket);
   74: 
   75:   if (ysd->dom_client != NULL)
   76:     {
   77:       /* If the program exits, close the socket */
   78:       if (fcntl (ysd->dom_socket, F_SETFD, FD_CLOEXEC) == -1)
   79:         perror ("fcntl: F_SETFD");
   80:     }
   81: }
   82: 
   83: #if USE_BINDINGDIR
   84: static void
   85: yp_bind_file (const char *domain, dom_binding *ysd)
   86: {
   87:   char path[sizeof (BINDINGDIR) + strlen (domain) + 3 * sizeof (unsigned) + 3];
   88: 
   89:   snprintf (path, sizeof (path), "%s/%s.%u", BINDINGDIR, domain, YPBINDVERS);
   90:   int fd = open (path, O_RDONLY);
   91:   if (fd >= 0)
   92:     {
   93:       /* We have a binding file and could save a RPC call.  The file
   94:          contains a port number and the YPBIND_RESP record.  The port
   95:          number (16 bits) can be ignored.  */
   96:       struct ypbind_resp ypbr;
   97: 
   98:       if (pread (fd, &ypbr, sizeof (ypbr), 2) == sizeof (ypbr))
   99:         yp_bind_client_create (domain, ysd, &ypbr);
  100: 
  101:       close (fd);
  102:     }
  103: }
  104: #endif
  105: 
  106: static int
  107: yp_bind_ypbindprog (const char *domain, dom_binding *ysd)
  108: {
  109:   struct sockaddr_in clnt_saddr;
  110:   struct ypbind_resp ypbr;
  111:   int clnt_sock;
  112:   CLIENT *client;
  113: 
  114:   clnt_saddr.sin_family = AF_INET;
  115:   clnt_saddr.sin_port = 0;
  116:   clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
  117:   clnt_sock = RPC_ANYSOCK;
  118:   client = clnttcp_create (&clnt_saddr, YPBINDPROG, YPBINDVERS,
  119:                            &clnt_sock, 0, 0);
  120:   if (client == NULL)
  121:     return YPERR_YPBIND;
  122: 
  123:   /* Check the port number -- should be < IPPORT_RESERVED.
  124:      If not, it's possible someone has registered a bogus
  125:      ypbind with the portmapper and is trying to trick us. */
  126:   if (ntohs (clnt_saddr.sin_port) >= IPPORT_RESERVED)
  127:     {
  128:       clnt_destroy (client);
  129:       return YPERR_YPBIND;
  130:     }
  131: 
  132:   if (clnt_call (client, YPBINDPROC_DOMAIN,
  133:                  (xdrproc_t) xdr_domainname, (caddr_t) &domain,
  134:                  (xdrproc_t) xdr_ypbind_resp,
  135:                  (caddr_t) &ypbr, RPCTIMEOUT) != RPC_SUCCESS)
  136:     {
  137:       clnt_destroy (client);
  138:       return YPERR_YPBIND;
  139:     }
  140: 
  141:   clnt_destroy (client);
  142: 
  143:   if (ypbr.ypbind_status != YPBIND_SUCC_VAL)
  144:     {
  145:       fprintf (stderr, "YPBINDPROC_DOMAIN: %s\n",
  146:                ypbinderr_string (ypbr.ypbind_resp_u.ypbind_error));
  147:       return YPERR_DOMAIN;
  148:     }
  149:   memset (&ysd->dom_server_addr, '\0', sizeof ysd->dom_server_addr);
  150: 
  151:   yp_bind_client_create (domain, ysd, &ypbr);
  152: 
  153:   return YPERR_SUCCESS;
  154: }
  155: 
  156: static int
  157: __yp_bind (const char *domain, dom_binding **ypdb)
  158: {
  159:   dom_binding *ysd = NULL;
  160:   int is_new = 0;
  161: 
  162:   if (domain == NULL || domain[0] == '\0')
  163:     return YPERR_BADARGS;
  164: 
  165:   ysd = *ypdb;
  166:   while (ysd != NULL)
  167:     {
  168:       if (strcmp (domain, ysd->dom_domain) == 0)
  169:         break;
  170:       ysd = ysd->dom_pnext;
  171:     }
  172: 
  173:   if (ysd == NULL)
  174:     {
  175:       is_new = 1;
  176:       ysd = (dom_binding *) calloc (1, sizeof *ysd);
  177:       if (__builtin_expect (ysd == NULL, 0))
  178:         return YPERR_RESRC;
  179:     }
  180: 
  181: #if USE_BINDINGDIR
  182:   /* Try binding dir at first if we have no binding */
  183:   if (ysd->dom_client == NULL)
  184:     yp_bind_file (domain, ysd);
  185: #endif /* USE_BINDINGDIR */
  186: 
  187:   if (ysd->dom_client == NULL)
  188:     {
  189:       int retval = yp_bind_ypbindprog (domain, ysd);
  190:       if (retval != YPERR_SUCCESS)
  191:         {
  192:           if (is_new)
  193:             free (ysd);
  194:           return retval;
  195:         }
  196:     }
  197: 
  198:   if (ysd->dom_client == NULL)
  199:     {
  200:       if (is_new)
  201:         free (ysd);
  202:       return YPERR_YPSERV;
  203:     }
  204: 
  205:   if (is_new)
  206:     {
  207:       ysd->dom_pnext = *ypdb;
  208:       *ypdb = ysd;
  209:     }
  210: 
  211:   return YPERR_SUCCESS;
  212: }
  213: 
  214: static void
  215: __yp_unbind (dom_binding *ydb)
  216: {
  217:   clnt_destroy (ydb->dom_client);
  218:   free (ydb);
  219: }
  220: 
  221: int
  222: yp_bind (const char *indomain)
  223: {
  224:   int status;
  225: 
  226:   __libc_lock_lock (ypbindlist_lock);
  227: 
  228:   status = __yp_bind (indomain, &ypbindlist);
  229: 
  230:   __libc_lock_unlock (ypbindlist_lock);
  231: 
  232:   return status;
  233: }
  234: libnsl_hidden_def (yp_bind)
  235: 
  236: static void
  237: yp_unbind_locked (const char *indomain)
  238: {
  239:   dom_binding *ydbptr, *ydbptr2;
  240: 
  241:   ydbptr2 = NULL;
  242:   ydbptr = ypbindlist;
  243: 
  244:   while (ydbptr != NULL)
  245:     {
  246:       if (strcmp (ydbptr->dom_domain, indomain) == 0)
  247:         {
  248:           dom_binding *work;
  249: 
  250:           work = ydbptr;
  251:           if (ydbptr2 == NULL)
  252:             ypbindlist = ypbindlist->dom_pnext;
  253:           else
  254:             ydbptr2 = ydbptr->dom_pnext;
  255:           __yp_unbind (work);
  256:           break;
  257:         }
  258:       ydbptr2 = ydbptr;
  259:       ydbptr = ydbptr->dom_pnext;
  260:     }
  261: }
  262: 
  263: void
  264: yp_unbind (const char *indomain)
  265: {
  266:   __libc_lock_lock (ypbindlist_lock);
  267: 
  268:   yp_unbind_locked (indomain);
  269: 
  270:   __libc_lock_unlock (ypbindlist_lock);
  271: 
  272:   return;
  273: }
  274: 
  275: static int
  276: __ypclnt_call (const char *domain, u_long prog, xdrproc_t xargs,
  277:                caddr_t req, xdrproc_t xres, caddr_t resp, dom_binding **ydb,
  278:                int print_error)
  279: {
  280:   enum clnt_stat result;
  281: 
  282:   result = clnt_call ((*ydb)->dom_client, prog,
  283:                       xargs, req, xres, resp, RPCTIMEOUT);
  284: 
  285:   if (result != RPC_SUCCESS)
  286:     {
  287:       /* We don't print an error message, if we try our old,
  288:          cached data. Only print this for data, which should work.  */
  289:       if (print_error)
  290:         clnt_perror ((*ydb)->dom_client, "do_ypcall: clnt_call");
  291: 
  292:       return YPERR_RPC;
  293:     }
  294: 
  295:   return YPERR_SUCCESS;
  296: }
  297: 
  298: static int
  299: do_ypcall (const char *domain, u_long prog, xdrproc_t xargs,
  300:            caddr_t req, xdrproc_t xres, caddr_t resp)
  301: {
  302:   dom_binding *ydb;
  303:   int status;
  304:   int saved_errno = errno;
  305: 
  306:   status = YPERR_YPERR;
  307: 
  308:   __libc_lock_lock (ypbindlist_lock);
  309:   ydb = ypbindlist;
  310:   while (ydb != NULL)
  311:     {
  312:       if (strcmp (domain, ydb->dom_domain) == 0)
  313:         {
  314:           if (__yp_bind (domain, &ydb) == 0)
  315:             {
  316:               /* Call server, print no error message, do not unbind.  */
  317:               status = __ypclnt_call (domain, prog, xargs, req, xres,
  318:                                       resp, &ydb, 0);
  319:               if (status == YPERR_SUCCESS)
  320:                 {
  321:                   __libc_lock_unlock (ypbindlist_lock);
  322:                   __set_errno (saved_errno);
  323:                   return status;
  324:                 }
  325:             }
  326:           /* We use ypbindlist, and the old cached data is
  327:              invalid. unbind now and create a new binding */
  328:           yp_unbind_locked (domain);
  329: 
  330:           break;
  331:         }
  332:       ydb = ydb->dom_pnext;
  333:     }
  334:   __libc_lock_unlock (ypbindlist_lock);
  335: 
  336:   /* First try with cached data failed. Now try to get
  337:      current data from the system.  */
  338:   ydb = NULL;
  339:   if (__yp_bind (domain, &ydb) == 0)
  340:     {
  341:       status = __ypclnt_call (domain, prog, xargs, req, xres,
  342:                               resp, &ydb, 1);
  343:       __yp_unbind (ydb);
  344:     }
  345: 
  346: #if USE_BINDINGDIR
  347:   /* If we support binding dir data, we have a third chance:
  348:      Ask ypbind.  */
  349:   if (status != YPERR_SUCCESS)
  350:     {
  351:       ydb = calloc (1, sizeof (dom_binding));
  352:       if (ydb != NULL && yp_bind_ypbindprog (domain, ydb) == YPERR_SUCCESS)
  353:         {
  354:           status = __ypclnt_call (domain, prog, xargs, req, xres,
  355:                                   resp, &ydb, 1);
  356:           __yp_unbind (ydb);
  357:         }
  358:       else
  359:         free (ydb);
  360:     }
  361: #endif
  362: 
  363:   __set_errno (saved_errno);
  364: 
  365:   return status;
  366: }
  367: 
  368: /* Like do_ypcall, but translate the status value if necessary.  */
  369: static int
  370: do_ypcall_tr (const char *domain, u_long prog, xdrproc_t xargs,
  371:               caddr_t req, xdrproc_t xres, caddr_t resp)
  372: {
  373:   int status = do_ypcall (domain, prog, xargs, req, xres, resp);
  374:   if (status == YPERR_SUCCESS)
  375:     /* We cast to ypresp_val although the pointer could also be of
  376:        type ypresp_key_val or ypresp_master or ypresp_order or
  377:        ypresp_maplist.  But the stat element is in a common prefix so
  378:        this does not matter.  */
  379:     status = ypprot_err (((struct ypresp_val *) resp)->stat);
  380:   return status;
  381: }
  382: 
  383: 
  384: __libc_lock_define_initialized (static, domainname_lock)
  385: 
  386: int
  387: yp_get_default_domain (char **outdomain)
  388: {
  389:   int result = YPERR_SUCCESS;;
  390:   *outdomain = NULL;
  391: 
  392:   __libc_lock_lock (domainname_lock);
  393: 
  394:   if (ypdomainname[0] == '\0')
  395:     {
  396:       if (getdomainname (ypdomainname, NIS_MAXNAMELEN))
  397:         result = YPERR_NODOM;
  398:       else if (strcmp (ypdomainname, "(none)") == 0)
  399:         {
  400:           /* If domainname is not set, some systems will return "(none)" */
  401:           ypdomainname[0] = '\0';
  402:           result = YPERR_NODOM;
  403:         }
  404:       else
  405:         *outdomain = ypdomainname;
  406:     }
  407:   else
  408:     *outdomain = ypdomainname;
  409: 
  410:   __libc_lock_unlock (domainname_lock);
  411: 
  412:   return result;
  413: }
  414: libnsl_hidden_def (yp_get_default_domain)
  415: 
  416: int
  417: __yp_check (char **domain)
  418: {
  419:   char *unused;
  420: 
  421:   if (ypdomainname[0] == '\0')
  422:     if (yp_get_default_domain (&unused))
  423:       return 0;
  424: 
  425:   if (domain)
  426:     *domain = ypdomainname;
  427: 
  428:   if (yp_bind (ypdomainname) == 0)
  429:     return 1;
  430:   return 0;
  431: }
  432: 
  433: int
  434: yp_match (const char *indomain, const char *inmap, const char *inkey,
  435:           const int inkeylen, char **outval, int *outvallen)
  436: {
  437:   ypreq_key req;
  438:   ypresp_val resp;
  439:   enum clnt_stat result;
  440: 
  441:   if (indomain == NULL || indomain[0] == '\0' ||
  442:       inmap == NULL || inmap[0] == '\0' ||
  443:       inkey == NULL || inkey[0] == '\0' || inkeylen <= 0)
  444:     return YPERR_BADARGS;
  445: 
  446:   req.domain = (char *) indomain;
  447:   req.map = (char *) inmap;
  448:   req.key.keydat_val = (char *) inkey;
  449:   req.key.keydat_len = inkeylen;
  450: 
  451:   *outval = NULL;
  452:   *outvallen = 0;
  453:   memset (&resp, '\0', sizeof (resp));
  454: 
  455:   result = do_ypcall_tr (indomain, YPPROC_MATCH, (xdrproc_t) xdr_ypreq_key,
  456:                          (caddr_t) &req, (xdrproc_t) xdr_ypresp_val,
  457:                          (caddr_t) &resp);
  458: 
  459:   if (result != YPERR_SUCCESS)
  460:     return result;
  461: 
  462:   *outvallen = resp.val.valdat_len;
  463:   *outval = malloc (*outvallen + 1);
  464:   int status = YPERR_RESRC;
  465:   if (__builtin_expect (*outval != NULL, 1))
  466:     {
  467:       memcpy (*outval, resp.val.valdat_val, *outvallen);
  468:       (*outval)[*outvallen] = '\0';
  469:       status = YPERR_SUCCESS;
  470:     }
  471: 
  472:   xdr_free ((xdrproc_t) xdr_ypresp_val, (char *) &resp);
  473: 
  474:   return status;
  475: }
  476: 
  477: int
  478: yp_first (const char *indomain, const char *inmap, char **outkey,
  479:           int *outkeylen, char **outval, int *outvallen)
  480: {
  481:   ypreq_nokey req;
  482:   ypresp_key_val resp;
  483:   enum clnt_stat result;
  484: 
  485:   if (indomain == NULL || indomain[0] == '\0' ||
  486:       inmap == NULL || inmap[0] == '\0')
  487:     return YPERR_BADARGS;
  488: 
  489:   req.domain = (char *) indomain;
  490:   req.map = (char *) inmap;
  491: 
  492:   *outkey = *outval = NULL;
  493:   *outkeylen = *outvallen = 0;
  494:   memset (&resp, '\0', sizeof (resp));
  495: 
  496:   result = do_ypcall (indomain, YPPROC_FIRST, (xdrproc_t) xdr_ypreq_nokey,
  497:                       (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val,
  498:                       (caddr_t) &resp);
  499: 
  500:   if (result != RPC_SUCCESS)
  501:     return YPERR_RPC;
  502:   if (resp.stat != YP_TRUE)
  503:     return ypprot_err (resp.stat);
  504: 
  505:   int status;
  506:   if (__builtin_expect ((*outkey  = malloc (resp.key.keydat_len + 1)) != NULL
  507:                         && (*outval = malloc (resp.val.valdat_len
  508:                                               + 1)) != NULL, 1))
  509:     {
  510:       *outkeylen = resp.key.keydat_len;
  511:       memcpy (*outkey, resp.key.keydat_val, *outkeylen);
  512:       (*outkey)[*outkeylen] = '\0';
  513: 
  514:       *outvallen = resp.val.valdat_len;
  515:       memcpy (*outval, resp.val.valdat_val, *outvallen);
  516:       (*outval)[*outvallen] = '\0';
  517: 
  518:       status = YPERR_SUCCESS;
  519:     }
  520:   else
  521:     {
  522:       free (*outkey);
  523:       status = YPERR_RESRC;
  524:     }
  525: 
  526:   xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
  527: 
  528:   return status;
  529: }
  530: 
  531: int
  532: yp_next (const char *indomain, const char *inmap, const char *inkey,
  533:          const int inkeylen, char **outkey, int *outkeylen, char **outval,
  534:          int *outvallen)
  535: {
  536:   ypreq_key req;
  537:   ypresp_key_val resp;
  538:   enum clnt_stat result;
  539: 
  540:   if (indomain == NULL || indomain[0] == '\0' ||
  541:       inmap == NULL || inmap[0] == '\0' ||
  542:       inkeylen <= 0 || inkey == NULL || inkey[0] == '\0')
  543:     return YPERR_BADARGS;
  544: 
  545:   req.domain = (char *) indomain;
  546:   req.map = (char *) inmap;
  547:   req.key.keydat_val = (char *) inkey;
  548:   req.key.keydat_len = inkeylen;
  549: 
  550:   *outkey = *outval = NULL;
  551:   *outkeylen = *outvallen = 0;
  552:   memset (&resp, '\0', sizeof (resp));
  553: 
  554:   result = do_ypcall_tr (indomain, YPPROC_NEXT, (xdrproc_t) xdr_ypreq_key,
  555:                          (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val,
  556:                          (caddr_t) &resp);
  557: 
  558:   if (result != YPERR_SUCCESS)
  559:     return result;
  560: 
  561:   int status;
  562:   if (__builtin_expect ((*outkey  = malloc (resp.key.keydat_len + 1)) != NULL
  563:                         && (*outval = malloc (resp.val.valdat_len
  564:                                               + 1)) != NULL, 1))
  565:     {
  566:       *outkeylen = resp.key.keydat_len;
  567:       memcpy (*outkey, resp.key.keydat_val, *outkeylen);
  568:       (*outkey)[*outkeylen] = '\0';
  569: 
  570:       *outvallen = resp.val.valdat_len;
  571:       memcpy (*outval, resp.val.valdat_val, *outvallen);
  572:       (*outval)[*outvallen] = '\0';
  573: 
  574:       status = YPERR_SUCCESS;
  575:     }
  576:   else
  577:     {
  578:       free (*outkey);
  579:       status = YPERR_RESRC;
  580:     }
  581: 
  582:   xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
  583: 
  584:   return status;
  585: }
  586: 
  587: int
  588: yp_master (const char *indomain, const char *inmap, char **outname)
  589: {
  590:   ypreq_nokey req;
  591:   ypresp_master resp;
  592:   enum clnt_stat result;
  593: 
  594:   if (indomain == NULL || indomain[0] == '\0' ||
  595:       inmap == NULL || inmap[0] == '\0')
  596:     return YPERR_BADARGS;
  597: 
  598:   req.domain = (char *) indomain;
  599:   req.map = (char *) inmap;