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