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