Fix getpeerucred and ucred_get
[kopensolaris-gnu/glibc.git] / 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;
600
601   memset (&resp, '\0', sizeof (ypresp_master));
602
603   result = do_ypcall_tr (indomain, YPPROC_MASTER, (xdrproc_t) xdr_ypreq_nokey,
604                          (caddr_t) &req, (xdrproc_t) xdr_ypresp_master,
605                          (caddr_t) &resp);
606
607   if (result != YPERR_SUCCESS)
608     return result;
609
610   *outname = strdup (resp.peer);
611   xdr_free ((xdrproc_t) xdr_ypresp_master, (char *) &resp);
612
613   return *outname == NULL ? YPERR_YPERR : YPERR_SUCCESS;
614 }
615 libnsl_hidden_def (yp_master)
616
617 int
618 yp_order (const char *indomain, const char *inmap, unsigned int *outorder)
619 {
620   struct ypreq_nokey req;
621   struct ypresp_order resp;
622   enum clnt_stat result;
623
624   if (indomain == NULL || indomain[0] == '\0' ||
625       inmap == NULL || inmap[0] == '\0')
626     return YPERR_BADARGS;
627
628   req.domain = (char *) indomain;
629   req.map = (char *) inmap;
630
631   memset (&resp, '\0', sizeof (resp));
632
633   result = do_ypcall_tr (indomain, YPPROC_ORDER, (xdrproc_t) xdr_ypreq_nokey,
634                          (caddr_t) &req, (xdrproc_t) xdr_ypresp_order,
635                          (caddr_t) &resp);
636
637   if (result == YPERR_SUCCESS)
638     return result;
639
640   *outorder = resp.ordernum;
641   xdr_free ((xdrproc_t) xdr_ypresp_order, (char *) &resp);
642
643   return result;
644 }
645
646 struct ypresp_all_data
647 {
648   unsigned long status;
649   void *data;
650   int (*foreach) (int status, char *key, int keylen,
651                   char *val, int vallen, char *data);
652 };
653
654 static bool_t
655 __xdr_ypresp_all (XDR *xdrs, struct ypresp_all_data *objp)
656 {
657   while (1)
658     {
659       struct ypresp_all resp;
660
661       memset (&resp, '\0', sizeof (struct ypresp_all));
662       if (!xdr_ypresp_all (xdrs, &resp))
663         {
664           xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
665           objp->status = YP_YPERR;
666           return FALSE;
667         }
668       if (resp.more == 0)
669         {
670           xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
671           objp->status = YP_NOMORE;
672           return TRUE;
673         }
674
675       switch (resp.ypresp_all_u.val.stat)
676         {
677         case YP_TRUE:
678           {
679             char key[resp.ypresp_all_u.val.key.keydat_len + 1];
680             char val[resp.ypresp_all_u.val.val.valdat_len + 1];
681             int keylen = resp.ypresp_all_u.val.key.keydat_len;
682             int vallen = resp.ypresp_all_u.val.val.valdat_len;
683
684             /* We are not allowed to modify the key and val data.
685                But we are allowed to add data behind the buffer,
686                if we don't modify the length. So add an extra NUL
687                character to avoid trouble with broken code. */
688             objp->status = YP_TRUE;
689             *((char *) __mempcpy (key, resp.ypresp_all_u.val.key.keydat_val,
690                                   keylen)) = '\0';
691             *((char *) __mempcpy (val, resp.ypresp_all_u.val.val.valdat_val,
692                                   vallen)) = '\0';
693             xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
694             if ((*objp->foreach) (objp->status, key, keylen,
695                                   val, vallen, objp->data))
696               return TRUE;
697           }
698           break;
699         default:
700           objp->status = resp.ypresp_all_u.val.stat;
701           xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
702           /* Sun says we don't need to make this call, but must return
703              immediately. Since Solaris makes this call, we will call
704              the callback function, too. */
705           (*objp->foreach) (objp->status, NULL, 0, NULL, 0, objp->data);
706           return TRUE;
707         }
708     }
709 }
710
711 int
712 yp_all (const char *indomain, const char *inmap,
713         const struct ypall_callback *incallback)
714 {
715   struct ypreq_nokey req;
716   dom_binding *ydb = NULL;
717   int try, res;
718   enum clnt_stat result;
719   struct sockaddr_in clnt_sin;
720   CLIENT *clnt;
721   struct ypresp_all_data data;
722   int clnt_sock;
723   int saved_errno = errno;
724
725   if (indomain == NULL || indomain[0] == '\0'
726       || inmap == NULL || inmap[0] == '\0')
727     return YPERR_BADARGS;
728
729   try = 0;
730   res = YPERR_YPERR;
731
732   while (try < MAXTRIES && res != YPERR_SUCCESS)
733     {
734       if (__yp_bind (indomain, &ydb) != 0)
735         {
736           __set_errno (saved_errno);
737           return YPERR_DOMAIN;
738         }
739
740       clnt_sock = RPC_ANYSOCK;
741       clnt_sin = ydb->dom_server_addr;
742       clnt_sin.sin_port = 0;
743
744       /* We don't need the UDP connection anymore.  */
745       __yp_unbind (ydb);
746       ydb = NULL;
747
748       clnt = clnttcp_create (&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
749       if (clnt == NULL)
750         {
751           __set_errno (saved_errno);
752           return YPERR_PMAP;
753         }
754       req.domain = (char *) indomain;
755       req.map = (char *) inmap;
756
757       data.foreach = incallback->foreach;
758       data.data = (void *) incallback->data;
759
760       result = clnt_call (clnt, YPPROC_ALL, (xdrproc_t) xdr_ypreq_nokey,
761                           (caddr_t) &req, (xdrproc_t) __xdr_ypresp_all,
762                           (caddr_t) &data, RPCTIMEOUT);
763
764       if (__builtin_expect (result != RPC_SUCCESS, 0))
765         {
766           /* Print the error message only on the last try.  */
767           if (try == MAXTRIES - 1)
768             clnt_perror (clnt, "yp_all: clnt_call");
769           res = YPERR_RPC;
770         }
771       else
772         res = YPERR_SUCCESS;
773
774       clnt_destroy (clnt);
775
776       if (res == YPERR_SUCCESS && data.status != YP_NOMORE)
777         {
778           __set_errno (saved_errno);
779           return ypprot_err (data.status);
780         }
781       ++try;
782     }
783
784   __set_errno (saved_errno);
785
786   return res;
787 }
788
789 int
790
791 yp_maplist (const char *indomain, struct ypmaplist **outmaplist)
792 {
793   struct ypresp_maplist resp;
794   enum clnt_stat result;
795
796   if (indomain == NULL || indomain[0] == '\0')
797     return YPERR_BADARGS;
798
799   memset (&resp, '\0', sizeof (resp));
800
801   result = do_ypcall_tr (indomain, YPPROC_MAPLIST, (xdrproc_t) xdr_domainname,
802                          (caddr_t) &indomain, (xdrproc_t) xdr_ypresp_maplist,
803                          (caddr_t) &resp);
804
805   if (__builtin_expect (result == YPERR_SUCCESS, 1))
806     {
807       *outmaplist = resp.maps;
808       /* We don't free the list, this will be done by ypserv
809          xdr_free((xdrproc_t)xdr_ypresp_maplist, (char *)&resp); */
810     }
811
812   return result;
813 }
814
815 const char *
816 yperr_string (const int error)
817 {
818   const char *str;
819   switch (error)
820     {
821     case YPERR_SUCCESS:
822       str = N_("Success");
823       break;
824     case YPERR_BADARGS:
825       str = N_("Request arguments bad");
826       break;
827     case YPERR_RPC:
828       str = N_("RPC failure on NIS operation");
829       break;
830     case YPERR_DOMAIN:
831       str = N_("Can't bind to server which serves this domain");
832       break;
833     case YPERR_MAP:
834       str = N_("No such map in server's domain");
835       break;
836     case YPERR_KEY:
837       str = N_("No such key in map");
838       break;
839     case YPERR_YPERR:
840       str = N_("Internal NIS error");
841       break;
842     case YPERR_RESRC:
843       str = N_("Local resource allocation failure");
844       break;
845     case YPERR_NOMORE:
846       str = N_("No more records in map database");
847       break;
848     case YPERR_PMAP:
849       str = N_("Can't communicate with portmapper");
850       break;
851     case YPERR_YPBIND:
852       str = N_("Can't communicate with ypbind");
853       break;
854     case YPERR_YPSERV:
855       str = N_("Can't communicate with ypserv");
856       break;
857     case YPERR_NODOM:
858       str = N_("Local domain name not set");
859       break;
860     case YPERR_BADDB:
861       str = N_("NIS map database is bad");
862       break;
863     case YPERR_VERS:
864       str = N_("NIS client/server version mismatch - can't supply service");
865       break;
866     case YPERR_ACCESS:
867       str = N_("Permission denied");
868       break;
869     case YPERR_BUSY:
870       str = N_("Database is busy");
871       break;
872     default:
873       str = N_("Unknown NIS error code");
874       break;
875     }
876   return _(str);
877 }
878
879 static const int8_t yp_2_yperr[] =
880   {
881 #define YP2YPERR(yp, yperr)  [YP_##yp - YP_VERS] = YPERR_##yperr
882     YP2YPERR (TRUE, SUCCESS),
883     YP2YPERR (NOMORE, NOMORE),
884     YP2YPERR (FALSE, YPERR),
885     YP2YPERR (NOMAP, MAP),
886     YP2YPERR (NODOM, DOMAIN),
887     YP2YPERR (NOKEY, KEY),
888     YP2YPERR (BADOP, YPERR),
889     YP2YPERR (BADDB, BADDB),
890     YP2YPERR (YPERR, YPERR),
891     YP2YPERR (BADARGS, BADARGS),
892     YP2YPERR (VERS, VERS)
893   };
894 int
895 ypprot_err (const int code)
896 {
897   if (code < YP_VERS || code > YP_NOMORE)
898     return YPERR_YPERR;
899   return yp_2_yperr[code - YP_VERS];
900 }
901 libnsl_hidden_def (ypprot_err)
902
903 const char *
904 ypbinderr_string (const int error)
905 {
906   const char *str;
907   switch (error)
908     {
909     case 0:
910       str = N_("Success");
911       break;
912     case YPBIND_ERR_ERR:
913       str = N_("Internal ypbind error");
914       break;
915     case YPBIND_ERR_NOSERV:
916       str = N_("Domain not bound");
917       break;
918     case YPBIND_ERR_RESC:
919       str = N_("System resource allocation failure");
920       break;
921     default:
922       str = N_("Unknown ypbind error");
923       break;
924     }
925   return _(str);
926 }
927 libnsl_hidden_def (ypbinderr_string)
928
929 #define WINDOW 60
930
931 int
932 yp_update (char *domain, char *map, unsigned ypop,
933            char *key, int keylen, char *data, int datalen)
934 {
935   union
936     {
937       ypupdate_args update_args;
938       ypdelete_args delete_args;
939     }
940   args;
941   xdrproc_t xdr_argument;
942   unsigned res = 0;
943   CLIENT *clnt;
944   char *master;
945   struct sockaddr saddr;
946   char servername[MAXNETNAMELEN + 1];
947   int r;
948
949   if (!domain || !map || !key || (ypop != YPOP_DELETE && !data))
950     return YPERR_BADARGS;
951
952   args.update_args.mapname = map;
953   args.update_args.key.yp_buf_len = keylen;
954   args.update_args.key.yp_buf_val = key;
955   args.update_args.datum.yp_buf_len = datalen;
956   args.update_args.datum.yp_buf_val = data;
957
958   if ((r = yp_master (domain, map, &master)) != YPERR_SUCCESS)
959     return r;
960
961   if (!host2netname (servername, master, domain))
962     {
963       fputs (_("yp_update: cannot convert host to netname\n"), stderr);
964       free (master);
965       return YPERR_YPERR;
966     }
967
968   clnt = clnt_create (master, YPU_PROG, YPU_VERS, "tcp");
969
970   /* We do not need the string anymore.  */
971   free (master);
972
973   if (clnt == NULL)
974     {
975       clnt_pcreateerror ("yp_update: clnt_create");
976       return YPERR_RPC;
977     }
978
979   if (!clnt_control (clnt, CLGET_SERVER_ADDR, (char *) &saddr))
980     {
981       fputs (_("yp_update: cannot get server address\n"), stderr);
982       return YPERR_RPC;
983     }
984
985   switch (ypop)
986     {
987     case YPOP_CHANGE:
988     case YPOP_INSERT:
989     case YPOP_STORE:
990       xdr_argument = (xdrproc_t) xdr_ypupdate_args;
991       break;
992     case YPOP_DELETE:
993       xdr_argument = (xdrproc_t) xdr_ypdelete_args;
994       break;
995     default:
996       return YPERR_BADARGS;
997       break;
998     }
999
1000   clnt->cl_auth = authdes_create (servername, WINDOW, &saddr, NULL);
1001
1002   if (clnt->cl_auth == NULL)
1003     clnt->cl_auth = authunix_create_default ();
1004
1005 again:
1006   r = clnt_call (clnt, ypop, xdr_argument, (caddr_t) &args,
1007                  (xdrproc_t) xdr_u_int, (caddr_t) &res, RPCTIMEOUT);
1008
1009   if (r == RPC_AUTHERROR)
1010     {
1011       if (clnt->cl_auth->ah_cred.oa_flavor == AUTH_DES)
1012         {
1013           auth_destroy (clnt->cl_auth);
1014           clnt->cl_auth = authunix_create_default ();
1015           goto again;
1016         }
1017       else
1018         return YPERR_ACCESS;
1019     }
1020   if (r != RPC_SUCCESS)
1021     {
1022       clnt_perror (clnt, "yp_update: clnt_call");
1023       return YPERR_RPC;
1024     }
1025   return res;
1026 }