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