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