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