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