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