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