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