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