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