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