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