1 /* 2 * Copyright (c) 1992/3 Theo de Raadt <deraadt@fsa.ca> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote 14 * products derived from this software without specific prior written 15 * permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 18 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #ifndef LINT 31 static char *rcsid = "$Id: yplib.c,v 1.25 1996/11/08 01:42:02 wpaul Exp $"; 32 #endif 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 /* 50 * We have to define these here due to clashes between yp_prot.h and 51 * yp.h. 52 */ 53 54 struct dom_binding { 55 struct dom_binding *dom_pnext; 56 char dom_domain[YPMAXDOMAIN + 1]; 57 struct sockaddr_in dom_server_addr; 58 u_short dom_server_port; 59 int dom_socket; 60 CLIENT *dom_client; 61 u_short dom_local_port; /* now I finally know what this is for. */ 62 long dom_vers; 63 }; 64 65 #include <rpcsvc/ypclnt.h> 66 67 #ifndef BINDINGDIR 68 #define BINDINGDIR "/var/yp/binding" 69 #endif 70 #define YPMATCHCACHE 71 #define MAX_RETRIES 20 72 73 extern bool_t xdr_domainname(), xdr_ypbind_resp(); 74 extern bool_t xdr_ypreq_key(), xdr_ypresp_val(); 75 extern bool_t xdr_ypreq_nokey(), xdr_ypresp_key_val(); 76 extern bool_t xdr_ypresp_all(), xdr_ypresp_all_seq(); 77 extern bool_t xdr_ypresp_master(); 78 79 int (*ypresp_allfn)(); 80 void *ypresp_data; 81 82 static void _yp_unbind __P(( struct dom_binding * )); 83 struct dom_binding *_ypbindlist; 84 static char _yp_domain[MAXHOSTNAMELEN]; 85 int _yplib_timeout = 10; 86 87 #ifdef YPMATCHCACHE 88 int _yplib_cache = 5; 89 90 static struct ypmatch_ent { 91 struct ypmatch_ent *next; 92 char *map, *key, *val; 93 int keylen, vallen; 94 time_t expire_t; 95 } *ypmc; 96 97 static void 98 ypmatch_add(map, key, keylen, val, vallen) 99 char *map; 100 char *key; 101 int keylen; 102 char *val; 103 int vallen; 104 { 105 struct ypmatch_ent *ep; 106 time_t t; 107 108 time(&t); 109 110 for(ep=ypmc; ep; ep=ep->next) 111 if(ep->expire_t < t) 112 break; 113 if(ep==NULL) { 114 ep = (struct ypmatch_ent *)malloc(sizeof *ep); 115 bzero((char *)ep, sizeof *ep); 116 if(ypmc) 117 ep->next = ypmc; 118 ypmc = ep; 119 } 120 121 if(ep->key) 122 free(ep->key); 123 if(ep->val) 124 free(ep->val); 125 126 ep->key = NULL; 127 ep->val = NULL; 128 129 ep->key = (char *)malloc(keylen); 130 if(ep->key==NULL) 131 return; 132 133 ep->val = (char *)malloc(vallen); 134 if(ep->key==NULL) { 135 free(ep->key); 136 ep->key = NULL; 137 return; 138 } 139 ep->keylen = keylen; 140 ep->vallen = vallen; 141 142 bcopy(key, ep->key, ep->keylen); 143 bcopy(val, ep->val, ep->vallen); 144 145 if(ep->map) { 146 if( strcmp(ep->map, map) ) { 147 free(ep->map); 148 ep->map = strdup(map); 149 } 150 } else { 151 ep->map = strdup(map); 152 } 153 154 ep->expire_t = t + _yplib_cache; 155 } 156 157 static bool_t 158 ypmatch_find(map, key, keylen, val, vallen) 159 char *map; 160 char *key; 161 int keylen; 162 char **val; 163 int *vallen; 164 { 165 struct ypmatch_ent *ep; 166 time_t t; 167 168 if(ypmc==NULL) 169 return 0; 170 171 time(&t); 172 173 for(ep=ypmc; ep; ep=ep->next) { 174 if(ep->keylen != keylen) 175 continue; 176 if(strcmp(ep->map, map)) 177 continue; 178 if(bcmp(ep->key, key, keylen)) 179 continue; 180 if(t > ep->expire_t) 181 continue; 182 183 *val = ep->val; 184 *vallen = ep->vallen; 185 return 1; 186 } 187 return 0; 188 } 189 #endif 190 191 char * 192 ypbinderr_string(incode) 193 int incode; 194 { 195 static char err[80]; 196 switch(incode) { 197 case 0: 198 return "Success"; 199 case YPBIND_ERR_ERR: 200 return "Internal ypbind error"; 201 case YPBIND_ERR_NOSERV: 202 return "Domain not bound"; 203 case YPBIND_ERR_RESC: 204 return "System resource allocation failure"; 205 } 206 sprintf(err, "Unknown ypbind error: #%d\n", incode); 207 return err; 208 } 209 210 int 211 _yp_dobind(dom, ypdb) 212 char *dom; 213 struct dom_binding **ypdb; 214 { 215 static pid_t pid = -1; 216 char path[MAXPATHLEN]; 217 struct dom_binding *ysd, *ysd2; 218 struct ypbind_resp ypbr; 219 struct timeval tv; 220 struct sockaddr_in clnt_sin; 221 int clnt_sock, fd; 222 pid_t gpid; 223 CLIENT *client; 224 int new = 0, r; 225 int retries = 0; 226 struct sockaddr_in check; 227 int checklen = sizeof(struct sockaddr_in); 228 229 gpid = getpid(); 230 if( !(pid==-1 || pid==gpid) ) { 231 ysd = _ypbindlist; 232 while(ysd) { 233 if(ysd->dom_client != NULL) 234 _yp_unbind(ysd); 235 ysd2 = ysd->dom_pnext; 236 free(ysd); 237 ysd = ysd2; 238 } 239 _ypbindlist = NULL; 240 } 241 pid = gpid; 242 243 if(ypdb!=NULL) 244 *ypdb = NULL; 245 246 if(dom==NULL || strlen(dom)==0) 247 return YPERR_BADARGS; 248 249 for(ysd = _ypbindlist; ysd; ysd = ysd->dom_pnext) 250 if( strcmp(dom, ysd->dom_domain) == 0) 251 break; 252 253 254 if(ysd==NULL) { 255 ysd = (struct dom_binding *)malloc(sizeof *ysd); 256 bzero((char *)ysd, sizeof *ysd); 257 ysd->dom_socket = -1; 258 ysd->dom_vers = 0; 259 new = 1; 260 } else { 261 /* Check the socket -- may have been hosed by the caller. */ 262 if (getsockname(ysd->dom_socket, (struct sockaddr *)&check, 263 &checklen) == -1 || check.sin_family != AF_INET || 264 check.sin_port != ysd->dom_local_port) { 265 /* Socket became bogus somehow... need to rebind. */ 266 int save, sock; 267 268 sock = ysd->dom_socket; 269 save = dup(ysd->dom_socket); 270 if (ysd->dom_client != NULL) 271 clnt_destroy(ysd->dom_client); 272 ysd->dom_vers = 0; 273 ysd->dom_client = NULL; 274 sock = dup2(save, sock); 275 close(save); 276 } 277 } 278 279 again: 280 retries++; 281 if (retries > MAX_RETRIES) { 282 if (new) 283 free(ysd); 284 return(YPERR_YPBIND); 285 } 286 #ifdef BINDINGDIR 287 if(ysd->dom_vers==0) { 288 /* 289 * We're trying to make a new binding: zorch the 290 * existing handle now (if any). 291 */ 292 if(ysd->dom_client != NULL) { 293 clnt_destroy(ysd->dom_client); 294 ysd->dom_client = NULL; 295 ysd->dom_socket = -1; 296 } 297 sprintf(path, "%s/%s.%d", BINDINGDIR, dom, 2); 298 if( (fd=open(path, O_RDONLY)) == -1) { 299 /* no binding file, YP is dead. */ 300 /* Try to bring it back to life. */ 301 close(fd); 302 goto skipit; 303 } 304 if( flock(fd, LOCK_EX|LOCK_NB) == -1 && errno==EWOULDBLOCK) { 305 struct iovec iov[2]; 306 struct ypbind_resp ybr; 307 u_short ypb_port; 308 309 iov[0].iov_base = (caddr_t)&ypb_port; 310 iov[0].iov_len = sizeof ypb_port; 311 iov[1].iov_base = (caddr_t)&ybr; 312 iov[1].iov_len = sizeof ybr; 313 314 r = readv(fd, iov, 2); 315 if(r != iov[0].iov_len + iov[1].iov_len) { 316 close(fd); 317 ysd->dom_vers = -1; 318 goto again; 319 } 320 321 bzero(&ysd->dom_server_addr, sizeof ysd->dom_server_addr); 322 ysd->dom_server_addr.sin_family = AF_INET; 323 ysd->dom_server_addr.sin_len = sizeof(struct sockaddr_in); 324 ysd->dom_server_addr.sin_addr.s_addr = 325 *(u_long *)&ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr; 326 ysd->dom_server_addr.sin_port = 327 *(u_short *)&ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port; 328 329 ysd->dom_server_port = ysd->dom_server_addr.sin_port; 330 close(fd); 331 goto gotit; 332 } else { 333 /* no lock on binding file, YP is dead. */ 334 /* Try to bring it back to life. */ 335 close(fd); 336 goto skipit; 337 } 338 } 339 skipit: 340 #endif 341 if(ysd->dom_vers==-1 || ysd->dom_vers==0) { 342 /* 343 * We're trying to make a new binding: zorch the 344 * existing handle now (if any). 345 */ 346 if(ysd->dom_client != NULL) { 347 clnt_destroy(ysd->dom_client); 348 ysd->dom_client = NULL; 349 ysd->dom_socket = -1; 350 } 351 bzero((char *)&clnt_sin, sizeof clnt_sin); 352 clnt_sin.sin_family = AF_INET; 353 clnt_sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 354 355 clnt_sock = RPC_ANYSOCK; 356 client = clnttcp_create(&clnt_sin, YPBINDPROG, YPBINDVERS, &clnt_sock, 357 0, 0); 358 if(client==NULL) { 359 /* 360 * These conditions indicate ypbind just isn't 361 * alive -- we probably don't want to shoot our 362 * mouth off in this case; instead generate error 363 * messages only for really exotic problems. 364 */ 365 if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED && 366 (rpc_createerr.cf_stat != RPC_SYSTEMERROR && 367 rpc_createerr.cf_error.re_errno == ECONNREFUSED)) 368 clnt_pcreateerror("clnttcp_create"); 369 if(new) 370 free(ysd); 371 return (YPERR_YPBIND); 372 } 373 374 /* 375 * Check the port number -- should be < IPPORT_RESERVED. 376 * If not, it's possible someone has registered a bogus 377 * ypbind with the portmapper and is trying to trick us. 378 */ 379 if (ntohs(clnt_sin.sin_port) >= IPPORT_RESERVED) { 380 if (client != NULL) 381 clnt_destroy(client); 382 if (new) 383 free(ysd); 384 return(YPERR_YPBIND); 385 } 386 tv.tv_sec = _yplib_timeout/2; 387 tv.tv_usec = 0; 388 r = clnt_call(client, YPBINDPROC_DOMAIN, 389 xdr_domainname, (char *)&dom, xdr_ypbind_resp, &ypbr, tv); 390 if(r != RPC_SUCCESS) { 391 clnt_destroy(client); 392 ysd->dom_vers = -1; 393 if (r == RPC_PROGUNAVAIL || r == RPC_PROCUNAVAIL) { 394 if (new) 395 free(ysd); 396 return(YPERR_YPBIND); 397 } 398 fprintf(stderr, 399 "YP: server for domain %s not responding, retrying\n", dom); 400 goto again; 401 } else { 402 if (ypbr.ypbind_status != YPBIND_SUCC_VAL) { 403 clnt_destroy(client); 404 ysd->dom_vers = -1; 405 sleep(_yplib_timeout/2); 406 goto again; 407 } 408 } 409 clnt_destroy(client); 410 411 bzero((char *)&ysd->dom_server_addr, sizeof ysd->dom_server_addr); 412 ysd->dom_server_addr.sin_family = AF_INET; 413 ysd->dom_server_addr.sin_port = 414 *(u_short *)&ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port; 415 ysd->dom_server_addr.sin_addr.s_addr = 416 *(u_long *)&ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr; 417 418 /* 419 * We could do a reserved port check here too, but this 420 * could pose compatibility problems. The local ypbind is 421 * supposed to decide whether or not to trust yp servers 422 * on insecure ports. For now, we trust its judgement. 423 */ 424 ysd->dom_server_port = 425 *(u_short *)&ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port; 426 gotit: 427 ysd->dom_vers = YPVERS; 428 strcpy(ysd->dom_domain, dom); 429 } 430 431 /* Don't rebuild the connection to the server unless we have to. */ 432 if (ysd->dom_client == NULL) { 433 tv.tv_sec = _yplib_timeout/2; 434 tv.tv_usec = 0; 435 ysd->dom_socket = RPC_ANYSOCK; 436 ysd->dom_client = clntudp_create(&ysd->dom_server_addr, 437 YPPROG, YPVERS, tv, &ysd->dom_socket); 438 if(ysd->dom_client==NULL) { 439 clnt_pcreateerror("clntudp_create"); 440 ysd->dom_vers = -1; 441 goto again; 442 } 443 if( fcntl(ysd->dom_socket, F_SETFD, 1) == -1) 444 perror("fcntl: F_SETFD"); 445 /* 446 * We want a port number associated with this socket 447 * so that we can check its authenticity later. 448 */ 449 checklen = sizeof(struct sockaddr_in); 450 bzero((char *)&check, checklen); 451 bind(ysd->dom_socket, (struct sockaddr *)&check, checklen); 452 check.sin_family = AF_INET; 453 if (!getsockname(ysd->dom_socket, 454 (struct sockaddr *)&check, &checklen)) { 455 ysd->dom_local_port = check.sin_port; 456 } else { 457 clnt_destroy(ysd->dom_client); 458 if (new) 459 free(ysd); 460 return(YPERR_YPBIND); 461 } 462 } 463 464 if(new) { 465 ysd->dom_pnext = _ypbindlist; 466 _ypbindlist = ysd; 467 } 468 469 if(ypdb!=NULL) 470 *ypdb = ysd; 471 return 0; 472 } 473 474 static void 475 _yp_unbind(ypb) 476 struct dom_binding *ypb; 477 { 478 struct sockaddr_in check; 479 int checklen = sizeof(struct sockaddr_in); 480 481 if (ypb->dom_client != NULL) { 482 /* Check the socket -- may have been hosed by the caller. */ 483 if (getsockname(ypb->dom_socket, (struct sockaddr *)&check, 484 &checklen) == -1 || check.sin_family != AF_INET || 485 check.sin_port != ypb->dom_local_port) { 486 int save, sock; 487 488 sock = ypb->dom_socket; 489 save = dup(ypb->dom_socket); 490 clnt_destroy(ypb->dom_client); 491 sock = dup2(save, sock); 492 close(save); 493 } else 494 clnt_destroy(ypb->dom_client); 495 } 496 497 ypb->dom_client = NULL; 498 ypb->dom_socket = -1; 499 ypb->dom_vers = -1; 500 } 501 502 int 503 yp_bind(dom) 504 char *dom; 505 { 506 return _yp_dobind(dom, NULL); 507 } 508 509 void 510 yp_unbind(dom) 511 char *dom; 512 { 513 struct dom_binding *ypb, *ypbp; 514 515 ypbp = NULL; 516 for(ypb=_ypbindlist; ypb; ypb=ypb->dom_pnext) { 517 if( strcmp(dom, ypb->dom_domain) == 0) { 518 _yp_unbind(ypb); 519 if(ypbp) 520 ypbp->dom_pnext = ypb->dom_pnext; 521 else 522 _ypbindlist = ypb->dom_pnext; 523 free(ypb); 524 return; 525 } 526 ypbp = ypb; 527 } 528 return; 529 } 530 531 int 532 yp_match(indomain, inmap, inkey, inkeylen, outval, outvallen) 533 char *indomain; 534 char *inmap; 535 const char *inkey; 536 int inkeylen; 537 char **outval; 538 int *outvallen; 539 { 540 struct dom_binding *ysd; 541 struct ypresp_val yprv; 542 struct timeval tv; 543 struct ypreq_key yprk; 544 int r; 545 546 *outval = NULL; 547 *outvallen = 0; 548 549 /* Sanity check */ 550 551 if (inkey == NULL || !strlen(inkey) || inkeylen <= 0 || 552 inmap == NULL || !strlen(inmap) || 553 indomain == NULL || !strlen(indomain)) 554 return YPERR_BADARGS; 555 556 #ifdef YPMATCHCACHE 557 if( !strcmp(_yp_domain, indomain) && ypmatch_find(inmap, inkey, 558 inkeylen, &yprv.val.valdat_val, &yprv.val.valdat_len)) { 559 *outvallen = yprv.val.valdat_len; 560 *outval = (char *)malloc(*outvallen+1); 561 bcopy(yprv.val.valdat_val, *outval, *outvallen); 562 (*outval)[*outvallen] = '\0'; 563 return 0; 564 } 565 #endif 566 567 again: 568 if( _yp_dobind(indomain, &ysd) != 0) 569 return YPERR_DOMAIN; 570 571 tv.tv_sec = _yplib_timeout; 572 tv.tv_usec = 0; 573 574 yprk.domain = indomain; 575 yprk.map = inmap; 576 yprk.key.keydat_val = (char *)inkey; 577 yprk.key.keydat_len = inkeylen; 578 579 bzero((char *)&yprv, sizeof yprv); 580 581 r = clnt_call(ysd->dom_client, YPPROC_MATCH, 582 xdr_ypreq_key, &yprk, xdr_ypresp_val, &yprv, tv); 583 if(r != RPC_SUCCESS) { 584 clnt_perror(ysd->dom_client, "yp_match: clnt_call"); 585 _yp_unbind(ysd); 586 goto again; 587 } 588 589 if( !(r=ypprot_err(yprv.stat)) ) { 590 *outvallen = yprv.val.valdat_len; 591 *outval = (char *)malloc(*outvallen+1); 592 bcopy(yprv.val.valdat_val, *outval, *outvallen); 593 (*outval)[*outvallen] = '\0'; 594 #ifdef YPMATCHCACHE 595 if( strcmp(_yp_domain, indomain)==0 ) 596 ypmatch_add(inmap, inkey, inkeylen, *outval, *outvallen); 597 #endif 598 } 599 600 xdr_free(xdr_ypresp_val, (char *)&yprv); 601 return r; 602 } 603 604 int 605 yp_get_default_domain(domp) 606 char **domp; 607 { 608 *domp = NULL; 609 if(_yp_domain[0] == '\0') 610 if( getdomainname(_yp_domain, sizeof _yp_domain)) 611 return YPERR_NODOM; 612 *domp = _yp_domain; 613 return 0; 614 } 615 616 int 617 yp_first(indomain, inmap, outkey, outkeylen, outval, outvallen) 618 char *indomain; 619 char *inmap; 620 char **outkey; 621 int *outkeylen; 622 char **outval; 623 int *outvallen; 624 { 625 struct ypresp_key_val yprkv; 626 struct ypreq_nokey yprnk; 627 struct dom_binding *ysd; 628 struct timeval tv; 629 int r; 630 631 /* Sanity check */ 632 633 if (indomain == NULL || !strlen(indomain) || 634 inmap == NULL || !strlen(inmap)) 635 return YPERR_BADARGS; 636 637 *outkey = *outval = NULL; 638 *outkeylen = *outvallen = 0; 639 640 again: 641 if( _yp_dobind(indomain, &ysd) != 0) 642 return YPERR_DOMAIN; 643 644 tv.tv_sec = _yplib_timeout; 645 tv.tv_usec = 0; 646 647 yprnk.domain = indomain; 648 yprnk.map = inmap; 649 bzero((char *)&yprkv, sizeof yprkv); 650 651 r = clnt_call(ysd->dom_client, YPPROC_FIRST, 652 xdr_ypreq_nokey, &yprnk, xdr_ypresp_key_val, &yprkv, tv); 653 if(r != RPC_SUCCESS) { 654 clnt_perror(ysd->dom_client, "yp_first: clnt_call"); 655 _yp_unbind(ysd); 656 goto again; 657 } 658 if( !(r=ypprot_err(yprkv.stat)) ) { 659 *outkeylen = yprkv.key.keydat_len; 660 *outkey = (char *)malloc(*outkeylen+1); 661 bcopy(yprkv.key.keydat_val, *outkey, *outkeylen); 662 (*outkey)[*outkeylen] = '\0'; 663 *outvallen = yprkv.val.valdat_len; 664 *outval = (char *)malloc(*outvallen+1); 665 bcopy(yprkv.val.valdat_val, *outval, *outvallen); 666 (*outval)[*outvallen] = '\0'; 667 } 668 669 xdr_free(xdr_ypresp_key_val, (char *)&yprkv); 670 return r; 671 } 672 673 int 674 yp_next(indomain, inmap, inkey, inkeylen, outkey, outkeylen, outval, outvallen) 675 char *indomain; 676 char *inmap; 677 char *inkey; 678 int inkeylen; 679 char **outkey; 680 int *outkeylen; 681 char **outval; 682 int *outvallen; 683 { 684 struct ypresp_key_val yprkv; 685 struct ypreq_key yprk; 686 struct dom_binding *ysd; 687 struct timeval tv; 688 int r; 689 690 /* Sanity check */ 691 692 if (inkey == NULL || !strlen(inkey) || inkeylen <= 0 || 693 inmap == NULL || !strlen(inmap) || 694 indomain == NULL || !strlen(indomain)) 695 return YPERR_BADARGS; 696 697 *outkey = *outval = NULL; 698 *outkeylen = *outvallen = 0; 699 700 again: 701 if( _yp_dobind(indomain, &ysd) != 0) 702 return YPERR_DOMAIN; 703 704 tv.tv_sec = _yplib_timeout; 705 tv.tv_usec = 0; 706 707 yprk.domain = indomain; 708 yprk.map = inmap; 709 yprk.key.keydat_val = inkey; 710 yprk.key.keydat_len = inkeylen; 711 bzero((char *)&yprkv, sizeof yprkv); 712 713 r = clnt_call(ysd->dom_client, YPPROC_NEXT, 714 xdr_ypreq_key, &yprk, xdr_ypresp_key_val, &yprkv, tv); 715 if(r != RPC_SUCCESS) { 716 clnt_perror(ysd->dom_client, "yp_next: clnt_call"); 717 _yp_unbind(ysd); 718 goto again; 719 } 720 if( !(r=ypprot_err(yprkv.stat)) ) { 721 *outkeylen = yprkv.key.keydat_len; 722 *outkey = (char *)malloc(*outkeylen+1); 723 bcopy(yprkv.key.keydat_val, *outkey, *outkeylen); 724 (*outkey)[*outkeylen] = '\0'; 725 *outvallen = yprkv.val.valdat_len; 726 *outval = (char *)malloc(*outvallen+1); 727 bcopy(yprkv.val.valdat_val, *outval, *outvallen); 728 (*outval)[*outvallen] = '\0'; 729 } 730 731 xdr_free(xdr_ypresp_key_val, (char *)&yprkv); 732 return r; 733 } 734 735 int 736 yp_all(indomain, inmap, incallback) 737 char *indomain; 738 char *inmap; 739 struct ypall_callback *incallback; 740 { 741 struct ypreq_nokey yprnk; 742 struct dom_binding *ysd; 743 struct timeval tv; 744 struct sockaddr_in clnt_sin; 745 CLIENT *clnt; 746 u_long status, savstat; 747 int clnt_sock; 748 749 /* Sanity check */ 750 751 if (indomain == NULL || !strlen(indomain) || 752 inmap == NULL || !strlen(inmap)) 753 return YPERR_BADARGS; 754 755 again: 756 757 if( _yp_dobind(indomain, &ysd) != 0) 758 return YPERR_DOMAIN; 759 760 tv.tv_sec = _yplib_timeout; 761 tv.tv_usec = 0; 762 763 /* YPPROC_ALL manufactures its own channel to ypserv using TCP */ 764 765 clnt_sock = RPC_ANYSOCK; 766 clnt_sin = ysd->dom_server_addr; 767 clnt_sin.sin_port = 0; 768 clnt = clnttcp_create(&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0); 769 if(clnt==NULL) { 770 printf("clnttcp_create failed\n"); 771 return YPERR_PMAP; 772 } 773 774 yprnk.domain = indomain; 775 yprnk.map = inmap; 776 ypresp_allfn = incallback->foreach; 777 ypresp_data = (void *)incallback->data; 778 779 if (clnt_call(clnt, YPPROC_ALL, 780 xdr_ypreq_nokey, &yprnk, 781 xdr_ypresp_all_seq, &status, tv) != RPC_SUCCESS) { 782 clnt_perror(ysd->dom_client, "yp_next: clnt_call"); 783 clnt_destroy(clnt); 784 _yp_unbind(ysd); 785 goto again; 786 } 787 788 clnt_destroy(clnt); 789 savstat = status; 790 xdr_free(xdr_ypresp_all_seq, (char *)&status); /* not really needed... */ 791 if(savstat != YP_NOMORE) 792 return ypprot_err(savstat); 793 return 0; 794 } 795 796 int 797 yp_order(indomain, inmap, outorder) 798 char *indomain; 799 char *inmap; 800 int *outorder; 801 { 802 struct dom_binding *ysd; 803 struct ypresp_order ypro; 804 struct ypreq_nokey yprnk; 805 struct timeval tv; 806 int r; 807 808 /* Sanity check */ 809 810 if (indomain == NULL || !strlen(indomain) || 811 inmap == NULL || !strlen(inmap)) 812 return YPERR_BADARGS; 813 814 again: 815 if( _yp_dobind(indomain, &ysd) != 0) 816 return YPERR_DOMAIN; 817 818 tv.tv_sec = _yplib_timeout; 819 tv.tv_usec = 0; 820 821 yprnk.domain = indomain; 822 yprnk.map = inmap; 823 824 bzero((char *)(char *)&ypro, sizeof ypro); 825 826 r = clnt_call(ysd->dom_client, YPPROC_ORDER, 827 xdr_ypreq_nokey, &yprnk, xdr_ypresp_order, &ypro, tv); 828 829 /* 830 * NIS+ in YP compat mode doesn't support the YPPROC_ORDER 831 * procedure. 832 */ 833 if (r == RPC_PROCUNAVAIL) { 834 return(YPERR_YPERR); 835 } 836 837 if(r != RPC_SUCCESS) { 838 clnt_perror(ysd->dom_client, "yp_order: clnt_call"); 839 _yp_unbind(ysd); 840 goto again; 841 } 842 843 if( !(r=ypprot_err(ypro.stat)) ) { 844 *outorder = ypro.ordernum; 845 } 846 847 xdr_free(xdr_ypresp_order, (char *)&ypro); 848 return (r); 849 } 850 851 int 852 yp_master(indomain, inmap, outname) 853 char *indomain; 854 char *inmap; 855 char **outname; 856 { 857 struct dom_binding *ysd; 858 struct ypresp_master yprm; 859 struct ypreq_nokey yprnk; 860 struct timeval tv; 861 int r; 862 863 /* Sanity check */ 864 865 if (indomain == NULL || !strlen(indomain) || 866 inmap == NULL || !strlen(inmap)) 867 return YPERR_BADARGS; 868 again: 869 if( _yp_dobind(indomain, &ysd) != 0) 870 return YPERR_DOMAIN; 871 872 tv.tv_sec = _yplib_timeout; 873 tv.tv_usec = 0; 874 875 yprnk.domain = indomain; 876 yprnk.map = inmap; 877 878 bzero((char *)&yprm, sizeof yprm); 879 880 r = clnt_call(ysd->dom_client, YPPROC_MASTER, 881 xdr_ypreq_nokey, &yprnk, xdr_ypresp_master, &yprm, tv); 882 if(r != RPC_SUCCESS) { 883 clnt_perror(ysd->dom_client, "yp_master: clnt_call"); 884 _yp_unbind(ysd); 885 goto again; 886 } 887 888 if( !(r=ypprot_err(yprm.stat)) ) { 889 *outname = (char *)strdup(yprm.peer); 890 } 891 892 xdr_free(xdr_ypresp_master, (char *)&yprm); 893 return (r); 894 } 895 int 896 yp_maplist(indomain, outmaplist) 897 char *indomain; 898 struct ypmaplist **outmaplist; 899 { 900 struct dom_binding *ysd; 901 struct ypresp_maplist ypml; 902 struct timeval tv; 903 int r; 904 905 /* Sanity check */ 906 907 if (indomain == NULL || !strlen(indomain)) 908 return YPERR_BADARGS; 909 910 again: 911 if( _yp_dobind(indomain, &ysd) != 0) 912 return YPERR_DOMAIN; 913 914 tv.tv_sec = _yplib_timeout; 915 tv.tv_usec = 0; 916 917 bzero((char *)&ypml, sizeof ypml); 918 919 r = clnt_call(ysd->dom_client, YPPROC_MAPLIST, 920 xdr_domainname,(char *)&indomain,xdr_ypresp_maplist,&ypml,tv); 921 if (r != RPC_SUCCESS) { 922 clnt_perror(ysd->dom_client, "yp_maplist: clnt_call"); 923 _yp_unbind(ysd); 924 goto again; 925 } 926 if( !(r=ypprot_err(ypml.stat)) ) { 927 *outmaplist = ypml.maps; 928 } 929 930 /* NO: xdr_free(xdr_ypresp_maplist, &ypml);*/ 931 return (r); 932 } 933 934 char * 935 yperr_string(incode) 936 int incode; 937 { 938 static char err[80]; 939 940 switch(incode) { 941 case 0: 942 return "Success"; 943 case YPERR_BADARGS: 944 return "Request arguments bad"; 945 case YPERR_RPC: 946 return "RPC failure"; 947 case YPERR_DOMAIN: 948 return "Can't bind to server which serves this domain"; 949 case YPERR_MAP: 950 return "No such map in server's domain"; 951 case YPERR_KEY: 952 return "No such key in map"; 953 case YPERR_YPERR: 954 return "YP server error"; 955 case YPERR_RESRC: 956 return "Local resource allocation failure"; 957 case YPERR_NOMORE: 958 return "No more records in map database"; 959 case YPERR_PMAP: 960 return "Can't communicate with portmapper"; 961 case YPERR_YPBIND: 962 return "Can't communicate with ypbind"; 963 case YPERR_YPSERV: 964 return "Can't communicate with ypserv"; 965 case YPERR_NODOM: 966 return "Local domain name not set"; 967 case YPERR_BADDB: 968 return "Server data base is bad"; 969 case YPERR_VERS: 970 return "YP server version mismatch - server can't supply service."; 971 case YPERR_ACCESS: 972 return "Access violation"; 973 case YPERR_BUSY: 974 return "Database is busy"; 975 } 976 sprintf(err, "YP unknown error %d\n", incode); 977 return err; 978 } 979 980 int 981 ypprot_err(incode) 982 unsigned int incode; 983 { 984 switch(incode) { 985 case YP_TRUE: 986 return 0; 987 case YP_FALSE: 988 return YPERR_YPBIND; 989 case YP_NOMORE: 990 return YPERR_NOMORE; 991 case YP_NOMAP: 992 return YPERR_MAP; 993 case YP_NODOM: 994 return YPERR_DOMAIN; 995 case YP_NOKEY: 996 return YPERR_KEY; 997 case YP_BADOP: 998 return YPERR_YPERR; 999 case YP_BADDB: 1000 return YPERR_BADDB; 1001 case YP_YPERR: 1002 return YPERR_YPERR; 1003 case YP_BADARGS: 1004 return YPERR_BADARGS; 1005 case YP_VERS: 1006 return YPERR_VERS; 1007 } 1008 return YPERR_YPERR; 1009 } 1010 1011 int 1012 _yp_check(dom) 1013 char **dom; 1014 { 1015 char *unused; 1016 1017 if( _yp_domain[0]=='\0' ) 1018 if( yp_get_default_domain(&unused) ) 1019 return 0; 1020 1021 if(dom) 1022 *dom = _yp_domain; 1023 1024 if( yp_bind(_yp_domain)==0 ) { 1025 yp_unbind(_yp_domain); 1026 return 1; 1027 } 1028 return 0; 1029 } 1030