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