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