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