AMD64 - yp functions take pointers to int, not pointers to size_t.
[dragonfly.git] / lib / libc / yp / yplib.c
CommitLineData
984263bc
MD
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.
5 *
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.
17 *
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.
1de703da 29 *
63882998 30 * $FreeBSD: src/lib/libc/yp/yplib.c,v 1.51 2007/07/24 13:06:08 simon Exp $
fc6d0222 31 * $DragonFly: src/lib/libc/yp/yplib.c,v 1.9 2006/08/03 16:40:46 swildner Exp $
984263bc
MD
32 */
33
17ea2221 34#include "namespace.h"
63882998 35#include "reentrant.h"
984263bc
MD
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>
63882998 41#include <arpa/inet.h>
984263bc
MD
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>
17ea2221 50#include "un-namespace.h"
63882998 51#include "libc_private.h"
984263bc 52
2375287c
JS
53bool_t xdr_ypresp_all_seq(XDR *, u_long *);
54int _yp_check(char **);
55
a71fb5b1
JS
56int (*ypresp_allfn)(unsigned long, char *, int, char *, int, void *);
57
984263bc
MD
58/*
59 * We have to define these here due to clashes between yp_prot.h and
60 * yp.h.
61 */
62
63#define YPMATCHCACHE
64
65#ifdef YPMATCHCACHE
66struct 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;
72};
73#define YPLIB_MAXCACHE 5 /* At most 5 entries */
74#define YPLIB_EXPIRE 5 /* Expire after 5 seconds */
75#endif
76
77struct 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
90};
91
2375287c 92#include <rpcsvc/yp.h>
984263bc
MD
93#include <rpcsvc/ypclnt.h>
94
95#ifndef BINDINGDIR
96#define BINDINGDIR "/var/yp/binding"
97#endif
98#define MAX_RETRIES 20
99
984263bc
MD
100void *ypresp_data;
101
102static void _yp_unbind(struct dom_binding *);
103struct dom_binding *_ypbindlist;
104static char _yp_domain[MAXHOSTNAMELEN];
63882998
PA
105int _yplib_timeout = 20;
106
107static mutex_t _ypmutex = MUTEX_INITIALIZER;
108#define YPLOCK() mutex_lock(&_ypmutex);
109#define YPUNLOCK() mutex_unlock(&_ypmutex);
984263bc
MD
110
111#ifdef YPMATCHCACHE
e9c93684
HP
112static void
113ypmatch_cache_delete(struct dom_binding *ypdb, struct ypmatch_ent *prev,
114 struct ypmatch_ent *cur)
984263bc
MD
115{
116 if (prev == NULL)
117 ypdb->cache = cur->ypc_next;
118 else
119 prev->ypc_next = cur->ypc_next;
120
121 free(cur->ypc_map);
122 free(cur->ypc_key.keydat_val);
123 free(cur->ypc_val.valdat_val);
124 free(cur);
125
126 ypdb->ypmatch_cachecnt--;
127
128 return;
129}
130
e9c93684
HP
131static void
132ypmatch_cache_flush(struct dom_binding *ypdb)
984263bc
MD
133{
134 struct ypmatch_ent *n, *c = ypdb->cache;
135
136 while (c != NULL) {
137 n = c->ypc_next;
138 ypmatch_cache_delete(ypdb, NULL, c);
139 c = n;
140 }
141
142 return;
143}
144
e9c93684
HP
145static void
146ypmatch_cache_expire(struct dom_binding *ypdb)
984263bc
MD
147{
148 struct ypmatch_ent *c = ypdb->cache;
149 struct ypmatch_ent *n, *p = NULL;
150 time_t t;
151
152 time(&t);
153
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;
162 }
163 }
164
165 return;
166}
167
e9c93684
HP
168static void
169ypmatch_cache_insert(struct dom_binding *ypdb, char *map, keydat *key,
170 valdat *val)
984263bc
MD
171{
172 struct ypmatch_ent *new;
173
174 /* Do an expire run to maybe open up a slot. */
175 if (ypdb->ypmatch_cachecnt)
176 ypmatch_cache_expire(ypdb);
177
178 /*
179 * If there are no slots free, then force an expire of
180 * the least recently used entry.
181 */
182 if (ypdb->ypmatch_cachecnt >= YPLIB_MAXCACHE) {
183 struct ypmatch_ent *o = NULL, *c = ypdb->cache;
184 time_t oldest = 0;
185
186 oldest = ~oldest;
187
188 while (c != NULL) {
189 if (c->ypc_expire_t < oldest) {
190 oldest = c->ypc_expire_t;
191 o = c;
192 }
193 c = c->ypc_next;
194 }
195
196 if (o == NULL)
197 return;
198 o->ypc_expire_t = 0;
199 ypmatch_cache_expire(ypdb);
200 }
201
202 new = malloc(sizeof(struct ypmatch_ent));
203 if (new == NULL)
204 return;
205
206 new->ypc_map = strdup(map);
207 if (new->ypc_map == NULL) {
208 free(new);
209 return;
210 }
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;
216 }
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;
223 }
224
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);
230
231 new->ypc_next = ypdb->cache;
232 ypdb->cache = new;
233
234 ypdb->ypmatch_cachecnt++;
235
236 return;
237}
238
e9c93684
HP
239static bool_t
240ypmatch_cache_lookup(struct dom_binding *ypdb, char *map, keydat *key,
241 valdat *val)
984263bc
MD
242{
243 struct ypmatch_ent *c = ypdb->cache;
244
245 ypmatch_cache_expire(ypdb);
246
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;
255 }
256
257 if (c == NULL)
258 return(FALSE);
259
260 val->valdat_len = c->ypc_val.valdat_len;
261 val->valdat_val = c->ypc_val.valdat_val;
262
263 return(TRUE);
264}
265#endif
266
267char *
e9c93684 268ypbinderr_string(int incode)
984263bc 269{
2375287c 270 const char *errstr;
984263bc
MD
271 static char err[80];
272 switch (incode) {
273 case 0:
2375287c
JS
274 errstr = "Success";
275 break;
984263bc 276 case YPBIND_ERR_ERR:
2375287c
JS
277 errstr = "Internal ypbind error";
278 break;
984263bc 279 case YPBIND_ERR_NOSERV:
2375287c
JS
280 errstr = "Domain not bound";
281 break;
984263bc 282 case YPBIND_ERR_RESC:
2375287c
JS
283 errstr = "System resource allocation failure";
284 break;
285 default:
286 errstr = NULL;
287 break;
984263bc 288 }
2375287c
JS
289 if (errstr != NULL)
290 strlcpy(err, errstr, sizeof(err));
291 else
292 snprintf(err, sizeof(err), "Unknown ypbind error: #%d\n", incode);
984263bc
MD
293 return (err);
294}
295
296int
2375287c 297_yp_dobind(const char *dom, struct dom_binding **ypdb)
984263bc
MD
298{
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;
2375287c
JS
308 int new = 0;
309 ssize_t r;
984263bc
MD
310 int retries = 0;
311 struct sockaddr_in check;
63882998 312 socklen_t checklen = sizeof(struct sockaddr_in);
984263bc
MD
313
314 /* Not allowed; bad doggie. Bad. */
315 if (strchr(dom, '/') != NULL)
316 return(YPERR_BADARGS);
317
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;
327 }
328 _ypbindlist = NULL;
329 }
330 pid = gpid;
331
332 if (ypdb != NULL)
333 *ypdb = NULL;
334
335 if (dom == NULL || strlen(dom) == 0)
336 return (YPERR_BADARGS);
337
338 for (ysd = _ypbindlist; ysd; ysd = ysd->dom_pnext)
339 if (strcmp(dom, ysd->dom_domain) == 0)
340 break;
341
342
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. */
17ea2221 351 if (_getsockname(ysd->dom_socket, (struct sockaddr *)&check,
984263bc
MD
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;
356
357 sock = ysd->dom_socket;
17ea2221 358 save = _dup(ysd->dom_socket);
984263bc
MD
359 if (ysd->dom_client != NULL)
360 clnt_destroy(ysd->dom_client);
361 ysd->dom_vers = 0;
362 ysd->dom_client = NULL;
17ea2221 363 sock = _dup2(save, sock);
984263bc
MD
364 _close(save);
365 }
366 }
367
368again:
369 retries++;
370 if (retries > MAX_RETRIES) {
371 if (new)
372 free(ysd);
373 return(YPERR_YPBIND);
374 }
375#ifdef BINDINGDIR
376 if (ysd->dom_vers == 0) {
377 /*
378 * We're trying to make a new binding: zorch the
379 * existing handle now (if any).
380 */
381 if (ysd->dom_client != NULL) {
382 clnt_destroy(ysd->dom_client);
383 ysd->dom_client = NULL;
384 ysd->dom_socket = -1;
385 }
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;
392 }
17ea2221 393 if (_flock(fd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK) {
984263bc
MD
394 struct iovec iov[2];
395 struct ypbind_resp ybr;
396 u_short ypb_port;
397
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;
402
17ea2221 403 r = _readv(fd, iov, 2);
2375287c 404 if (r != (ssize_t)(iov[0].iov_len + iov[1].iov_len)) {
984263bc
MD
405 _close(fd);
406 ysd->dom_vers = -1;
407 goto again;
408 }
409
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);
63882998
PA
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));
984263bc
MD
419
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;
428 }
429 }
430skipit:
431#endif
432 if (ysd->dom_vers == -1 || ysd->dom_vers == 0) {
433 /*
434 * We're trying to make a new binding: zorch the
435 * existing handle now (if any).
436 */
437 if (ysd->dom_client != NULL) {
438 clnt_destroy(ysd->dom_client);
439 ysd->dom_client = NULL;
440 ysd->dom_socket = -1;
441 }
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);
445
446 clnt_sock = RPC_ANYSOCK;
447 client = clnttcp_create(&clnt_sin, YPBINDPROG, YPBINDVERS, &clnt_sock,
448 0, 0);
449 if (client == NULL) {
450 /*
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.
455 */
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);
463 }
464
465 /*
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.
469 */
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);
476 }
477 tv.tv_sec = _yplib_timeout/2;
478 tv.tv_usec = 0;
479 r = clnt_call(client, YPBINDPROC_DOMAIN,
63882998 480 (xdrproc_t)xdr_domainname, &dom,
7048805a 481 (xdrproc_t)xdr_ypbind_resp, &ypbr, tv);
984263bc
MD
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);
489 }
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;
496
497 clnt_destroy(client);
498 ysd->dom_vers = -1;
499
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;
505 }
506 }
507 clnt_destroy(client);
508
509 bzero((char *)&ysd->dom_server_addr, sizeof ysd->dom_server_addr);
510 ysd->dom_server_addr.sin_family = AF_INET;
63882998
PA
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));
984263bc
MD
517
518 /*
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.
523 */
524 ysd->dom_server_port =
525 *(u_short *)&ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port;
526gotit:
527 ysd->dom_vers = YPVERS;
528 strlcpy(ysd->dom_domain, dom, sizeof(ysd->dom_domain));
529 }
530
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;
542 }
543 if (_fcntl(ysd->dom_socket, F_SETFD, 1) == -1)
544 perror("fcntl: F_SETFD");
545 /*
546 * We want a port number associated with this socket
547 * so that we can check its authenticity later.
548 */
549 checklen = sizeof(struct sockaddr_in);
550 bzero((char *)&check, checklen);
17ea2221 551 _bind(ysd->dom_socket, (struct sockaddr *)&check, checklen);
984263bc 552 check.sin_family = AF_INET;
17ea2221 553 if (!_getsockname(ysd->dom_socket,
984263bc
MD
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);
561 }
562 }
563
564 if (new) {
565 ysd->dom_pnext = _ypbindlist;
566 _ypbindlist = ysd;
567 }
568
63882998
PA
569 /*
570 * Set low retry timeout to realistically handle UDP packet
571 * loss for YP packet bursts.
572 */
573 tv.tv_sec = 1;
574 tv.tv_usec = 0;
575 clnt_control(ysd->dom_client, CLSET_RETRY_TIMEOUT, (char*)&tv);
576
984263bc
MD
577 if (ypdb != NULL)
578 *ypdb = ysd;
579 return (0);
580}
581
582static void
e9c93684 583_yp_unbind(struct dom_binding *ypb)
984263bc
MD
584{
585 struct sockaddr_in check;
63882998 586 socklen_t checklen = sizeof(struct sockaddr_in);
984263bc
MD
587
588 if (ypb->dom_client != NULL) {
589 /* Check the socket -- may have been hosed by the caller. */
17ea2221 590 if (_getsockname(ypb->dom_socket, (struct sockaddr *)&check,
984263bc
MD
591 &checklen) == -1 || check.sin_family != AF_INET ||
592 check.sin_port != ypb->dom_local_port) {
593 int save, sock;
594
595 sock = ypb->dom_socket;
17ea2221 596 save = _dup(ypb->dom_socket);
984263bc 597 clnt_destroy(ypb->dom_client);
17ea2221 598 sock = _dup2(save, sock);
984263bc
MD
599 _close(save);
600 } else
601 clnt_destroy(ypb->dom_client);
602 }
603
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
610}
611
63882998
PA
612static int
613yp_bind_locked(char *dom)
614{
615 return (_yp_dobind(dom, NULL));
616}
617
984263bc 618int
e9c93684 619yp_bind(char *dom)
984263bc 620{
63882998
PA
621 int r;
622
623 YPLOCK();
624 r = yp_bind_locked(dom);
625 YPUNLOCK();
626 return (r);
984263bc
MD
627}
628
63882998
PA
629static void
630yp_unbind_locked(char *dom)
984263bc
MD
631{
632 struct dom_binding *ypb, *ypbp;
633
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;
644 }
645 ypbp = ypb;
646 }
647 return;
648}
649
63882998
PA
650void
651yp_unbind(char *dom)
652{
653 YPLOCK();
654 yp_unbind_locked(dom);
655 YPUNLOCK();
656}
657
984263bc 658int
7048805a 659yp_match(char *indomain, char *inmap, const char *inkey, int inkeylen,
e9c93684 660 char **outval, int *outvallen)
984263bc
MD
661{
662 struct dom_binding *ysd;
663 struct ypresp_val yprv;
664 struct timeval tv;
665 struct ypreq_key yprk;
666 int r;
667
668 *outval = NULL;
669 *outvallen = 0;
670
671 /* Sanity check */
672
673 if (inkey == NULL || !strlen(inkey) || inkeylen <= 0 ||
674 inmap == NULL || !strlen(inmap) ||
675 indomain == NULL || !strlen(indomain))
676 return (YPERR_BADARGS);
677
63882998
PA
678 YPLOCK();
679 if (_yp_dobind(indomain, &ysd) != 0) {
680 YPUNLOCK();
984263bc 681 return(YPERR_DOMAIN);
63882998 682 }
984263bc
MD
683
684 yprk.domain = indomain;
685 yprk.map = inmap;
686 yprk.key.keydat_val = (char *)inkey;
687 yprk.key.keydat_len = inkeylen;
688
689#ifdef YPMATCHCACHE
690 if (ypmatch_cache_lookup(ysd, yprk.map, &yprk.key, &yprv.val) == TRUE) {
691/*
692 if (!strcmp(_yp_domain, indomain) && ypmatch_find(inmap, inkey,
693 inkeylen, &yprv.val.valdat_val, &yprv.val.valdat_len)) {
694*/
695 *outvallen = yprv.val.valdat_len;
696 *outval = (char *)malloc(*outvallen+1);
697 bcopy(yprv.val.valdat_val, *outval, *outvallen);
698 (*outval)[*outvallen] = '\0';
63882998 699 YPUNLOCK();
984263bc
MD
700 return (0);
701 }
702#endif
703
704again:
63882998
PA
705 if (_yp_dobind(indomain, &ysd) != 0) {
706 YPUNLOCK();
984263bc 707 return (YPERR_DOMAIN);
63882998 708 }
984263bc
MD
709
710 tv.tv_sec = _yplib_timeout;
711 tv.tv_usec = 0;
712
713 bzero((char *)&yprv, sizeof yprv);
714
715 r = clnt_call(ysd->dom_client, YPPROC_MATCH,
7048805a
SW
716 (xdrproc_t)xdr_ypreq_key, &yprk,
717 (xdrproc_t)xdr_ypresp_val, &yprv, tv);
984263bc
MD
718 if (r != RPC_SUCCESS) {
719 clnt_perror(ysd->dom_client, "yp_match: clnt_call");
720 _yp_unbind(ysd);
721 goto again;
722 }
723
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
732 }
733
7048805a 734 xdr_free((xdrproc_t)xdr_ypresp_val, &yprv);
63882998 735 YPUNLOCK();
984263bc
MD
736 return (r);
737}
738
63882998
PA
739static int
740yp_get_default_domain_locked(char **domp)
984263bc
MD
741{
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);
748}
749
750int
63882998
PA
751yp_get_default_domain(char **domp)
752{
753 int r;
754
755 YPLOCK();
756 r = yp_get_default_domain_locked(domp);
757 YPUNLOCK();
758 return (r);
759}
760
761int
4ae574ee
MD
762yp_first(char *indomain, char *inmap, char **outkey, int *outkeylen,
763 char **outval, int *outvallen)
984263bc
MD
764{
765 struct ypresp_key_val yprkv;
766 struct ypreq_nokey yprnk;
767 struct dom_binding *ysd;
768 struct timeval tv;
769 int r;
770
771 /* Sanity check */
772
773 if (indomain == NULL || !strlen(indomain) ||
774 inmap == NULL || !strlen(inmap))
775 return (YPERR_BADARGS);
776
777 *outkey = *outval = NULL;
778 *outkeylen = *outvallen = 0;
779
63882998 780 YPLOCK();
984263bc 781again:
63882998
PA
782 if (_yp_dobind(indomain, &ysd) != 0) {
783 YPUNLOCK();
984263bc 784 return (YPERR_DOMAIN);
63882998 785 }
984263bc
MD
786
787 tv.tv_sec = _yplib_timeout;
788 tv.tv_usec = 0;
789
790 yprnk.domain = indomain;
791 yprnk.map = inmap;
792 bzero((char *)&yprkv, sizeof yprkv);
793
794 r = clnt_call(ysd->dom_client, YPPROC_FIRST,
7048805a
SW
795 (xdrproc_t)xdr_ypreq_nokey, &yprnk,
796 (xdrproc_t)xdr_ypresp_key_val, &yprkv, tv);
984263bc
MD
797 if (r != RPC_SUCCESS) {
798 clnt_perror(ysd->dom_client, "yp_first: clnt_call");
799 _yp_unbind(ysd);
800 goto again;
801 }
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';
811 }
812
7048805a 813 xdr_free((xdrproc_t)xdr_ypresp_key_val, &yprkv);
63882998 814 YPUNLOCK();
984263bc
MD
815 return (r);
816}
817
818int
4ae574ee
MD
819yp_next(char *indomain, char *inmap, char *inkey, int inkeylen,
820 char **outkey, int *outkeylen, char **outval, int *outvallen)
984263bc
MD
821{
822 struct ypresp_key_val yprkv;
823 struct ypreq_key yprk;
824 struct dom_binding *ysd;
825 struct timeval tv;
826 int r;
827
828 /* Sanity check */
829
830 if (inkey == NULL || !strlen(inkey) || inkeylen <= 0 ||
831 inmap == NULL || !strlen(inmap) ||
832 indomain == NULL || !strlen(indomain))
833 return (YPERR_BADARGS);
834
835 *outkey = *outval = NULL;
836 *outkeylen = *outvallen = 0;
837
63882998 838 YPLOCK();
984263bc 839again:
63882998
PA
840 if (_yp_dobind(indomain, &ysd) != 0) {
841 YPUNLOCK();
984263bc 842 return (YPERR_DOMAIN);
63882998 843 }
984263bc
MD
844
845 tv.tv_sec = _yplib_timeout;
846 tv.tv_usec = 0;
847
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);
853
854 r = clnt_call(ysd->dom_client, YPPROC_NEXT,
7048805a
SW
855 (xdrproc_t)xdr_ypreq_key, &yprk,
856 (xdrproc_t)xdr_ypresp_key_val, &yprkv, tv);
984263bc
MD
857 if (r != RPC_SUCCESS) {
858 clnt_perror(ysd->dom_client, "yp_next: clnt_call");
859 _yp_unbind(ysd);
860 goto again;
861 }
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';
871 }
872
7048805a 873 xdr_free((xdrproc_t)xdr_ypresp_key_val, &yprkv);
63882998 874 YPUNLOCK();
984263bc
MD
875 return (r);
876}
877
878int
e9c93684 879yp_all(char *indomain, char *inmap, struct ypall_callback *incallback)
984263bc
MD
880{
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;
888
889 /* Sanity check */
890
891 if (indomain == NULL || !strlen(indomain) ||
892 inmap == NULL || !strlen(inmap))
893 return (YPERR_BADARGS);
894
63882998 895 YPLOCK();
984263bc
MD
896again:
897
63882998
PA
898 if (_yp_dobind(indomain, &ysd) != 0) {
899 YPUNLOCK();
984263bc 900 return (YPERR_DOMAIN);
63882998 901 }
984263bc
MD
902
903 tv.tv_sec = _yplib_timeout;
904 tv.tv_usec = 0;
905
906 /* YPPROC_ALL manufactures its own channel to ypserv using TCP */
907
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) {
63882998 913 YPUNLOCK();
984263bc
MD
914 printf("clnttcp_create failed\n");
915 return (YPERR_PMAP);
916 }
917
918 yprnk.domain = indomain;
919 yprnk.map = inmap;
a71fb5b1 920 ypresp_allfn = incallback->foreach;
984263bc
MD
921 ypresp_data = (void *)incallback->data;
922
923 if (clnt_call(clnt, YPPROC_ALL,
7048805a
SW
924 (xdrproc_t)xdr_ypreq_nokey, &yprnk,
925 (xdrproc_t)xdr_ypresp_all_seq, &status, tv) != RPC_SUCCESS) {
984263bc
MD
926 clnt_perror(ysd->dom_client, "yp_all: clnt_call");
927 clnt_destroy(clnt);
928 _yp_unbind(ysd);
929 goto again;
930 }
931
932 clnt_destroy(clnt);
933 savstat = status;
7048805a 934 xdr_free((xdrproc_t)xdr_ypresp_all_seq, &status); /* not really needed... */
63882998 935 YPUNLOCK();
984263bc
MD
936 if (savstat != YP_NOMORE)
937 return (ypprot_err(savstat));
938 return (0);
939}
940
941int
e9c93684 942yp_order(char *indomain, char *inmap, int *outorder)
984263bc
MD
943{
944 struct dom_binding *ysd;
945 struct ypresp_order ypro;
946 struct ypreq_nokey yprnk;
947 struct timeval tv;
948 int r;
949
950 /* Sanity check */
951
952 if (indomain == NULL || !strlen(indomain) ||
953 inmap == NULL || !strlen(inmap))
954 return (YPERR_BADARGS);
955
63882998 956 YPLOCK();
984263bc 957again:
63882998
PA
958 if (_yp_dobind(indomain, &ysd) != 0) {
959 YPUNLOCK();
984263bc 960 return (YPERR_DOMAIN);
63882998 961 }
984263bc
MD
962
963 tv.tv_sec = _yplib_timeout;
964 tv.tv_usec = 0;
965
966 yprnk.domain = indomain;
967 yprnk.map = inmap;
968
969 bzero((char *)(char *)&ypro, sizeof ypro);
970
971 r = clnt_call(ysd->dom_client, YPPROC_ORDER,
7048805a
SW
972 (xdrproc_t)xdr_ypreq_nokey, &yprnk,
973 (xdrproc_t)xdr_ypresp_order, &ypro, tv);
984263bc
MD
974
975 /*
976 * NIS+ in YP compat mode doesn't support the YPPROC_ORDER
977 * procedure.
978 */
979 if (r == RPC_PROCUNAVAIL) {
63882998 980 YPUNLOCK();
984263bc
MD
981 return(YPERR_YPERR);
982 }
983
984 if (r != RPC_SUCCESS) {
985 clnt_perror(ysd->dom_client, "yp_order: clnt_call");
986 _yp_unbind(ysd);
987 goto again;
988 }
989
990 if (!(r = ypprot_err(ypro.stat))) {
991 *outorder = ypro.ordernum;
992 }
993
7048805a 994 xdr_free((xdrproc_t)xdr_ypresp_order, &ypro);
63882998 995 YPUNLOCK();
984263bc
MD
996 return (r);
997}
998
999int
e9c93684 1000yp_master(char *indomain, char *inmap, char **outname)
984263bc
MD
1001{
1002 struct dom_binding *ysd;
1003 struct ypresp_master yprm;
1004 struct ypreq_nokey yprnk;
1005 struct timeval tv;
1006 int r;
1007
1008 /* Sanity check */
1009
1010 if (indomain == NULL || !strlen(indomain) ||
1011 inmap == NULL || !strlen(inmap))
1012 return (YPERR_BADARGS);
63882998 1013 YPLOCK();
984263bc 1014again:
63882998
PA
1015 if (_yp_dobind(indomain, &ysd) != 0) {
1016 YPUNLOCK();
984263bc 1017 return (YPERR_DOMAIN);
63882998 1018 }
984263bc
MD
1019
1020 tv.tv_sec = _yplib_timeout;
1021 tv.tv_usec = 0;
1022
1023 yprnk.domain = indomain;
1024 yprnk.map = inmap;
1025
1026 bzero((char *)&yprm, sizeof yprm);
1027
1028 r = clnt_call(ysd->dom_client, YPPROC_MASTER,
7048805a
SW
1029 (xdrproc_t)xdr_ypreq_nokey, &yprnk,
1030 (xdrproc_t)xdr_ypresp_master, &yprm, tv);
984263bc
MD
1031 if (r != RPC_SUCCESS) {
1032 clnt_perror(ysd->dom_client, "yp_master: clnt_call");
1033 _yp_unbind(ysd);
1034 goto again;
1035 }
1036
1037 if (!(r = ypprot_err(yprm.stat))) {
1038 *outname = (char *)strdup(yprm.peer);
1039 }
1040
7048805a 1041 xdr_free((xdrproc_t)xdr_ypresp_master, &yprm);
63882998 1042 YPUNLOCK();
984263bc
MD
1043 return (r);
1044}
e9c93684 1045
984263bc 1046int
e9c93684 1047yp_maplist(char *indomain, struct ypmaplist **outmaplist)
984263bc
MD
1048{
1049 struct dom_binding *ysd;
1050 struct ypresp_maplist ypml;
1051 struct timeval tv;
1052 int r;
1053
1054 /* Sanity check */
1055
1056 if (indomain == NULL || !strlen(indomain))
1057 return (YPERR_BADARGS);
1058
63882998 1059 YPLOCK();
984263bc 1060again:
63882998
PA
1061 if (_yp_dobind(indomain, &ysd) != 0) {
1062 YPUNLOCK();
984263bc 1063 return (YPERR_DOMAIN);
63882998 1064 }
984263bc
MD
1065
1066 tv.tv_sec = _yplib_timeout;
1067 tv.tv_usec = 0;
1068
1069 bzero((char *)&ypml, sizeof ypml);
1070
1071 r = clnt_call(ysd->dom_client, YPPROC_MAPLIST,
63882998 1072 (xdrproc_t)xdr_domainname, &indomain,
7048805a 1073 (xdrproc_t)xdr_ypresp_maplist, &ypml, tv);
984263bc
MD
1074 if (r != RPC_SUCCESS) {
1075 clnt_perror(ysd->dom_client, "yp_maplist: clnt_call");
1076 _yp_unbind(ysd);
1077 goto again;
1078 }
1079 if (!(r = ypprot_err(ypml.stat))) {
1080 *outmaplist = ypml.maps;
1081 }
1082
63882998
PA
1083 /* NO: xdr_free((xdrproc_t)xdr_ypresp_maplist, &ypml);*/
1084 YPUNLOCK();
984263bc
MD
1085 return (r);
1086}
1087
1088char *
e9c93684 1089yperr_string(int incode)
984263bc 1090{
2375287c 1091 const char *errstr;
984263bc
MD
1092 static char err[80];
1093
1094 switch (incode) {
1095 case 0:
fc6d0222 1096 errstr = "Success";
2375287c 1097 break;
984263bc 1098 case YPERR_BADARGS:
2375287c
JS
1099 errstr = "Request arguments bad";
1100 break;
984263bc 1101 case YPERR_RPC:
2375287c
JS
1102 errstr = "RPC failure";
1103 break;
984263bc 1104 case YPERR_DOMAIN:
2375287c
JS
1105 errstr = "Can't bind to server which serves this domain";
1106 break;
984263bc 1107 case YPERR_MAP:
2375287c
JS
1108 errstr = "No such map in server's domain";
1109 break;
984263bc 1110 case YPERR_KEY:
2375287c
JS
1111 errstr = "No such key in map";
1112 break;
984263bc 1113 case YPERR_YPERR:
2375287c
JS
1114 errstr = "YP server error";
1115 break;
984263bc 1116 case YPERR_RESRC:
2375287c
JS
1117 errstr = "Local resource allocation failure";
1118 break;
984263bc 1119 case YPERR_NOMORE:
2375287c
JS
1120 errstr = "No more records in map database";
1121 break;
984263bc 1122 case YPERR_PMAP:
2375287c
JS
1123 errstr = "Can't communicate with portmapper";
1124 break;
984263bc 1125 case YPERR_YPBIND:
2375287c
JS
1126 errstr = "Can't communicate with ypbind";
1127 break;
984263bc 1128 case YPERR_YPSERV:
2375287c
JS
1129 errstr = "Can't communicate with ypserv";
1130 break;
984263bc 1131 case YPERR_NODOM:
2375287c
JS
1132 errstr = "Local domain name not set";
1133 break;
984263bc 1134 case YPERR_BADDB:
2375287c
JS
1135 errstr = "Server data base is bad";
1136 break;
984263bc 1137 case YPERR_VERS:
2375287c
JS
1138 errstr = "YP server version mismatch - server can't supply service.";
1139 break;
984263bc 1140 case YPERR_ACCESS:
2375287c
JS
1141 errstr = "Access violation";
1142 break;
984263bc 1143 case YPERR_BUSY:
2375287c
JS
1144 errstr = "Database is busy";
1145 break;
1146 default:
1147 errstr = NULL;
1148 break;
984263bc 1149 }
2375287c
JS
1150 if (errstr != NULL)
1151 strlcpy(err, errstr, sizeof(err));
1152 else
1153 snprintf(err, sizeof(err), "YP unknown error %d\n", incode);
984263bc
MD
1154 return (err);
1155}
1156
1157int
e9c93684 1158ypprot_err(unsigned int incode)
984263bc
MD
1159{
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);
1183 }
1184 return (YPERR_YPERR);
1185}
1186
1187int
e9c93684 1188_yp_check(char **dom)
984263bc
MD
1189{
1190 char *unused;
1191
63882998 1192 YPLOCK();
984263bc 1193 if (_yp_domain[0]=='\0')
63882998
PA
1194 if (yp_get_default_domain_locked(&unused)) {
1195 YPUNLOCK();
984263bc 1196 return (0);
63882998 1197 }
984263bc
MD
1198
1199 if (dom)
1200 *dom = _yp_domain;
1201
63882998
PA
1202 if (yp_bind_locked(_yp_domain) == 0) {
1203 yp_unbind_locked(_yp_domain);
1204 YPUNLOCK();
984263bc
MD
1205 return (1);
1206 }
63882998 1207 YPUNLOCK();
984263bc
MD
1208 return (0);
1209}