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