Make sure, that all sockets are closed.
[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               close (clnt_sock);
134               if (is_new)
135                 free (ysd);
136               return YPERR_YPBIND;
137             }
138
139           clnt_destroy (client);
140           close (clnt_sock);
141
142           if (ypbr.ypbind_status != YPBIND_SUCC_VAL)
143             {
144               switch (ypbr.ypbind_resp_u.ypbind_error)
145                 {
146                 case YPBIND_ERR_ERR:
147                   fputs (_("YPBINDPROC_DOMAIN: Internal error\n"), stderr);
148                   break;
149                 case YPBIND_ERR_NOSERV:
150                   fprintf (stderr,
151                            _("YPBINDPROC_DOMAIN: No server for domain %s\n"),
152                            domain);
153                   break;
154                 case YPBIND_ERR_RESC:
155                   fputs (_("YPBINDPROC_DOMAIN: Resource allocation failure\n"),
156                          stderr);
157                   break;
158                 default:
159                   fputs (_("YPBINDPROC_DOMAIN: Unknown error\n"), stderr);
160                   break;
161                 }
162               if (is_new)
163                 free (ysd);
164               return YPERR_DOMAIN;
165             }
166           memset (&ysd->dom_server_addr, '\0', sizeof ysd->dom_server_addr);
167           ysd->dom_server_addr.sin_family = AF_INET;
168           memcpy (&ysd->dom_server_addr.sin_port,
169                   ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
170                   sizeof (ysd->dom_server_addr.sin_port));
171           memcpy (&ysd->dom_server_addr.sin_addr.s_addr,
172                   ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
173                   sizeof (ysd->dom_server_addr.sin_addr.s_addr));
174           ysd->dom_vers = YPVERS;
175           strncpy (ysd->dom_domain, domain, YPMAXDOMAIN);
176           ysd->dom_domain[YPMAXDOMAIN] = '\0';
177         }
178
179       if (ysd->dom_client)
180         {
181           clnt_destroy (ysd->dom_client);
182           close (ysd->dom_socket);
183         }
184       ysd->dom_socket = RPC_ANYSOCK;
185       ysd->dom_client = clntudp_create (&ysd->dom_server_addr, YPPROG, YPVERS,
186                                         TIMEOUT, &ysd->dom_socket);
187       if (ysd->dom_client == NULL)
188         ysd->dom_vers = -1;
189
190     }
191   while (ysd->dom_client == NULL);
192
193   /* If the program exists, close the socket */
194   if (fcntl (ysd->dom_socket, F_SETFD, 1) == -1)
195     perror (_("fcntl: F_SETFD"));
196
197   if (is_new)
198     {
199       ysd->dom_pnext = __ypbindlist;
200       __ypbindlist = ysd;
201     }
202
203   if (NULL != ypdb)
204     *ypdb = ysd;
205
206   return YPERR_SUCCESS;
207 }
208
209 static void
210 __yp_unbind (dom_binding *ydb)
211 {
212   clnt_destroy (ydb->dom_client);
213   ydb->dom_client = NULL;
214   ydb->dom_socket = -1;
215 }
216
217 static int
218 do_ypcall (const char *domain, u_long prog, xdrproc_t xargs,
219            caddr_t req, xdrproc_t xres, caddr_t resp)
220 {
221   dom_binding *ydb = NULL;
222   int try, result;
223
224   try = 0;
225   result = YPERR_YPERR;
226
227   while (try < MAXTRIES && result != RPC_SUCCESS)
228     {
229       __libc_lock_lock (ypbindlist_lock);
230
231       if (__yp_bind (domain, &ydb) != 0)
232         {
233           __libc_lock_unlock (ypbindlist_lock);
234           return YPERR_DOMAIN;
235         }
236
237       result = clnt_call (ydb->dom_client, prog,
238                           xargs, req, xres, resp, TIMEOUT);
239
240       if (result != RPC_SUCCESS)
241         {
242           clnt_perror (ydb->dom_client, "do_ypcall: clnt_call");
243           ydb->dom_vers = -1;
244           __yp_unbind (ydb);
245           result = YPERR_RPC;
246         }
247
248       __libc_lock_unlock (ypbindlist_lock);
249
250       try++;
251     }
252
253   return result;
254 }
255
256 int
257 yp_bind (const char *indomain)
258 {
259   int status;
260
261   __libc_lock_lock (ypbindlist_lock);
262
263   status = __yp_bind (indomain, NULL);
264
265   __libc_lock_unlock (ypbindlist_lock);
266
267   return status;
268 }
269
270 void
271 yp_unbind (const char *indomain)
272 {
273   dom_binding *ydbptr, *ydbptr2;
274
275   __libc_lock_lock (ypbindlist_lock);
276
277   ydbptr2 = NULL;
278   ydbptr = __ypbindlist;
279   while (ydbptr != NULL)
280     {
281       if (strcmp (ydbptr->dom_domain, indomain) == 0)
282         {
283           dom_binding *work;
284
285           work = ydbptr;
286           if (ydbptr2 == NULL)
287             __ypbindlist = __ypbindlist->dom_pnext;
288           else
289             ydbptr2 = ydbptr->dom_pnext;
290           __yp_unbind (work);
291           free (work);
292           break;
293         }
294       ydbptr2 = ydbptr;
295       ydbptr = ydbptr->dom_pnext;
296     }
297
298   __libc_lock_unlock (ypbindlist_lock);
299
300   return;
301 }
302
303 __libc_lock_define_initialized (static, domainname_lock)
304
305 int
306 yp_get_default_domain (char **outdomain)
307 {
308   int result = YPERR_SUCCESS;;
309   *outdomain = NULL;
310
311   __libc_lock_lock (domainname_lock);
312
313   if (__ypdomainname[0] == '\0')
314     {
315       if (getdomainname (__ypdomainname, NIS_MAXNAMELEN))
316         result = YPERR_NODOM;
317       else
318         *outdomain = __ypdomainname;
319     }
320   else
321     *outdomain = __ypdomainname;
322
323   __libc_lock_unlock (domainname_lock);
324
325   return result;
326 }
327
328 int
329 __yp_check (char **domain)
330 {
331   char *unused;
332
333   if (__ypdomainname[0] == '\0')
334     if (yp_get_default_domain (&unused))
335       return 0;
336     else if (strcmp (__ypdomainname, "(none)") == 0)
337       return 0;
338
339   if (domain)
340     *domain = __ypdomainname;
341
342   if (yp_bind (__ypdomainname) == 0)
343     return 1;
344   return 0;
345 }
346
347 int
348 yp_match (const char *indomain, const char *inmap, const char *inkey,
349           const int inkeylen, char **outval, int *outvallen)
350 {
351   ypreq_key req;
352   ypresp_val resp;
353   int result;
354
355   if (indomain == NULL || indomain[0] == '\0' ||
356       inmap == NULL || inmap[0] == '\0' ||
357       inkey == NULL || inkey[0] == '\0' || inkeylen <= 0)
358     return YPERR_BADARGS;
359
360   req.domain = (char *) indomain;
361   req.map = (char *) inmap;
362   req.key.keydat_val = (char *) inkey;
363   req.key.keydat_len = inkeylen;
364
365   *outval = NULL;
366   *outvallen = 0;
367   memset (&resp, '\0', sizeof (resp));
368
369   result = do_ypcall (indomain, YPPROC_MATCH, (xdrproc_t) xdr_ypreq_key,
370                       (caddr_t) & req, (xdrproc_t) xdr_ypresp_val,
371                       (caddr_t) & resp);
372
373   if (result != RPC_SUCCESS)
374     return result;
375   if (resp.stat != YP_TRUE)
376     return ypprot_err (resp.stat);
377
378   *outvallen = resp.val.valdat_len;
379   *outval = malloc (*outvallen + 1);
380   memcpy (*outval, resp.val.valdat_val, *outvallen);
381   (*outval)[*outvallen] = '\0';
382
383   xdr_free ((xdrproc_t) xdr_ypresp_val, (char *) &resp);
384
385   return YPERR_SUCCESS;
386 }
387
388 int
389 yp_first (const char *indomain, const char *inmap, char **outkey,
390           int *outkeylen, char **outval, int *outvallen)
391 {
392   ypreq_nokey req;
393   ypresp_key_val resp;
394   int result;
395
396   if (indomain == NULL || indomain[0] == '\0' ||
397       inmap == NULL || inmap[0] == '\0')
398     return YPERR_BADARGS;
399
400   req.domain = (char *) indomain;
401   req.map = (char *) inmap;
402
403   *outkey = *outval = NULL;
404   *outkeylen = *outvallen = 0;
405   memset (&resp, '\0', sizeof (resp));
406
407   result = do_ypcall (indomain, YPPROC_FIRST, (xdrproc_t) xdr_ypreq_nokey,
408                       (caddr_t) & req, (xdrproc_t) xdr_ypresp_key_val,
409                       (caddr_t) & resp);
410
411   if (result != RPC_SUCCESS)
412     return result;
413   if (resp.stat != YP_TRUE)
414     return ypprot_err (resp.stat);
415
416   *outkeylen = resp.key.keydat_len;
417   *outkey = malloc (*outkeylen + 1);
418   memcpy (*outkey, resp.key.keydat_val, *outkeylen);
419   (*outkey)[*outkeylen] = '\0';
420   *outvallen = resp.val.valdat_len;
421   *outval = malloc (*outvallen + 1);
422   memcpy (*outval, resp.val.valdat_val, *outvallen);
423   (*outval)[*outvallen] = '\0';
424
425   xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
426
427   return YPERR_SUCCESS;
428 }
429
430 int
431 yp_next (const char *indomain, const char *inmap, const char *inkey,
432          const int inkeylen, char **outkey, int *outkeylen, char **outval,
433          int *outvallen)
434 {
435   ypreq_key req;
436   ypresp_key_val resp;
437   int result;
438
439   if (indomain == NULL || indomain[0] == '\0' ||
440       inmap == NULL || inmap[0] == '\0' ||
441       inkeylen <= 0 || inkey == NULL || inkey[0] == '\0')
442     return YPERR_BADARGS;
443
444   req.domain = (char *) indomain;
445   req.map = (char *) inmap;
446   req.key.keydat_val = (char *) inkey;
447   req.key.keydat_len = inkeylen;
448
449   *outkey = *outval = NULL;
450   *outkeylen = *outvallen = 0;
451   memset (&resp, '\0', sizeof (resp));
452
453   result = do_ypcall (indomain, YPPROC_NEXT, (xdrproc_t) xdr_ypreq_key,
454                       (caddr_t) & req, (xdrproc_t) xdr_ypresp_key_val,
455                       (caddr_t) & resp);
456
457   if (result != RPC_SUCCESS)
458     return result;
459   if (resp.stat != YP_TRUE)
460     return ypprot_err (resp.stat);
461
462   *outkeylen = resp.key.keydat_len;
463   *outkey = malloc (*outkeylen + 1);
464   memcpy (*outkey, resp.key.keydat_val, *outkeylen);
465   (*outkey)[*outkeylen] = '\0';
466   *outvallen = resp.val.valdat_len;
467   *outval = malloc (*outvallen + 1);
468   memcpy (*outval, resp.val.valdat_val, *outvallen);
469   (*outval)[*outvallen] = '\0';
470
471   xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
472
473   return YPERR_SUCCESS;
474 }
475
476 int
477 yp_master (const char *indomain, const char *inmap, char **outname)
478 {
479   ypreq_nokey req;
480   ypresp_master resp;
481   int result;
482
483   if (indomain == NULL || indomain[0] == '\0' ||
484       inmap == NULL || inmap[0] == '\0')
485     return YPERR_BADARGS;
486
487   req.domain = (char *) indomain;
488   req.map = (char *) inmap;
489
490   memset (&resp, '\0', sizeof (ypresp_master));
491
492   result = do_ypcall (indomain, YPPROC_MASTER, (xdrproc_t) xdr_ypreq_nokey,
493           (caddr_t) & req, (xdrproc_t) xdr_ypresp_master, (caddr_t) & resp);
494
495   if (result != RPC_SUCCESS)
496     return result;
497   if (resp.stat != YP_TRUE)
498     return ypprot_err (resp.stat);
499
500   *outname = strdup (resp.peer);
501   xdr_free ((xdrproc_t) xdr_ypresp_master, (char *) &resp);
502
503   return YPERR_SUCCESS;
504 }
505
506 int
507 yp_order (const char *indomain, const char *inmap, unsigned int *outorder)
508 {
509   struct ypreq_nokey req;
510   struct ypresp_order resp;
511   int result;
512
513   if (indomain == NULL || indomain[0] == '\0' ||
514       inmap == NULL || inmap == '\0')
515     return YPERR_BADARGS;
516
517   req.domain = (char *) indomain;
518   req.map = (char *) inmap;
519
520   memset (&resp, '\0', sizeof (resp));
521
522   result = do_ypcall (indomain, YPPROC_ORDER, (xdrproc_t) xdr_ypreq_nokey,
523            (caddr_t) & req, (xdrproc_t) xdr_ypresp_order, (caddr_t) & resp);
524
525   if (result != RPC_SUCCESS)
526     return result;
527   if (resp.stat != YP_TRUE)
528     return ypprot_err (resp.stat);
529
530   *outorder = resp.ordernum;
531   xdr_free ((xdrproc_t) xdr_ypresp_order, (char *) &resp);
532
533   return YPERR_SUCCESS;
534 }
535
536 static void *ypall_data;
537 static int (*ypall_foreach) __P ((int status, char *key, int keylen,
538                                   char *val, int vallen, char *data));
539
540 static bool_t
541 __xdr_ypresp_all (XDR * xdrs, u_long * objp)
542 {
543   while (1)
544     {
545       struct ypresp_all resp;
546
547       memset (&resp, '\0', sizeof (struct ypresp_all));
548       if (!xdr_ypresp_all (xdrs, &resp))
549         {
550           xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
551           *objp = YP_YPERR;
552           return (FALSE);
553         }
554       if (resp.more == 0)
555         {
556           xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
557           *objp = YP_NOMORE;
558           return (FALSE);
559         }
560
561       switch (resp.ypresp_all_u.val.stat)
562         {
563         case YP_TRUE:
564           {
565             char key[resp.ypresp_all_u.val.key.keydat_len + 1];
566             char val[resp.ypresp_all_u.val.val.valdat_len + 1];
567             int keylen = resp.ypresp_all_u.val.key.keydat_len;
568             int vallen = resp.ypresp_all_u.val.val.valdat_len;
569
570             *objp = YP_TRUE;
571             memcpy (key, resp.ypresp_all_u.val.key.keydat_val, keylen);
572             key[keylen] = '\0';
573             memcpy (val, resp.ypresp_all_u.val.val.valdat_val, vallen);
574             val[vallen] = '\0';
575             xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
576             if ((*ypall_foreach) (*objp, key, keylen,
577                                   val, vallen, ypall_data))
578               return TRUE;
579           }
580           break;
581         case YP_NOMORE:
582           *objp = YP_NOMORE;
583           xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
584           return TRUE;
585           break;
586         default:
587           *objp = resp.ypresp_all_u.val.stat;
588           xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
589           return TRUE;
590         }
591     }
592 }
593
594 int
595 yp_all (const char *indomain, const char *inmap,
596         const struct ypall_callback *incallback)
597 {
598   struct ypreq_nokey req;
599   dom_binding *ydb;
600   int try, result;
601   struct sockaddr_in clnt_sin;
602   CLIENT *clnt;
603   unsigned long status;
604   int clnt_sock;
605
606   if (indomain == NULL || indomain[0] == '\0' ||
607       inmap == NULL || inmap == '\0')
608     return YPERR_BADARGS;
609
610   try = 0;
611   result = YPERR_YPERR;
612
613   while (try < MAXTRIES && result != RPC_SUCCESS)
614     {
615       __libc_lock_lock (ypbindlist_lock);
616
617       if (__yp_bind (indomain, &ydb) != 0)
618         {
619           __libc_lock_unlock (ypbindlist_lock);
620           return YPERR_DOMAIN;
621         }
622
623       /* YPPROC_ALL get its own TCP channel to ypserv */
624       clnt_sock = RPC_ANYSOCK;
625       clnt_sin = ydb->dom_server_addr;
626       clnt_sin.sin_port = 0;
627       clnt = clnttcp_create (&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
628       if (clnt == NULL)
629         {
630           puts ("yp_all: clnttcp_create failed");
631           __libc_lock_unlock (ypbindlist_lock);
632           return YPERR_PMAP;
633         }
634       req.domain = (char *) indomain;
635       req.map = (char *) inmap;
636
637       ypall_foreach = incallback->foreach;
638       ypall_data = (void *) incallback->data;
639
640       result = clnt_call (clnt, YPPROC_ALL, (xdrproc_t) xdr_ypreq_nokey,
641                           (caddr_t) &req, (xdrproc_t) __xdr_ypresp_all,
642                           (caddr_t) &status, TIMEOUT);
643
644       clnt_destroy (clnt);
645       close (clnt_sock);
646       if (result != RPC_SUCCESS)
647         {
648           clnt_perror (ydb->dom_client, "yp_all: clnt_call");
649           __yp_unbind (ydb);
650           result = YPERR_RPC;
651         }
652       else
653         result = YPERR_SUCCESS;
654
655       __libc_lock_unlock (ypbindlist_lock);
656
657       if (status != YP_NOMORE)
658         return ypprot_err (status);
659       try++;
660     }
661
662   return result;
663 }
664
665 int
666 yp_maplist (const char *indomain, struct ypmaplist **outmaplist)
667 {
668   struct ypresp_maplist resp;
669   int result;
670
671   if (indomain == NULL || indomain[0] == '\0')
672     return YPERR_BADARGS;
673
674   memset (&resp, '\0', sizeof (resp));
675
676   result = do_ypcall (indomain, YPPROC_MAPLIST, (xdrproc_t) xdr_domainname,
677     (caddr_t) & indomain, (xdrproc_t) xdr_ypresp_maplist, (caddr_t) & resp);
678
679   if (result != RPC_SUCCESS)
680     return result;
681   if (resp.stat != YP_TRUE)
682     return ypprot_err (resp.stat);
683
684   *outmaplist = resp.maps;
685   /* We give the list not free, this will be done by ypserv
686      xdr_free((xdrproc_t)xdr_ypresp_maplist, (char *)&resp); */
687
688   return YPERR_SUCCESS;
689 }
690
691 const char *
692 yperr_string (const int error)
693 {
694   switch (error)
695     {
696     case YPERR_SUCCESS:
697       return _("Success");
698     case YPERR_BADARGS:
699       return _("Request arguments bad");
700     case YPERR_RPC:
701       return _("RPC failure on NIS operation");
702     case YPERR_DOMAIN:
703       return _("Can't bind to server which serves this domain");
704     case YPERR_MAP:
705       return _("No such map in server's domain");
706     case YPERR_KEY:
707       return _("No such key in map");
708     case YPERR_YPERR:
709       return _("Internal NIS error");
710     case YPERR_RESRC:
711       return _("Local resource allocation failure");
712     case YPERR_NOMORE:
713       return _("No more records in map database");
714     case YPERR_PMAP:
715       return _("Can't communicate with portmapper");
716     case YPERR_YPBIND:
717       return _("Can't communicate with ypbind");
718     case YPERR_YPSERV:
719       return _("Can't communicate with ypserv");
720     case YPERR_NODOM:
721       return _("Local domain name not set");
722     case YPERR_BADDB:
723       return _("NIS map data base is bad");
724     case YPERR_VERS:
725       return _("NIS client/server version mismatch - can't supply service");
726     case YPERR_ACCESS:
727       return _("Permission denied");
728     case YPERR_BUSY:
729       return _("Database is busy");
730     }
731   return _("Unknown NIS error code");
732 }
733
734 int
735 ypprot_err (const int code)
736 {
737   switch (code)
738     {
739     case YP_TRUE:
740       return YPERR_SUCCESS;
741     case YP_NOMORE:
742       return YPERR_NOMORE;
743     case YP_FALSE:
744       return YPERR_YPERR;
745     case YP_NOMAP:
746       return YPERR_MAP;
747     case YP_NODOM:
748       return YPERR_DOMAIN;
749     case YP_NOKEY:
750       return YPERR_KEY;
751     case YP_BADOP:
752       return YPERR_YPERR;
753     case YP_BADDB:
754       return YPERR_BADDB;
755     case YP_YPERR:
756       return YPERR_YPERR;
757     case YP_BADARGS:
758       return YPERR_BADARGS;
759     case YP_VERS:
760       return YPERR_VERS;
761     }
762   return YPERR_YPERR;
763 }
764
765 const char *
766 ypbinderr_string (const int error)
767 {
768   switch (error)
769     {
770     case 0:
771       return _("Success");
772     case YPBIND_ERR_ERR:
773       return _("Internal ypbind error");
774     case YPBIND_ERR_NOSERV:
775       return _("Domain not bound");
776     case YPBIND_ERR_RESC:
777       return _("System resource allocation failure");
778     default:
779       return _("Unknown ypbind error");
780     }
781 }
782
783
784 #define WINDOW 60
785
786 int
787 yp_update (char *domain, char *map, unsigned ypop,
788            char *key, int keylen, char *data, int datalen)
789 {
790 #if defined (HAVE_SECURE_RPC)
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 #else
876   return YPERR_YPERR;
877 #endif
878 }