(__yp_bind): Expect ypdb parameter to always we != NULL. Remove code
[kopensolaris-gnu/glibc.git] / nis / ypclnt.c
1 /* Copyright (C) 1996-2001, 2002, 2003 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <libintl.h>
25 #include <rpc/rpc.h>
26 #include <rpcsvc/nis.h>
27 #include <rpcsvc/yp.h>
28 #include <rpcsvc/ypclnt.h>
29 #include <rpcsvc/ypupd.h>
30 #include <sys/uio.h>
31 #include <bits/libc-lock.h>
32
33 /* This should only be defined on systems with a BSD compatible ypbind */
34 #ifndef BINDINGDIR
35 # define BINDINGDIR "/var/yp/binding"
36 #endif
37
38 struct dom_binding
39   {
40     struct dom_binding *dom_pnext;
41     char dom_domain[YPMAXDOMAIN + 1];
42     struct sockaddr_in dom_server_addr;
43     int dom_socket;
44     CLIENT *dom_client;
45   };
46 typedef struct dom_binding dom_binding;
47
48 static struct timeval RPCTIMEOUT = {25, 0};
49 static struct timeval UDPTIMEOUT = {5, 0};
50 static int const MAXTRIES = 2;
51 static char __ypdomainname[NIS_MAXNAMELEN + 1] = "\0";
52 __libc_lock_define_initialized (static, ypbindlist_lock)
53 static dom_binding *__ypbindlist = NULL;
54
55
56 static int
57 __yp_bind (const char *domain, dom_binding **ypdb)
58 {
59   struct sockaddr_in clnt_saddr;
60   struct ypbind_resp ypbr;
61   dom_binding *ysd = NULL;
62   int clnt_sock;
63   CLIENT *client;
64   int is_new = 0;
65
66   if (domain == NULL || domain[0] == '\0')
67     return YPERR_BADARGS;
68
69   ysd = *ypdb;
70   while (ysd != NULL)
71     {
72       if (strcmp (domain, ysd->dom_domain) == 0)
73         break;
74       ysd = ysd->dom_pnext;
75     }
76
77   if (ysd == NULL)
78     {
79       is_new = 1;
80       ysd = (dom_binding *) calloc (1, sizeof *ysd);
81       if (__builtin_expect (ysd == NULL, 0))
82         return YPERR_RESRC;
83     }
84
85 #if USE_BINDINGDIR
86   if (ysd->dom_client == NULL)
87     {
88       /* Try binding dir at first if we have no binding */
89       char path[sizeof (BINDINGDIR) + strlen (domain) + 10];
90       struct iovec vec[2];
91       unsigned short port;
92       int fd;
93
94       sprintf (path, "%s/%s.%d", BINDINGDIR, domain, YPBINDVERS);
95       fd = open (path, O_RDONLY);
96       if (fd >= 0)
97         {
98           /* We have a binding file and could save a RPC call */
99           vec[0].iov_base = &port;
100           vec[0].iov_len = sizeof (port);
101           vec[1].iov_base = &ypbr;
102           vec[1].iov_len = sizeof (ypbr);
103
104           if (readv (fd, vec, 2) == sizeof (port) + sizeof (ypbr))
105             {
106               ysd->dom_server_addr.sin_family = AF_INET;
107               memcpy (&ysd->dom_server_addr.sin_port,
108                       ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
109                       sizeof (ysd->dom_server_addr.sin_port));
110               memcpy (&ysd->dom_server_addr.sin_addr.s_addr,
111                       ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
112                       sizeof (ysd->dom_server_addr.sin_addr.s_addr));
113               strncpy (ysd->dom_domain, domain, YPMAXDOMAIN);
114               ysd->dom_domain[YPMAXDOMAIN] = '\0';
115
116               ysd->dom_socket = RPC_ANYSOCK;
117               ysd->dom_client = clntudp_create (&ysd->dom_server_addr, YPPROG,
118                                                 YPVERS, UDPTIMEOUT,
119                                                 &ysd->dom_socket);
120
121               if (ysd->dom_client != NULL)
122                 /* If the program exits, close the socket */
123                 if (fcntl (ysd->dom_socket, F_SETFD, 1) == -1)
124                   perror ("fcntl: F_SETFD");
125             }
126           close (fd);
127         }
128     }
129 #endif /* USE_BINDINGDIR */
130
131   if (ysd->dom_client == NULL)
132     {
133       memset (&clnt_saddr, '\0', sizeof clnt_saddr);
134       clnt_saddr.sin_family = AF_INET;
135       clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
136       clnt_sock = RPC_ANYSOCK;
137       client = clnttcp_create (&clnt_saddr, YPBINDPROG, YPBINDVERS,
138                                &clnt_sock, 0, 0);
139       if (client == NULL)
140         {
141           if (is_new)
142             free (ysd);
143           return YPERR_YPBIND;
144         }
145       /* Check the port number -- should be < IPPORT_RESERVED.
146          If not, it's possible someone has registered a bogus
147          ypbind with the portmapper and is trying to trick us. */
148       if (ntohs (clnt_saddr.sin_port) >= IPPORT_RESERVED)
149         {
150           clnt_destroy (client);
151           if (is_new)
152             free (ysd);
153           return YPERR_YPBIND;
154         }
155
156       if (clnt_call (client, YPBINDPROC_DOMAIN,
157                      (xdrproc_t) xdr_domainname, (caddr_t) &domain,
158                      (xdrproc_t) xdr_ypbind_resp,
159                      (caddr_t) &ypbr, RPCTIMEOUT) != RPC_SUCCESS)
160         {
161           clnt_destroy (client);
162           if (is_new)
163             free (ysd);
164           return YPERR_YPBIND;
165         }
166
167       clnt_destroy (client);
168
169       if (ypbr.ypbind_status != YPBIND_SUCC_VAL)
170         {
171           fprintf (stderr, _("YPBINDPROC_DOMAIN: %s\n"),
172                    ypbinderr_string (ypbr.ypbind_resp_u.ypbind_error));
173           if (is_new)
174             free (ysd);
175           return YPERR_DOMAIN;
176         }
177       memset (&ysd->dom_server_addr, '\0', sizeof ysd->dom_server_addr);
178       ysd->dom_server_addr.sin_family = AF_INET;
179       memcpy (&ysd->dom_server_addr.sin_port,
180               ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
181               sizeof (ysd->dom_server_addr.sin_port));
182       memcpy (&ysd->dom_server_addr.sin_addr.s_addr,
183               ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
184               sizeof (ysd->dom_server_addr.sin_addr.s_addr));
185       strncpy (ysd->dom_domain, domain, YPMAXDOMAIN);
186       ysd->dom_domain[YPMAXDOMAIN] = '\0';
187
188       ysd->dom_socket = RPC_ANYSOCK;
189       ysd->dom_client = clntudp_create (&ysd->dom_server_addr, YPPROG, YPVERS,
190                                         UDPTIMEOUT, &ysd->dom_socket);
191
192       if (ysd->dom_client != NULL)
193         /* If the program exits, close the socket */
194         if (fcntl (ysd->dom_socket, F_SETFD, 1) == -1)
195           perror ("fcntl: F_SETFD");
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   ydb->dom_client = NULL;
219   free (ydb);
220 }
221
222 int
223 yp_bind (const char *indomain)
224 {
225   int status;
226
227   __libc_lock_lock (ypbindlist_lock);
228
229   status = __yp_bind (indomain, &__ypbindlist);
230
231   __libc_lock_unlock (ypbindlist_lock);
232
233   return status;
234 }
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 do_ypcall (const char *domain, u_long prog, xdrproc_t xargs,
277            caddr_t req, xdrproc_t xres, caddr_t resp)
278 {
279   dom_binding *ydb = NULL;
280   bool_t use_ypbindlist = FALSE;
281   int try, status;
282   enum clnt_stat result;
283   int saved_errno = errno;
284
285   try = 0;
286   status = YPERR_YPERR;
287
288   __libc_lock_lock (ypbindlist_lock);
289   if (__ypbindlist != NULL)
290     {
291       ydb = __ypbindlist;
292       while (ydb != NULL)
293         {
294           if (strcmp (domain, ydb->dom_domain) == 0)
295             break;
296           ydb = ydb->dom_pnext;
297         }
298       if (ydb != NULL)
299         use_ypbindlist = TRUE;
300       else
301         __libc_lock_unlock (ypbindlist_lock);
302     }
303   else
304     __libc_lock_unlock (ypbindlist_lock);
305
306   while (try < MAXTRIES && status != YPERR_SUCCESS)
307     {
308       if (__yp_bind (domain, &ydb) != 0)
309         {
310           if (use_ypbindlist)
311             __libc_lock_unlock (ypbindlist_lock);
312           __set_errno (saved_errno);
313           return YPERR_DOMAIN;
314         }
315
316       result = clnt_call (ydb->dom_client, prog,
317                           xargs, req, xres, resp, RPCTIMEOUT);
318
319       if (result != RPC_SUCCESS)
320         {
321           /* Don't print the error message on the first try. It
322              could be that we use cached data which is now invalid. */
323           if (try != 0)
324             clnt_perror (ydb->dom_client, "do_ypcall: clnt_call");
325
326           if (use_ypbindlist)
327             {
328               /* We use ypbindlist, and the old cached data is
329                  invalid. unbind now and create a new binding */
330               yp_unbind_locked (domain);
331               __libc_lock_unlock (ypbindlist_lock);
332               use_ypbindlist = FALSE;
333             }
334           else
335             __yp_unbind (ydb);
336
337           ydb = NULL;
338           status = YPERR_RPC;
339         }
340       else
341         status = YPERR_SUCCESS;
342
343       try++;
344     }
345   if (use_ypbindlist)
346     {
347       __libc_lock_unlock (ypbindlist_lock);
348       use_ypbindlist = FALSE;
349     }
350   else
351     if (ydb != NULL)
352       __yp_unbind (ydb);
353
354   __set_errno (saved_errno);
355
356   return status;
357 }
358
359
360 __libc_lock_define_initialized (static, domainname_lock)
361
362 int
363 yp_get_default_domain (char **outdomain)
364 {
365   int result = YPERR_SUCCESS;;
366   *outdomain = NULL;
367
368   __libc_lock_lock (domainname_lock);
369
370   if (__ypdomainname[0] == '\0')
371     {
372       if (getdomainname (__ypdomainname, NIS_MAXNAMELEN))
373         result = YPERR_NODOM;
374       else if (strcmp (__ypdomainname, "(none)") == 0)
375         {
376           /* If domainname is not set, some systems will return "(none)" */
377           __ypdomainname[0] = '\0';
378           result = YPERR_NODOM;
379         }
380       else
381         *outdomain = __ypdomainname;
382     }
383   else
384     *outdomain = __ypdomainname;
385
386   __libc_lock_unlock (domainname_lock);
387
388   return result;
389 }
390
391 int
392 __yp_check (char **domain)
393 {
394   char *unused;
395
396   if (__ypdomainname[0] == '\0')
397     if (yp_get_default_domain (&unused))
398       return 0;
399
400   if (domain)
401     *domain = __ypdomainname;
402
403   if (yp_bind (__ypdomainname) == 0)
404     return 1;
405   return 0;
406 }
407
408 int
409 yp_match (const char *indomain, const char *inmap, const char *inkey,
410           const int inkeylen, char **outval, int *outvallen)
411 {
412   ypreq_key req;
413   ypresp_val resp;
414   enum clnt_stat result;
415
416   if (indomain == NULL || indomain[0] == '\0' ||
417       inmap == NULL || inmap[0] == '\0' ||
418       inkey == NULL || inkey[0] == '\0' || inkeylen <= 0)
419     return YPERR_BADARGS;
420
421   req.domain = (char *) indomain;
422   req.map = (char *) inmap;
423   req.key.keydat_val = (char *) inkey;
424   req.key.keydat_len = inkeylen;
425
426   *outval = NULL;
427   *outvallen = 0;
428   memset (&resp, '\0', sizeof (resp));
429
430   result = do_ypcall (indomain, YPPROC_MATCH, (xdrproc_t) xdr_ypreq_key,
431                       (caddr_t) & req, (xdrproc_t) xdr_ypresp_val,
432                       (caddr_t) & resp);
433
434   if (result != YPERR_SUCCESS)
435     return result;
436   if (resp.stat != YP_TRUE)
437     return ypprot_err (resp.stat);
438
439   *outvallen = resp.val.valdat_len;
440   *outval = malloc (*outvallen + 1);
441   if (__builtin_expect (*outval == NULL, 0))
442     return YPERR_RESRC;
443   memcpy (*outval, resp.val.valdat_val, *outvallen);
444   (*outval)[*outvallen] = '\0';
445
446   xdr_free ((xdrproc_t) xdr_ypresp_val, (char *) &resp);
447
448   return YPERR_SUCCESS;
449 }
450
451 int
452 yp_first (const char *indomain, const char *inmap, char **outkey,
453           int *outkeylen, char **outval, int *outvallen)
454 {
455   ypreq_nokey req;
456   ypresp_key_val resp;
457   enum clnt_stat result;
458
459   if (indomain == NULL || indomain[0] == '\0' ||
460       inmap == NULL || inmap[0] == '\0')
461     return YPERR_BADARGS;
462
463   req.domain = (char *) indomain;
464   req.map = (char *) inmap;
465
466   *outkey = *outval = NULL;
467   *outkeylen = *outvallen = 0;
468   memset (&resp, '\0', sizeof (resp));
469
470   result = do_ypcall (indomain, YPPROC_FIRST, (xdrproc_t) xdr_ypreq_nokey,
471                       (caddr_t) & req, (xdrproc_t) xdr_ypresp_key_val,
472                       (caddr_t) & resp);
473
474   if (result != RPC_SUCCESS)
475     return YPERR_RPC;
476   if (resp.stat != YP_TRUE)
477     return ypprot_err (resp.stat);
478
479   *outkeylen = resp.key.keydat_len;
480   *outkey = malloc (*outkeylen + 1);
481   if (__builtin_expect (*outkey == NULL, 0))
482     return YPERR_RESRC;
483   memcpy (*outkey, resp.key.keydat_val, *outkeylen);
484   (*outkey)[*outkeylen] = '\0';
485   *outvallen = resp.val.valdat_len;
486   *outval = malloc (*outvallen + 1);
487   if (__builtin_expect (*outval == NULL, 0))
488     return YPERR_RESRC;
489   memcpy (*outval, resp.val.valdat_val, *outvallen);
490   (*outval)[*outvallen] = '\0';
491
492   xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
493
494   return YPERR_SUCCESS;
495 }
496
497 int
498 yp_next (const char *indomain, const char *inmap, const char *inkey,
499          const int inkeylen, char **outkey, int *outkeylen, char **outval,
500          int *outvallen)
501 {
502   ypreq_key req;
503   ypresp_key_val resp;
504   enum clnt_stat result;
505
506   if (indomain == NULL || indomain[0] == '\0' ||
507       inmap == NULL || inmap[0] == '\0' ||
508       inkeylen <= 0 || inkey == NULL || inkey[0] == '\0')
509     return YPERR_BADARGS;
510
511   req.domain = (char *) indomain;
512   req.map = (char *) inmap;
513   req.key.keydat_val = (char *) inkey;
514   req.key.keydat_len = inkeylen;
515
516   *outkey = *outval = NULL;
517   *outkeylen = *outvallen = 0;
518   memset (&resp, '\0', sizeof (resp));
519
520   result = do_ypcall (indomain, YPPROC_NEXT, (xdrproc_t) xdr_ypreq_key,
521                       (caddr_t) & req, (xdrproc_t) xdr_ypresp_key_val,
522                       (caddr_t) & resp);
523
524   if (result != YPERR_SUCCESS)
525     return result;
526   if (resp.stat != YP_TRUE)
527     return ypprot_err (resp.stat);
528
529   *outkeylen = resp.key.keydat_len;
530   *outkey = malloc (*outkeylen + 1);
531   if (__builtin_expect (*outkey == NULL, 0))
532     return YPERR_RESRC;
533   memcpy (*outkey, resp.key.keydat_val, *outkeylen);
534   (*outkey)[*outkeylen] = '\0';
535   *outvallen = resp.val.valdat_len;
536   *outval = malloc (*outvallen + 1);
537   if (__builtin_expect (*outval == NULL, 0))
538     return YPERR_RESRC;
539   memcpy (*outval, resp.val.valdat_val, *outvallen);
540   (*outval)[*outvallen] = '\0';
541
542   xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
543
544   return YPERR_SUCCESS;
545 }
546
547 int
548 yp_master (const char *indomain, const char *inmap, char **outname)
549 {
550   ypreq_nokey req;
551   ypresp_master resp;
552   enum clnt_stat result;
553
554   if (indomain == NULL || indomain[0] == '\0' ||
555       inmap == NULL || inmap[0] == '\0')
556     return YPERR_BADARGS;
557
558   req.domain = (char *) indomain;
559   req.map = (char *) inmap;
560
561   memset (&resp, '\0', sizeof (ypresp_master));
562
563   result = do_ypcall (indomain, YPPROC_MASTER, (xdrproc_t) xdr_ypreq_nokey,
564           (caddr_t) & req, (xdrproc_t) xdr_ypresp_master, (caddr_t) & resp);
565
566   if (result != YPERR_SUCCESS)
567     return result;
568   if (resp.stat != YP_TRUE)
569     return ypprot_err (resp.stat);
570
571   *outname = strdup (resp.peer);
572   xdr_free ((xdrproc_t) xdr_ypresp_master, (char *) &resp);
573
574   return *outname == NULL ? YPERR_YPERR : YPERR_SUCCESS;
575 }
576
577 int
578 yp_order (const char *indomain, const char *inmap, unsigned int *outorder)
579 {
580   struct ypreq_nokey req;
581   struct ypresp_order resp;
582   enum clnt_stat result;
583
584   if (indomain == NULL || indomain[0] == '\0' ||
585       inmap == NULL || inmap == '\0')
586     return YPERR_BADARGS;
587
588   req.domain = (char *) indomain;
589   req.map = (char *) inmap;
590
591   memset (&resp, '\0', sizeof (resp));
592
593   result = do_ypcall (indomain, YPPROC_ORDER, (xdrproc_t) xdr_ypreq_nokey,
594            (caddr_t) & req, (xdrproc_t) xdr_ypresp_order, (caddr_t) & resp);
595
596   if (result != YPERR_SUCCESS)
597     return result;
598   if (resp.stat != YP_TRUE)
599     return ypprot_err (resp.stat);
600
601   *outorder = resp.ordernum;
602   xdr_free ((xdrproc_t) xdr_ypresp_order, (char *) &resp);
603
604   return YPERR_SUCCESS;
605 }
606
607 static void *ypall_data;
608 static int (*ypall_foreach) (int status, char *key, int keylen,
609                              char *val, int vallen, char *data);
610
611 static bool_t
612 __xdr_ypresp_all (XDR *xdrs, u_long *objp)
613 {
614   while (1)
615     {
616       struct ypresp_all resp;
617
618       memset (&resp, '\0', sizeof (struct ypresp_all));
619       if (!xdr_ypresp_all (xdrs, &resp))
620         {
621           xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
622           *objp = YP_YPERR;
623           return FALSE;
624         }
625       if (resp.more == 0)
626         {
627           xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
628           *objp = YP_NOMORE;
629           return TRUE;
630         }
631
632       switch (resp.ypresp_all_u.val.stat)
633         {
634         case YP_TRUE:
635           {
636             char key[resp.ypresp_all_u.val.key.keydat_len + 1];
637             char val[resp.ypresp_all_u.val.val.valdat_len + 1];
638             int keylen = resp.ypresp_all_u.val.key.keydat_len;
639             int vallen = resp.ypresp_all_u.val.val.valdat_len;
640
641             /* We are not allowed to modify the key and val data.
642                But we are allowed to add data behind the buffer,
643                if we don't modify the length. So add an extra NUL
644                character to avoid trouble with broken code. */
645             *objp = YP_TRUE;
646             memcpy (key, resp.ypresp_all_u.val.key.keydat_val, keylen);
647             key[keylen] = '\0';
648             memcpy (val, resp.ypresp_all_u.val.val.valdat_val, vallen);
649             val[vallen] = '\0';
650             xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
651             if ((*ypall_foreach) (*objp, key, keylen,
652                                   val, vallen, ypall_data))
653               return TRUE;
654           }
655           break;
656         default:
657           *objp = resp.ypresp_all_u.val.stat;
658           xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
659           /* Sun says we don't need to make this call, but must return
660              immediatly. Since Solaris makes this call, we will call
661              the callback function, too. */
662           (*ypall_foreach) (*objp, NULL, 0, NULL, 0, ypall_data);
663           return TRUE;
664         }
665     }
666 }
667
668 int
669 yp_all (const char *indomain, const char *inmap,
670         const struct ypall_callback *incallback)
671 {
672   struct ypreq_nokey req;
673   dom_binding *ydb = NULL;
674   int try, res;
675   enum clnt_stat result;
676   struct sockaddr_in clnt_sin;
677   CLIENT *clnt;
678   unsigned long status;
679   int clnt_sock;
680   int saved_errno = errno;
681
682   if (indomain == NULL || indomain[0] == '\0' ||
683       inmap == NULL || inmap == '\0')
684     return YPERR_BADARGS;
685
686   try = 0;
687   res = YPERR_YPERR;
688
689   while (try < MAXTRIES && res != YPERR_SUCCESS)
690     {
691       if (__yp_bind (indomain, &ydb) != 0)
692         {
693           __set_errno (saved_errno);
694           return YPERR_DOMAIN;
695         }
696
697       clnt_sock = RPC_ANYSOCK;
698       clnt_sin = ydb->dom_server_addr;
699       clnt_sin.sin_port = 0;
700
701       /* We don't need the UDP connection anymore.  */
702       __yp_unbind (ydb);
703       ydb = NULL;
704
705       clnt = clnttcp_create (&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
706       if (clnt == NULL)
707         {
708           __set_errno (saved_errno);
709           return YPERR_PMAP;
710         }
711       req.domain = (char *) indomain;
712       req.map = (char *) inmap;
713
714       ypall_foreach = incallback->foreach;
715       ypall_data = (void *) incallback->data;
716
717       result = clnt_call (clnt, YPPROC_ALL, (xdrproc_t) xdr_ypreq_nokey,
718                           (caddr_t) &req, (xdrproc_t) __xdr_ypresp_all,
719                           (caddr_t) &status, RPCTIMEOUT);
720
721       if (result != RPC_SUCCESS)
722         {
723           /* Print the error message only on the last try */
724           if (try == MAXTRIES - 1)
725             clnt_perror (clnt, "yp_all: clnt_call");
726           res = YPERR_RPC;
727         }
728       else
729         res = YPERR_SUCCESS;
730
731       clnt_destroy (clnt);
732
733       if (res == YPERR_SUCCESS && status != YP_NOMORE)
734         {
735           __set_errno (saved_errno);
736           return ypprot_err (status);
737         }
738       ++try;
739     }
740
741   __set_errno (saved_errno);
742
743   return res;
744 }
745
746 int
747 yp_maplist (const char *indomain, struct ypmaplist **outmaplist)
748 {
749   struct ypresp_maplist resp;
750   enum clnt_stat result;
751
752   if (indomain == NULL || indomain[0] == '\0')
753     return YPERR_BADARGS;
754
755   memset (&resp, '\0', sizeof (resp));
756
757   result = do_ypcall (indomain, YPPROC_MAPLIST, (xdrproc_t) xdr_domainname,
758     (caddr_t) & indomain, (xdrproc_t) xdr_ypresp_maplist, (caddr_t) & resp);
759
760   if (result != YPERR_SUCCESS)
761     return result;
762   if (resp.stat != YP_TRUE)
763     return ypprot_err (resp.stat);
764
765   *outmaplist = resp.maps;
766   /* We give the list not free, this will be done by ypserv
767      xdr_free((xdrproc_t)xdr_ypresp_maplist, (char *)&resp); */
768
769   return YPERR_SUCCESS;
770 }
771
772 const char *
773 yperr_string (const int error)
774 {
775   switch (error)
776     {
777     case YPERR_SUCCESS:
778       return _("Success");
779     case YPERR_BADARGS:
780       return _("Request arguments bad");
781     case YPERR_RPC:
782       return _("RPC failure on NIS operation");
783     case YPERR_DOMAIN:
784       return _("Can't bind to server which serves this domain");
785     case YPERR_MAP:
786       return _("No such map in server's domain");
787     case YPERR_KEY:
788       return _("No such key in map");
789     case YPERR_YPERR:
790       return _("Internal NIS error");
791     case YPERR_RESRC:
792       return _("Local resource allocation failure");
793     case YPERR_NOMORE:
794       return _("No more records in map database");
795     case YPERR_PMAP:
796       return _("Can't communicate with portmapper");
797     case YPERR_YPBIND:
798       return _("Can't communicate with ypbind");
799     case YPERR_YPSERV:
800       return _("Can't communicate with ypserv");
801     case YPERR_NODOM:
802       return _("Local domain name not set");
803     case YPERR_BADDB:
804       return _("NIS map database is bad");
805     case YPERR_VERS:
806       return _("NIS client/server version mismatch - can't supply service");
807     case YPERR_ACCESS:
808       return _("Permission denied");
809     case YPERR_BUSY:
810       return _("Database is busy");
811     }
812   return _("Unknown NIS error code");
813 }
814
815 int
816 ypprot_err (const int code)
817 {
818   switch (code)
819     {
820     case YP_TRUE:
821       return YPERR_SUCCESS;
822     case YP_NOMORE:
823       return YPERR_NOMORE;
824     case YP_FALSE:
825       return YPERR_YPERR;
826     case YP_NOMAP:
827       return YPERR_MAP;
828     case YP_NODOM:
829       return YPERR_DOMAIN;
830     case YP_NOKEY:
831       return YPERR_KEY;
832     case YP_BADOP:
833       return YPERR_YPERR;
834     case YP_BADDB:
835       return YPERR_BADDB;
836     case YP_YPERR:
837       return YPERR_YPERR;
838     case YP_BADARGS:
839       return YPERR_BADARGS;
840     case YP_VERS:
841       return YPERR_VERS;
842     }
843   return YPERR_YPERR;
844 }
845
846 const char *
847 ypbinderr_string (const int error)
848 {
849   switch (error)
850     {
851     case 0:
852       return _("Success");
853     case YPBIND_ERR_ERR:
854       return _("Internal ypbind error");
855     case YPBIND_ERR_NOSERV:
856       return _("Domain not bound");
857     case YPBIND_ERR_RESC:
858       return _("System resource allocation failure");
859     default:
860       return _("Unknown ypbind error");
861     }
862 }
863
864
865 #define WINDOW 60
866
867 int
868 yp_update (char *domain, char *map, unsigned ypop,
869            char *key, int keylen, char *data, int datalen)
870 {
871   union
872     {
873       ypupdate_args update_args;
874       ypdelete_args delete_args;
875     }
876   args;
877   xdrproc_t xdr_argument;
878   unsigned res = 0;
879   CLIENT *clnt;
880   char *master;
881   struct sockaddr saddr;
882   char servername[MAXNETNAMELEN + 1];
883   int r;
884
885   if (!domain || !map || !key || (ypop != YPOP_DELETE && !data))
886     return YPERR_BADARGS;
887
888   args.update_args.mapname = map;
889   args.update_args.key.yp_buf_len = keylen;
890   args.update_args.key.yp_buf_val = key;
891   args.update_args.datum.yp_buf_len = datalen;
892   args.update_args.datum.yp_buf_val = data;
893
894   if ((r = yp_master (domain, map, &master)) != 0)
895     return r;
896
897   if (!host2netname (servername, master, domain))
898     {
899       fputs (_("yp_update: cannot convert host to netname\n"), stderr);
900       return YPERR_YPERR;
901     }
902
903   if ((clnt = clnt_create (master, YPU_PROG, YPU_VERS, "tcp")) == NULL)
904     {
905       clnt_pcreateerror ("yp_update: clnt_create");
906       return YPERR_RPC;
907     }
908
909   if (!clnt_control (clnt, CLGET_SERVER_ADDR, (char *) &saddr))
910     {
911       fputs (_("yp_update: cannot get server address\n"), stderr);
912       return YPERR_RPC;
913     }
914
915   switch (ypop)
916     {
917     case YPOP_CHANGE:
918     case YPOP_INSERT:
919     case YPOP_STORE:
920       xdr_argument = (xdrproc_t) xdr_ypupdate_args;
921       break;
922     case YPOP_DELETE:
923       xdr_argument = (xdrproc_t) xdr_ypdelete_args;
924       break;
925     default:
926       return YPERR_BADARGS;
927       break;
928     }
929
930   clnt->cl_auth = authdes_create (servername, WINDOW, &saddr, NULL);
931
932   if (clnt->cl_auth == NULL)
933     clnt->cl_auth = authunix_create_default ();
934
935 again:
936   r = clnt_call (clnt, ypop, xdr_argument, (caddr_t) &args,
937                  (xdrproc_t) xdr_u_int, (caddr_t) &res, RPCTIMEOUT);
938
939   if (r == RPC_AUTHERROR)
940     {
941       if (clnt->cl_auth->ah_cred.oa_flavor == AUTH_DES)
942         {
943           clnt->cl_auth = authunix_create_default ();
944           goto again;
945         }
946       else
947         return YPERR_ACCESS;
948     }
949   if (r != RPC_SUCCESS)
950     {
951       clnt_perror (clnt, "yp_update: clnt_call");
952       return YPERR_RPC;
953     }
954   return res;
955 }