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