]> git.ipfire.org Git - thirdparty/glibc.git/blame - nis/ypclnt.c
Update copyright dates with scripts/update-copyrights
[thirdparty/glibc.git] / nis / ypclnt.c
CommitLineData
dff8da6b 1/* Copyright (C) 1996-2024 Free Software Foundation, Inc.
6259ec0d 2 This file is part of the GNU C Library.
6259ec0d
UD
3
4 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
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.
6259ec0d
UD
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
41bdb6e2 12 Lesser General Public License for more details.
6259ec0d 13
41bdb6e2 14 You should have received a copy of the GNU Lesser General Public
59ba27a6 15 License along with the GNU C Library; if not, see
5a82c748 16 <https://www.gnu.org/licenses/>. */
6259ec0d 17
ee74a442 18#include <errno.h>
cc3fa755 19#include <fcntl.h>
6259ec0d
UD
20#include <string.h>
21#include <unistd.h>
4360eafd 22#include <libintl.h>
26dee9c4 23#include <rpc/rpc.h>
f21acc89 24#include <rpcsvc/nis.h>
6259ec0d
UD
25#include <rpcsvc/yp.h>
26#include <rpcsvc/ypclnt.h>
27#include <rpcsvc/ypupd.h>
8ccf22f9 28#include <sys/socket.h>
9931ba24 29#include <sys/uio.h>
ec999b8e 30#include <libc-lock.h>
82f43dd2 31#include <shlib-compat.h>
88277465 32#include <libc-diag.h>
6259ec0d 33
9931ba24
UD
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
6259ec0d
UD
39struct 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;
6259ec0d
UD
46 };
47typedef struct dom_binding dom_binding;
48
3218d55b
UD
49static const struct timeval RPCTIMEOUT = {25, 0};
50static const struct timeval UDPTIMEOUT = {5, 0};
66f72f03 51static int const MAXTRIES = 2;
2c2efdc1 52static char ypdomainname[NIS_MAXNAMELEN + 1];
6259ec0d 53__libc_lock_define_initialized (static, ypbindlist_lock)
2c2efdc1 54static dom_binding *ypbindlist = NULL;
6259ec0d 55
f8b87ef0 56
57be8a82 57static void
4c9ae37b
UD
58yp_bind_client_create (const char *domain, dom_binding *ysd,
59 struct ypbind_resp *ypbr)
57be8a82
RM
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;
8ccf22f9
UD
72 ysd->dom_client = __libc_clntudp_bufcreate (&ysd->dom_server_addr, YPPROG,
73 YPVERS, UDPTIMEOUT,
74 &ysd->dom_socket,
75 UDPMSGSIZE, UDPMSGSIZE,
52fb79d6 76 SOCK_CLOEXEC);
57be8a82
RM
77}
78
4c9ae37b 79#if USE_BINDINGDIR
57be8a82 80static void
4c9ae37b 81yp_bind_file (const char *domain, dom_binding *ysd)
57be8a82 82{
3900770e 83 char path[sizeof (BINDINGDIR) + strlen (domain) + 3 * sizeof (unsigned) + 3];
57be8a82 84
3900770e
UD
85 snprintf (path, sizeof (path), "%s/%s.%u", BINDINGDIR, domain, YPBINDVERS);
86 int fd = open (path, O_RDONLY);
57be8a82
RM
87 if (fd >= 0)
88 {
3900770e
UD
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;
57be8a82 93
3900770e 94 if (pread (fd, &ypbr, sizeof (ypbr), 2) == sizeof (ypbr))
4c9ae37b 95 yp_bind_client_create (domain, ysd, &ypbr);
57be8a82
RM
96
97 close (fd);
98 }
99}
4c9ae37b 100#endif
57be8a82 101
6259ec0d 102static int
4c9ae37b 103yp_bind_ypbindprog (const char *domain, dom_binding *ysd)
6259ec0d
UD
104{
105 struct sockaddr_in clnt_saddr;
106 struct ypbind_resp ypbr;
6259ec0d
UD
107 int clnt_sock;
108 CLIENT *client;
57be8a82 109
57be8a82 110 clnt_saddr.sin_family = AF_INET;
2c2efdc1 111 clnt_saddr.sin_port = 0;
57be8a82
RM
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 {
2c2efdc1 141 fprintf (stderr, "YPBINDPROC_DOMAIN: %s\n",
57be8a82
RM
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
4c9ae37b 147 yp_bind_client_create (domain, ysd, &ypbr);
57be8a82
RM
148
149 return YPERR_SUCCESS;
150}
151
152static int
153__yp_bind (const char *domain, dom_binding **ypdb)
154{
155 dom_binding *ysd = NULL;
6259ec0d 156 int is_new = 0;
6259ec0d 157
6ff5bc68 158 if (domain == NULL || domain[0] == '\0')
6259ec0d
UD
159 return YPERR_BADARGS;
160
345d9208
UD
161 ysd = *ypdb;
162 while (ysd != NULL)
6259ec0d 163 {
345d9208
UD
164 if (strcmp (domain, ysd->dom_domain) == 0)
165 break;
166 ysd = ysd->dom_pnext;
6259ec0d
UD
167 }
168
169 if (ysd == NULL)
170 {
171 is_new = 1;
bd355af0 172 ysd = (dom_binding *) calloc (1, sizeof *ysd);
a1ffb40e 173 if (__glibc_unlikely (ysd == NULL))
3b965a7d 174 return YPERR_RESRC;
6259ec0d
UD
175 }
176
9931ba24 177#if USE_BINDINGDIR
3900770e 178 /* Try binding dir at first if we have no binding */
57be8a82 179 if (ysd->dom_client == NULL)
3900770e 180 yp_bind_file (domain, ysd);
9931ba24
UD
181#endif /* USE_BINDINGDIR */
182
b85697f6
UD
183 if (ysd->dom_client == NULL)
184 {
4c9ae37b 185 int retval = yp_bind_ypbindprog (domain, ysd);
57be8a82 186 if (retval != YPERR_SUCCESS)
b85697f6 187 {
b85697f6
UD
188 if (is_new)
189 free (ysd);
57be8a82 190 return retval;
b85697f6 191 }
6259ec0d 192 }
6259ec0d 193
b85697f6
UD
194 if (ysd->dom_client == NULL)
195 {
196 if (is_new)
197 free (ysd);
198 return YPERR_YPSERV;
199 }
6259ec0d 200
47ae3942 201 if (is_new)
6259ec0d 202 {
345d9208
UD
203 ysd->dom_pnext = *ypdb;
204 *ypdb = ysd;
6259ec0d
UD
205 }
206
6259ec0d
UD
207 return YPERR_SUCCESS;
208}
209
210static void
211__yp_unbind (dom_binding *ydb)
212{
213 clnt_destroy (ydb->dom_client);
345d9208 214 free (ydb);
b85697f6
UD
215}
216
217int
218yp_bind (const char *indomain)
219{
220 int status;
221
222 __libc_lock_lock (ypbindlist_lock);
223
2c2efdc1 224 status = __yp_bind (indomain, &ypbindlist);
b85697f6
UD
225
226 __libc_lock_unlock (ypbindlist_lock);
227
228 return status;
229}
1e4d83f6 230libnsl_hidden_nolink_def (yp_bind, GLIBC_2_0)
b85697f6
UD
231
232static void
233yp_unbind_locked (const char *indomain)
234{
235 dom_binding *ydbptr, *ydbptr2;
236
237 ydbptr2 = NULL;
2c2efdc1 238 ydbptr = ypbindlist;
b85697f6
UD
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)
2c2efdc1 248 ypbindlist = ypbindlist->dom_pnext;
b85697f6
UD
249 else
250 ydbptr2 = ydbptr->dom_pnext;
251 __yp_unbind (work);
b85697f6
UD
252 break;
253 }
254 ydbptr2 = ydbptr;
255 ydbptr = ydbptr->dom_pnext;
256 }
257}
258
259void
260yp_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;
6259ec0d 269}
1e4d83f6 270libnsl_hidden_nolink_def(yp_unbind, GLIBC_2_0)
6259ec0d 271
57be8a82
RM
272static 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
6259ec0d
UD
295static int
296do_ypcall (const char *domain, u_long prog, xdrproc_t xargs,
297 caddr_t req, xdrproc_t xres, caddr_t resp)
298{
57be8a82
RM
299 dom_binding *ydb;
300 int status;
a788b6c2 301 int saved_errno = errno;
6259ec0d 302
d111572f 303 status = YPERR_YPERR;
6259ec0d 304
cc3fa755 305 __libc_lock_lock (ypbindlist_lock);
2c2efdc1 306 ydb = ypbindlist;
9435d38c 307 while (ydb != NULL)
6259ec0d 308 {
9435d38c 309 if (strcmp (domain, ydb->dom_domain) == 0)
57be8a82
RM
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 {
9435d38c 318 __libc_lock_unlock (ypbindlist_lock);
57be8a82
RM
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);
9435d38c
UD
326
327 break;
57be8a82 328 }
9435d38c 329 ydb = ydb->dom_pnext;
cc3fa755 330 }
4c9ae37b 331 __libc_lock_unlock (ypbindlist_lock);
6259ec0d 332
57be8a82
RM
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)
cc3fa755 337 {
57be8a82
RM
338 status = __ypclnt_call (domain, prog, xargs, req, xres,
339 resp, &ydb, 1);
340 __yp_unbind (ydb);
341 }
6259ec0d 342
57be8a82
RM
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));
2c2efdc1 349 if (ydb != NULL && yp_bind_ypbindprog (domain, ydb) == YPERR_SUCCESS)
6259ec0d 350 {
57be8a82
RM
351 status = __ypclnt_call (domain, prog, xargs, req, xres,
352 resp, &ydb, 1);
353 __yp_unbind (ydb);
6259ec0d 354 }
d111572f 355 else
57be8a82 356 free (ydb);
6259ec0d 357 }
57be8a82 358#endif
6259ec0d 359
a788b6c2
UD
360 __set_errno (saved_errno);
361
d111572f 362 return status;
6259ec0d
UD
363}
364
2c2efdc1
UD
365/* Like do_ypcall, but translate the status value if necessary. */
366static int
367do_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);
88277465
JM
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");
2c2efdc1
UD
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);
88277465 383 DIAG_POP_NEEDS_COMMENT;
2c2efdc1
UD
384 return status;
385}
386
6259ec0d
UD
387
388__libc_lock_define_initialized (static, domainname_lock)
389
390int
391yp_get_default_domain (char **outdomain)
392{
393 int result = YPERR_SUCCESS;;
394 *outdomain = NULL;
395
396 __libc_lock_lock (domainname_lock);
397
2c2efdc1 398 if (ypdomainname[0] == '\0')
6259ec0d 399 {
2c2efdc1 400 if (getdomainname (ypdomainname, NIS_MAXNAMELEN))
6259ec0d 401 result = YPERR_NODOM;
2c2efdc1 402 else if (strcmp (ypdomainname, "(none)") == 0)
ee74a442 403 {
b85697f6 404 /* If domainname is not set, some systems will return "(none)" */
2c2efdc1 405 ypdomainname[0] = '\0';
ee74a442
UD
406 result = YPERR_NODOM;
407 }
6259ec0d 408 else
2c2efdc1 409 *outdomain = ypdomainname;
6259ec0d
UD
410 }
411 else
2c2efdc1 412 *outdomain = ypdomainname;
6259ec0d
UD
413
414 __libc_lock_unlock (domainname_lock);
415
416 return result;
417}
1e4d83f6 418libnsl_hidden_nolink_def (yp_get_default_domain, GLIBC_2_0)
6259ec0d
UD
419
420int
421__yp_check (char **domain)
422{
423 char *unused;
424
2c2efdc1 425 if (ypdomainname[0] == '\0')
6259ec0d
UD
426 if (yp_get_default_domain (&unused))
427 return 0;
6259ec0d
UD
428
429 if (domain)
2c2efdc1 430 *domain = ypdomainname;
6259ec0d 431
2c2efdc1 432 if (yp_bind (ypdomainname) == 0)
6259ec0d
UD
433 return 1;
434 return 0;
435}
1e4d83f6 436libnsl_hidden_nolink_def(__yp_check, GLIBC_2_0)
6259ec0d
UD
437
438int
439yp_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;
d111572f 444 enum clnt_stat result;
6259ec0d 445
34a5a146
JM
446 if (indomain == NULL || indomain[0] == '\0'
447 || inmap == NULL || inmap[0] == '\0'
448 || inkey == NULL || inkey[0] == '\0' || inkeylen <= 0)
6259ec0d
UD
449 return YPERR_BADARGS;
450
68dbb3a6
UD
451 req.domain = (char *) indomain;
452 req.map = (char *) inmap;
453 req.key.keydat_val = (char *) inkey;
6259ec0d
UD
454 req.key.keydat_len = inkeylen;
455
456 *outval = NULL;
457 *outvallen = 0;
458 memset (&resp, '\0', sizeof (resp));
459
2c2efdc1
UD
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);
6259ec0d 463
4bca4c17
UD
464 if (result != YPERR_SUCCESS)
465 return result;
6259ec0d
UD
466
467 *outvallen = resp.val.valdat_len;
468 *outval = malloc (*outvallen + 1);
2c2efdc1 469 int status = YPERR_RESRC;
a1ffb40e 470 if (__glibc_likely (*outval != NULL))
2c2efdc1
UD
471 {
472 memcpy (*outval, resp.val.valdat_val, *outvallen);
473 (*outval)[*outvallen] = '\0';
474 status = YPERR_SUCCESS;
475 }
6259ec0d
UD
476
477 xdr_free ((xdrproc_t) xdr_ypresp_val, (char *) &resp);
478
2c2efdc1 479 return status;
6259ec0d 480}
1e4d83f6 481libnsl_hidden_nolink_def(yp_match, GLIBC_2_0)
6259ec0d
UD
482
483int
484yp_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;
d111572f 489 enum clnt_stat result;
6259ec0d 490
34a5a146
JM
491 if (indomain == NULL || indomain[0] == '\0'
492 || inmap == NULL || inmap[0] == '\0')
6259ec0d
UD
493 return YPERR_BADARGS;
494
68dbb3a6
UD
495 req.domain = (char *) indomain;
496 req.map = (char *) inmap;
6259ec0d
UD
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,
2c2efdc1
UD
503 (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val,
504 (caddr_t) &resp);
6259ec0d
UD
505
506 if (result != RPC_SUCCESS)
d111572f 507 return YPERR_RPC;
6259ec0d
UD
508 if (resp.stat != YP_TRUE)
509 return ypprot_err (resp.stat);
510
2c2efdc1
UD
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 }
6259ec0d
UD
531
532 xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
533
2c2efdc1 534 return status;
6259ec0d 535}
1e4d83f6 536libnsl_hidden_nolink_def(yp_first, GLIBC_2_0)
6259ec0d
UD
537
538int
539yp_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;
d111572f 545 enum clnt_stat result;
6259ec0d 546
34a5a146
JM
547 if (indomain == NULL || indomain[0] == '\0'
548 || inmap == NULL || inmap[0] == '\0'
549 || inkeylen <= 0 || inkey == NULL || inkey[0] == '\0')
6259ec0d
UD
550 return YPERR_BADARGS;
551
68dbb3a6
UD
552 req.domain = (char *) indomain;
553 req.map = (char *) inmap;
554 req.key.keydat_val = (char *) inkey;
6259ec0d
UD
555 req.key.keydat_len = inkeylen;
556
557 *outkey = *outval = NULL;
558 *outkeylen = *outvallen = 0;
559 memset (&resp, '\0', sizeof (resp));
560
2c2efdc1
UD
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);
6259ec0d 564
4bca4c17
UD
565 if (result != YPERR_SUCCESS)
566 return result;
6259ec0d 567
2c2efdc1
UD
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 }
6259ec0d
UD
588
589 xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
590
2c2efdc1 591 return status;
6259ec0d 592}
1e4d83f6 593libnsl_hidden_nolink_def(yp_next, GLIBC_2_0)
6259ec0d
UD
594
595int
596yp_master (const char *indomain, const char *inmap, char **outname)
597{
598 ypreq_nokey req;
599 ypresp_master resp;
d111572f 600 enum clnt_stat result;
6259ec0d 601
34a5a146
JM
602 if (indomain == NULL || indomain[0] == '\0'
603 || inmap == NULL || inmap[0] == '\0')
6259ec0d
UD
604 return YPERR_BADARGS;
605
68dbb3a6
UD
606 req.domain = (char *) indomain;
607 req.map = (char *) inmap;
6259ec0d
UD
608
609 memset (&resp, '\0', sizeof (ypresp_master));
610
2c2efdc1
UD
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);
6259ec0d 614
4bca4c17
UD
615 if (result != YPERR_SUCCESS)
616 return result;
6259ec0d
UD
617
618 *outname = strdup (resp.peer);
619 xdr_free ((xdrproc_t) xdr_ypresp_master, (char *) &resp);
620
d111572f 621 return *outname == NULL ? YPERR_YPERR : YPERR_SUCCESS;
6259ec0d 622}
1e4d83f6 623libnsl_hidden_nolink_def (yp_master, GLIBC_2_0)
6259ec0d
UD
624
625int
626yp_order (const char *indomain, const char *inmap, unsigned int *outorder)
627{
628 struct ypreq_nokey req;
629 struct ypresp_order resp;
d111572f 630 enum clnt_stat result;
6259ec0d 631
34a5a146
JM
632 if (indomain == NULL || indomain[0] == '\0'
633 || inmap == NULL || inmap[0] == '\0')
6259ec0d
UD
634 return YPERR_BADARGS;
635
68dbb3a6
UD
636 req.domain = (char *) indomain;
637 req.map = (char *) inmap;
6259ec0d
UD
638
639 memset (&resp, '\0', sizeof (resp));
640
2c2efdc1
UD
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);
6259ec0d 644
0f749099 645 if (result != YPERR_SUCCESS)
4bca4c17 646 return result;
6259ec0d
UD
647
648 *outorder = resp.ordernum;
649 xdr_free ((xdrproc_t) xdr_ypresp_order, (char *) &resp);
650
2c2efdc1 651 return result;
6259ec0d 652}
1e4d83f6 653libnsl_hidden_nolink_def(yp_order, GLIBC_2_0)
6259ec0d 654
ffdd5e50
UD
655struct 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};
6259ec0d
UD
662
663static bool_t
ffdd5e50 664__xdr_ypresp_all (XDR *xdrs, struct ypresp_all_data *objp)
6259ec0d
UD
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);
ffdd5e50 674 objp->status = YP_YPERR;
d111572f 675 return FALSE;
6259ec0d
UD
676 }
677 if (resp.more == 0)
678 {
679 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
ffdd5e50 680 objp->status = YP_NOMORE;
d111572f 681 return TRUE;
6259ec0d
UD
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
b85697f6
UD
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. */
ffdd5e50 697 objp->status = YP_TRUE;
91287339
UD
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';
6259ec0d 702 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
ffdd5e50
UD
703 if ((*objp->foreach) (objp->status, key, keylen,
704 val, vallen, objp->data))
6259ec0d
UD
705 return TRUE;
706 }
707 break;
6259ec0d 708 default:
ffdd5e50 709 objp->status = resp.ypresp_all_u.val.stat;
6259ec0d 710 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
b85697f6 711 /* Sun says we don't need to make this call, but must return
91287339 712 immediately. Since Solaris makes this call, we will call
b85697f6 713 the callback function, too. */
ffdd5e50 714 (*objp->foreach) (objp->status, NULL, 0, NULL, 0, objp->data);
6259ec0d
UD
715 return TRUE;
716 }
717 }
718}
719
720int
721yp_all (const char *indomain, const char *inmap,
722 const struct ypall_callback *incallback)
723{
724 struct ypreq_nokey req;
cc3fa755 725 dom_binding *ydb = NULL;
d111572f
UD
726 int try, res;
727 enum clnt_stat result;
6259ec0d
UD
728 struct sockaddr_in clnt_sin;
729 CLIENT *clnt;
ffdd5e50 730 struct ypresp_all_data data;
6259ec0d 731 int clnt_sock;
a788b6c2 732 int saved_errno = errno;
6259ec0d 733
2c2efdc1
UD
734 if (indomain == NULL || indomain[0] == '\0'
735 || inmap == NULL || inmap[0] == '\0')
6259ec0d
UD
736 return YPERR_BADARGS;
737
738 try = 0;
d111572f 739 res = YPERR_YPERR;
6259ec0d 740
d111572f 741 while (try < MAXTRIES && res != YPERR_SUCCESS)
6259ec0d 742 {
6259ec0d
UD
743 if (__yp_bind (indomain, &ydb) != 0)
744 {
a788b6c2 745 __set_errno (saved_errno);
6259ec0d
UD
746 return YPERR_DOMAIN;
747 }
748
6259ec0d
UD
749 clnt_sock = RPC_ANYSOCK;
750 clnt_sin = ydb->dom_server_addr;
751 clnt_sin.sin_port = 0;
85939c79
UD
752
753 /* We don't need the UDP connection anymore. */
754 __yp_unbind (ydb);
47ae3942 755 ydb = NULL;
85939c79 756
6259ec0d
UD
757 clnt = clnttcp_create (&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
758 if (clnt == NULL)
a788b6c2
UD
759 {
760 __set_errno (saved_errno);
761 return YPERR_PMAP;
762 }
68dbb3a6
UD
763 req.domain = (char *) indomain;
764 req.map = (char *) inmap;
6259ec0d 765
ffdd5e50
UD
766 data.foreach = incallback->foreach;
767 data.data = (void *) incallback->data;
6259ec0d 768
3e5f5557
UD
769 result = clnt_call (clnt, YPPROC_ALL, (xdrproc_t) xdr_ypreq_nokey,
770 (caddr_t) &req, (xdrproc_t) __xdr_ypresp_all,
ffdd5e50 771 (caddr_t) &data, RPCTIMEOUT);
6259ec0d 772
a1ffb40e 773 if (__glibc_unlikely (result != RPC_SUCCESS))
6259ec0d 774 {
2c2efdc1 775 /* Print the error message only on the last try. */
c891b2df
UD
776 if (try == MAXTRIES - 1)
777 clnt_perror (clnt, "yp_all: clnt_call");
d111572f 778 res = YPERR_RPC;
6259ec0d
UD
779 }
780 else
d111572f
UD
781 res = YPERR_SUCCESS;
782
783 clnt_destroy (clnt);
6259ec0d 784
ffdd5e50 785 if (res == YPERR_SUCCESS && data.status != YP_NOMORE)
a788b6c2
UD
786 {
787 __set_errno (saved_errno);
ffdd5e50 788 return ypprot_err (data.status);
a788b6c2
UD
789 }
790 ++try;
6259ec0d
UD
791 }
792
a788b6c2
UD
793 __set_errno (saved_errno);
794
d111572f 795 return res;
6259ec0d 796}
1e4d83f6 797libnsl_hidden_nolink_def (yp_all, GLIBC_2_0)
6259ec0d
UD
798
799int
800yp_maplist (const char *indomain, struct ypmaplist **outmaplist)
801{
802 struct ypresp_maplist resp;
d111572f 803 enum clnt_stat result;
6259ec0d
UD
804
805 if (indomain == NULL || indomain[0] == '\0')
806 return YPERR_BADARGS;
807
808 memset (&resp, '\0', sizeof (resp));
809
2c2efdc1
UD
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);
6259ec0d 813
a1ffb40e 814 if (__glibc_likely (result == YPERR_SUCCESS))
2c2efdc1
UD
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 }
a334319f 820
2c2efdc1 821 return result;
6259ec0d 822}
cdd14619 823libnsl_hidden_nolink_def (yp_maplist, GLIBC_2_0)
6259ec0d
UD
824
825const char *
826yperr_string (const int error)
827{
2c2efdc1 828 const char *str;
6259ec0d
UD
829 switch (error)
830 {
831 case YPERR_SUCCESS:
3e64e913 832 str = N_("Success");
2c2efdc1 833 break;
6259ec0d 834 case YPERR_BADARGS:
3e64e913 835 str = N_("Request arguments bad");
2c2efdc1 836 break;
6259ec0d 837 case YPERR_RPC:
3e64e913 838 str = N_("RPC failure on NIS operation");
2c2efdc1 839 break;
6259ec0d 840 case YPERR_DOMAIN:
3e64e913 841 str = N_("Can't bind to server which serves this domain");
2c2efdc1 842 break;
6259ec0d 843 case YPERR_MAP:
3e64e913 844 str = N_("No such map in server's domain");
2c2efdc1 845 break;
6259ec0d 846 case YPERR_KEY:
3e64e913 847 str = N_("No such key in map");
2c2efdc1 848 break;
6259ec0d 849 case YPERR_YPERR:
3e64e913 850 str = N_("Internal NIS error");
2c2efdc1 851 break;
6259ec0d 852 case YPERR_RESRC:
3e64e913 853 str = N_("Local resource allocation failure");
2c2efdc1 854 break;
6259ec0d 855 case YPERR_NOMORE:
3e64e913 856 str = N_("No more records in map database");
2c2efdc1 857 break;
6259ec0d 858 case YPERR_PMAP:
3e64e913 859 str = N_("Can't communicate with portmapper");
2c2efdc1 860 break;
6259ec0d 861 case YPERR_YPBIND:
3e64e913 862 str = N_("Can't communicate with ypbind");
2c2efdc1 863 break;
6259ec0d 864 case YPERR_YPSERV:
3e64e913 865 str = N_("Can't communicate with ypserv");
2c2efdc1 866 break;
6259ec0d 867 case YPERR_NODOM:
3e64e913 868 str = N_("Local domain name not set");
2c2efdc1 869 break;
6259ec0d 870 case YPERR_BADDB:
3e64e913 871 str = N_("NIS map database is bad");
2c2efdc1 872 break;
6259ec0d 873 case YPERR_VERS:
3e64e913 874 str = N_("NIS client/server version mismatch - can't supply service");
2c2efdc1 875 break;
6259ec0d 876 case YPERR_ACCESS:
3e64e913 877 str = N_("Permission denied");
2c2efdc1 878 break;
6259ec0d 879 case YPERR_BUSY:
3e64e913 880 str = N_("Database is busy");
2c2efdc1
UD
881 break;
882 default:
3e64e913 883 str = N_("Unknown NIS error code");
2c2efdc1 884 break;
6259ec0d 885 }
2c2efdc1 886 return _(str);
6259ec0d 887}
1e4d83f6 888libnsl_hidden_nolink_def(yperr_string, GLIBC_2_0)
6259ec0d 889
7440c23e
UD
890static const int8_t yp_2_yperr[] =
891 {
892#define YP2YPERR(yp, yperr) [YP_##yp - YP_VERS] = YPERR_##yperr
509230ca
UD
893 YP2YPERR (TRUE, SUCCESS),
894 YP2YPERR (NOMORE, NOMORE),
895 YP2YPERR (FALSE, YPERR),
896 YP2YPERR (NOMAP, MAP),
897 YP2YPERR (NODOM, DOMAIN),
7440c23e
UD
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 };
6259ec0d
UD
905int
906ypprot_err (const int code)
907{
509230ca 908 if (code < YP_VERS || code > YP_NOMORE)
7440c23e 909 return YPERR_YPERR;
a45e13bd 910 return yp_2_yperr[code - YP_VERS];
6259ec0d 911}
1e4d83f6 912libnsl_hidden_nolink_def (ypprot_err, GLIBC_2_0)
6259ec0d
UD
913
914const char *
915ypbinderr_string (const int error)
916{
2c2efdc1 917 const char *str;
6259ec0d
UD
918 switch (error)
919 {
920 case 0:
3e64e913 921 str = N_("Success");
2c2efdc1 922 break;
6259ec0d 923 case YPBIND_ERR_ERR:
3e64e913 924 str = N_("Internal ypbind error");
2c2efdc1 925 break;
6259ec0d 926 case YPBIND_ERR_NOSERV:
3e64e913 927 str = N_("Domain not bound");
2c2efdc1 928 break;
6259ec0d 929 case YPBIND_ERR_RESC:
3e64e913 930 str = N_("System resource allocation failure");
2c2efdc1 931 break;
6259ec0d 932 default:
3e64e913 933 str = N_("Unknown ypbind error");
2c2efdc1 934 break;
6259ec0d 935 }
2c2efdc1 936 return _(str);
6259ec0d 937}
1e4d83f6 938libnsl_hidden_nolink_def (ypbinderr_string, GLIBC_2_0)
6259ec0d
UD
939
940#define WINDOW 60
941
942int
943yp_update (char *domain, char *map, unsigned ypop,
944 char *key, int keylen, char *data, int datalen)
945{
6259ec0d
UD
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
0292b0dd 969 if ((r = yp_master (domain, map, &master)) != YPERR_SUCCESS)
6259ec0d
UD
970 return r;
971
972 if (!host2netname (servername, master, domain))
973 {
974 fputs (_("yp_update: cannot convert host to netname\n"), stderr);
0292b0dd 975 free (master);
6259ec0d
UD
976 return YPERR_YPERR;
977 }
978
0292b0dd
UD
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)
6259ec0d
UD
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
1016again:
26dee9c4 1017 r = clnt_call (clnt, ypop, xdr_argument, (caddr_t) &args,
cc3fa755 1018 (xdrproc_t) xdr_u_int, (caddr_t) &res, RPCTIMEOUT);
6259ec0d
UD
1019
1020 if (r == RPC_AUTHERROR)
1021 {
1022 if (clnt->cl_auth->ah_cred.oa_flavor == AUTH_DES)
1023 {
e975f14e 1024 auth_destroy (clnt->cl_auth);
6259ec0d
UD
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;
6259ec0d 1037}
1e4d83f6 1038libnsl_hidden_nolink_def(yp_update, GLIBC_2_0)