]> git.ipfire.org Git - thirdparty/glibc.git/blob - nis/ypclnt.c
(yp_2_yperr): Revert 2004-11-30 patch. (ypprot_err): Use yp_2_yperr table also for...
[thirdparty/glibc.git] / nis / ypclnt.c
1 /* Copyright (C) 1996-2001, 2002, 2003, 2004, 2005
2 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996.
5
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA. */
20
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <libintl.h>
26 #include <rpc/rpc.h>
27 #include <rpcsvc/nis.h>
28 #include <rpcsvc/yp.h>
29 #include <rpcsvc/ypclnt.h>
30 #include <rpcsvc/ypupd.h>
31 #include <sys/uio.h>
32 #include <bits/libc-lock.h>
33
34 /* This should only be defined on systems with a BSD compatible ypbind */
35 #ifndef BINDINGDIR
36 # define BINDINGDIR "/var/yp/binding"
37 #endif
38
39 struct dom_binding
40 {
41 struct dom_binding *dom_pnext;
42 char dom_domain[YPMAXDOMAIN + 1];
43 struct sockaddr_in dom_server_addr;
44 int dom_socket;
45 CLIENT *dom_client;
46 };
47 typedef struct dom_binding dom_binding;
48
49 static struct timeval RPCTIMEOUT = {25, 0};
50 static struct timeval UDPTIMEOUT = {5, 0};
51 static int const MAXTRIES = 2;
52 static char __ypdomainname[NIS_MAXNAMELEN + 1] = "\0";
53 __libc_lock_define_initialized (static, ypbindlist_lock)
54 static dom_binding *__ypbindlist = NULL;
55
56
57 static void
58 yp_bind_client_create (const char *domain, dom_binding *ysd,
59 struct ypbind_resp *ypbr)
60 {
61 ysd->dom_server_addr.sin_family = AF_INET;
62 memcpy (&ysd->dom_server_addr.sin_port,
63 ypbr->ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
64 sizeof (ysd->dom_server_addr.sin_port));
65 memcpy (&ysd->dom_server_addr.sin_addr.s_addr,
66 ypbr->ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
67 sizeof (ysd->dom_server_addr.sin_addr.s_addr));
68 strncpy (ysd->dom_domain, domain, YPMAXDOMAIN);
69 ysd->dom_domain[YPMAXDOMAIN] = '\0';
70
71 ysd->dom_socket = RPC_ANYSOCK;
72 ysd->dom_client = clntudp_create (&ysd->dom_server_addr, YPPROG, YPVERS,
73 UDPTIMEOUT, &ysd->dom_socket);
74
75 if (ysd->dom_client != NULL)
76 {
77 /* If the program exits, close the socket */
78 if (fcntl (ysd->dom_socket, F_SETFD, FD_CLOEXEC) == -1)
79 perror ("fcntl: F_SETFD");
80 }
81 }
82
83 #if USE_BINDINGDIR
84 static void
85 yp_bind_file (const char *domain, dom_binding *ysd)
86 {
87 char path[sizeof (BINDINGDIR) + strlen (domain) + 3 * sizeof (unsigned) + 3];
88
89 snprintf (path, sizeof (path), "%s/%s.%u", BINDINGDIR, domain, YPBINDVERS);
90 int fd = open (path, O_RDONLY);
91 if (fd >= 0)
92 {
93 /* We have a binding file and could save a RPC call. The file
94 contains a port number and the YPBIND_RESP record. The port
95 number (16 bits) can be ignored. */
96 struct ypbind_resp ypbr;
97
98 if (pread (fd, &ypbr, sizeof (ypbr), 2) == sizeof (ypbr))
99 yp_bind_client_create (domain, ysd, &ypbr);
100
101 close (fd);
102 }
103 }
104 #endif
105
106 static int
107 yp_bind_ypbindprog (const char *domain, dom_binding *ysd)
108 {
109 struct sockaddr_in clnt_saddr;
110 struct ypbind_resp ypbr;
111 int clnt_sock;
112 CLIENT *client;
113
114 memset (&clnt_saddr, '\0', sizeof clnt_saddr);
115 clnt_saddr.sin_family = AF_INET;
116 clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
117 clnt_sock = RPC_ANYSOCK;
118 client = clnttcp_create (&clnt_saddr, YPBINDPROG, YPBINDVERS,
119 &clnt_sock, 0, 0);
120 if (client == NULL)
121 return YPERR_YPBIND;
122
123 /* Check the port number -- should be < IPPORT_RESERVED.
124 If not, it's possible someone has registered a bogus
125 ypbind with the portmapper and is trying to trick us. */
126 if (ntohs (clnt_saddr.sin_port) >= IPPORT_RESERVED)
127 {
128 clnt_destroy (client);
129 return YPERR_YPBIND;
130 }
131
132 if (clnt_call (client, YPBINDPROC_DOMAIN,
133 (xdrproc_t) xdr_domainname, (caddr_t) &domain,
134 (xdrproc_t) xdr_ypbind_resp,
135 (caddr_t) &ypbr, RPCTIMEOUT) != RPC_SUCCESS)
136 {
137 clnt_destroy (client);
138 return YPERR_YPBIND;
139 }
140
141 clnt_destroy (client);
142
143 if (ypbr.ypbind_status != YPBIND_SUCC_VAL)
144 {
145 fprintf (stderr, _("YPBINDPROC_DOMAIN: %s\n"),
146 ypbinderr_string (ypbr.ypbind_resp_u.ypbind_error));
147 return YPERR_DOMAIN;
148 }
149 memset (&ysd->dom_server_addr, '\0', sizeof ysd->dom_server_addr);
150
151 yp_bind_client_create (domain, ysd, &ypbr);
152
153 return YPERR_SUCCESS;
154 }
155
156 static int
157 __yp_bind (const char *domain, dom_binding **ypdb)
158 {
159 dom_binding *ysd = NULL;
160 int is_new = 0;
161
162 if (domain == NULL || domain[0] == '\0')
163 return YPERR_BADARGS;
164
165 ysd = *ypdb;
166 while (ysd != NULL)
167 {
168 if (strcmp (domain, ysd->dom_domain) == 0)
169 break;
170 ysd = ysd->dom_pnext;
171 }
172
173 if (ysd == NULL)
174 {
175 is_new = 1;
176 ysd = (dom_binding *) calloc (1, sizeof *ysd);
177 if (__builtin_expect (ysd == NULL, 0))
178 return YPERR_RESRC;
179 }
180
181 #if USE_BINDINGDIR
182 /* Try binding dir at first if we have no binding */
183 if (ysd->dom_client == NULL)
184 yp_bind_file (domain, ysd);
185 #endif /* USE_BINDINGDIR */
186
187 if (ysd->dom_client == NULL)
188 {
189 int retval = yp_bind_ypbindprog (domain, ysd);
190 if (retval != YPERR_SUCCESS)
191 {
192 if (is_new)
193 free (ysd);
194 return retval;
195 }
196 }
197
198 if (ysd->dom_client == NULL)
199 {
200 if (is_new)
201 free (ysd);
202 return YPERR_YPSERV;
203 }
204
205 if (is_new)
206 {
207 ysd->dom_pnext = *ypdb;
208 *ypdb = ysd;
209 }
210
211 return YPERR_SUCCESS;
212 }
213
214 static void
215 __yp_unbind (dom_binding *ydb)
216 {
217 clnt_destroy (ydb->dom_client);
218 free (ydb);
219 }
220
221 int
222 yp_bind (const char *indomain)
223 {
224 int status;
225
226 __libc_lock_lock (ypbindlist_lock);
227
228 status = __yp_bind (indomain, &__ypbindlist);
229
230 __libc_lock_unlock (ypbindlist_lock);
231
232 return status;
233 }
234 libnsl_hidden_def (yp_bind)
235
236 static void
237 yp_unbind_locked (const char *indomain)
238 {
239 dom_binding *ydbptr, *ydbptr2;
240
241 ydbptr2 = NULL;
242 ydbptr = __ypbindlist;
243
244 while (ydbptr != NULL)
245 {
246 if (strcmp (ydbptr->dom_domain, indomain) == 0)
247 {
248 dom_binding *work;
249
250 work = ydbptr;
251 if (ydbptr2 == NULL)
252 __ypbindlist = __ypbindlist->dom_pnext;
253 else
254 ydbptr2 = ydbptr->dom_pnext;
255 __yp_unbind (work);
256 break;
257 }
258 ydbptr2 = ydbptr;
259 ydbptr = ydbptr->dom_pnext;
260 }
261 }
262
263 void
264 yp_unbind (const char *indomain)
265 {
266 __libc_lock_lock (ypbindlist_lock);
267
268 yp_unbind_locked (indomain);
269
270 __libc_lock_unlock (ypbindlist_lock);
271
272 return;
273 }
274
275 static int
276 __ypclnt_call (const char *domain, u_long prog, xdrproc_t xargs,
277 caddr_t req, xdrproc_t xres, caddr_t resp, dom_binding **ydb,
278 int print_error)
279 {
280 enum clnt_stat result;
281
282 result = clnt_call ((*ydb)->dom_client, prog,
283 xargs, req, xres, resp, RPCTIMEOUT);
284
285 if (result != RPC_SUCCESS)
286 {
287 /* We don't print an error message, if we try our old,
288 cached data. Only print this for data, which should work. */
289 if (print_error)
290 clnt_perror ((*ydb)->dom_client, "do_ypcall: clnt_call");
291
292 return YPERR_RPC;
293 }
294
295 return YPERR_SUCCESS;
296 }
297
298 static int
299 do_ypcall (const char *domain, u_long prog, xdrproc_t xargs,
300 caddr_t req, xdrproc_t xres, caddr_t resp)
301 {
302 dom_binding *ydb;
303 int status;
304 int saved_errno = errno;
305
306 status = YPERR_YPERR;
307
308 __libc_lock_lock (ypbindlist_lock);
309 ydb = __ypbindlist;
310 while (ydb != NULL)
311 {
312 if (strcmp (domain, ydb->dom_domain) == 0)
313 {
314 if (__yp_bind (domain, &ydb) == 0)
315 {
316 /* Call server, print no error message, do not unbind. */
317 status = __ypclnt_call (domain, prog, xargs, req, xres,
318 resp, &ydb, 0);
319 if (status == YPERR_SUCCESS)
320 {
321 __libc_lock_unlock (ypbindlist_lock);
322 __set_errno (saved_errno);
323 return status;
324 }
325 }
326 /* We use ypbindlist, and the old cached data is
327 invalid. unbind now and create a new binding */
328 yp_unbind_locked (domain);
329
330 break;
331 }
332 ydb = ydb->dom_pnext;
333 }
334 __libc_lock_unlock (ypbindlist_lock);
335
336 /* First try with cached data failed. Now try to get
337 current data from the system. */
338 ydb = NULL;
339 if (__yp_bind (domain, &ydb) == 0)
340 {
341 status = __ypclnt_call (domain, prog, xargs, req, xres,
342 resp, &ydb, 1);
343 __yp_unbind (ydb);
344 }
345
346 #if USE_BINDINGDIR
347 /* If we support binding dir data, we have a third chance:
348 Ask ypbind. */
349 if (status != YPERR_SUCCESS)
350 {
351 ydb = calloc (1, sizeof (dom_binding));
352 if (yp_bind_ypbindprog (domain, ydb) == YPERR_SUCCESS)
353 {
354 status = __ypclnt_call (domain, prog, xargs, req, xres,
355 resp, &ydb, 1);
356 __yp_unbind (ydb);
357 }
358 else
359 free (ydb);
360 }
361 #endif
362
363 __set_errno (saved_errno);
364
365 return status;
366 }
367
368
369 __libc_lock_define_initialized (static, domainname_lock)
370
371 int
372 yp_get_default_domain (char **outdomain)
373 {
374 int result = YPERR_SUCCESS;;
375 *outdomain = NULL;
376
377 __libc_lock_lock (domainname_lock);
378
379 if (__ypdomainname[0] == '\0')
380 {
381 if (getdomainname (__ypdomainname, NIS_MAXNAMELEN))
382 result = YPERR_NODOM;
383 else if (strcmp (__ypdomainname, "(none)") == 0)
384 {
385 /* If domainname is not set, some systems will return "(none)" */
386 __ypdomainname[0] = '\0';
387 result = YPERR_NODOM;
388 }
389 else
390 *outdomain = __ypdomainname;
391 }
392 else
393 *outdomain = __ypdomainname;
394
395 __libc_lock_unlock (domainname_lock);
396
397 return result;
398 }
399 libnsl_hidden_def (yp_get_default_domain)
400
401 int
402 __yp_check (char **domain)
403 {
404 char *unused;
405
406 if (__ypdomainname[0] == '\0')
407 if (yp_get_default_domain (&unused))
408 return 0;
409
410 if (domain)
411 *domain = __ypdomainname;
412
413 if (yp_bind (__ypdomainname) == 0)
414 return 1;
415 return 0;
416 }
417
418 int
419 yp_match (const char *indomain, const char *inmap, const char *inkey,
420 const int inkeylen, char **outval, int *outvallen)
421 {
422 ypreq_key req;
423 ypresp_val resp;
424 enum clnt_stat result;
425
426 if (indomain == NULL || indomain[0] == '\0' ||
427 inmap == NULL || inmap[0] == '\0' ||
428 inkey == NULL || inkey[0] == '\0' || inkeylen <= 0)
429 return YPERR_BADARGS;
430
431 req.domain = (char *) indomain;
432 req.map = (char *) inmap;
433 req.key.keydat_val = (char *) inkey;
434 req.key.keydat_len = inkeylen;
435
436 *outval = NULL;
437 *outvallen = 0;
438 memset (&resp, '\0', sizeof (resp));
439
440 result = do_ypcall (indomain, YPPROC_MATCH, (xdrproc_t) xdr_ypreq_key,
441 (caddr_t) & req, (xdrproc_t) xdr_ypresp_val,
442 (caddr_t) & resp);
443
444 if (result != YPERR_SUCCESS)
445 return result;
446 if (resp.stat != YP_TRUE)
447 return ypprot_err (resp.stat);
448
449 *outvallen = resp.val.valdat_len;
450 *outval = malloc (*outvallen + 1);
451 if (__builtin_expect (*outval == NULL, 0))
452 return YPERR_RESRC;
453 memcpy (*outval, resp.val.valdat_val, *outvallen);
454 (*outval)[*outvallen] = '\0';
455
456 xdr_free ((xdrproc_t) xdr_ypresp_val, (char *) &resp);
457
458 return YPERR_SUCCESS;
459 }
460
461 int
462 yp_first (const char *indomain, const char *inmap, char **outkey,
463 int *outkeylen, char **outval, int *outvallen)
464 {
465 ypreq_nokey req;
466 ypresp_key_val resp;
467 enum clnt_stat result;
468
469 if (indomain == NULL || indomain[0] == '\0' ||
470 inmap == NULL || inmap[0] == '\0')
471 return YPERR_BADARGS;
472
473 req.domain = (char *) indomain;
474 req.map = (char *) inmap;
475
476 *outkey = *outval = NULL;
477 *outkeylen = *outvallen = 0;
478 memset (&resp, '\0', sizeof (resp));
479
480 result = do_ypcall (indomain, YPPROC_FIRST, (xdrproc_t) xdr_ypreq_nokey,
481 (caddr_t) & req, (xdrproc_t) xdr_ypresp_key_val,
482 (caddr_t) & resp);
483
484 if (result != RPC_SUCCESS)
485 return YPERR_RPC;
486 if (resp.stat != YP_TRUE)
487 return ypprot_err (resp.stat);
488
489 *outkeylen = resp.key.keydat_len;
490 *outkey = malloc (*outkeylen + 1);
491 if (__builtin_expect (*outkey == NULL, 0))
492 return YPERR_RESRC;
493 memcpy (*outkey, resp.key.keydat_val, *outkeylen);
494 (*outkey)[*outkeylen] = '\0';
495 *outvallen = resp.val.valdat_len;
496 *outval = malloc (*outvallen + 1);
497 if (__builtin_expect (*outval == NULL, 0))
498 return YPERR_RESRC;
499 memcpy (*outval, resp.val.valdat_val, *outvallen);
500 (*outval)[*outvallen] = '\0';
501
502 xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
503
504 return YPERR_SUCCESS;
505 }
506
507 int
508 yp_next (const char *indomain, const char *inmap, const char *inkey,
509 const int inkeylen, char **outkey, int *outkeylen, char **outval,
510 int *outvallen)
511 {
512 ypreq_key req;
513 ypresp_key_val resp;
514 enum clnt_stat result;
515
516 if (indomain == NULL || indomain[0] == '\0' ||
517 inmap == NULL || inmap[0] == '\0' ||
518 inkeylen <= 0 || inkey == NULL || inkey[0] == '\0')
519 return YPERR_BADARGS;
520
521 req.domain = (char *) indomain;
522 req.map = (char *) inmap;
523 req.key.keydat_val = (char *) inkey;
524 req.key.keydat_len = inkeylen;
525
526 *outkey = *outval = NULL;
527 *outkeylen = *outvallen = 0;
528 memset (&resp, '\0', sizeof (resp));
529
530 result = do_ypcall (indomain, YPPROC_NEXT, (xdrproc_t) xdr_ypreq_key,
531 (caddr_t) & req, (xdrproc_t) xdr_ypresp_key_val,
532 (caddr_t) & resp);
533
534 if (result != YPERR_SUCCESS)
535 return result;
536 if (resp.stat != YP_TRUE)
537 return ypprot_err (resp.stat);
538
539 *outkeylen = resp.key.keydat_len;
540 *outkey = malloc (*outkeylen + 1);
541 if (__builtin_expect (*outkey == NULL, 0))
542 return YPERR_RESRC;
543 memcpy (*outkey, resp.key.keydat_val, *outkeylen);
544 (*outkey)[*outkeylen] = '\0';
545 *outvallen = resp.val.valdat_len;
546 *outval = malloc (*outvallen + 1);
547 if (__builtin_expect (*outval == NULL, 0))
548 return YPERR_RESRC;
549 memcpy (*outval, resp.val.valdat_val, *outvallen);
550 (*outval)[*outvallen] = '\0';
551
552 xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
553
554 return YPERR_SUCCESS;
555 }
556
557 int
558 yp_master (const char *indomain, const char *inmap, char **outname)
559 {
560 ypreq_nokey req;
561 ypresp_master resp;
562 enum clnt_stat result;
563
564 if (indomain == NULL || indomain[0] == '\0' ||
565 inmap == NULL || inmap[0] == '\0')
566 return YPERR_BADARGS;
567
568 req.domain = (char *) indomain;
569 req.map = (char *) inmap;
570
571 memset (&resp, '\0', sizeof (ypresp_master));
572
573 result = do_ypcall (indomain, YPPROC_MASTER, (xdrproc_t) xdr_ypreq_nokey,
574 (caddr_t) & req, (xdrproc_t) xdr_ypresp_master, (caddr_t) & resp);
575
576 if (result != YPERR_SUCCESS)
577 return result;
578 if (resp.stat != YP_TRUE)
579 return ypprot_err (resp.stat);
580
581 *outname = strdup (resp.peer);
582 xdr_free ((xdrproc_t) xdr_ypresp_master, (char *) &resp);
583
584 return *outname == NULL ? YPERR_YPERR : YPERR_SUCCESS;
585 }
586 libnsl_hidden_def (yp_master)
587
588 int
589 yp_order (const char *indomain, const char *inmap, unsigned int *outorder)
590 {
591 struct ypreq_nokey req;
592 struct ypresp_order resp;
593 enum clnt_stat result;
594
595 if (indomain == NULL || indomain[0] == '\0' ||
596 inmap == NULL || inmap == '\0')
597 return YPERR_BADARGS;
598
599 req.domain = (char *) indomain;
600 req.map = (char *) inmap;
601
602 memset (&resp, '\0', sizeof (resp));
603
604 result = do_ypcall (indomain, YPPROC_ORDER, (xdrproc_t) xdr_ypreq_nokey,
605 (caddr_t) & req, (xdrproc_t) xdr_ypresp_order, (caddr_t) & resp);
606
607 if (result != YPERR_SUCCESS)
608 return result;
609 if (resp.stat != YP_TRUE)
610 return ypprot_err (resp.stat);
611
612 *outorder = resp.ordernum;
613 xdr_free ((xdrproc_t) xdr_ypresp_order, (char *) &resp);
614
615 return YPERR_SUCCESS;
616 }
617
618 struct ypresp_all_data
619 {
620 unsigned long status;
621 void *data;
622 int (*foreach) (int status, char *key, int keylen,
623 char *val, int vallen, char *data);
624 };
625
626 static bool_t
627 __xdr_ypresp_all (XDR *xdrs, struct ypresp_all_data *objp)
628 {
629 while (1)
630 {
631 struct ypresp_all resp;
632
633 memset (&resp, '\0', sizeof (struct ypresp_all));
634 if (!xdr_ypresp_all (xdrs, &resp))
635 {
636 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
637 objp->status = YP_YPERR;
638 return FALSE;
639 }
640 if (resp.more == 0)
641 {
642 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
643 objp->status = YP_NOMORE;
644 return TRUE;
645 }
646
647 switch (resp.ypresp_all_u.val.stat)
648 {
649 case YP_TRUE:
650 {
651 char key[resp.ypresp_all_u.val.key.keydat_len + 1];
652 char val[resp.ypresp_all_u.val.val.valdat_len + 1];
653 int keylen = resp.ypresp_all_u.val.key.keydat_len;
654 int vallen = resp.ypresp_all_u.val.val.valdat_len;
655
656 /* We are not allowed to modify the key and val data.
657 But we are allowed to add data behind the buffer,
658 if we don't modify the length. So add an extra NUL
659 character to avoid trouble with broken code. */
660 objp->status = YP_TRUE;
661 memcpy (key, resp.ypresp_all_u.val.key.keydat_val, keylen);
662 key[keylen] = '\0';
663 memcpy (val, resp.ypresp_all_u.val.val.valdat_val, vallen);
664 val[vallen] = '\0';
665 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
666 if ((*objp->foreach) (objp->status, key, keylen,
667 val, vallen, objp->data))
668 return TRUE;
669 }
670 break;
671 default:
672 objp->status = resp.ypresp_all_u.val.stat;
673 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
674 /* Sun says we don't need to make this call, but must return
675 immediatly. Since Solaris makes this call, we will call
676 the callback function, too. */
677 (*objp->foreach) (objp->status, NULL, 0, NULL, 0, objp->data);
678 return TRUE;
679 }
680 }
681 }
682
683 int
684 yp_all (const char *indomain, const char *inmap,
685 const struct ypall_callback *incallback)
686 {
687 struct ypreq_nokey req;
688 dom_binding *ydb = NULL;
689 int try, res;
690 enum clnt_stat result;
691 struct sockaddr_in clnt_sin;
692 CLIENT *clnt;
693 struct ypresp_all_data data;
694 int clnt_sock;
695 int saved_errno = errno;
696
697 if (indomain == NULL || indomain[0] == '\0' ||
698 inmap == NULL || inmap == '\0')
699 return YPERR_BADARGS;
700
701 try = 0;
702 res = YPERR_YPERR;
703
704 while (try < MAXTRIES && res != YPERR_SUCCESS)
705 {
706 if (__yp_bind (indomain, &ydb) != 0)
707 {
708 __set_errno (saved_errno);
709 return YPERR_DOMAIN;
710 }
711
712 clnt_sock = RPC_ANYSOCK;
713 clnt_sin = ydb->dom_server_addr;
714 clnt_sin.sin_port = 0;
715
716 /* We don't need the UDP connection anymore. */
717 __yp_unbind (ydb);
718 ydb = NULL;
719
720 clnt = clnttcp_create (&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
721 if (clnt == NULL)
722 {
723 __set_errno (saved_errno);
724 return YPERR_PMAP;
725 }
726 req.domain = (char *) indomain;
727 req.map = (char *) inmap;
728
729 data.foreach = incallback->foreach;
730 data.data = (void *) incallback->data;
731
732 result = clnt_call (clnt, YPPROC_ALL, (xdrproc_t) xdr_ypreq_nokey,
733 (caddr_t) &req, (xdrproc_t) __xdr_ypresp_all,
734 (caddr_t) &data, RPCTIMEOUT);
735
736 if (result != RPC_SUCCESS)
737 {
738 /* Print the error message only on the last try */
739 if (try == MAXTRIES - 1)
740 clnt_perror (clnt, "yp_all: clnt_call");
741 res = YPERR_RPC;
742 }
743 else
744 res = YPERR_SUCCESS;
745
746 clnt_destroy (clnt);
747
748 if (res == YPERR_SUCCESS && data.status != YP_NOMORE)
749 {
750 __set_errno (saved_errno);
751 return ypprot_err (data.status);
752 }
753 ++try;
754 }
755
756 __set_errno (saved_errno);
757
758 return res;
759 }
760
761 int
762 yp_maplist (const char *indomain, struct ypmaplist **outmaplist)
763 {
764 struct ypresp_maplist resp;
765 enum clnt_stat result;
766
767 if (indomain == NULL || indomain[0] == '\0')
768 return YPERR_BADARGS;
769
770 memset (&resp, '\0', sizeof (resp));
771
772 result = do_ypcall (indomain, YPPROC_MAPLIST, (xdrproc_t) xdr_domainname,
773 (caddr_t) & indomain, (xdrproc_t) xdr_ypresp_maplist, (caddr_t) & resp);
774
775 if (result != YPERR_SUCCESS)
776 return result;
777 if (resp.stat != YP_TRUE)
778 return ypprot_err (resp.stat);
779
780 *outmaplist = resp.maps;
781 /* We give the list not free, this will be done by ypserv
782 xdr_free((xdrproc_t)xdr_ypresp_maplist, (char *)&resp); */
783
784 return YPERR_SUCCESS;
785 }
786
787 const char *
788 yperr_string (const int error)
789 {
790 switch (error)
791 {
792 case YPERR_SUCCESS:
793 return _("Success");
794 case YPERR_BADARGS:
795 return _("Request arguments bad");
796 case YPERR_RPC:
797 return _("RPC failure on NIS operation");
798 case YPERR_DOMAIN:
799 return _("Can't bind to server which serves this domain");
800 case YPERR_MAP:
801 return _("No such map in server's domain");
802 case YPERR_KEY:
803 return _("No such key in map");
804 case YPERR_YPERR:
805 return _("Internal NIS error");
806 case YPERR_RESRC:
807 return _("Local resource allocation failure");
808 case YPERR_NOMORE:
809 return _("No more records in map database");
810 case YPERR_PMAP:
811 return _("Can't communicate with portmapper");
812 case YPERR_YPBIND:
813 return _("Can't communicate with ypbind");
814 case YPERR_YPSERV:
815 return _("Can't communicate with ypserv");
816 case YPERR_NODOM:
817 return _("Local domain name not set");
818 case YPERR_BADDB:
819 return _("NIS map database is bad");
820 case YPERR_VERS:
821 return _("NIS client/server version mismatch - can't supply service");
822 case YPERR_ACCESS:
823 return _("Permission denied");
824 case YPERR_BUSY:
825 return _("Database is busy");
826 }
827 return _("Unknown NIS error code");
828 }
829
830 static const int8_t yp_2_yperr[] =
831 {
832 #define YP2YPERR(yp, yperr) [YP_##yp - YP_VERS] = YPERR_##yperr
833 YP2YPERR (TRUE, SUCCESS),
834 YP2YPERR (NOMORE, NOMORE),
835 YP2YPERR (FALSE, YPERR),
836 YP2YPERR (NOMAP, MAP),
837 YP2YPERR (NODOM, DOMAIN),
838 YP2YPERR (NOKEY, KEY),
839 YP2YPERR (BADOP, YPERR),
840 YP2YPERR (BADDB, BADDB),
841 YP2YPERR (YPERR, YPERR),
842 YP2YPERR (BADARGS, BADARGS),
843 YP2YPERR (VERS, VERS)
844 };
845 int
846 ypprot_err (const int code)
847 {
848 if (code < YP_VERS || code > YP_NOMORE)
849 return YPERR_YPERR;
850 return yp_2_yperr[code - YP_VERS];
851 }
852 libnsl_hidden_def (ypprot_err)
853
854 const char *
855 ypbinderr_string (const int error)
856 {
857 switch (error)
858 {
859 case 0:
860 return _("Success");
861 case YPBIND_ERR_ERR:
862 return _("Internal ypbind error");
863 case YPBIND_ERR_NOSERV:
864 return _("Domain not bound");
865 case YPBIND_ERR_RESC:
866 return _("System resource allocation failure");
867 default:
868 return _("Unknown ypbind error");
869 }
870 }
871 libnsl_hidden_def (ypbinderr_string)
872
873 #define WINDOW 60
874
875 int
876 yp_update (char *domain, char *map, unsigned ypop,
877 char *key, int keylen, char *data, int datalen)
878 {
879 union
880 {
881 ypupdate_args update_args;
882 ypdelete_args delete_args;
883 }
884 args;
885 xdrproc_t xdr_argument;
886 unsigned res = 0;
887 CLIENT *clnt;
888 char *master;
889 struct sockaddr saddr;
890 char servername[MAXNETNAMELEN + 1];
891 int r;
892
893 if (!domain || !map || !key || (ypop != YPOP_DELETE && !data))
894 return YPERR_BADARGS;
895
896 args.update_args.mapname = map;
897 args.update_args.key.yp_buf_len = keylen;
898 args.update_args.key.yp_buf_val = key;
899 args.update_args.datum.yp_buf_len = datalen;
900 args.update_args.datum.yp_buf_val = data;
901
902 if ((r = yp_master (domain, map, &master)) != 0)
903 return r;
904
905 if (!host2netname (servername, master, domain))
906 {
907 fputs (_("yp_update: cannot convert host to netname\n"), stderr);
908 return YPERR_YPERR;
909 }
910
911 if ((clnt = clnt_create (master, YPU_PROG, YPU_VERS, "tcp")) == NULL)
912 {
913 clnt_pcreateerror ("yp_update: clnt_create");
914 return YPERR_RPC;
915 }
916
917 if (!clnt_control (clnt, CLGET_SERVER_ADDR, (char *) &saddr))
918 {
919 fputs (_("yp_update: cannot get server address\n"), stderr);
920 return YPERR_RPC;
921 }
922
923 switch (ypop)
924 {
925 case YPOP_CHANGE:
926 case YPOP_INSERT:
927 case YPOP_STORE:
928 xdr_argument = (xdrproc_t) xdr_ypupdate_args;
929 break;
930 case YPOP_DELETE:
931 xdr_argument = (xdrproc_t) xdr_ypdelete_args;
932 break;
933 default:
934 return YPERR_BADARGS;
935 break;
936 }
937
938 clnt->cl_auth = authdes_create (servername, WINDOW, &saddr, NULL);
939
940 if (clnt->cl_auth == NULL)
941 clnt->cl_auth = authunix_create_default ();
942
943 again:
944 r = clnt_call (clnt, ypop, xdr_argument, (caddr_t) &args,
945 (xdrproc_t) xdr_u_int, (caddr_t) &res, RPCTIMEOUT);
946
947 if (r == RPC_AUTHERROR)
948 {
949 if (clnt->cl_auth->ah_cred.oa_flavor == AUTH_DES)
950 {
951 clnt->cl_auth = authunix_create_default ();
952 goto again;
953 }
954 else
955 return YPERR_ACCESS;
956 }
957 if (r != RPC_SUCCESS)
958 {
959 clnt_perror (clnt, "yp_update: clnt_call");
960 return YPERR_RPC;
961 }
962 return res;
963 }