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