(yp_all): Remove error message, user should print it.
[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)
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, result;
249
250   try = 0;
251   result = YPERR_YPERR;
252
253   __libc_lock_lock (ypbindlist_lock);
254   if (__ypbindlist != NULL)
255     {
256       ydb = __ypbindlist;
257       while (ydb != NULL)
258         {
259           if (strcmp (domain, ydb->dom_domain) == 0)
260             break;
261           ydb = ydb->dom_pnext;
262         }
263       if (ydb != NULL)
264         use_ypbindlist = TRUE;
265       else
266         __libc_lock_unlock (ypbindlist_lock);
267     }
268   else
269     __libc_lock_unlock (ypbindlist_lock);
270
271   while (try < MAXTRIES && result != RPC_SUCCESS)
272     {
273       if (__yp_bind (domain, &ydb) != 0)
274         {
275           if (use_ypbindlist)
276             __libc_lock_unlock (ypbindlist_lock);
277           return YPERR_DOMAIN;
278         }
279
280       result = clnt_call (ydb->dom_client, prog,
281                           xargs, req, xres, resp, RPCTIMEOUT);
282
283       if (result != RPC_SUCCESS)
284         {
285           clnt_perror (ydb->dom_client, "do_ypcall: clnt_call");
286           ydb->dom_vers = -1;
287           if (!use_ypbindlist)
288             {
289               __yp_unbind (ydb);
290               free (ydb);
291               ydb = NULL;
292             }
293           result = YPERR_RPC;
294         }
295       try++;
296     }
297   if (use_ypbindlist)
298     {
299       __libc_lock_unlock (ypbindlist_lock);
300       use_ypbindlist = FALSE;
301     }
302   else
303     if (ydb != NULL)
304       {
305         __yp_unbind (ydb);
306         free (ydb);
307         ydb = NULL;
308       }
309
310   return result;
311 }
312
313 int
314 yp_bind (const char *indomain)
315 {
316   int status;
317
318   __libc_lock_lock (ypbindlist_lock);
319
320   status = __yp_bind (indomain, &__ypbindlist);
321
322   __libc_lock_unlock (ypbindlist_lock);
323
324   return status;
325 }
326
327 void
328 yp_unbind (const char *indomain)
329 {
330   dom_binding *ydbptr, *ydbptr2;
331
332   __libc_lock_lock (ypbindlist_lock);
333
334   ydbptr2 = NULL;
335   ydbptr = __ypbindlist;
336   while (ydbptr != NULL)
337     {
338       if (strcmp (ydbptr->dom_domain, indomain) == 0)
339         {
340           dom_binding *work;
341
342           work = ydbptr;
343           if (ydbptr2 == NULL)
344             __ypbindlist = __ypbindlist->dom_pnext;
345           else
346             ydbptr2 = ydbptr->dom_pnext;
347           __yp_unbind (work);
348           free (work);
349           break;
350         }
351       ydbptr2 = ydbptr;
352       ydbptr = ydbptr->dom_pnext;
353     }
354
355   __libc_lock_unlock (ypbindlist_lock);
356
357   return;
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
375         *outdomain = __ypdomainname;
376     }
377   else
378     *outdomain = __ypdomainname;
379
380   __libc_lock_unlock (domainname_lock);
381
382   return result;
383 }
384
385 int
386 __yp_check (char **domain)
387 {
388   char *unused;
389
390   if (__ypdomainname[0] == '\0')
391     if (yp_get_default_domain (&unused))
392       return 0;
393     else if (strcmp (__ypdomainname, "(none)") == 0)
394       return 0;
395
396   if (domain)
397     *domain = __ypdomainname;
398
399   if (yp_bind (__ypdomainname) == 0)
400     return 1;
401   return 0;
402 }
403
404 int
405 yp_match (const char *indomain, const char *inmap, const char *inkey,
406           const int inkeylen, char **outval, int *outvallen)
407 {
408   ypreq_key req;
409   ypresp_val resp;
410   int result;
411
412   if (indomain == NULL || indomain[0] == '\0' ||
413       inmap == NULL || inmap[0] == '\0' ||
414       inkey == NULL || inkey[0] == '\0' || inkeylen <= 0)
415     return YPERR_BADARGS;
416
417   req.domain = (char *) indomain;
418   req.map = (char *) inmap;
419   req.key.keydat_val = (char *) inkey;
420   req.key.keydat_len = inkeylen;
421
422   *outval = NULL;
423   *outvallen = 0;
424   memset (&resp, '\0', sizeof (resp));
425
426   result = do_ypcall (indomain, YPPROC_MATCH, (xdrproc_t) xdr_ypreq_key,
427                       (caddr_t) & req, (xdrproc_t) xdr_ypresp_val,
428                       (caddr_t) & resp);
429
430   if (result != RPC_SUCCESS)
431     return result;
432   if (resp.stat != YP_TRUE)
433     return ypprot_err (resp.stat);
434
435   *outvallen = resp.val.valdat_len;
436   *outval = malloc (*outvallen + 1);
437   memcpy (*outval, resp.val.valdat_val, *outvallen);
438   (*outval)[*outvallen] = '\0';
439
440   xdr_free ((xdrproc_t) xdr_ypresp_val, (char *) &resp);
441
442   return YPERR_SUCCESS;
443 }
444
445 int
446 yp_first (const char *indomain, const char *inmap, char **outkey,
447           int *outkeylen, char **outval, int *outvallen)
448 {
449   ypreq_nokey req;
450   ypresp_key_val resp;
451   int result;
452
453   if (indomain == NULL || indomain[0] == '\0' ||
454       inmap == NULL || inmap[0] == '\0')
455     return YPERR_BADARGS;
456
457   req.domain = (char *) indomain;
458   req.map = (char *) inmap;
459
460   *outkey = *outval = NULL;
461   *outkeylen = *outvallen = 0;
462   memset (&resp, '\0', sizeof (resp));
463
464   result = do_ypcall (indomain, YPPROC_FIRST, (xdrproc_t) xdr_ypreq_nokey,
465                       (caddr_t) & req, (xdrproc_t) xdr_ypresp_key_val,
466                       (caddr_t) & resp);
467
468   if (result != RPC_SUCCESS)
469     return result;
470   if (resp.stat != YP_TRUE)
471     return ypprot_err (resp.stat);
472
473   *outkeylen = resp.key.keydat_len;
474   *outkey = malloc (*outkeylen + 1);
475   memcpy (*outkey, resp.key.keydat_val, *outkeylen);
476   (*outkey)[*outkeylen] = '\0';
477   *outvallen = resp.val.valdat_len;
478   *outval = malloc (*outvallen + 1);
479   memcpy (*outval, resp.val.valdat_val, *outvallen);
480   (*outval)[*outvallen] = '\0';
481
482   xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
483
484   return YPERR_SUCCESS;
485 }
486
487 int
488 yp_next (const char *indomain, const char *inmap, const char *inkey,
489          const int inkeylen, char **outkey, int *outkeylen, char **outval,
490          int *outvallen)
491 {
492   ypreq_key req;
493   ypresp_key_val resp;
494   int result;
495
496   if (indomain == NULL || indomain[0] == '\0' ||
497       inmap == NULL || inmap[0] == '\0' ||
498       inkeylen <= 0 || inkey == NULL || inkey[0] == '\0')
499     return YPERR_BADARGS;
500
501   req.domain = (char *) indomain;
502   req.map = (char *) inmap;
503   req.key.keydat_val = (char *) inkey;
504   req.key.keydat_len = inkeylen;
505
506   *outkey = *outval = NULL;
507   *outkeylen = *outvallen = 0;
508   memset (&resp, '\0', sizeof (resp));
509
510   result = do_ypcall (indomain, YPPROC_NEXT, (xdrproc_t) xdr_ypreq_key,
511                       (caddr_t) & req, (xdrproc_t) xdr_ypresp_key_val,
512                       (caddr_t) & resp);
513
514   if (result != RPC_SUCCESS)
515     return result;
516   if (resp.stat != YP_TRUE)
517     return ypprot_err (resp.stat);
518
519   *outkeylen = resp.key.keydat_len;
520   *outkey = malloc (*outkeylen + 1);
521   memcpy (*outkey, resp.key.keydat_val, *outkeylen);
522   (*outkey)[*outkeylen] = '\0';
523   *outvallen = resp.val.valdat_len;
524   *outval = malloc (*outvallen + 1);
525   memcpy (*outval, resp.val.valdat_val, *outvallen);
526   (*outval)[*outvallen] = '\0';
527
528   xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
529
530   return YPERR_SUCCESS;
531 }
532
533 int
534 yp_master (const char *indomain, const char *inmap, char **outname)
535 {
536   ypreq_nokey req;
537   ypresp_master resp;
538   int result;
539
540   if (indomain == NULL || indomain[0] == '\0' ||
541       inmap == NULL || inmap[0] == '\0')
542     return YPERR_BADARGS;
543
544   req.domain = (char *) indomain;
545   req.map = (char *) inmap;
546
547   memset (&resp, '\0', sizeof (ypresp_master));
548
549   result = do_ypcall (indomain, YPPROC_MASTER, (xdrproc_t) xdr_ypreq_nokey,
550           (caddr_t) & req, (xdrproc_t) xdr_ypresp_master, (caddr_t) & resp);
551
552   if (result != RPC_SUCCESS)
553     return result;
554   if (resp.stat != YP_TRUE)
555     return ypprot_err (resp.stat);
556
557   *outname = strdup (resp.peer);
558   xdr_free ((xdrproc_t) xdr_ypresp_master, (char *) &resp);
559
560   return YPERR_SUCCESS;
561 }
562
563 int
564 yp_order (const char *indomain, const char *inmap, unsigned int *outorder)
565 {
566   struct ypreq_nokey req;
567   struct ypresp_order resp;
568   int result;
569
570   if (indomain == NULL || indomain[0] == '\0' ||
571       inmap == NULL || inmap == '\0')
572     return YPERR_BADARGS;
573
574   req.domain = (char *) indomain;
575   req.map = (char *) inmap;
576
577   memset (&resp, '\0', sizeof (resp));
578
579   result = do_ypcall (indomain, YPPROC_ORDER, (xdrproc_t) xdr_ypreq_nokey,
580            (caddr_t) & req, (xdrproc_t) xdr_ypresp_order, (caddr_t) & resp);
581
582   if (result != RPC_SUCCESS)
583     return result;
584   if (resp.stat != YP_TRUE)
585     return ypprot_err (resp.stat);
586
587   *outorder = resp.ordernum;
588   xdr_free ((xdrproc_t) xdr_ypresp_order, (char *) &resp);
589
590   return YPERR_SUCCESS;
591 }
592
593 static void *ypall_data;
594 static int (*ypall_foreach) __P ((int status, char *key, int keylen,
595                                   char *val, int vallen, char *data));
596
597 static bool_t
598 __xdr_ypresp_all (XDR * xdrs, u_long * objp)
599 {
600   while (1)
601     {
602       struct ypresp_all resp;
603
604       memset (&resp, '\0', sizeof (struct ypresp_all));
605       if (!xdr_ypresp_all (xdrs, &resp))
606         {
607           xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
608           *objp = YP_YPERR;
609           return (FALSE);
610         }
611       if (resp.more == 0)
612         {
613           xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
614           *objp = YP_NOMORE;
615           return (FALSE);
616         }
617
618       switch (resp.ypresp_all_u.val.stat)
619         {
620         case YP_TRUE:
621           {
622             char key[resp.ypresp_all_u.val.key.keydat_len + 1];
623             char val[resp.ypresp_all_u.val.val.valdat_len + 1];
624             int keylen = resp.ypresp_all_u.val.key.keydat_len;
625             int vallen = resp.ypresp_all_u.val.val.valdat_len;
626
627             *objp = YP_TRUE;
628             memcpy (key, resp.ypresp_all_u.val.key.keydat_val, keylen);
629             key[keylen] = '\0';
630             memcpy (val, resp.ypresp_all_u.val.val.valdat_val, vallen);
631             val[vallen] = '\0';
632             xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
633             if ((*ypall_foreach) (*objp, key, keylen,
634                                   val, vallen, ypall_data))
635               return TRUE;
636           }
637           break;
638         case YP_NOMORE:
639           *objp = YP_NOMORE;
640           xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
641           return TRUE;
642           break;
643         default:
644           *objp = resp.ypresp_all_u.val.stat;
645           xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
646           return TRUE;
647         }
648     }
649 }
650
651 int
652 yp_all (const char *indomain, const char *inmap,
653         const struct ypall_callback *incallback)
654 {
655   struct ypreq_nokey req;
656   dom_binding *ydb = NULL;
657   int try, result;
658   struct sockaddr_in clnt_sin;
659   CLIENT *clnt;
660   unsigned long status;
661   int clnt_sock;
662
663   if (indomain == NULL || indomain[0] == '\0' ||
664       inmap == NULL || inmap == '\0')
665     return YPERR_BADARGS;
666
667   try = 0;
668   result = YPERR_YPERR;
669
670   while (try < MAXTRIES && result != RPC_SUCCESS)
671     {
672       if (__yp_bind (indomain, &ydb) != 0)
673         {
674           return YPERR_DOMAIN;
675         }
676
677       /* YPPROC_ALL get its own TCP channel to ypserv */
678       clnt_sock = RPC_ANYSOCK;
679       clnt_sin = ydb->dom_server_addr;
680       clnt_sin.sin_port = 0;
681       clnt = clnttcp_create (&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
682       if (clnt == NULL)
683         return YPERR_PMAP;
684       req.domain = (char *) indomain;
685       req.map = (char *) inmap;
686
687       ypall_foreach = incallback->foreach;
688       ypall_data = (void *) incallback->data;
689
690       result = clnt_call (clnt, YPPROC_ALL, (xdrproc_t) xdr_ypreq_nokey,
691                           (caddr_t) &req, (xdrproc_t) __xdr_ypresp_all,
692                           (caddr_t) &status, RPCTIMEOUT);
693
694       clnt_destroy (clnt);
695       close (clnt_sock);
696       if (result != RPC_SUCCESS)
697         {
698           clnt_perror (ydb->dom_client, "yp_all: clnt_call");
699           __yp_unbind (ydb);
700           free (ydb);
701           result = YPERR_RPC;
702         }
703       else
704         result = YPERR_SUCCESS;
705
706       if (status != YP_NOMORE)
707         return ypprot_err (status);
708       try++;
709     }
710
711   return result;
712 }
713
714 int
715 yp_maplist (const char *indomain, struct ypmaplist **outmaplist)
716 {
717   struct ypresp_maplist resp;
718   int result;
719
720   if (indomain == NULL || indomain[0] == '\0')
721     return YPERR_BADARGS;
722
723   memset (&resp, '\0', sizeof (resp));
724
725   result = do_ypcall (indomain, YPPROC_MAPLIST, (xdrproc_t) xdr_domainname,
726     (caddr_t) & indomain, (xdrproc_t) xdr_ypresp_maplist, (caddr_t) & resp);
727
728   if (result != RPC_SUCCESS)
729     return result;
730   if (resp.stat != YP_TRUE)
731     return ypprot_err (resp.stat);
732
733   *outmaplist = resp.maps;
734   /* We give the list not free, this will be done by ypserv
735      xdr_free((xdrproc_t)xdr_ypresp_maplist, (char *)&resp); */
736
737   return YPERR_SUCCESS;
738 }
739
740 const char *
741 yperr_string (const int error)
742 {
743   switch (error)
744     {
745     case YPERR_SUCCESS:
746       return _("Success");
747     case YPERR_BADARGS:
748       return _("Request arguments bad");
749     case YPERR_RPC:
750       return _("RPC failure on NIS operation");
751     case YPERR_DOMAIN:
752       return _("Can't bind to server which serves this domain");
753     case YPERR_MAP:
754       return _("No such map in server's domain");
755     case YPERR_KEY:
756       return _("No such key in map");
757     case YPERR_YPERR:
758       return _("Internal NIS error");
759     case YPERR_RESRC:
760       return _("Local resource allocation failure");
761     case YPERR_NOMORE:
762       return _("No more records in map database");
763     case YPERR_PMAP:
764       return _("Can't communicate with portmapper");
765     case YPERR_YPBIND:
766       return _("Can't communicate with ypbind");
767     case YPERR_YPSERV:
768       return _("Can't communicate with ypserv");
769     case YPERR_NODOM:
770       return _("Local domain name not set");
771     case YPERR_BADDB:
772       return _("NIS map database is bad");
773     case YPERR_VERS:
774       return _("NIS client/server version mismatch - can't supply service");
775     case YPERR_ACCESS:
776       return _("Permission denied");
777     case YPERR_BUSY:
778       return _("Database is busy");
779     }
780   return _("Unknown NIS error code");
781 }
782
783 int
784 ypprot_err (const int code)
785 {
786   switch (code)
787     {
788     case YP_TRUE:
789       return YPERR_SUCCESS;
790     case YP_NOMORE:
791       return YPERR_NOMORE;
792     case YP_FALSE:
793       return YPERR_YPERR;
794     case YP_NOMAP:
795       return YPERR_MAP;
796     case YP_NODOM:
797       return YPERR_DOMAIN;
798     case YP_NOKEY:
799       return YPERR_KEY;
800     case YP_BADOP:
801       return YPERR_YPERR;
802     case YP_BADDB:
803       return YPERR_BADDB;
804     case YP_YPERR:
805       return YPERR_YPERR;
806     case YP_BADARGS:
807       return YPERR_BADARGS;
808     case YP_VERS:
809       return YPERR_VERS;
810     }
811   return YPERR_YPERR;
812 }
813
814 const char *
815 ypbinderr_string (const int error)
816 {
817   switch (error)
818     {
819     case 0:
820       return _("Success");
821     case YPBIND_ERR_ERR:
822       return _("Internal ypbind error");
823     case YPBIND_ERR_NOSERV:
824       return _("Domain not bound");
825     case YPBIND_ERR_RESC:
826       return _("System resource allocation failure");
827     default:
828       return _("Unknown ypbind error");
829     }
830 }
831
832
833 #define WINDOW 60
834
835 int
836 yp_update (char *domain, char *map, unsigned ypop,
837            char *key, int keylen, char *data, int datalen)
838 {
839   union
840     {
841       ypupdate_args update_args;
842       ypdelete_args delete_args;
843     }
844   args;
845   xdrproc_t xdr_argument;
846   unsigned res = 0;
847   CLIENT *clnt;
848   char *master;
849   struct sockaddr saddr;
850   char servername[MAXNETNAMELEN + 1];
851   int r;
852
853   if (!domain || !map || !key || (ypop != YPOP_DELETE && !data))
854     return YPERR_BADARGS;
855
856   args.update_args.mapname = map;
857   args.update_args.key.yp_buf_len = keylen;
858   args.update_args.key.yp_buf_val = key;
859   args.update_args.datum.yp_buf_len = datalen;
860   args.update_args.datum.yp_buf_val = data;
861
862   if ((r = yp_master (domain, map, &master)) != 0)
863     return r;
864
865   if (!host2netname (servername, master, domain))
866     {
867       fputs (_("yp_update: cannot convert host to netname\n"), stderr);
868       return YPERR_YPERR;
869     }
870
871   if ((clnt = clnt_create (master, YPU_PROG, YPU_VERS, "tcp")) == NULL)
872     {
873       clnt_pcreateerror ("yp_update: clnt_create");
874       return YPERR_RPC;
875     }
876
877   if (!clnt_control (clnt, CLGET_SERVER_ADDR, (char *) &saddr))
878     {
879       fputs (_("yp_update: cannot get server address\n"), stderr);
880       return YPERR_RPC;
881     }
882
883   switch (ypop)
884     {
885     case YPOP_CHANGE:
886     case YPOP_INSERT:
887     case YPOP_STORE:
888       xdr_argument = (xdrproc_t) xdr_ypupdate_args;
889       break;
890     case YPOP_DELETE:
891       xdr_argument = (xdrproc_t) xdr_ypdelete_args;
892       break;
893     default:
894       return YPERR_BADARGS;
895       break;
896     }
897
898   clnt->cl_auth = authdes_create (servername, WINDOW, &saddr, NULL);
899
900   if (clnt->cl_auth == NULL)
901     clnt->cl_auth = authunix_create_default ();
902
903 again:
904   r = clnt_call (clnt, ypop, xdr_argument, (caddr_t) &args,
905                  (xdrproc_t) xdr_u_int, (caddr_t) &res, RPCTIMEOUT);
906
907   if (r == RPC_AUTHERROR)
908     {
909       if (clnt->cl_auth->ah_cred.oa_flavor == AUTH_DES)
910         {
911           clnt->cl_auth = authunix_create_default ();
912           goto again;
913         }
914       else
915         return YPERR_ACCESS;
916     }
917   if (r != RPC_SUCCESS)
918     {
919       clnt_perror (clnt, "yp_update: clnt_call");
920       return YPERR_RPC;
921     }
922   return res;
923 }