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