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