]> git.ipfire.org Git - thirdparty/glibc.git/blame - nis/ypclnt.c
Use __attribute_pure__ macro in bits/mathcalls.h
[thirdparty/glibc.git] / nis / ypclnt.c
CommitLineData
04277e02 1/* Copyright (C) 1996-2019 Free Software Foundation, Inc.
6259ec0d 2 This file is part of the GNU C Library.
b85697f6 3 Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996.
6259ec0d
UD
4
5 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
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.
6259ec0d
UD
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
41bdb6e2 13 Lesser General Public License for more details.
6259ec0d 14
41bdb6e2 15 You should have received a copy of the GNU Lesser General Public
59ba27a6
PE
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
6259ec0d 18
ee74a442 19#include <errno.h>
cc3fa755 20#include <fcntl.h>
6259ec0d
UD
21#include <string.h>
22#include <unistd.h>
4360eafd 23#include <libintl.h>
26dee9c4 24#include <rpc/rpc.h>
f21acc89 25#include <rpcsvc/nis.h>
6259ec0d
UD
26#include <rpcsvc/yp.h>
27#include <rpcsvc/ypclnt.h>
28#include <rpcsvc/ypupd.h>
8ccf22f9 29#include <sys/socket.h>
9931ba24 30#include <sys/uio.h>
ec999b8e 31#include <libc-lock.h>
82f43dd2 32#include <shlib-compat.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);
371 if (status == YPERR_SUCCESS)
372 /* We cast to ypresp_val although the pointer could also be of
373 type ypresp_key_val or ypresp_master or ypresp_order or
374 ypresp_maplist. But the stat element is in a common prefix so
375 this does not matter. */
376 status = ypprot_err (((struct ypresp_val *) resp)->stat);
377 return status;
378}
379
6259ec0d
UD
380
381__libc_lock_define_initialized (static, domainname_lock)
382
383int
384yp_get_default_domain (char **outdomain)
385{
386 int result = YPERR_SUCCESS;;
387 *outdomain = NULL;
388
389 __libc_lock_lock (domainname_lock);
390
2c2efdc1 391 if (ypdomainname[0] == '\0')
6259ec0d 392 {
2c2efdc1 393 if (getdomainname (ypdomainname, NIS_MAXNAMELEN))
6259ec0d 394 result = YPERR_NODOM;
2c2efdc1 395 else if (strcmp (ypdomainname, "(none)") == 0)
ee74a442 396 {
b85697f6 397 /* If domainname is not set, some systems will return "(none)" */
2c2efdc1 398 ypdomainname[0] = '\0';
ee74a442
UD
399 result = YPERR_NODOM;
400 }
6259ec0d 401 else
2c2efdc1 402 *outdomain = ypdomainname;
6259ec0d
UD
403 }
404 else
2c2efdc1 405 *outdomain = ypdomainname;
6259ec0d
UD
406
407 __libc_lock_unlock (domainname_lock);
408
409 return result;
410}
1e4d83f6 411libnsl_hidden_nolink_def (yp_get_default_domain, GLIBC_2_0)
6259ec0d
UD
412
413int
414__yp_check (char **domain)
415{
416 char *unused;
417
2c2efdc1 418 if (ypdomainname[0] == '\0')
6259ec0d
UD
419 if (yp_get_default_domain (&unused))
420 return 0;
6259ec0d
UD
421
422 if (domain)
2c2efdc1 423 *domain = ypdomainname;
6259ec0d 424
2c2efdc1 425 if (yp_bind (ypdomainname) == 0)
6259ec0d
UD
426 return 1;
427 return 0;
428}
1e4d83f6 429libnsl_hidden_nolink_def(__yp_check, GLIBC_2_0)
6259ec0d
UD
430
431int
432yp_match (const char *indomain, const char *inmap, const char *inkey,
433 const int inkeylen, char **outval, int *outvallen)
434{
435 ypreq_key req;
436 ypresp_val resp;
d111572f 437 enum clnt_stat result;
6259ec0d 438
34a5a146
JM
439 if (indomain == NULL || indomain[0] == '\0'
440 || inmap == NULL || inmap[0] == '\0'
441 || inkey == NULL || inkey[0] == '\0' || inkeylen <= 0)
6259ec0d
UD
442 return YPERR_BADARGS;
443
68dbb3a6
UD
444 req.domain = (char *) indomain;
445 req.map = (char *) inmap;
446 req.key.keydat_val = (char *) inkey;
6259ec0d
UD
447 req.key.keydat_len = inkeylen;
448
449 *outval = NULL;
450 *outvallen = 0;
451 memset (&resp, '\0', sizeof (resp));
452
2c2efdc1
UD
453 result = do_ypcall_tr (indomain, YPPROC_MATCH, (xdrproc_t) xdr_ypreq_key,
454 (caddr_t) &req, (xdrproc_t) xdr_ypresp_val,
455 (caddr_t) &resp);
6259ec0d 456
4bca4c17
UD
457 if (result != YPERR_SUCCESS)
458 return result;
6259ec0d
UD
459
460 *outvallen = resp.val.valdat_len;
461 *outval = malloc (*outvallen + 1);
2c2efdc1 462 int status = YPERR_RESRC;
a1ffb40e 463 if (__glibc_likely (*outval != NULL))
2c2efdc1
UD
464 {
465 memcpy (*outval, resp.val.valdat_val, *outvallen);
466 (*outval)[*outvallen] = '\0';
467 status = YPERR_SUCCESS;
468 }
6259ec0d
UD
469
470 xdr_free ((xdrproc_t) xdr_ypresp_val, (char *) &resp);
471
2c2efdc1 472 return status;
6259ec0d 473}
1e4d83f6 474libnsl_hidden_nolink_def(yp_match, GLIBC_2_0)
6259ec0d
UD
475
476int
477yp_first (const char *indomain, const char *inmap, char **outkey,
478 int *outkeylen, char **outval, int *outvallen)
479{
480 ypreq_nokey req;
481 ypresp_key_val resp;
d111572f 482 enum clnt_stat result;
6259ec0d 483
34a5a146
JM
484 if (indomain == NULL || indomain[0] == '\0'
485 || inmap == NULL || inmap[0] == '\0')
6259ec0d
UD
486 return YPERR_BADARGS;
487
68dbb3a6
UD
488 req.domain = (char *) indomain;
489 req.map = (char *) inmap;
6259ec0d
UD
490
491 *outkey = *outval = NULL;
492 *outkeylen = *outvallen = 0;
493 memset (&resp, '\0', sizeof (resp));
494
495 result = do_ypcall (indomain, YPPROC_FIRST, (xdrproc_t) xdr_ypreq_nokey,
2c2efdc1
UD
496 (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val,
497 (caddr_t) &resp);
6259ec0d
UD
498
499 if (result != RPC_SUCCESS)
d111572f 500 return YPERR_RPC;
6259ec0d
UD
501 if (resp.stat != YP_TRUE)
502 return ypprot_err (resp.stat);
503
2c2efdc1
UD
504 int status;
505 if (__builtin_expect ((*outkey = malloc (resp.key.keydat_len + 1)) != NULL
506 && (*outval = malloc (resp.val.valdat_len
507 + 1)) != NULL, 1))
508 {
509 *outkeylen = resp.key.keydat_len;
510 memcpy (*outkey, resp.key.keydat_val, *outkeylen);
511 (*outkey)[*outkeylen] = '\0';
512
513 *outvallen = resp.val.valdat_len;
514 memcpy (*outval, resp.val.valdat_val, *outvallen);
515 (*outval)[*outvallen] = '\0';
516
517 status = YPERR_SUCCESS;
518 }
519 else
520 {
521 free (*outkey);
522 status = YPERR_RESRC;
523 }
6259ec0d
UD
524
525 xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
526
2c2efdc1 527 return status;
6259ec0d 528}
1e4d83f6 529libnsl_hidden_nolink_def(yp_first, GLIBC_2_0)
6259ec0d
UD
530
531int
532yp_next (const char *indomain, const char *inmap, const char *inkey,
533 const int inkeylen, char **outkey, int *outkeylen, char **outval,
534 int *outvallen)
535{
536 ypreq_key req;
537 ypresp_key_val resp;
d111572f 538 enum clnt_stat result;
6259ec0d 539
34a5a146
JM
540 if (indomain == NULL || indomain[0] == '\0'
541 || inmap == NULL || inmap[0] == '\0'
542 || inkeylen <= 0 || inkey == NULL || inkey[0] == '\0')
6259ec0d
UD
543 return YPERR_BADARGS;
544
68dbb3a6
UD
545 req.domain = (char *) indomain;
546 req.map = (char *) inmap;
547 req.key.keydat_val = (char *) inkey;
6259ec0d
UD
548 req.key.keydat_len = inkeylen;
549
550 *outkey = *outval = NULL;
551 *outkeylen = *outvallen = 0;
552 memset (&resp, '\0', sizeof (resp));
553
2c2efdc1
UD
554 result = do_ypcall_tr (indomain, YPPROC_NEXT, (xdrproc_t) xdr_ypreq_key,
555 (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val,
556 (caddr_t) &resp);
6259ec0d 557
4bca4c17
UD
558 if (result != YPERR_SUCCESS)
559 return result;
6259ec0d 560
2c2efdc1
UD
561 int status;
562 if (__builtin_expect ((*outkey = malloc (resp.key.keydat_len + 1)) != NULL
563 && (*outval = malloc (resp.val.valdat_len
564 + 1)) != NULL, 1))
565 {
566 *outkeylen = resp.key.keydat_len;
567 memcpy (*outkey, resp.key.keydat_val, *outkeylen);
568 (*outkey)[*outkeylen] = '\0';
569
570 *outvallen = resp.val.valdat_len;
571 memcpy (*outval, resp.val.valdat_val, *outvallen);
572 (*outval)[*outvallen] = '\0';
573
574 status = YPERR_SUCCESS;
575 }
576 else
577 {
578 free (*outkey);
579 status = YPERR_RESRC;
580 }
6259ec0d
UD
581
582 xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
583
2c2efdc1 584 return status;
6259ec0d 585}
1e4d83f6 586libnsl_hidden_nolink_def(yp_next, GLIBC_2_0)
6259ec0d
UD
587
588int
589yp_master (const char *indomain, const char *inmap, char **outname)
590{
591 ypreq_nokey req;
592 ypresp_master resp;
d111572f 593 enum clnt_stat result;
6259ec0d 594
34a5a146
JM
595 if (indomain == NULL || indomain[0] == '\0'
596 || inmap == NULL || inmap[0] == '\0')
6259ec0d
UD
597 return YPERR_BADARGS;
598
68dbb3a6
UD
599 req.domain = (char *) indomain;
600 req.map = (char *) inmap;
6259ec0d
UD
601
602 memset (&resp, '\0', sizeof (ypresp_master));
603
2c2efdc1
UD
604 result = do_ypcall_tr (indomain, YPPROC_MASTER, (xdrproc_t) xdr_ypreq_nokey,
605 (caddr_t) &req, (xdrproc_t) xdr_ypresp_master,
606 (caddr_t) &resp);
6259ec0d 607
4bca4c17
UD
608 if (result != YPERR_SUCCESS)
609 return result;
6259ec0d
UD
610
611 *outname = strdup (resp.peer);
612 xdr_free ((xdrproc_t) xdr_ypresp_master, (char *) &resp);
613
d111572f 614 return *outname == NULL ? YPERR_YPERR : YPERR_SUCCESS;
6259ec0d 615}
1e4d83f6 616libnsl_hidden_nolink_def (yp_master, GLIBC_2_0)
6259ec0d
UD
617
618int
619yp_order (const char *indomain, const char *inmap, unsigned int *outorder)
620{
621 struct ypreq_nokey req;
622 struct ypresp_order resp;
d111572f 623 enum clnt_stat result;
6259ec0d 624
34a5a146
JM
625 if (indomain == NULL || indomain[0] == '\0'
626 || inmap == NULL || inmap[0] == '\0')
6259ec0d
UD
627 return YPERR_BADARGS;
628
68dbb3a6
UD
629 req.domain = (char *) indomain;
630 req.map = (char *) inmap;
6259ec0d
UD
631
632 memset (&resp, '\0', sizeof (resp));
633
2c2efdc1
UD
634 result = do_ypcall_tr (indomain, YPPROC_ORDER, (xdrproc_t) xdr_ypreq_nokey,
635 (caddr_t) &req, (xdrproc_t) xdr_ypresp_order,
636 (caddr_t) &resp);
6259ec0d 637
0f749099 638 if (result != YPERR_SUCCESS)
4bca4c17 639 return result;
6259ec0d
UD
640
641 *outorder = resp.ordernum;
642 xdr_free ((xdrproc_t) xdr_ypresp_order, (char *) &resp);
643
2c2efdc1 644 return result;
6259ec0d 645}
1e4d83f6 646libnsl_hidden_nolink_def(yp_order, GLIBC_2_0)
6259ec0d 647
ffdd5e50
UD
648struct ypresp_all_data
649{
650 unsigned long status;
651 void *data;
652 int (*foreach) (int status, char *key, int keylen,
653 char *val, int vallen, char *data);
654};
6259ec0d
UD
655
656static bool_t
ffdd5e50 657__xdr_ypresp_all (XDR *xdrs, struct ypresp_all_data *objp)
6259ec0d
UD
658{
659 while (1)
660 {
661 struct ypresp_all resp;
662
663 memset (&resp, '\0', sizeof (struct ypresp_all));
664 if (!xdr_ypresp_all (xdrs, &resp))
665 {
666 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
ffdd5e50 667 objp->status = YP_YPERR;
d111572f 668 return FALSE;
6259ec0d
UD
669 }
670 if (resp.more == 0)
671 {
672 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
ffdd5e50 673 objp->status = YP_NOMORE;
d111572f 674 return TRUE;
6259ec0d
UD
675 }
676
677 switch (resp.ypresp_all_u.val.stat)
678 {
679 case YP_TRUE:
680 {
681 char key[resp.ypresp_all_u.val.key.keydat_len + 1];
682 char val[resp.ypresp_all_u.val.val.valdat_len + 1];
683 int keylen = resp.ypresp_all_u.val.key.keydat_len;
684 int vallen = resp.ypresp_all_u.val.val.valdat_len;
685
b85697f6
UD
686 /* We are not allowed to modify the key and val data.
687 But we are allowed to add data behind the buffer,
688 if we don't modify the length. So add an extra NUL
689 character to avoid trouble with broken code. */
ffdd5e50 690 objp->status = YP_TRUE;
91287339
UD
691 *((char *) __mempcpy (key, resp.ypresp_all_u.val.key.keydat_val,
692 keylen)) = '\0';
693 *((char *) __mempcpy (val, resp.ypresp_all_u.val.val.valdat_val,
694 vallen)) = '\0';
6259ec0d 695 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
ffdd5e50
UD
696 if ((*objp->foreach) (objp->status, key, keylen,
697 val, vallen, objp->data))
6259ec0d
UD
698 return TRUE;
699 }
700 break;
6259ec0d 701 default:
ffdd5e50 702 objp->status = resp.ypresp_all_u.val.stat;
6259ec0d 703 xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
b85697f6 704 /* Sun says we don't need to make this call, but must return
91287339 705 immediately. Since Solaris makes this call, we will call
b85697f6 706 the callback function, too. */
ffdd5e50 707 (*objp->foreach) (objp->status, NULL, 0, NULL, 0, objp->data);
6259ec0d
UD
708 return TRUE;
709 }
710 }
711}
712
713int
714yp_all (const char *indomain, const char *inmap,
715 const struct ypall_callback *incallback)
716{
717 struct ypreq_nokey req;
cc3fa755 718 dom_binding *ydb = NULL;
d111572f
UD
719 int try, res;
720 enum clnt_stat result;
6259ec0d
UD
721 struct sockaddr_in clnt_sin;
722 CLIENT *clnt;
ffdd5e50 723 struct ypresp_all_data data;
6259ec0d 724 int clnt_sock;
a788b6c2 725 int saved_errno = errno;
6259ec0d 726
2c2efdc1
UD
727 if (indomain == NULL || indomain[0] == '\0'
728 || inmap == NULL || inmap[0] == '\0')
6259ec0d
UD
729 return YPERR_BADARGS;
730
731 try = 0;
d111572f 732 res = YPERR_YPERR;
6259ec0d 733
d111572f 734 while (try < MAXTRIES && res != YPERR_SUCCESS)
6259ec0d 735 {
6259ec0d
UD
736 if (__yp_bind (indomain, &ydb) != 0)
737 {
a788b6c2 738 __set_errno (saved_errno);
6259ec0d
UD
739 return YPERR_DOMAIN;
740 }
741
6259ec0d
UD
742 clnt_sock = RPC_ANYSOCK;
743 clnt_sin = ydb->dom_server_addr;
744 clnt_sin.sin_port = 0;
85939c79
UD
745
746 /* We don't need the UDP connection anymore. */
747 __yp_unbind (ydb);
47ae3942 748 ydb = NULL;
85939c79 749
6259ec0d
UD
750 clnt = clnttcp_create (&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
751 if (clnt == NULL)
a788b6c2
UD
752 {
753 __set_errno (saved_errno);
754 return YPERR_PMAP;
755 }
68dbb3a6
UD
756 req.domain = (char *) indomain;
757 req.map = (char *) inmap;
6259ec0d 758
ffdd5e50
UD
759 data.foreach = incallback->foreach;
760 data.data = (void *) incallback->data;
6259ec0d 761
3e5f5557
UD
762 result = clnt_call (clnt, YPPROC_ALL, (xdrproc_t) xdr_ypreq_nokey,
763 (caddr_t) &req, (xdrproc_t) __xdr_ypresp_all,
ffdd5e50 764 (caddr_t) &data, RPCTIMEOUT);
6259ec0d 765
a1ffb40e 766 if (__glibc_unlikely (result != RPC_SUCCESS))
6259ec0d 767 {
2c2efdc1 768 /* Print the error message only on the last try. */
c891b2df
UD
769 if (try == MAXTRIES - 1)
770 clnt_perror (clnt, "yp_all: clnt_call");
d111572f 771 res = YPERR_RPC;
6259ec0d
UD
772 }
773 else
d111572f
UD
774 res = YPERR_SUCCESS;
775
776 clnt_destroy (clnt);
6259ec0d 777
ffdd5e50 778 if (res == YPERR_SUCCESS && data.status != YP_NOMORE)
a788b6c2
UD
779 {
780 __set_errno (saved_errno);
ffdd5e50 781 return ypprot_err (data.status);
a788b6c2
UD
782 }
783 ++try;
6259ec0d
UD
784 }
785
a788b6c2
UD
786 __set_errno (saved_errno);
787
d111572f 788 return res;
6259ec0d 789}
1e4d83f6 790libnsl_hidden_nolink_def (yp_all, GLIBC_2_0)
6259ec0d
UD
791
792int
793yp_maplist (const char *indomain, struct ypmaplist **outmaplist)
794{
795 struct ypresp_maplist resp;
d111572f 796 enum clnt_stat result;
6259ec0d
UD
797
798 if (indomain == NULL || indomain[0] == '\0')
799 return YPERR_BADARGS;
800
801 memset (&resp, '\0', sizeof (resp));
802
2c2efdc1
UD
803 result = do_ypcall_tr (indomain, YPPROC_MAPLIST, (xdrproc_t) xdr_domainname,
804 (caddr_t) &indomain, (xdrproc_t) xdr_ypresp_maplist,
805 (caddr_t) &resp);
6259ec0d 806
a1ffb40e 807 if (__glibc_likely (result == YPERR_SUCCESS))
2c2efdc1
UD
808 {
809 *outmaplist = resp.maps;
810 /* We don't free the list, this will be done by ypserv
811 xdr_free((xdrproc_t)xdr_ypresp_maplist, (char *)&resp); */
812 }
a334319f 813
2c2efdc1 814 return result;
6259ec0d 815}
cdd14619 816libnsl_hidden_nolink_def (yp_maplist, GLIBC_2_0)
6259ec0d
UD
817
818const char *
819yperr_string (const int error)
820{
2c2efdc1 821 const char *str;
6259ec0d
UD
822 switch (error)
823 {
824 case YPERR_SUCCESS:
3e64e913 825 str = N_("Success");
2c2efdc1 826 break;
6259ec0d 827 case YPERR_BADARGS:
3e64e913 828 str = N_("Request arguments bad");
2c2efdc1 829 break;
6259ec0d 830 case YPERR_RPC:
3e64e913 831 str = N_("RPC failure on NIS operation");
2c2efdc1 832 break;
6259ec0d 833 case YPERR_DOMAIN:
3e64e913 834 str = N_("Can't bind to server which serves this domain");
2c2efdc1 835 break;
6259ec0d 836 case YPERR_MAP:
3e64e913 837 str = N_("No such map in server's domain");
2c2efdc1 838 break;
6259ec0d 839 case YPERR_KEY:
3e64e913 840 str = N_("No such key in map");
2c2efdc1 841 break;
6259ec0d 842 case YPERR_YPERR:
3e64e913 843 str = N_("Internal NIS error");
2c2efdc1 844 break;
6259ec0d 845 case YPERR_RESRC:
3e64e913 846 str = N_("Local resource allocation failure");
2c2efdc1 847 break;
6259ec0d 848 case YPERR_NOMORE:
3e64e913 849 str = N_("No more records in map database");
2c2efdc1 850 break;
6259ec0d 851 case YPERR_PMAP:
3e64e913 852 str = N_("Can't communicate with portmapper");
2c2efdc1 853 break;
6259ec0d 854 case YPERR_YPBIND:
3e64e913 855 str = N_("Can't communicate with ypbind");
2c2efdc1 856 break;
6259ec0d 857 case YPERR_YPSERV:
3e64e913 858 str = N_("Can't communicate with ypserv");
2c2efdc1 859 break;
6259ec0d 860 case YPERR_NODOM:
3e64e913 861 str = N_("Local domain name not set");
2c2efdc1 862 break;
6259ec0d 863 case YPERR_BADDB:
3e64e913 864 str = N_("NIS map database is bad");
2c2efdc1 865 break;
6259ec0d 866 case YPERR_VERS:
3e64e913 867 str = N_("NIS client/server version mismatch - can't supply service");
2c2efdc1 868 break;
6259ec0d 869 case YPERR_ACCESS:
3e64e913 870 str = N_("Permission denied");
2c2efdc1 871 break;
6259ec0d 872 case YPERR_BUSY:
3e64e913 873 str = N_("Database is busy");
2c2efdc1
UD
874 break;
875 default:
3e64e913 876 str = N_("Unknown NIS error code");
2c2efdc1 877 break;
6259ec0d 878 }
2c2efdc1 879 return _(str);
6259ec0d 880}
1e4d83f6 881libnsl_hidden_nolink_def(yperr_string, GLIBC_2_0)
6259ec0d 882
7440c23e
UD
883static const int8_t yp_2_yperr[] =
884 {
885#define YP2YPERR(yp, yperr) [YP_##yp - YP_VERS] = YPERR_##yperr
509230ca
UD
886 YP2YPERR (TRUE, SUCCESS),
887 YP2YPERR (NOMORE, NOMORE),
888 YP2YPERR (FALSE, YPERR),
889 YP2YPERR (NOMAP, MAP),
890 YP2YPERR (NODOM, DOMAIN),
7440c23e
UD
891 YP2YPERR (NOKEY, KEY),
892 YP2YPERR (BADOP, YPERR),
893 YP2YPERR (BADDB, BADDB),
894 YP2YPERR (YPERR, YPERR),
895 YP2YPERR (BADARGS, BADARGS),
896 YP2YPERR (VERS, VERS)
897 };
6259ec0d
UD
898int
899ypprot_err (const int code)
900{
509230ca 901 if (code < YP_VERS || code > YP_NOMORE)
7440c23e 902 return YPERR_YPERR;
a45e13bd 903 return yp_2_yperr[code - YP_VERS];
6259ec0d 904}
1e4d83f6 905libnsl_hidden_nolink_def (ypprot_err, GLIBC_2_0)
6259ec0d
UD
906
907const char *
908ypbinderr_string (const int error)
909{
2c2efdc1 910 const char *str;
6259ec0d
UD
911 switch (error)
912 {
913 case 0:
3e64e913 914 str = N_("Success");
2c2efdc1 915 break;
6259ec0d 916 case YPBIND_ERR_ERR:
3e64e913 917 str = N_("Internal ypbind error");
2c2efdc1 918 break;
6259ec0d 919 case YPBIND_ERR_NOSERV:
3e64e913 920 str = N_("Domain not bound");
2c2efdc1 921 break;
6259ec0d 922 case YPBIND_ERR_RESC:
3e64e913 923 str = N_("System resource allocation failure");
2c2efdc1 924 break;
6259ec0d 925 default:
3e64e913 926 str = N_("Unknown ypbind error");
2c2efdc1 927 break;
6259ec0d 928 }
2c2efdc1 929 return _(str);
6259ec0d 930}
1e4d83f6 931libnsl_hidden_nolink_def (ypbinderr_string, GLIBC_2_0)
6259ec0d
UD
932
933#define WINDOW 60
934
935int
936yp_update (char *domain, char *map, unsigned ypop,
937 char *key, int keylen, char *data, int datalen)
938{
6259ec0d
UD
939 union
940 {
941 ypupdate_args update_args;
942 ypdelete_args delete_args;
943 }
944 args;
945 xdrproc_t xdr_argument;
946 unsigned res = 0;
947 CLIENT *clnt;
948 char *master;
949 struct sockaddr saddr;
950 char servername[MAXNETNAMELEN + 1];
951 int r;
952
953 if (!domain || !map || !key || (ypop != YPOP_DELETE && !data))
954 return YPERR_BADARGS;
955
956 args.update_args.mapname = map;
957 args.update_args.key.yp_buf_len = keylen;
958 args.update_args.key.yp_buf_val = key;
959 args.update_args.datum.yp_buf_len = datalen;
960 args.update_args.datum.yp_buf_val = data;
961
0292b0dd 962 if ((r = yp_master (domain, map, &master)) != YPERR_SUCCESS)
6259ec0d
UD
963 return r;
964
965 if (!host2netname (servername, master, domain))
966 {
967 fputs (_("yp_update: cannot convert host to netname\n"), stderr);
0292b0dd 968 free (master);
6259ec0d
UD
969 return YPERR_YPERR;
970 }
971
0292b0dd
UD
972 clnt = clnt_create (master, YPU_PROG, YPU_VERS, "tcp");
973
974 /* We do not need the string anymore. */
975 free (master);
976
977 if (clnt == NULL)
6259ec0d
UD
978 {
979 clnt_pcreateerror ("yp_update: clnt_create");
980 return YPERR_RPC;
981 }
982
983 if (!clnt_control (clnt, CLGET_SERVER_ADDR, (char *) &saddr))
984 {
985 fputs (_("yp_update: cannot get server address\n"), stderr);
986 return YPERR_RPC;
987 }
988
989 switch (ypop)
990 {
991 case YPOP_CHANGE:
992 case YPOP_INSERT:
993 case YPOP_STORE:
994 xdr_argument = (xdrproc_t) xdr_ypupdate_args;
995 break;
996 case YPOP_DELETE:
997 xdr_argument = (xdrproc_t) xdr_ypdelete_args;
998 break;
999 default:
1000 return YPERR_BADARGS;
1001 break;
1002 }
1003
1004 clnt->cl_auth = authdes_create (servername, WINDOW, &saddr, NULL);
1005
1006 if (clnt->cl_auth == NULL)
1007 clnt->cl_auth = authunix_create_default ();
1008
1009again:
26dee9c4 1010 r = clnt_call (clnt, ypop, xdr_argument, (caddr_t) &args,
cc3fa755 1011 (xdrproc_t) xdr_u_int, (caddr_t) &res, RPCTIMEOUT);
6259ec0d
UD
1012
1013 if (r == RPC_AUTHERROR)
1014 {
1015 if (clnt->cl_auth->ah_cred.oa_flavor == AUTH_DES)
1016 {
e975f14e 1017 auth_destroy (clnt->cl_auth);
6259ec0d
UD
1018 clnt->cl_auth = authunix_create_default ();
1019 goto again;
1020 }
1021 else
1022 return YPERR_ACCESS;
1023 }
1024 if (r != RPC_SUCCESS)
1025 {
1026 clnt_perror (clnt, "yp_update: clnt_call");
1027 return YPERR_RPC;
1028 }
1029 return res;
6259ec0d 1030}
1e4d83f6 1031libnsl_hidden_nolink_def(yp_update, GLIBC_2_0)