AMD64 - yp functions take pointers to int, not pointers to size_t.
[dragonfly.git] / lib / libc / yp / yplib.c
blob14c31410c14395b1e2d6fb9ef070bc158460eae6
1 /*
2 * Copyright (c) 1992/3 Theo de Raadt <deraadt@fsa.ca>
3 * Copyright (c) 1998 Bill Paul <wpaul@ctr.columbia.edu>
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote
15 * products derived from this software without specific prior written
16 * permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
19 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
30 * $FreeBSD: src/lib/libc/yp/yplib.c,v 1.51 2007/07/24 13:06:08 simon Exp $
31 * $DragonFly: src/lib/libc/yp/yplib.c,v 1.9 2006/08/03 16:40:46 swildner Exp $
34 #include "namespace.h"
35 #include "reentrant.h"
36 #include <sys/param.h>
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <sys/file.h>
40 #include <sys/uio.h>
41 #include <arpa/inet.h>
42 #include <errno.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include <stdlib.h>
46 #include <unistd.h>
47 #include <rpc/rpc.h>
48 #include <rpc/xdr.h>
49 #include <rpcsvc/yp.h>
50 #include "un-namespace.h"
51 #include "libc_private.h"
53 bool_t xdr_ypresp_all_seq(XDR *, u_long *);
54 int _yp_check(char **);
56 int (*ypresp_allfn)(unsigned long, char *, int, char *, int, void *);
59 * We have to define these here due to clashes between yp_prot.h and
60 * yp.h.
63 #define YPMATCHCACHE
65 #ifdef YPMATCHCACHE
66 struct ypmatch_ent {
67 char *ypc_map;
68 keydat ypc_key;
69 valdat ypc_val;
70 time_t ypc_expire_t;
71 struct ypmatch_ent *ypc_next;
73 #define YPLIB_MAXCACHE 5 /* At most 5 entries */
74 #define YPLIB_EXPIRE 5 /* Expire after 5 seconds */
75 #endif
77 struct dom_binding {
78 struct dom_binding *dom_pnext;
79 char dom_domain[YPMAXDOMAIN + 1];
80 struct sockaddr_in dom_server_addr;
81 u_short dom_server_port;
82 int dom_socket;
83 CLIENT *dom_client;
84 u_short dom_local_port; /* now I finally know what this is for. */
85 long dom_vers;
86 #ifdef YPMATCHCACHE
87 struct ypmatch_ent *cache;
88 int ypmatch_cachecnt;
89 #endif
92 #include <rpcsvc/yp.h>
93 #include <rpcsvc/ypclnt.h>
95 #ifndef BINDINGDIR
96 #define BINDINGDIR "/var/yp/binding"
97 #endif
98 #define MAX_RETRIES 20
100 void *ypresp_data;
102 static void _yp_unbind(struct dom_binding *);
103 struct dom_binding *_ypbindlist;
104 static char _yp_domain[MAXHOSTNAMELEN];
105 int _yplib_timeout = 20;
107 static mutex_t _ypmutex = MUTEX_INITIALIZER;
108 #define YPLOCK() mutex_lock(&_ypmutex);
109 #define YPUNLOCK() mutex_unlock(&_ypmutex);
111 #ifdef YPMATCHCACHE
112 static void
113 ypmatch_cache_delete(struct dom_binding *ypdb, struct ypmatch_ent *prev,
114 struct ypmatch_ent *cur)
116 if (prev == NULL)
117 ypdb->cache = cur->ypc_next;
118 else
119 prev->ypc_next = cur->ypc_next;
121 free(cur->ypc_map);
122 free(cur->ypc_key.keydat_val);
123 free(cur->ypc_val.valdat_val);
124 free(cur);
126 ypdb->ypmatch_cachecnt--;
128 return;
131 static void
132 ypmatch_cache_flush(struct dom_binding *ypdb)
134 struct ypmatch_ent *n, *c = ypdb->cache;
136 while (c != NULL) {
137 n = c->ypc_next;
138 ypmatch_cache_delete(ypdb, NULL, c);
139 c = n;
142 return;
145 static void
146 ypmatch_cache_expire(struct dom_binding *ypdb)
148 struct ypmatch_ent *c = ypdb->cache;
149 struct ypmatch_ent *n, *p = NULL;
150 time_t t;
152 time(&t);
154 while (c != NULL) {
155 if (t >= c->ypc_expire_t) {
156 n = c->ypc_next;
157 ypmatch_cache_delete(ypdb, p, c);
158 c = n;
159 } else {
160 p = c;
161 c = c->ypc_next;
165 return;
168 static void
169 ypmatch_cache_insert(struct dom_binding *ypdb, char *map, keydat *key,
170 valdat *val)
172 struct ypmatch_ent *new;
174 /* Do an expire run to maybe open up a slot. */
175 if (ypdb->ypmatch_cachecnt)
176 ypmatch_cache_expire(ypdb);
179 * If there are no slots free, then force an expire of
180 * the least recently used entry.
182 if (ypdb->ypmatch_cachecnt >= YPLIB_MAXCACHE) {
183 struct ypmatch_ent *o = NULL, *c = ypdb->cache;
184 time_t oldest = 0;
186 oldest = ~oldest;
188 while (c != NULL) {
189 if (c->ypc_expire_t < oldest) {
190 oldest = c->ypc_expire_t;
191 o = c;
193 c = c->ypc_next;
196 if (o == NULL)
197 return;
198 o->ypc_expire_t = 0;
199 ypmatch_cache_expire(ypdb);
202 new = malloc(sizeof(struct ypmatch_ent));
203 if (new == NULL)
204 return;
206 new->ypc_map = strdup(map);
207 if (new->ypc_map == NULL) {
208 free(new);
209 return;
211 new->ypc_key.keydat_val = malloc(key->keydat_len);
212 if (new->ypc_key.keydat_val == NULL) {
213 free(new->ypc_map);
214 free(new);
215 return;
217 new->ypc_val.valdat_val = malloc(val->valdat_len);
218 if (new->ypc_val.valdat_val == NULL) {
219 free(new->ypc_val.valdat_val);
220 free(new->ypc_map);
221 free(new);
222 return;
225 new->ypc_expire_t = time(NULL) + YPLIB_EXPIRE;
226 new->ypc_key.keydat_len = key->keydat_len;
227 new->ypc_val.valdat_len = val->valdat_len;
228 bcopy(key->keydat_val, new->ypc_key.keydat_val, key->keydat_len);
229 bcopy(val->valdat_val, new->ypc_val.valdat_val, val->valdat_len);
231 new->ypc_next = ypdb->cache;
232 ypdb->cache = new;
234 ypdb->ypmatch_cachecnt++;
236 return;
239 static bool_t
240 ypmatch_cache_lookup(struct dom_binding *ypdb, char *map, keydat *key,
241 valdat *val)
243 struct ypmatch_ent *c = ypdb->cache;
245 ypmatch_cache_expire(ypdb);
247 for (c = ypdb->cache; c != NULL; c = c->ypc_next) {
248 if (strcmp(map, c->ypc_map))
249 continue;
250 if (key->keydat_len != c->ypc_key.keydat_len)
251 continue;
252 if (bcmp(key->keydat_val, c->ypc_key.keydat_val,
253 key->keydat_len))
254 continue;
257 if (c == NULL)
258 return(FALSE);
260 val->valdat_len = c->ypc_val.valdat_len;
261 val->valdat_val = c->ypc_val.valdat_val;
263 return(TRUE);
265 #endif
267 char *
268 ypbinderr_string(int incode)
270 const char *errstr;
271 static char err[80];
272 switch (incode) {
273 case 0:
274 errstr = "Success";
275 break;
276 case YPBIND_ERR_ERR:
277 errstr = "Internal ypbind error";
278 break;
279 case YPBIND_ERR_NOSERV:
280 errstr = "Domain not bound";
281 break;
282 case YPBIND_ERR_RESC:
283 errstr = "System resource allocation failure";
284 break;
285 default:
286 errstr = NULL;
287 break;
289 if (errstr != NULL)
290 strlcpy(err, errstr, sizeof(err));
291 else
292 snprintf(err, sizeof(err), "Unknown ypbind error: #%d\n", incode);
293 return (err);
297 _yp_dobind(const char *dom, struct dom_binding **ypdb)
299 static pid_t pid = -1;
300 char path[MAXPATHLEN];
301 struct dom_binding *ysd, *ysd2;
302 struct ypbind_resp ypbr;
303 struct timeval tv;
304 struct sockaddr_in clnt_sin;
305 int clnt_sock, fd;
306 pid_t gpid;
307 CLIENT *client;
308 int new = 0;
309 ssize_t r;
310 int retries = 0;
311 struct sockaddr_in check;
312 socklen_t checklen = sizeof(struct sockaddr_in);
314 /* Not allowed; bad doggie. Bad. */
315 if (strchr(dom, '/') != NULL)
316 return(YPERR_BADARGS);
318 gpid = getpid();
319 if (!(pid == -1 || pid == gpid)) {
320 ysd = _ypbindlist;
321 while (ysd) {
322 if (ysd->dom_client != NULL)
323 _yp_unbind(ysd);
324 ysd2 = ysd->dom_pnext;
325 free(ysd);
326 ysd = ysd2;
328 _ypbindlist = NULL;
330 pid = gpid;
332 if (ypdb != NULL)
333 *ypdb = NULL;
335 if (dom == NULL || strlen(dom) == 0)
336 return (YPERR_BADARGS);
338 for (ysd = _ypbindlist; ysd; ysd = ysd->dom_pnext)
339 if (strcmp(dom, ysd->dom_domain) == 0)
340 break;
343 if (ysd == NULL) {
344 ysd = (struct dom_binding *)malloc(sizeof *ysd);
345 bzero((char *)ysd, sizeof *ysd);
346 ysd->dom_socket = -1;
347 ysd->dom_vers = 0;
348 new = 1;
349 } else {
350 /* Check the socket -- may have been hosed by the caller. */
351 if (_getsockname(ysd->dom_socket, (struct sockaddr *)&check,
352 &checklen) == -1 || check.sin_family != AF_INET ||
353 check.sin_port != ysd->dom_local_port) {
354 /* Socket became bogus somehow... need to rebind. */
355 int save, sock;
357 sock = ysd->dom_socket;
358 save = _dup(ysd->dom_socket);
359 if (ysd->dom_client != NULL)
360 clnt_destroy(ysd->dom_client);
361 ysd->dom_vers = 0;
362 ysd->dom_client = NULL;
363 sock = _dup2(save, sock);
364 _close(save);
368 again:
369 retries++;
370 if (retries > MAX_RETRIES) {
371 if (new)
372 free(ysd);
373 return(YPERR_YPBIND);
375 #ifdef BINDINGDIR
376 if (ysd->dom_vers == 0) {
378 * We're trying to make a new binding: zorch the
379 * existing handle now (if any).
381 if (ysd->dom_client != NULL) {
382 clnt_destroy(ysd->dom_client);
383 ysd->dom_client = NULL;
384 ysd->dom_socket = -1;
386 snprintf(path, sizeof(path), "%s/%s.%d", BINDINGDIR, dom, 2);
387 if ((fd = _open(path, O_RDONLY)) == -1) {
388 /* no binding file, YP is dead. */
389 /* Try to bring it back to life. */
390 _close(fd);
391 goto skipit;
393 if (_flock(fd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK) {
394 struct iovec iov[2];
395 struct ypbind_resp ybr;
396 u_short ypb_port;
398 iov[0].iov_base = (caddr_t)&ypb_port;
399 iov[0].iov_len = sizeof ypb_port;
400 iov[1].iov_base = (caddr_t)&ybr;
401 iov[1].iov_len = sizeof ybr;
403 r = _readv(fd, iov, 2);
404 if (r != (ssize_t)(iov[0].iov_len + iov[1].iov_len)) {
405 _close(fd);
406 ysd->dom_vers = -1;
407 goto again;
410 bzero(&ysd->dom_server_addr, sizeof ysd->dom_server_addr);
411 ysd->dom_server_addr.sin_family = AF_INET;
412 ysd->dom_server_addr.sin_len = sizeof(struct sockaddr_in);
413 bcopy(&ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
414 &ysd->dom_server_addr.sin_addr.s_addr,
415 sizeof(ysd->dom_server_addr.sin_addr.s_addr));
416 bcopy(&ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
417 &ysd->dom_server_addr.sin_port,
418 sizeof(ysd->dom_server_addr.sin_port));
420 ysd->dom_server_port = ysd->dom_server_addr.sin_port;
421 _close(fd);
422 goto gotit;
423 } else {
424 /* no lock on binding file, YP is dead. */
425 /* Try to bring it back to life. */
426 _close(fd);
427 goto skipit;
430 skipit:
431 #endif
432 if (ysd->dom_vers == -1 || ysd->dom_vers == 0) {
434 * We're trying to make a new binding: zorch the
435 * existing handle now (if any).
437 if (ysd->dom_client != NULL) {
438 clnt_destroy(ysd->dom_client);
439 ysd->dom_client = NULL;
440 ysd->dom_socket = -1;
442 bzero((char *)&clnt_sin, sizeof clnt_sin);
443 clnt_sin.sin_family = AF_INET;
444 clnt_sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
446 clnt_sock = RPC_ANYSOCK;
447 client = clnttcp_create(&clnt_sin, YPBINDPROG, YPBINDVERS, &clnt_sock,
448 0, 0);
449 if (client == NULL) {
451 * These conditions indicate ypbind just isn't
452 * alive -- we probably don't want to shoot our
453 * mouth off in this case; instead generate error
454 * messages only for really exotic problems.
456 if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED &&
457 (rpc_createerr.cf_stat != RPC_SYSTEMERROR &&
458 rpc_createerr.cf_error.re_errno == ECONNREFUSED))
459 clnt_pcreateerror("clnttcp_create");
460 if (new)
461 free(ysd);
462 return (YPERR_YPBIND);
466 * Check the port number -- should be < IPPORT_RESERVED.
467 * If not, it's possible someone has registered a bogus
468 * ypbind with the portmapper and is trying to trick us.
470 if (ntohs(clnt_sin.sin_port) >= IPPORT_RESERVED) {
471 if (client != NULL)
472 clnt_destroy(client);
473 if (new)
474 free(ysd);
475 return(YPERR_YPBIND);
477 tv.tv_sec = _yplib_timeout/2;
478 tv.tv_usec = 0;
479 r = clnt_call(client, YPBINDPROC_DOMAIN,
480 (xdrproc_t)xdr_domainname, &dom,
481 (xdrproc_t)xdr_ypbind_resp, &ypbr, tv);
482 if (r != RPC_SUCCESS) {
483 clnt_destroy(client);
484 ysd->dom_vers = -1;
485 if (r == RPC_PROGUNAVAIL || r == RPC_PROCUNAVAIL) {
486 if (new)
487 free(ysd);
488 return(YPERR_YPBIND);
490 fprintf(stderr,
491 "YP: server for domain %s not responding, retrying\n", dom);
492 goto again;
493 } else {
494 if (ypbr.ypbind_status != YPBIND_SUCC_VAL) {
495 struct timespec time_to_sleep, time_remaining;
497 clnt_destroy(client);
498 ysd->dom_vers = -1;
500 time_to_sleep.tv_sec = _yplib_timeout/2;
501 time_to_sleep.tv_nsec = 0;
502 _nanosleep(&time_to_sleep,
503 &time_remaining);
504 goto again;
507 clnt_destroy(client);
509 bzero((char *)&ysd->dom_server_addr, sizeof ysd->dom_server_addr);
510 ysd->dom_server_addr.sin_family = AF_INET;
511 bcopy(&ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
512 &ysd->dom_server_addr.sin_port,
513 sizeof(ysd->dom_server_addr.sin_port));
514 bcopy(&ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
515 &ysd->dom_server_addr.sin_addr.s_addr,
516 sizeof(ysd->dom_server_addr.sin_addr.s_addr));
519 * We could do a reserved port check here too, but this
520 * could pose compatibility problems. The local ypbind is
521 * supposed to decide whether or not to trust yp servers
522 * on insecure ports. For now, we trust its judgement.
524 ysd->dom_server_port =
525 *(u_short *)&ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port;
526 gotit:
527 ysd->dom_vers = YPVERS;
528 strlcpy(ysd->dom_domain, dom, sizeof(ysd->dom_domain));
531 /* Don't rebuild the connection to the server unless we have to. */
532 if (ysd->dom_client == NULL) {
533 tv.tv_sec = _yplib_timeout/2;
534 tv.tv_usec = 0;
535 ysd->dom_socket = RPC_ANYSOCK;
536 ysd->dom_client = clntudp_bufcreate(&ysd->dom_server_addr,
537 YPPROG, YPVERS, tv, &ysd->dom_socket, 1280, 2304);
538 if (ysd->dom_client == NULL) {
539 clnt_pcreateerror("clntudp_create");
540 ysd->dom_vers = -1;
541 goto again;
543 if (_fcntl(ysd->dom_socket, F_SETFD, 1) == -1)
544 perror("fcntl: F_SETFD");
546 * We want a port number associated with this socket
547 * so that we can check its authenticity later.
549 checklen = sizeof(struct sockaddr_in);
550 bzero((char *)&check, checklen);
551 _bind(ysd->dom_socket, (struct sockaddr *)&check, checklen);
552 check.sin_family = AF_INET;
553 if (!_getsockname(ysd->dom_socket,
554 (struct sockaddr *)&check, &checklen)) {
555 ysd->dom_local_port = check.sin_port;
556 } else {
557 clnt_destroy(ysd->dom_client);
558 if (new)
559 free(ysd);
560 return(YPERR_YPBIND);
564 if (new) {
565 ysd->dom_pnext = _ypbindlist;
566 _ypbindlist = ysd;
570 * Set low retry timeout to realistically handle UDP packet
571 * loss for YP packet bursts.
573 tv.tv_sec = 1;
574 tv.tv_usec = 0;
575 clnt_control(ysd->dom_client, CLSET_RETRY_TIMEOUT, (char*)&tv);
577 if (ypdb != NULL)
578 *ypdb = ysd;
579 return (0);
582 static void
583 _yp_unbind(struct dom_binding *ypb)
585 struct sockaddr_in check;
586 socklen_t checklen = sizeof(struct sockaddr_in);
588 if (ypb->dom_client != NULL) {
589 /* Check the socket -- may have been hosed by the caller. */
590 if (_getsockname(ypb->dom_socket, (struct sockaddr *)&check,
591 &checklen) == -1 || check.sin_family != AF_INET ||
592 check.sin_port != ypb->dom_local_port) {
593 int save, sock;
595 sock = ypb->dom_socket;
596 save = _dup(ypb->dom_socket);
597 clnt_destroy(ypb->dom_client);
598 sock = _dup2(save, sock);
599 _close(save);
600 } else
601 clnt_destroy(ypb->dom_client);
604 ypb->dom_client = NULL;
605 ypb->dom_socket = -1;
606 ypb->dom_vers = -1;
607 #ifdef YPMATCHCACHE
608 ypmatch_cache_flush(ypb);
609 #endif
612 static int
613 yp_bind_locked(char *dom)
615 return (_yp_dobind(dom, NULL));
619 yp_bind(char *dom)
621 int r;
623 YPLOCK();
624 r = yp_bind_locked(dom);
625 YPUNLOCK();
626 return (r);
629 static void
630 yp_unbind_locked(char *dom)
632 struct dom_binding *ypb, *ypbp;
634 ypbp = NULL;
635 for (ypb = _ypbindlist; ypb; ypb = ypb->dom_pnext) {
636 if (strcmp(dom, ypb->dom_domain) == 0) {
637 _yp_unbind(ypb);
638 if (ypbp)
639 ypbp->dom_pnext = ypb->dom_pnext;
640 else
641 _ypbindlist = ypb->dom_pnext;
642 free(ypb);
643 return;
645 ypbp = ypb;
647 return;
650 void
651 yp_unbind(char *dom)
653 YPLOCK();
654 yp_unbind_locked(dom);
655 YPUNLOCK();
659 yp_match(char *indomain, char *inmap, const char *inkey, int inkeylen,
660 char **outval, int *outvallen)
662 struct dom_binding *ysd;
663 struct ypresp_val yprv;
664 struct timeval tv;
665 struct ypreq_key yprk;
666 int r;
668 *outval = NULL;
669 *outvallen = 0;
671 /* Sanity check */
673 if (inkey == NULL || !strlen(inkey) || inkeylen <= 0 ||
674 inmap == NULL || !strlen(inmap) ||
675 indomain == NULL || !strlen(indomain))
676 return (YPERR_BADARGS);
678 YPLOCK();
679 if (_yp_dobind(indomain, &ysd) != 0) {
680 YPUNLOCK();
681 return(YPERR_DOMAIN);
684 yprk.domain = indomain;
685 yprk.map = inmap;
686 yprk.key.keydat_val = (char *)inkey;
687 yprk.key.keydat_len = inkeylen;
689 #ifdef YPMATCHCACHE
690 if (ypmatch_cache_lookup(ysd, yprk.map, &yprk.key, &yprv.val) == TRUE) {
692 if (!strcmp(_yp_domain, indomain) && ypmatch_find(inmap, inkey,
693 inkeylen, &yprv.val.valdat_val, &yprv.val.valdat_len)) {
695 *outvallen = yprv.val.valdat_len;
696 *outval = (char *)malloc(*outvallen+1);
697 bcopy(yprv.val.valdat_val, *outval, *outvallen);
698 (*outval)[*outvallen] = '\0';
699 YPUNLOCK();
700 return (0);
702 #endif
704 again:
705 if (_yp_dobind(indomain, &ysd) != 0) {
706 YPUNLOCK();
707 return (YPERR_DOMAIN);
710 tv.tv_sec = _yplib_timeout;
711 tv.tv_usec = 0;
713 bzero((char *)&yprv, sizeof yprv);
715 r = clnt_call(ysd->dom_client, YPPROC_MATCH,
716 (xdrproc_t)xdr_ypreq_key, &yprk,
717 (xdrproc_t)xdr_ypresp_val, &yprv, tv);
718 if (r != RPC_SUCCESS) {
719 clnt_perror(ysd->dom_client, "yp_match: clnt_call");
720 _yp_unbind(ysd);
721 goto again;
724 if (!(r = ypprot_err(yprv.stat))) {
725 *outvallen = yprv.val.valdat_len;
726 *outval = (char *)malloc(*outvallen+1);
727 bcopy(yprv.val.valdat_val, *outval, *outvallen);
728 (*outval)[*outvallen] = '\0';
729 #ifdef YPMATCHCACHE
730 ypmatch_cache_insert(ysd, yprk.map, &yprk.key, &yprv.val);
731 #endif
734 xdr_free((xdrproc_t)xdr_ypresp_val, &yprv);
735 YPUNLOCK();
736 return (r);
739 static int
740 yp_get_default_domain_locked(char **domp)
742 *domp = NULL;
743 if (_yp_domain[0] == '\0')
744 if (getdomainname(_yp_domain, sizeof _yp_domain))
745 return (YPERR_NODOM);
746 *domp = _yp_domain;
747 return (0);
751 yp_get_default_domain(char **domp)
753 int r;
755 YPLOCK();
756 r = yp_get_default_domain_locked(domp);
757 YPUNLOCK();
758 return (r);
762 yp_first(char *indomain, char *inmap, char **outkey, int *outkeylen,
763 char **outval, int *outvallen)
765 struct ypresp_key_val yprkv;
766 struct ypreq_nokey yprnk;
767 struct dom_binding *ysd;
768 struct timeval tv;
769 int r;
771 /* Sanity check */
773 if (indomain == NULL || !strlen(indomain) ||
774 inmap == NULL || !strlen(inmap))
775 return (YPERR_BADARGS);
777 *outkey = *outval = NULL;
778 *outkeylen = *outvallen = 0;
780 YPLOCK();
781 again:
782 if (_yp_dobind(indomain, &ysd) != 0) {
783 YPUNLOCK();
784 return (YPERR_DOMAIN);
787 tv.tv_sec = _yplib_timeout;
788 tv.tv_usec = 0;
790 yprnk.domain = indomain;
791 yprnk.map = inmap;
792 bzero((char *)&yprkv, sizeof yprkv);
794 r = clnt_call(ysd->dom_client, YPPROC_FIRST,
795 (xdrproc_t)xdr_ypreq_nokey, &yprnk,
796 (xdrproc_t)xdr_ypresp_key_val, &yprkv, tv);
797 if (r != RPC_SUCCESS) {
798 clnt_perror(ysd->dom_client, "yp_first: clnt_call");
799 _yp_unbind(ysd);
800 goto again;
802 if (!(r = ypprot_err(yprkv.stat))) {
803 *outkeylen = yprkv.key.keydat_len;
804 *outkey = (char *)malloc(*outkeylen+1);
805 bcopy(yprkv.key.keydat_val, *outkey, *outkeylen);
806 (*outkey)[*outkeylen] = '\0';
807 *outvallen = yprkv.val.valdat_len;
808 *outval = (char *)malloc(*outvallen+1);
809 bcopy(yprkv.val.valdat_val, *outval, *outvallen);
810 (*outval)[*outvallen] = '\0';
813 xdr_free((xdrproc_t)xdr_ypresp_key_val, &yprkv);
814 YPUNLOCK();
815 return (r);
819 yp_next(char *indomain, char *inmap, char *inkey, int inkeylen,
820 char **outkey, int *outkeylen, char **outval, int *outvallen)
822 struct ypresp_key_val yprkv;
823 struct ypreq_key yprk;
824 struct dom_binding *ysd;
825 struct timeval tv;
826 int r;
828 /* Sanity check */
830 if (inkey == NULL || !strlen(inkey) || inkeylen <= 0 ||
831 inmap == NULL || !strlen(inmap) ||
832 indomain == NULL || !strlen(indomain))
833 return (YPERR_BADARGS);
835 *outkey = *outval = NULL;
836 *outkeylen = *outvallen = 0;
838 YPLOCK();
839 again:
840 if (_yp_dobind(indomain, &ysd) != 0) {
841 YPUNLOCK();
842 return (YPERR_DOMAIN);
845 tv.tv_sec = _yplib_timeout;
846 tv.tv_usec = 0;
848 yprk.domain = indomain;
849 yprk.map = inmap;
850 yprk.key.keydat_val = inkey;
851 yprk.key.keydat_len = inkeylen;
852 bzero((char *)&yprkv, sizeof yprkv);
854 r = clnt_call(ysd->dom_client, YPPROC_NEXT,
855 (xdrproc_t)xdr_ypreq_key, &yprk,
856 (xdrproc_t)xdr_ypresp_key_val, &yprkv, tv);
857 if (r != RPC_SUCCESS) {
858 clnt_perror(ysd->dom_client, "yp_next: clnt_call");
859 _yp_unbind(ysd);
860 goto again;
862 if (!(r = ypprot_err(yprkv.stat))) {
863 *outkeylen = yprkv.key.keydat_len;
864 *outkey = (char *)malloc(*outkeylen+1);
865 bcopy(yprkv.key.keydat_val, *outkey, *outkeylen);
866 (*outkey)[*outkeylen] = '\0';
867 *outvallen = yprkv.val.valdat_len;
868 *outval = (char *)malloc(*outvallen+1);
869 bcopy(yprkv.val.valdat_val, *outval, *outvallen);
870 (*outval)[*outvallen] = '\0';
873 xdr_free((xdrproc_t)xdr_ypresp_key_val, &yprkv);
874 YPUNLOCK();
875 return (r);
879 yp_all(char *indomain, char *inmap, struct ypall_callback *incallback)
881 struct ypreq_nokey yprnk;
882 struct dom_binding *ysd;
883 struct timeval tv;
884 struct sockaddr_in clnt_sin;
885 CLIENT *clnt;
886 u_long status, savstat;
887 int clnt_sock;
889 /* Sanity check */
891 if (indomain == NULL || !strlen(indomain) ||
892 inmap == NULL || !strlen(inmap))
893 return (YPERR_BADARGS);
895 YPLOCK();
896 again:
898 if (_yp_dobind(indomain, &ysd) != 0) {
899 YPUNLOCK();
900 return (YPERR_DOMAIN);
903 tv.tv_sec = _yplib_timeout;
904 tv.tv_usec = 0;
906 /* YPPROC_ALL manufactures its own channel to ypserv using TCP */
908 clnt_sock = RPC_ANYSOCK;
909 clnt_sin = ysd->dom_server_addr;
910 clnt_sin.sin_port = 0;
911 clnt = clnttcp_create(&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
912 if (clnt == NULL) {
913 YPUNLOCK();
914 printf("clnttcp_create failed\n");
915 return (YPERR_PMAP);
918 yprnk.domain = indomain;
919 yprnk.map = inmap;
920 ypresp_allfn = incallback->foreach;
921 ypresp_data = (void *)incallback->data;
923 if (clnt_call(clnt, YPPROC_ALL,
924 (xdrproc_t)xdr_ypreq_nokey, &yprnk,
925 (xdrproc_t)xdr_ypresp_all_seq, &status, tv) != RPC_SUCCESS) {
926 clnt_perror(ysd->dom_client, "yp_all: clnt_call");
927 clnt_destroy(clnt);
928 _yp_unbind(ysd);
929 goto again;
932 clnt_destroy(clnt);
933 savstat = status;
934 xdr_free((xdrproc_t)xdr_ypresp_all_seq, &status); /* not really needed... */
935 YPUNLOCK();
936 if (savstat != YP_NOMORE)
937 return (ypprot_err(savstat));
938 return (0);
942 yp_order(char *indomain, char *inmap, int *outorder)
944 struct dom_binding *ysd;
945 struct ypresp_order ypro;
946 struct ypreq_nokey yprnk;
947 struct timeval tv;
948 int r;
950 /* Sanity check */
952 if (indomain == NULL || !strlen(indomain) ||
953 inmap == NULL || !strlen(inmap))
954 return (YPERR_BADARGS);
956 YPLOCK();
957 again:
958 if (_yp_dobind(indomain, &ysd) != 0) {
959 YPUNLOCK();
960 return (YPERR_DOMAIN);
963 tv.tv_sec = _yplib_timeout;
964 tv.tv_usec = 0;
966 yprnk.domain = indomain;
967 yprnk.map = inmap;
969 bzero((char *)(char *)&ypro, sizeof ypro);
971 r = clnt_call(ysd->dom_client, YPPROC_ORDER,
972 (xdrproc_t)xdr_ypreq_nokey, &yprnk,
973 (xdrproc_t)xdr_ypresp_order, &ypro, tv);
976 * NIS+ in YP compat mode doesn't support the YPPROC_ORDER
977 * procedure.
979 if (r == RPC_PROCUNAVAIL) {
980 YPUNLOCK();
981 return(YPERR_YPERR);
984 if (r != RPC_SUCCESS) {
985 clnt_perror(ysd->dom_client, "yp_order: clnt_call");
986 _yp_unbind(ysd);
987 goto again;
990 if (!(r = ypprot_err(ypro.stat))) {
991 *outorder = ypro.ordernum;
994 xdr_free((xdrproc_t)xdr_ypresp_order, &ypro);
995 YPUNLOCK();
996 return (r);
1000 yp_master(char *indomain, char *inmap, char **outname)
1002 struct dom_binding *ysd;
1003 struct ypresp_master yprm;
1004 struct ypreq_nokey yprnk;
1005 struct timeval tv;
1006 int r;
1008 /* Sanity check */
1010 if (indomain == NULL || !strlen(indomain) ||
1011 inmap == NULL || !strlen(inmap))
1012 return (YPERR_BADARGS);
1013 YPLOCK();
1014 again:
1015 if (_yp_dobind(indomain, &ysd) != 0) {
1016 YPUNLOCK();
1017 return (YPERR_DOMAIN);
1020 tv.tv_sec = _yplib_timeout;
1021 tv.tv_usec = 0;
1023 yprnk.domain = indomain;
1024 yprnk.map = inmap;
1026 bzero((char *)&yprm, sizeof yprm);
1028 r = clnt_call(ysd->dom_client, YPPROC_MASTER,
1029 (xdrproc_t)xdr_ypreq_nokey, &yprnk,
1030 (xdrproc_t)xdr_ypresp_master, &yprm, tv);
1031 if (r != RPC_SUCCESS) {
1032 clnt_perror(ysd->dom_client, "yp_master: clnt_call");
1033 _yp_unbind(ysd);
1034 goto again;
1037 if (!(r = ypprot_err(yprm.stat))) {
1038 *outname = (char *)strdup(yprm.peer);
1041 xdr_free((xdrproc_t)xdr_ypresp_master, &yprm);
1042 YPUNLOCK();
1043 return (r);
1047 yp_maplist(char *indomain, struct ypmaplist **outmaplist)
1049 struct dom_binding *ysd;
1050 struct ypresp_maplist ypml;
1051 struct timeval tv;
1052 int r;
1054 /* Sanity check */
1056 if (indomain == NULL || !strlen(indomain))
1057 return (YPERR_BADARGS);
1059 YPLOCK();
1060 again:
1061 if (_yp_dobind(indomain, &ysd) != 0) {
1062 YPUNLOCK();
1063 return (YPERR_DOMAIN);
1066 tv.tv_sec = _yplib_timeout;
1067 tv.tv_usec = 0;
1069 bzero((char *)&ypml, sizeof ypml);
1071 r = clnt_call(ysd->dom_client, YPPROC_MAPLIST,
1072 (xdrproc_t)xdr_domainname, &indomain,
1073 (xdrproc_t)xdr_ypresp_maplist, &ypml, tv);
1074 if (r != RPC_SUCCESS) {
1075 clnt_perror(ysd->dom_client, "yp_maplist: clnt_call");
1076 _yp_unbind(ysd);
1077 goto again;
1079 if (!(r = ypprot_err(ypml.stat))) {
1080 *outmaplist = ypml.maps;
1083 /* NO: xdr_free((xdrproc_t)xdr_ypresp_maplist, &ypml);*/
1084 YPUNLOCK();
1085 return (r);
1088 char *
1089 yperr_string(int incode)
1091 const char *errstr;
1092 static char err[80];
1094 switch (incode) {
1095 case 0:
1096 errstr = "Success";
1097 break;
1098 case YPERR_BADARGS:
1099 errstr = "Request arguments bad";
1100 break;
1101 case YPERR_RPC:
1102 errstr = "RPC failure";
1103 break;
1104 case YPERR_DOMAIN:
1105 errstr = "Can't bind to server which serves this domain";
1106 break;
1107 case YPERR_MAP:
1108 errstr = "No such map in server's domain";
1109 break;
1110 case YPERR_KEY:
1111 errstr = "No such key in map";
1112 break;
1113 case YPERR_YPERR:
1114 errstr = "YP server error";
1115 break;
1116 case YPERR_RESRC:
1117 errstr = "Local resource allocation failure";
1118 break;
1119 case YPERR_NOMORE:
1120 errstr = "No more records in map database";
1121 break;
1122 case YPERR_PMAP:
1123 errstr = "Can't communicate with portmapper";
1124 break;
1125 case YPERR_YPBIND:
1126 errstr = "Can't communicate with ypbind";
1127 break;
1128 case YPERR_YPSERV:
1129 errstr = "Can't communicate with ypserv";
1130 break;
1131 case YPERR_NODOM:
1132 errstr = "Local domain name not set";
1133 break;
1134 case YPERR_BADDB:
1135 errstr = "Server data base is bad";
1136 break;
1137 case YPERR_VERS:
1138 errstr = "YP server version mismatch - server can't supply service.";
1139 break;
1140 case YPERR_ACCESS:
1141 errstr = "Access violation";
1142 break;
1143 case YPERR_BUSY:
1144 errstr = "Database is busy";
1145 break;
1146 default:
1147 errstr = NULL;
1148 break;
1150 if (errstr != NULL)
1151 strlcpy(err, errstr, sizeof(err));
1152 else
1153 snprintf(err, sizeof(err), "YP unknown error %d\n", incode);
1154 return (err);
1158 ypprot_err(unsigned int incode)
1160 switch (incode) {
1161 case YP_TRUE:
1162 return (0);
1163 case YP_FALSE:
1164 return (YPERR_YPBIND);
1165 case YP_NOMORE:
1166 return (YPERR_NOMORE);
1167 case YP_NOMAP:
1168 return (YPERR_MAP);
1169 case YP_NODOM:
1170 return (YPERR_DOMAIN);
1171 case YP_NOKEY:
1172 return (YPERR_KEY);
1173 case YP_BADOP:
1174 return (YPERR_YPERR);
1175 case YP_BADDB:
1176 return (YPERR_BADDB);
1177 case YP_YPERR:
1178 return (YPERR_YPERR);
1179 case YP_BADARGS:
1180 return (YPERR_BADARGS);
1181 case YP_VERS:
1182 return (YPERR_VERS);
1184 return (YPERR_YPERR);
1188 _yp_check(char **dom)
1190 char *unused;
1192 YPLOCK();
1193 if (_yp_domain[0]=='\0')
1194 if (yp_get_default_domain_locked(&unused)) {
1195 YPUNLOCK();
1196 return (0);
1199 if (dom)
1200 *dom = _yp_domain;
1202 if (yp_bind_locked(_yp_domain) == 0) {
1203 yp_unbind_locked(_yp_domain);
1204 YPUNLOCK();
1205 return (1);
1207 YPUNLOCK();
1208 return (0);