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