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