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