1 /* Copyright (C) 1996-2022 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <https://www.gnu.org/licenses/>. */
17
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <libintl.h>
23 #include <rpc/rpc.h>
24 #include <rpcsvc/nis.h>
25 #include <rpcsvc/yp.h>
26 #include <rpcsvc/ypclnt.h>
27 #include <rpcsvc/ypupd.h>
28 #include <sys/socket.h>
29 #include <sys/uio.h>
30 #include <libc-lock.h>
31 #include <shlib-compat.h>
32 #include <libc-diag.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 const struct timeval RPCTIMEOUT = {25, 0};
50 static const struct timeval UDPTIMEOUT = {5, 0};
51 static int const MAXTRIES = 2;
52 static char ypdomainname[NIS_MAXNAMELEN + 1];
53 __libc_lock_define_initialized (static, ypbindlist_lock)
54 static dom_binding *ypbindlist = NULL;
55
56
57 static void
yp_bind_client_create(const char * domain,dom_binding * ysd,struct ypbind_resp * ypbr)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 = __libc_clntudp_bufcreate (&ysd->dom_server_addr, YPPROG,
73 YPVERS, UDPTIMEOUT,
74 &ysd->dom_socket,
75 UDPMSGSIZE, UDPMSGSIZE,
76 SOCK_CLOEXEC);
77 }
78
79 #if USE_BINDINGDIR
80 static void
yp_bind_file(const char * domain,dom_binding * ysd)81 yp_bind_file (const char *domain, dom_binding *ysd)
82 {
83 char path[sizeof (BINDINGDIR) + strlen (domain) + 3 * sizeof (unsigned) + 3];
84
85 snprintf (path, sizeof (path), "%s/%s.%u", BINDINGDIR, domain, YPBINDVERS);
86 int fd = open (path, O_RDONLY);
87 if (fd >= 0)
88 {
89 /* We have a binding file and could save a RPC call. The file
90 contains a port number and the YPBIND_RESP record. The port
91 number (16 bits) can be ignored. */
92 struct ypbind_resp ypbr;
93
94 if (pread (fd, &ypbr, sizeof (ypbr), 2) == sizeof (ypbr))
95 yp_bind_client_create (domain, ysd, &ypbr);
96
97 close (fd);
98 }
99 }
100 #endif
101
102 static int
yp_bind_ypbindprog(const char * domain,dom_binding * ysd)103 yp_bind_ypbindprog (const char *domain, dom_binding *ysd)
104 {
105 struct sockaddr_in clnt_saddr;
106 struct ypbind_resp ypbr;
107 int clnt_sock;
108 CLIENT *client;
109
110 clnt_saddr.sin_family = AF_INET;
111 clnt_saddr.sin_port = 0;
112 clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
113 clnt_sock = RPC_ANYSOCK;
114 client = clnttcp_create (&clnt_saddr, YPBINDPROG, YPBINDVERS,
115 &clnt_sock, 0, 0);
116 if (client == NULL)
117 return YPERR_YPBIND;
118
119 /* Check the port number -- should be < IPPORT_RESERVED.
120 If not, it's possible someone has registered a bogus
121 ypbind with the portmapper and is trying to trick us. */
122 if (ntohs (clnt_saddr.sin_port) >= IPPORT_RESERVED)
123 {
124 clnt_destroy (client);
125 return YPERR_YPBIND;
126 }
127
128 if (clnt_call (client, YPBINDPROC_DOMAIN,
129 (xdrproc_t) xdr_domainname, (caddr_t) &domain,
130 (xdrproc_t) xdr_ypbind_resp,
131 (caddr_t) &ypbr, RPCTIMEOUT) != RPC_SUCCESS)
132 {
133 clnt_destroy (client);
134 return YPERR_YPBIND;
135 }
136
137 clnt_destroy (client);
138
139 if (ypbr.ypbind_status != YPBIND_SUCC_VAL)
140 {
141 fprintf (stderr, "YPBINDPROC_DOMAIN: %s\n",
142 ypbinderr_string (ypbr.ypbind_resp_u.ypbind_error));
143 return YPERR_DOMAIN;
144 }
145 memset (&ysd->dom_server_addr, '\0', sizeof ysd->dom_server_addr);
146
147 yp_bind_client_create (domain, ysd, &ypbr);
148
149 return YPERR_SUCCESS;
150 }
151
152 static int
__yp_bind(const char * domain,dom_binding ** ypdb)153 __yp_bind (const char *domain, dom_binding **ypdb)
154 {
155 dom_binding *ysd = NULL;
156 int is_new = 0;
157
158 if (domain == NULL || domain[0] == '\0')
159 return YPERR_BADARGS;
160
161 ysd = *ypdb;
162 while (ysd != NULL)
163 {
164 if (strcmp (domain, ysd->dom_domain) == 0)
165 break;
166 ysd = ysd->dom_pnext;
167 }
168
169 if (ysd == NULL)
170 {
171 is_new = 1;
172 ysd = (dom_binding *) calloc (1, sizeof *ysd);
173 if (__glibc_unlikely (ysd == NULL))
174 return YPERR_RESRC;
175 }
176
177 #if USE_BINDINGDIR
178 /* Try binding dir at first if we have no binding */
179 if (ysd->dom_client == NULL)
180 yp_bind_file (domain, ysd);
181 #endif /* USE_BINDINGDIR */
182
183 if (ysd->dom_client == NULL)
184 {
185 int retval = yp_bind_ypbindprog (domain, ysd);
186 if (retval != YPERR_SUCCESS)
187 {
188 if (is_new)
189 free (ysd);
190 return retval;
191 }
192 }
193
194 if (ysd->dom_client == NULL)
195 {
196 if (is_new)
197 free (ysd);
198 return YPERR_YPSERV;
199 }
200
201 if (is_new)
202 {
203 ysd->dom_pnext = *ypdb;
204 *ypdb = ysd;
205 }
206
207 return YPERR_SUCCESS;
208 }
209
210 static void
__yp_unbind(dom_binding * ydb)211 __yp_unbind (dom_binding *ydb)
212 {
213 clnt_destroy (ydb->dom_client);
214 free (ydb);
215 }
216
217 int
yp_bind(const char * indomain)218 yp_bind (const char *indomain)
219 {
220 int status;
221
222 __libc_lock_lock (ypbindlist_lock);
223
224 status = __yp_bind (indomain, &ypbindlist);
225
226 __libc_lock_unlock (ypbindlist_lock);
227
228 return status;
229 }
libnsl_hidden_nolink_def(yp_bind,GLIBC_2_0)230 libnsl_hidden_nolink_def (yp_bind, GLIBC_2_0)
231
232 static void
233 yp_unbind_locked (const char *indomain)
234 {
235 dom_binding *ydbptr, *ydbptr2;
236
237 ydbptr2 = NULL;
238 ydbptr = ypbindlist;
239
240 while (ydbptr != NULL)
241 {
242 if (strcmp (ydbptr->dom_domain, indomain) == 0)
243 {
244 dom_binding *work;
245
246 work = ydbptr;
247 if (ydbptr2 == NULL)
248 ypbindlist = ypbindlist->dom_pnext;
249 else
250 ydbptr2 = ydbptr->dom_pnext;
251 __yp_unbind (work);
252 break;
253 }
254 ydbptr2 = ydbptr;
255 ydbptr = ydbptr->dom_pnext;
256 }
257 }
258
259 void
yp_unbind(const char * indomain)260 yp_unbind (const char *indomain)
261 {
262 __libc_lock_lock (ypbindlist_lock);
263
264 yp_unbind_locked (indomain);
265
266 __libc_lock_unlock (ypbindlist_lock);
267
268 return;
269 }
libnsl_hidden_nolink_def(yp_unbind,GLIBC_2_0)270 libnsl_hidden_nolink_def(yp_unbind, GLIBC_2_0)
271
272 static int
273 __ypclnt_call (const char *domain, u_long prog, xdrproc_t xargs,
274 caddr_t req, xdrproc_t xres, caddr_t resp, dom_binding **ydb,
275 int print_error)
276 {
277 enum clnt_stat result;
278
279 result = clnt_call ((*ydb)->dom_client, prog,
280 xargs, req, xres, resp, RPCTIMEOUT);
281
282 if (result != RPC_SUCCESS)
283 {
284 /* We don't print an error message, if we try our old,
285 cached data. Only print this for data, which should work. */
286 if (print_error)
287 clnt_perror ((*ydb)->dom_client, "do_ypcall: clnt_call");
288
289 return YPERR_RPC;
290 }
291
292 return YPERR_SUCCESS;
293 }
294
295 static int
do_ypcall(const char * domain,u_long prog,xdrproc_t xargs,caddr_t req,xdrproc_t xres,caddr_t resp)296 do_ypcall (const char *domain, u_long prog, xdrproc_t xargs,
297 caddr_t req, xdrproc_t xres, caddr_t resp)
298 {
299 dom_binding *ydb;
300 int status;
301 int saved_errno = errno;
302
303 status = YPERR_YPERR;
304
305 __libc_lock_lock (ypbindlist_lock);
306 ydb = ypbindlist;
307 while (ydb != NULL)
308 {
309 if (strcmp (domain, ydb->dom_domain) == 0)
310 {
311 if (__yp_bind (domain, &ydb) == 0)
312 {
313 /* Call server, print no error message, do not unbind. */
314 status = __ypclnt_call (domain, prog, xargs, req, xres,
315 resp, &ydb, 0);
316 if (status == YPERR_SUCCESS)
317 {
318 __libc_lock_unlock (ypbindlist_lock);
319 __set_errno (saved_errno);
320 return status;
321 }
322 }
323 /* We use ypbindlist, and the old cached data is
324 invalid. unbind now and create a new binding */
325 yp_unbind_locked (domain);
326
327 break;
328 }
329 ydb = ydb->dom_pnext;
330 }
331 __libc_lock_unlock (ypbindlist_lock);
332
333 /* First try with cached data failed. Now try to get
334 current data from the system. */
335 ydb = NULL;
336 if (__yp_bind (domain, &ydb) == 0)
337 {
338 status = __ypclnt_call (domain, prog, xargs, req, xres,
339 resp, &ydb, 1);
340 __yp_unbind (ydb);
341 }
342
343 #if USE_BINDINGDIR
344 /* If we support binding dir data, we have a third chance:
345 Ask ypbind. */
346 if (status != YPERR_SUCCESS)
347 {
348 ydb = calloc (1, sizeof (dom_binding));
349 if (ydb != NULL && yp_bind_ypbindprog (domain, ydb) == YPERR_SUCCESS)
350 {
351 status = __ypclnt_call (domain, prog, xargs, req, xres,
352 resp, &ydb, 1);
353 __yp_unbind (ydb);
354 }
355 else
356 free (ydb);
357 }
358 #endif
359
360 __set_errno (saved_errno);
361
362 return status;
363 }
364
365 /* Like do_ypcall, but translate the status value if necessary. */
366 static int
do_ypcall_tr(const char * domain,u_long prog,xdrproc_t xargs,caddr_t req,xdrproc_t xres,caddr_t resp)367 do_ypcall_tr (const char *domain, u_long prog, xdrproc_t xargs,
368 caddr_t req, xdrproc_t xres, caddr_t resp)
369 {
370 int status = do_ypcall (domain, prog, xargs, req, xres, resp);
371 DIAG_PUSH_NEEDS_COMMENT;
372 /* This cast results in a warning that a ypresp_val is partly
373 outside the bounds of the actual object referenced, but as
374 explained below only the stat element (in a common prefix) is
375 accessed. */
376 DIAG_IGNORE_NEEDS_COMMENT (11, "-Warray-bounds");
377 if (status == YPERR_SUCCESS)
378 /* We cast to ypresp_val although the pointer could also be of
379 type ypresp_key_val or ypresp_master or ypresp_order or
380 ypresp_maplist. But the stat element is in a common prefix so
381 this does not matter. */
382 status = ypprot_err (((struct ypresp_val *) resp)->stat);
383 DIAG_POP_NEEDS_COMMENT;
384 return status;
385 }
386
387
__libc_lock_define_initialized(static,domainname_lock)388 __libc_lock_define_initialized (static, domainname_lock)
389
390 int
391 yp_get_default_domain (char **outdomain)
392 {
393 int result = YPERR_SUCCESS;;
394 *outdomain = NULL;
395
396 __libc_lock_lock (domainname_lock);
397
398 if (ypdomainname[0] == '\0')
399 {
400 if (getdomainname (ypdomainname, NIS_MAXNAMELEN))
401 result = YPERR_NODOM;
402 else if (strcmp (ypdomainname, "(none)") == 0)
403 {
404 /* If domainname is not set, some systems will return "(none)" */
405 ypdomainname[0] = '\0';
406 result = YPERR_NODOM;
407 }
408 else
409 *outdomain = ypdomainname;
410 }
411 else
412 *outdomain = ypdomainname;
413
414 __libc_lock_unlock (domainname_lock);
415
416 return result;
417 }
libnsl_hidden_nolink_def(yp_get_default_domain,GLIBC_2_0)418 libnsl_hidden_nolink_def (yp_get_default_domain, GLIBC_2_0)
419
420 int
421 __yp_check (char **domain)
422 {
423 char *unused;
424
425 if (ypdomainname[0] == '\0')
426 if (yp_get_default_domain (&unused))
427 return 0;
428
429 if (domain)
430 *domain = ypdomainname;
431
432 if (yp_bind (ypdomainname) == 0)
433 return 1;
434 return 0;
435 }
libnsl_hidden_nolink_def(__yp_check,GLIBC_2_0)436 libnsl_hidden_nolink_def(__yp_check, GLIBC_2_0)
437
438 int
439 yp_match (const char *indomain, const char *inmap, const char *inkey,
440 const int inkeylen, char **outval, int *outvallen)
441 {
442 ypreq_key req;
443 ypresp_val resp;
444 enum clnt_stat result;
445
446 if (indomain == NULL || indomain[0] == '\0'
447 || inmap == NULL || inmap[0] == '\0'
448 || inkey == NULL || inkey[0] == '\0' || inkeylen <= 0)
449 return YPERR_BADARGS;
450
451 req.domain = (char *) indomain;
452 req.map = (char *) inmap;
453 req.key.keydat_val = (char *) inkey;
454 req.key.keydat_len = inkeylen;
455
456 *outval = NULL;
457 *outvallen = 0;
458 memset (&resp, '\0', sizeof (resp));
459
460 result = do_ypcall_tr (indomain, YPPROC_MATCH, (xdrproc_t) xdr_ypreq_key,
461 (caddr_t) &req, (xdrproc_t) xdr_ypresp_val,
462 (caddr_t) &resp);
463
464 if (result != YPERR_SUCCESS)
465 return result;
466
467 *outvallen = resp.val.valdat_len;
468 *outval = malloc (*outvallen + 1);
469 int status = YPERR_RESRC;
470 if (__glibc_likely (*outval != NULL))
471 {
472 memcpy (*outval, resp.val.valdat_val, *outvallen);
473 (*outval)[*outvallen] = '\0';
474 status = YPERR_SUCCESS;
475 }
476
477 xdr_free ((xdrproc_t) xdr_ypresp_val, (char *) &resp);
478
479 return status;
480 }
libnsl_hidden_nolink_def(yp_match,GLIBC_2_0)481 libnsl_hidden_nolink_def(yp_match, GLIBC_2_0)
482
483 int
484 yp_first (const char *indomain, const char *inmap, char **outkey,
485 int *outkeylen, char **outval, int *outvallen)
486 {
487 ypreq_nokey req;
488 ypresp_key_val resp;
489 enum clnt_stat result;
490
491 if (indomain == NULL || indomain[0] == '\0'
492 || inmap == NULL || inmap[0] == '\0')
493 return YPERR_BADARGS;
494
495 req.domain = (char *) indomain;
496 req.map = (char *) inmap;
497
498 *outkey = *outval = NULL;
499 *outkeylen = *outvallen = 0;
500 memset (&resp, '\0', sizeof (resp));
501
502 result = do_ypcall (indomain, YPPROC_FIRST, (xdrproc_t) xdr_ypreq_nokey,
503 (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val,
504 (caddr_t) &resp);
505
506 if (result != RPC_SUCCESS)
507 return YPERR_RPC;
508 if (resp.stat != YP_TRUE)
509 return ypprot_err (resp.stat);
510
511 int status;
512 if (__builtin_expect ((*outkey = malloc (resp.key.keydat_len + 1)) != NULL
513 && (*outval = malloc (resp.val.valdat_len
514 + 1)) != NULL, 1))
515 {
516 *outkeylen = resp.key.keydat_len;
517 memcpy (*outkey, resp.key.keydat_val, *outkeylen);
518 (*outkey)[*outkeylen] = '\0';
519
520 *outvallen = resp.val.valdat_len;
521 memcpy (*outval, resp.val.valdat_val, *outvallen);
522 (*outval)[*outvallen] = '\0';
523
524 status = YPERR_SUCCESS;
525 }
526 else
527 {
528 free (*outkey);
529 status = YPERR_RESRC;
530 }
531
532 xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
533
534 return status;
535 }
libnsl_hidden_nolink_def(yp_first,GLIBC_2_0)536 libnsl_hidden_nolink_def(yp_first, GLIBC_2_0)
537
538 int
539 yp_next (const char *indomain, const char *inmap, const char *inkey,
540 const int inkeylen, char **outkey, int *outkeylen, char **outval,
541 int *outvallen)
542 {
543 ypreq_key req;
544 ypresp_key_val resp;
545 enum clnt_stat result;
546
547 if (indomain == NULL || indomain[0] == '\0'
548 || inmap == NULL || inmap[0] == '\0'
549 || inkeylen <= 0 || inkey == NULL || inkey[0] == '\0')
550 return YPERR_BADARGS;
551
552 req.domain = (char *) indomain;
553 req.map = (char *) inmap;
554 req.key.keydat_val = (char *) inkey;
555 req.key.keydat_len = inkeylen;
556
557 *outkey = *outval = NULL;
558 *outkeylen = *outvallen = 0;
559 memset (&resp, '\0', sizeof (resp));
560
561 result = do_ypcall_tr (indomain, YPPROC_NEXT, (xdrproc_t) xdr_ypreq_key,
562 (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val,
563 (caddr_t) &resp);
564
565 if (result != YPERR_SUCCESS)
566 return result;
567
568 int status;
569 if (__builtin_expect ((*outkey = malloc (resp.key.keydat_len + 1)) != NULL
570 && (*outval = malloc (resp.val.valdat_len
571 + 1)) != NULL, 1))
572 {
573 *outkeylen = resp.key.keydat_len;
574 memcpy (*outkey, resp.key.keydat_val, *outkeylen);
575 (*outkey)[*outkeylen] = '\0';
576
577 *outvallen = resp.val.valdat_len;
578 memcpy (*outval, resp.val.valdat_val, *outvallen);
579 (*outval)[*outvallen] = '\0';
580
581 status = YPERR_SUCCESS;
582 }
583 else
584 {
585 free (*outkey);
586 status = YPERR_RESRC;
587 }
588
589 xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
590
591 return status;
592 }
libnsl_hidden_nolink_def(yp_next,GLIBC_2_0)593 libnsl_hidden_nolink_def(yp_next, GLIBC_2_0)
594
595 int
596 yp_master (const char *indomain, const char *inmap, char **outname)
597 {
598 ypreq_nokey req;
599 ypresp_master resp;
600 enum clnt_stat result;
601
602 if (indomain == NULL || indomain[0] == '\0'
603 || inmap == NULL || inmap[0] == '\0')
604 return YPERR_BADARGS;
605
606 req.domain = (char *) indomain;
607 req.map = (char *) inmap;
608
609 memset (&resp, '\0', sizeof (ypresp_master));
610
611 result = do_ypcall_tr (indomain, YPPROC_MASTER, (xdrproc_t) xdr_ypreq_nokey,
612 (caddr_t) &req, (xdrproc_t) xdr_ypresp_master,
613 (caddr_t) &resp);
614
615 if (result != YPERR_SUCCESS)
616 return result;
617
618 *outname = strdup (resp.peer);
619 xdr_free ((xdrproc_t) xdr_ypresp_master, (char *) &resp);
620
621 return *outname == NULL ? YPERR_YPERR : YPERR_SUCCESS;
622 }
libnsl_hidden_nolink_def(yp_master,GLIBC_2_0)623 libnsl_hidden_nolink_def (yp_master, GLIBC_2_0)
624
625 int
626 yp_order (const char *indomain, const char *inmap, unsigned int *outorder)
627 {
628 struct ypreq_nokey req;
629 struct ypresp_order resp;
630 enum clnt_stat result;
631
632 if (indomain == NULL || indomain[0] == '\0'
633 || inmap == NULL || inmap[0] == '\0')
634 return YPERR_BADARGS;
635
636 req.domain = (char *) indomain;
637 req.map = (char *) inmap;
638
639 memset (&resp, '\0', sizeof (resp));
640
641 result = do_ypcall_tr (indomain, YPPROC_ORDER, (xdrproc_t) xdr_ypreq_nokey,
642 (caddr_t) &req, (xdrproc_t) xdr_ypresp_order,
643 (caddr_t) &resp);
644
645 if (result != YPERR_SUCCESS)
646 return result;
647
648 *outorder = resp.ordernum;
649 xdr_free ((xdrproc_t) xdr_ypresp_order, (char *) &resp);
650
651 return result;
652 }
653 libnsl_hidden_nolink_def(yp_order, GLIBC_2_0)
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
__xdr_ypresp_all(XDR * xdrs,struct ypresp_all_data * objp)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
yp_all(const char * indomain,const char * inmap,const struct ypall_callback * incallback)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 }
libnsl_hidden_nolink_def(yp_all,GLIBC_2_0)797 libnsl_hidden_nolink_def (yp_all, GLIBC_2_0)
798
799 int
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 }
libnsl_hidden_nolink_def(yp_maplist,GLIBC_2_0)823 libnsl_hidden_nolink_def (yp_maplist, GLIBC_2_0)
824
825 const char *
826 yperr_string (const int error)
827 {
828 const char *str;
829 switch (error)
830 {
831 case YPERR_SUCCESS:
832 str = N_("Success");
833 break;
834 case YPERR_BADARGS:
835 str = N_("Request arguments bad");
836 break;
837 case YPERR_RPC:
838 str = N_("RPC failure on NIS operation");
839 break;
840 case YPERR_DOMAIN:
841 str = N_("Can't bind to server which serves this domain");
842 break;
843 case YPERR_MAP:
844 str = N_("No such map in server's domain");
845 break;
846 case YPERR_KEY:
847 str = N_("No such key in map");
848 break;
849 case YPERR_YPERR:
850 str = N_("Internal NIS error");
851 break;
852 case YPERR_RESRC:
853 str = N_("Local resource allocation failure");
854 break;
855 case YPERR_NOMORE:
856 str = N_("No more records in map database");
857 break;
858 case YPERR_PMAP:
859 str = N_("Can't communicate with portmapper");
860 break;
861 case YPERR_YPBIND:
862 str = N_("Can't communicate with ypbind");
863 break;
864 case YPERR_YPSERV:
865 str = N_("Can't communicate with ypserv");
866 break;
867 case YPERR_NODOM:
868 str = N_("Local domain name not set");
869 break;
870 case YPERR_BADDB:
871 str = N_("NIS map database is bad");
872 break;
873 case YPERR_VERS:
874 str = N_("NIS client/server version mismatch - can't supply service");
875 break;
876 case YPERR_ACCESS:
877 str = N_("Permission denied");
878 break;
879 case YPERR_BUSY:
880 str = N_("Database is busy");
881 break;
882 default:
883 str = N_("Unknown NIS error code");
884 break;
885 }
886 return _(str);
887 }
888 libnsl_hidden_nolink_def(yperr_string, GLIBC_2_0)
889
890 static const int8_t yp_2_yperr[] =
891 {
892 #define YP2YPERR(yp, yperr) [YP_##yp - YP_VERS] = YPERR_##yperr
893 YP2YPERR (TRUE, SUCCESS),
894 YP2YPERR (NOMORE, NOMORE),
895 YP2YPERR (FALSE, YPERR),
896 YP2YPERR (NOMAP, MAP),
897 YP2YPERR (NODOM, DOMAIN),
898 YP2YPERR (NOKEY, KEY),
899 YP2YPERR (BADOP, YPERR),
900 YP2YPERR (BADDB, BADDB),
901 YP2YPERR (YPERR, YPERR),
902 YP2YPERR (BADARGS, BADARGS),
903 YP2YPERR (VERS, VERS)
904 };
905 int
ypprot_err(const int code)906 ypprot_err (const int code)
907 {
908 if (code < YP_VERS || code > YP_NOMORE)
909 return YPERR_YPERR;
910 return yp_2_yperr[code - YP_VERS];
911 }
libnsl_hidden_nolink_def(ypprot_err,GLIBC_2_0)912 libnsl_hidden_nolink_def (ypprot_err, GLIBC_2_0)
913
914 const char *
915 ypbinderr_string (const int error)
916 {
917 const char *str;
918 switch (error)
919 {
920 case 0:
921 str = N_("Success");
922 break;
923 case YPBIND_ERR_ERR:
924 str = N_("Internal ypbind error");
925 break;
926 case YPBIND_ERR_NOSERV:
927 str = N_("Domain not bound");
928 break;
929 case YPBIND_ERR_RESC:
930 str = N_("System resource allocation failure");
931 break;
932 default:
933 str = N_("Unknown ypbind error");
934 break;
935 }
936 return _(str);
937 }
libnsl_hidden_nolink_def(ypbinderr_string,GLIBC_2_0)938 libnsl_hidden_nolink_def (ypbinderr_string, GLIBC_2_0)
939
940 #define WINDOW 60
941
942 int
943 yp_update (char *domain, char *map, unsigned ypop,
944 char *key, int keylen, char *data, int datalen)
945 {
946 union
947 {
948 ypupdate_args update_args;
949 ypdelete_args delete_args;
950 }
951 args;
952 xdrproc_t xdr_argument;
953 unsigned res = 0;
954 CLIENT *clnt;
955 char *master;
956 struct sockaddr saddr;
957 char servername[MAXNETNAMELEN + 1];
958 int r;
959
960 if (!domain || !map || !key || (ypop != YPOP_DELETE && !data))
961 return YPERR_BADARGS;
962
963 args.update_args.mapname = map;
964 args.update_args.key.yp_buf_len = keylen;
965 args.update_args.key.yp_buf_val = key;
966 args.update_args.datum.yp_buf_len = datalen;
967 args.update_args.datum.yp_buf_val = data;
968
969 if ((r = yp_master (domain, map, &master)) != YPERR_SUCCESS)
970 return r;
971
972 if (!host2netname (servername, master, domain))
973 {
974 fputs (_("yp_update: cannot convert host to netname\n"), stderr);
975 free (master);
976 return YPERR_YPERR;
977 }
978
979 clnt = clnt_create (master, YPU_PROG, YPU_VERS, "tcp");
980
981 /* We do not need the string anymore. */
982 free (master);
983
984 if (clnt == NULL)
985 {
986 clnt_pcreateerror ("yp_update: clnt_create");
987 return YPERR_RPC;
988 }
989
990 if (!clnt_control (clnt, CLGET_SERVER_ADDR, (char *) &saddr))
991 {
992 fputs (_("yp_update: cannot get server address\n"), stderr);
993 return YPERR_RPC;
994 }
995
996 switch (ypop)
997 {
998 case YPOP_CHANGE:
999 case YPOP_INSERT:
1000 case YPOP_STORE:
1001 xdr_argument = (xdrproc_t) xdr_ypupdate_args;
1002 break;
1003 case YPOP_DELETE:
1004 xdr_argument = (xdrproc_t) xdr_ypdelete_args;
1005 break;
1006 default:
1007 return YPERR_BADARGS;
1008 break;
1009 }
1010
1011 clnt->cl_auth = authdes_create (servername, WINDOW, &saddr, NULL);
1012
1013 if (clnt->cl_auth == NULL)
1014 clnt->cl_auth = authunix_create_default ();
1015
1016 again:
1017 r = clnt_call (clnt, ypop, xdr_argument, (caddr_t) &args,
1018 (xdrproc_t) xdr_u_int, (caddr_t) &res, RPCTIMEOUT);
1019
1020 if (r == RPC_AUTHERROR)
1021 {
1022 if (clnt->cl_auth->ah_cred.oa_flavor == AUTH_DES)
1023 {
1024 auth_destroy (clnt->cl_auth);
1025 clnt->cl_auth = authunix_create_default ();
1026 goto again;
1027 }
1028 else
1029 return YPERR_ACCESS;
1030 }
1031 if (r != RPC_SUCCESS)
1032 {
1033 clnt_perror (clnt, "yp_update: clnt_call");
1034 return YPERR_RPC;
1035 }
1036 return res;
1037 }
1038 libnsl_hidden_nolink_def(yp_update, GLIBC_2_0)
1039