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