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