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