1139790Simp/*- 266633Sdfr * SPDX-License-Identifier: BSD-3-Clause 366633Sdfr * 466633Sdfr * Copyright (c) 1992/3 Theo de Raadt <deraadt@fsa.ca> 566633Sdfr * Copyright (c) 1998 Bill Paul <wpaul@ctr.columbia.edu> 666633Sdfr * All rights reserved. 766633Sdfr * 866633Sdfr * Redistribution and use in source and binary forms, with or without 966633Sdfr * modification, are permitted provided that the following conditions 1066633Sdfr * are met: 1166633Sdfr * 1. Redistributions of source code must retain the above copyright 1266633Sdfr * notice, this list of conditions and the following disclaimer. 1366633Sdfr * 2. Redistributions in binary form must reproduce the above copyright 1474031Sdfr * notice, this list of conditions and the following disclaimer in the 1566633Sdfr * documentation and/or other materials provided with the distribution. 1666633Sdfr * 3. The name of the author may not be used to endorse or promote 1766633Sdfr * products derived from this software without specific prior written 1866633Sdfr * permission. 1966633Sdfr * 2066633Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 2177448Sjhb * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 2277448Sjhb * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2366633Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 2477448Sjhb * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2577448Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2666633Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2781198Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2866633Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2966633Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3066633Sdfr * SUCH DAMAGE. 3166633Sdfr */ 3266633Sdfr 3366633Sdfr#include "namespace.h" 3466633Sdfr#include "reentrant.h" 3595761Smarcel#include <sys/param.h> 36113140Smarcel#include <sys/socket.h> 3766633Sdfr#include <sys/file.h> 3874031Sdfr#include <sys/uio.h> 3974031Sdfr#include <arpa/inet.h> 4074031Sdfr#include <errno.h> 4174031Sdfr#include <stdio.h> 4266633Sdfr#include <string.h> 4366633Sdfr#include <stdlib.h> 4466633Sdfr#include <unistd.h> 4566633Sdfr#include <rpc/rpc.h> 4666633Sdfr#include <rpc/xdr.h> 4766633Sdfr#include <rpcsvc/yp.h> 4866633Sdfr#include "un-namespace.h" 4966633Sdfr#include "libc_private.h" 5066633Sdfr 5166633Sdfr/* 5266633Sdfr * We have to define these here due to clashes between yp_prot.h and 5366633Sdfr * yp.h. 5466633Sdfr */ 5566633Sdfr 5666633Sdfr#define YPMATCHCACHE 5766633Sdfr 5866633Sdfr#ifdef YPMATCHCACHE 5966633Sdfrstruct ypmatch_ent { 6066633Sdfr char *ypc_map; 6166633Sdfr keydat ypc_key; 6266633Sdfr valdat ypc_val; 6366633Sdfr time_t ypc_expire_t; 6466633Sdfr struct ypmatch_ent *ypc_next; 6566633Sdfr}; 6666633Sdfr#define YPLIB_MAXCACHE 5 /* At most 5 entries */ 6766633Sdfr#define YPLIB_EXPIRE 5 /* Expire after 5 seconds */ 6866633Sdfr#endif 6966633Sdfr 7066633Sdfrstruct dom_binding { 7166633Sdfr struct dom_binding *dom_pnext; 7285304Sobrien char dom_domain[YPMAXDOMAIN + 1]; 7366633Sdfr struct sockaddr_in dom_server_addr; 7466633Sdfr u_short dom_server_port; 75151897Srwatson int dom_socket; 7666633Sdfr CLIENT *dom_client; 7766633Sdfr u_short dom_local_port; /* now I finally know what this is for. */ 7866633Sdfr long dom_vers; 7966633Sdfr#ifdef YPMATCHCACHE 8066633Sdfr struct ypmatch_ent *cache; 8166633Sdfr int ypmatch_cachecnt; 8266633Sdfr#endif 8366633Sdfr}; 8466633Sdfr 85125975Sphk#include <rpcsvc/ypclnt.h> 86130585Sphk 8766633Sdfr#ifndef BINDINGDIR 8866633Sdfr#define BINDINGDIR "/var/yp/binding" 8966633Sdfr#endif 9066633Sdfr#define MAX_RETRIES 20 9166633Sdfr 9266633Sdfrbool_t xdr_ypresp_all_seq(XDR *xdrs, u_long *objp); 9366633Sdfr 9466633Sdfrint (*ypresp_allfn)(unsigned long, char *, int, char *, int, void *); 9566633Sdfrvoid *ypresp_data; 9666633Sdfr 9766633Sdfrstatic void _yp_unbind(struct dom_binding *); 9866633Sdfrstruct dom_binding *_ypbindlist; 9966633Sdfrstatic char _yp_domain[MAXHOSTNAMELEN]; 10067018Sdfrint _yplib_timeout = 20; 10166633Sdfr 102112051Smarcelstatic mutex_t _ypmutex = MUTEX_INITIALIZER; 10366633Sdfr#define YPLOCK() mutex_lock(&_ypmutex); 10466633Sdfr#define YPUNLOCK() mutex_unlock(&_ypmutex); 10566633Sdfr 106112946Sphk#ifdef YPMATCHCACHE 10766633Sdfrstatic void 10866633Sdfrypmatch_cache_delete(struct dom_binding *ypdb, struct ypmatch_ent *prev, 10966633Sdfr struct ypmatch_ent *cur) 11066633Sdfr{ 11166633Sdfr if (prev == NULL) 11266633Sdfr ypdb->cache = cur->ypc_next; 11366633Sdfr else 11466633Sdfr prev->ypc_next = cur->ypc_next; 11566633Sdfr 116136809Sphk free(cur->ypc_map); 11766633Sdfr free(cur->ypc_key.keydat_val); 11866633Sdfr free(cur->ypc_val.valdat_val); 11966633Sdfr free(cur); 12066633Sdfr 12167018Sdfr ypdb->ypmatch_cachecnt--; 12267018Sdfr 12367018Sdfr return; 12467018Sdfr} 12567018Sdfr 12667018Sdfrstatic void 12767018Sdfrypmatch_cache_flush(struct dom_binding *ypdb) 12867018Sdfr{ 12967018Sdfr struct ypmatch_ent *n, *c = ypdb->cache; 13067018Sdfr 13167018Sdfr while (c != NULL) { 132112051Smarcel n = c->ypc_next; 133112051Smarcel ypmatch_cache_delete(ypdb, NULL, c); 13467018Sdfr c = n; 13567018Sdfr } 13667018Sdfr 13767018Sdfr return; 13867018Sdfr} 13967018Sdfr 14067018Sdfrstatic void 14166633Sdfrypmatch_cache_expire(struct dom_binding *ypdb) 142111979Sphk{ 14366633Sdfr struct ypmatch_ent *c = ypdb->cache; 14466633Sdfr struct ypmatch_ent *n, *p = NULL; 14566633Sdfr time_t t; 14666633Sdfr 14766633Sdfr time(&t); 14866633Sdfr 14966633Sdfr while (c != NULL) { 15066633Sdfr if (t >= c->ypc_expire_t) { 15166633Sdfr n = c->ypc_next; 15266633Sdfr ypmatch_cache_delete(ypdb, p, c); 15366633Sdfr c = n; 15483964Sdfr } else { 15566633Sdfr p = c; 15683964Sdfr c = c->ypc_next; 15783964Sdfr } 15883964Sdfr } 15983964Sdfr 16083964Sdfr return; 16166633Sdfr} 16266633Sdfr 16366633Sdfrstatic void 16466633Sdfrypmatch_cache_insert(struct dom_binding *ypdb, char *map, keydat *key, 16566633Sdfr valdat *val) 16666633Sdfr{ 16766633Sdfr struct ypmatch_ent *new; 168184205Sdes 16966633Sdfr /* Do an expire run to maybe open up a slot. */ 17066633Sdfr if (ypdb->ypmatch_cachecnt) 17166633Sdfr ypmatch_cache_expire(ypdb); 172110229Sphk 173125975Sphk /* 174125975Sphk * If there are no slots free, then force an expire of 175125975Sphk * the least recently used entry. 176125975Sphk */ 177125975Sphk if (ypdb->ypmatch_cachecnt >= YPLIB_MAXCACHE) { 178125975Sphk struct ypmatch_ent *o = NULL, *c = ypdb->cache; 179125975Sphk time_t oldest = 0; 180125975Sphk 181125975Sphk oldest = ~oldest; 182125975Sphk 183125975Sphk while (c != NULL) { 184125975Sphk if (c->ypc_expire_t < oldest) { 18583964Sdfr oldest = c->ypc_expire_t; 18666633Sdfr o = c; 187178028Smarcel } 18866633Sdfr c = c->ypc_next; 18966633Sdfr } 19066633Sdfr 19166633Sdfr if (o == NULL) 19266633Sdfr return; 19366633Sdfr o->ypc_expire_t = 0; 19466633Sdfr ypmatch_cache_expire(ypdb); 19566633Sdfr } 19666633Sdfr 197177253Srwatson new = malloc(sizeof(struct ypmatch_ent)); 198 if (new == NULL) 199 return; 200 201 new->ypc_map = strdup(map); 202 if (new->ypc_map == NULL) { 203 free(new); 204 return; 205 } 206 new->ypc_key.keydat_val = malloc(key->keydat_len); 207 if (new->ypc_key.keydat_val == NULL) { 208 free(new->ypc_map); 209 free(new); 210 return; 211 } 212 new->ypc_val.valdat_val = malloc(val->valdat_len); 213 if (new->ypc_val.valdat_val == NULL) { 214 free(new->ypc_val.valdat_val); 215 free(new->ypc_map); 216 free(new); 217 return; 218 } 219 220 new->ypc_expire_t = time(NULL) + YPLIB_EXPIRE; 221 new->ypc_key.keydat_len = key->keydat_len; 222 new->ypc_val.valdat_len = val->valdat_len; 223 bcopy(key->keydat_val, new->ypc_key.keydat_val, key->keydat_len); 224 bcopy(val->valdat_val, new->ypc_val.valdat_val, val->valdat_len); 225 226 new->ypc_next = ypdb->cache; 227 ypdb->cache = new; 228 229 ypdb->ypmatch_cachecnt++; 230 231 return; 232} 233 234static bool_t 235ypmatch_cache_lookup(struct dom_binding *ypdb, char *map, keydat *key, 236 valdat *val) 237{ 238 struct ypmatch_ent *c; 239 240 ypmatch_cache_expire(ypdb); 241 242 for (c = ypdb->cache; c != NULL; c = c->ypc_next) { 243 if (strcmp(map, c->ypc_map)) 244 continue; 245 if (key->keydat_len != c->ypc_key.keydat_len) 246 continue; 247 if (bcmp(key->keydat_val, c->ypc_key.keydat_val, 248 key->keydat_len)) 249 continue; 250 } 251 252 if (c == NULL) 253 return(FALSE); 254 255 val->valdat_len = c->ypc_val.valdat_len; 256 val->valdat_val = c->ypc_val.valdat_val; 257 258 return(TRUE); 259} 260#endif 261 262const char * 263ypbinderr_string(int incode) 264{ 265 static char err[80]; 266 switch (incode) { 267 case 0: 268 return ("Success"); 269 case YPBIND_ERR_ERR: 270 return ("Internal ypbind error"); 271 case YPBIND_ERR_NOSERV: 272 return ("Domain not bound"); 273 case YPBIND_ERR_RESC: 274 return ("System resource allocation failure"); 275 } 276 sprintf(err, "Unknown ypbind error: #%d\n", incode); 277 return (err); 278} 279 280int 281_yp_dobind(char *dom, struct dom_binding **ypdb) 282{ 283 static pid_t pid = -1; 284 char path[MAXPATHLEN]; 285 struct dom_binding *ysd, *ysd2; 286 struct ypbind_resp ypbr; 287 struct timeval tv; 288 struct sockaddr_in clnt_sin; 289 int clnt_sock, fd; 290 pid_t gpid; 291 CLIENT *client; 292 int new = 0, r; 293 int retries = 0; 294 struct sockaddr_in check; 295 socklen_t checklen = sizeof(struct sockaddr_in); 296 297 /* Not allowed; bad doggie. Bad. */ 298 if (strchr(dom, '/') != NULL) 299 return(YPERR_BADARGS); 300 301 gpid = getpid(); 302 if (!(pid == -1 || pid == gpid)) { 303 ysd = _ypbindlist; 304 while (ysd) { 305 if (ysd->dom_client != NULL) 306 _yp_unbind(ysd); 307 ysd2 = ysd->dom_pnext; 308 free(ysd); 309 ysd = ysd2; 310 } 311 _ypbindlist = NULL; 312 } 313 pid = gpid; 314 315 if (ypdb != NULL) 316 *ypdb = NULL; 317 318 if (dom == NULL || strlen(dom) == 0) 319 return (YPERR_BADARGS); 320 321 for (ysd = _ypbindlist; ysd; ysd = ysd->dom_pnext) 322 if (strcmp(dom, ysd->dom_domain) == 0) 323 break; 324 325 326 if (ysd == NULL) { 327 ysd = (struct dom_binding *)malloc(sizeof *ysd); 328 if (ysd == NULL) 329 return (YPERR_RESRC); 330 bzero((char *)ysd, sizeof *ysd); 331 ysd->dom_socket = -1; 332 ysd->dom_vers = 0; 333 new = 1; 334 } else { 335 /* Check the socket -- may have been hosed by the caller. */ 336 if (_getsockname(ysd->dom_socket, (struct sockaddr *)&check, 337 &checklen) == -1 || check.sin_family != AF_INET || 338 check.sin_port != ysd->dom_local_port) { 339 /* Socket became bogus somehow... need to rebind. */ 340 int save, sock; 341 342 sock = ysd->dom_socket; 343 save = _dup(ysd->dom_socket); 344 if (ysd->dom_client != NULL) 345 clnt_destroy(ysd->dom_client); 346 ysd->dom_vers = 0; 347 ysd->dom_client = NULL; 348 sock = _dup2(save, sock); 349 _close(save); 350 } 351 } 352 353again: 354 retries++; 355 if (retries > MAX_RETRIES) { 356 if (new) 357 free(ysd); 358 return(YPERR_YPBIND); 359 } 360#ifdef BINDINGDIR 361 if (ysd->dom_vers == 0) { 362 /* 363 * We're trying to make a new binding: zorch the 364 * existing handle now (if any). 365 */ 366 if (ysd->dom_client != NULL) { 367 clnt_destroy(ysd->dom_client); 368 ysd->dom_client = NULL; 369 ysd->dom_socket = -1; 370 } 371 snprintf(path, sizeof(path), "%s/%s.%d", BINDINGDIR, dom, 2); 372 if ((fd = _open(path, O_RDONLY | O_CLOEXEC)) == -1) { 373 /* no binding file, YP is dead. */ 374 /* Try to bring it back to life. */ 375 _close(fd); 376 goto skipit; 377 } 378 if (_flock(fd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK) { 379 struct iovec iov[2]; 380 struct ypbind_resp ybr; 381 u_short ypb_port; 382 383 iov[0].iov_base = (caddr_t)&ypb_port; 384 iov[0].iov_len = sizeof ypb_port; 385 iov[1].iov_base = (caddr_t)&ybr; 386 iov[1].iov_len = sizeof ybr; 387 388 r = _readv(fd, iov, 2); 389 if (r != iov[0].iov_len + iov[1].iov_len) { 390 _close(fd); 391 ysd->dom_vers = -1; 392 goto again; 393 } 394 395 bzero(&ysd->dom_server_addr, sizeof ysd->dom_server_addr); 396 ysd->dom_server_addr.sin_family = AF_INET; 397 ysd->dom_server_addr.sin_len = sizeof(struct sockaddr_in); 398 bcopy(&ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr, 399 &ysd->dom_server_addr.sin_addr.s_addr, 400 sizeof(ysd->dom_server_addr.sin_addr.s_addr)); 401 bcopy(&ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port, 402 &ysd->dom_server_addr.sin_port, 403 sizeof(ysd->dom_server_addr.sin_port)); 404 405 ysd->dom_server_port = ysd->dom_server_addr.sin_port; 406 _close(fd); 407 goto gotit; 408 } else { 409 /* no lock on binding file, YP is dead. */ 410 /* Try to bring it back to life. */ 411 _close(fd); 412 goto skipit; 413 } 414 } 415skipit: 416#endif 417 if (ysd->dom_vers == -1 || ysd->dom_vers == 0) { 418 /* 419 * We're trying to make a new binding: zorch the 420 * existing handle now (if any). 421 */ 422 if (ysd->dom_client != NULL) { 423 clnt_destroy(ysd->dom_client); 424 ysd->dom_client = NULL; 425 ysd->dom_socket = -1; 426 } 427 bzero((char *)&clnt_sin, sizeof clnt_sin); 428 clnt_sin.sin_family = AF_INET; 429 clnt_sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 430 431 clnt_sock = RPC_ANYSOCK; 432 client = clnttcp_create(&clnt_sin, YPBINDPROG, YPBINDVERS, &clnt_sock, 433 0, 0); 434 if (client == NULL) { 435 /* 436 * These conditions indicate ypbind just isn't 437 * alive -- we probably don't want to shoot our 438 * mouth off in this case; instead generate error 439 * messages only for really exotic problems. 440 */ 441 if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED && 442 (rpc_createerr.cf_stat != RPC_SYSTEMERROR && 443 rpc_createerr.cf_error.re_errno == ECONNREFUSED)) 444 clnt_pcreateerror("clnttcp_create"); 445 if (new) 446 free(ysd); 447 return (YPERR_YPBIND); 448 } 449 450 /* 451 * Check the port number -- should be < IPPORT_RESERVED. 452 * If not, it's possible someone has registered a bogus 453 * ypbind with the portmapper and is trying to trick us. 454 */ 455 if (ntohs(clnt_sin.sin_port) >= IPPORT_RESERVED) { 456 if (client != NULL) 457 clnt_destroy(client); 458 if (new) 459 free(ysd); 460 return(YPERR_YPBIND); 461 } 462 tv.tv_sec = _yplib_timeout/2; 463 tv.tv_usec = 0; 464 r = clnt_call(client, YPBINDPROC_DOMAIN, 465 (xdrproc_t)xdr_domainname, &dom, 466 (xdrproc_t)xdr_ypbind_resp, &ypbr, tv); 467 if (r != RPC_SUCCESS) { 468 clnt_destroy(client); 469 ysd->dom_vers = -1; 470 if (r == RPC_PROGUNAVAIL || r == RPC_PROCUNAVAIL) { 471 if (new) 472 free(ysd); 473 return(YPERR_YPBIND); 474 } 475 fprintf(stderr, 476 "YP: server for domain %s not responding, retrying\n", dom); 477 goto again; 478 } else { 479 if (ypbr.ypbind_status != YPBIND_SUCC_VAL) { 480 struct timespec time_to_sleep, time_remaining; 481 482 clnt_destroy(client); 483 ysd->dom_vers = -1; 484 485 time_to_sleep.tv_sec = _yplib_timeout/2; 486 time_to_sleep.tv_nsec = 0; 487 _nanosleep(&time_to_sleep, 488 &time_remaining); 489 goto again; 490 } 491 } 492 clnt_destroy(client); 493 494 bzero((char *)&ysd->dom_server_addr, sizeof ysd->dom_server_addr); 495 ysd->dom_server_addr.sin_family = AF_INET; 496 bcopy(&ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port, 497 &ysd->dom_server_addr.sin_port, 498 sizeof(ysd->dom_server_addr.sin_port)); 499 bcopy(&ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr, 500 &ysd->dom_server_addr.sin_addr.s_addr, 501 sizeof(ysd->dom_server_addr.sin_addr.s_addr)); 502 503 /* 504 * We could do a reserved port check here too, but this 505 * could pose compatibility problems. The local ypbind is 506 * supposed to decide whether or not to trust yp servers 507 * on insecure ports. For now, we trust its judgement. 508 */ 509 ysd->dom_server_port = 510 *(u_short *)&ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port; 511gotit: 512 ysd->dom_vers = YPVERS; 513 strlcpy(ysd->dom_domain, dom, sizeof(ysd->dom_domain)); 514 } 515 516 /* Don't rebuild the connection to the server unless we have to. */ 517 if (ysd->dom_client == NULL) { 518 tv.tv_sec = _yplib_timeout/2; 519 tv.tv_usec = 0; 520 ysd->dom_socket = RPC_ANYSOCK; 521 ysd->dom_client = clntudp_bufcreate(&ysd->dom_server_addr, 522 YPPROG, YPVERS, tv, &ysd->dom_socket, 65507, 65507); 523 if (ysd->dom_client == NULL) { 524 clnt_pcreateerror("clntudp_create"); 525 ysd->dom_vers = -1; 526 goto again; 527 } 528 if (_fcntl(ysd->dom_socket, F_SETFD, 1) == -1) 529 perror("fcntl: F_SETFD"); 530 /* 531 * We want a port number associated with this socket 532 * so that we can check its authenticity later. 533 */ 534 checklen = sizeof(struct sockaddr_in); 535 bzero((char *)&check, checklen); 536 _bind(ysd->dom_socket, (struct sockaddr *)&check, checklen); 537 check.sin_family = AF_INET; 538 if (!_getsockname(ysd->dom_socket, 539 (struct sockaddr *)&check, &checklen)) { 540 ysd->dom_local_port = check.sin_port; 541 } else { 542 clnt_destroy(ysd->dom_client); 543 if (new) 544 free(ysd); 545 return(YPERR_YPBIND); 546 } 547 } 548 549 if (new) { 550 ysd->dom_pnext = _ypbindlist; 551 _ypbindlist = ysd; 552 } 553 554 /* 555 * Set low retry timeout to realistically handle UDP packet 556 * loss for YP packet bursts. 557 */ 558 tv.tv_sec = 1; 559 tv.tv_usec = 0; 560 clnt_control(ysd->dom_client, CLSET_RETRY_TIMEOUT, (char*)&tv); 561 562 if (ypdb != NULL) 563 *ypdb = ysd; 564 return (0); 565} 566 567static void 568_yp_unbind(struct dom_binding *ypb) 569{ 570 struct sockaddr_in check; 571 socklen_t checklen = sizeof(struct sockaddr_in); 572 573 if (ypb->dom_client != NULL) { 574 /* Check the socket -- may have been hosed by the caller. */ 575 if (_getsockname(ypb->dom_socket, (struct sockaddr *)&check, 576 &checklen) == -1 || check.sin_family != AF_INET || 577 check.sin_port != ypb->dom_local_port) { 578 int save, sock; 579 580 sock = ypb->dom_socket; 581 save = _dup(ypb->dom_socket); 582 clnt_destroy(ypb->dom_client); 583 sock = _dup2(save, sock); 584 _close(save); 585 } else 586 clnt_destroy(ypb->dom_client); 587 } 588 589 ypb->dom_client = NULL; 590 ypb->dom_socket = -1; 591 ypb->dom_vers = -1; 592#ifdef YPMATCHCACHE 593 ypmatch_cache_flush(ypb); 594#endif 595} 596 597static int 598yp_bind_locked(char *dom) 599{ 600 return (_yp_dobind(dom, NULL)); 601} 602 603int 604yp_bind(char *dom) 605{ 606 int r; 607 608 YPLOCK(); 609 r = yp_bind_locked(dom); 610 YPUNLOCK(); 611 return (r); 612} 613 614static void 615yp_unbind_locked(char *dom) 616{ 617 struct dom_binding *ypb, *ypbp; 618 619 ypbp = NULL; 620 for (ypb = _ypbindlist; ypb; ypb = ypb->dom_pnext) { 621 if (strcmp(dom, ypb->dom_domain) == 0) { 622 _yp_unbind(ypb); 623 if (ypbp) 624 ypbp->dom_pnext = ypb->dom_pnext; 625 else 626 _ypbindlist = ypb->dom_pnext; 627 free(ypb); 628 return; 629 } 630 ypbp = ypb; 631 } 632 return; 633} 634 635void 636yp_unbind(char *dom) 637{ 638 YPLOCK(); 639 yp_unbind_locked(dom); 640 YPUNLOCK(); 641} 642 643int 644yp_match(char *indomain, char *inmap, const char *inkey, int inkeylen, 645 char **outval, int *outvallen) 646{ 647 struct dom_binding *ysd; 648 struct ypresp_val yprv; 649 struct timeval tv; 650 struct ypreq_key yprk; 651 int r; 652 int retries = 0; 653 *outval = NULL; 654 *outvallen = 0; 655 656 /* Sanity check */ 657 658 if (inkey == NULL || !strlen(inkey) || inkeylen <= 0 || 659 inmap == NULL || !strlen(inmap) || 660 indomain == NULL || !strlen(indomain)) 661 return (YPERR_BADARGS); 662 663 YPLOCK(); 664 if (_yp_dobind(indomain, &ysd) != 0) { 665 YPUNLOCK(); 666 return(YPERR_DOMAIN); 667 } 668 669 yprk.domain = indomain; 670 yprk.map = inmap; 671 yprk.key.keydat_val = (char *)inkey; 672 yprk.key.keydat_len = inkeylen; 673 674#ifdef YPMATCHCACHE 675 if (ypmatch_cache_lookup(ysd, yprk.map, &yprk.key, &yprv.val) == TRUE) { 676/* 677 if (!strcmp(_yp_domain, indomain) && ypmatch_find(inmap, inkey, 678 inkeylen, &yprv.val.valdat_val, &yprv.val.valdat_len)) { 679*/ 680 *outvallen = yprv.val.valdat_len; 681 *outval = (char *)malloc(*outvallen+1); 682 if (*outval == NULL) { 683 _yp_unbind(ysd); 684 *outvallen = 0; 685 YPUNLOCK(); 686 return (YPERR_RESRC); 687 } 688 bcopy(yprv.val.valdat_val, *outval, *outvallen); 689 (*outval)[*outvallen] = '\0'; 690 YPUNLOCK(); 691 return (0); 692 } 693 _yp_unbind(ysd); 694#endif 695 696again: 697 if (retries > MAX_RETRIES) { 698 YPUNLOCK(); 699 return (YPERR_RPC); 700 } 701 702 if (_yp_dobind(indomain, &ysd) != 0) { 703 YPUNLOCK(); 704 return (YPERR_DOMAIN); 705 } 706 707 tv.tv_sec = _yplib_timeout; 708 tv.tv_usec = 0; 709 710 bzero((char *)&yprv, sizeof yprv); 711 712 r = clnt_call(ysd->dom_client, YPPROC_MATCH, 713 (xdrproc_t)xdr_ypreq_key, &yprk, 714 (xdrproc_t)xdr_ypresp_val, &yprv, tv); 715 if (r != RPC_SUCCESS) { 716 clnt_perror(ysd->dom_client, "yp_match: clnt_call"); 717 _yp_unbind(ysd); 718 retries++; 719 goto again; 720 } 721 722 if (!(r = ypprot_err(yprv.stat))) { 723 *outvallen = yprv.val.valdat_len; 724 *outval = (char *)malloc(*outvallen+1); 725 if (*outval == NULL) { 726 _yp_unbind(ysd); 727 *outvallen = 0; 728 xdr_free((xdrproc_t)xdr_ypresp_val, &yprv); 729 YPUNLOCK(); 730 return (YPERR_RESRC); 731 } 732 bcopy(yprv.val.valdat_val, *outval, *outvallen); 733 (*outval)[*outvallen] = '\0'; 734#ifdef YPMATCHCACHE 735 ypmatch_cache_insert(ysd, yprk.map, &yprk.key, &yprv.val); 736#endif 737 } 738 739 xdr_free((xdrproc_t)xdr_ypresp_val, &yprv); 740 YPUNLOCK(); 741 return (r); 742} 743 744static int 745yp_get_default_domain_locked(char **domp) 746{ 747 *domp = NULL; 748 if (_yp_domain[0] == '\0') 749 if (getdomainname(_yp_domain, sizeof _yp_domain)) 750 return (YPERR_NODOM); 751 *domp = _yp_domain; 752 return (0); 753} 754 755int 756yp_get_default_domain(char **domp) 757{ 758 int r; 759 760 YPLOCK(); 761 r = yp_get_default_domain_locked(domp); 762 YPUNLOCK(); 763 return (r); 764} 765 766int 767yp_first(char *indomain, char *inmap, char **outkey, int *outkeylen, 768 char **outval, int *outvallen) 769{ 770 struct ypresp_key_val yprkv; 771 struct ypreq_nokey yprnk; 772 struct dom_binding *ysd; 773 struct timeval tv; 774 int r; 775 int retries = 0; 776 /* Sanity check */ 777 778 if (indomain == NULL || !strlen(indomain) || 779 inmap == NULL || !strlen(inmap)) 780 return (YPERR_BADARGS); 781 782 *outkey = *outval = NULL; 783 *outkeylen = *outvallen = 0; 784 785 YPLOCK(); 786again: 787 if (retries > MAX_RETRIES) { 788 YPUNLOCK(); 789 return (YPERR_RPC); 790 } 791 792 if (_yp_dobind(indomain, &ysd) != 0) { 793 YPUNLOCK(); 794 return (YPERR_DOMAIN); 795 } 796 797 tv.tv_sec = _yplib_timeout; 798 tv.tv_usec = 0; 799 800 yprnk.domain = indomain; 801 yprnk.map = inmap; 802 bzero((char *)&yprkv, sizeof yprkv); 803 804 r = clnt_call(ysd->dom_client, YPPROC_FIRST, 805 (xdrproc_t)xdr_ypreq_nokey, &yprnk, 806 (xdrproc_t)xdr_ypresp_key_val, &yprkv, tv); 807 if (r != RPC_SUCCESS) { 808 clnt_perror(ysd->dom_client, "yp_first: clnt_call"); 809 _yp_unbind(ysd); 810 retries++; 811 goto again; 812 } 813 if (!(r = ypprot_err(yprkv.stat))) { 814 *outkeylen = yprkv.key.keydat_len; 815 *outkey = (char *)malloc(*outkeylen+1); 816 if (*outkey == NULL) { 817 _yp_unbind(ysd); 818 *outkeylen = 0; 819 xdr_free((xdrproc_t)xdr_ypresp_key_val, &yprkv); 820 YPUNLOCK(); 821 return (YPERR_RESRC); 822 } 823 bcopy(yprkv.key.keydat_val, *outkey, *outkeylen); 824 (*outkey)[*outkeylen] = '\0'; 825 *outvallen = yprkv.val.valdat_len; 826 *outval = (char *)malloc(*outvallen+1); 827 if (*outval == NULL) { 828 free(*outkey); 829 _yp_unbind(ysd); 830 *outkeylen = *outvallen = 0; 831 xdr_free((xdrproc_t)xdr_ypresp_key_val, &yprkv); 832 YPUNLOCK(); 833 return (YPERR_RESRC); 834 } 835 bcopy(yprkv.val.valdat_val, *outval, *outvallen); 836 (*outval)[*outvallen] = '\0'; 837 } 838 839 xdr_free((xdrproc_t)xdr_ypresp_key_val, &yprkv); 840 YPUNLOCK(); 841 return (r); 842} 843 844int 845yp_next(char *indomain, char *inmap, char *inkey, int inkeylen, 846 char **outkey, int *outkeylen, char **outval, int *outvallen) 847{ 848 struct ypresp_key_val yprkv; 849 struct ypreq_key yprk; 850 struct dom_binding *ysd; 851 struct timeval tv; 852 int r; 853 int retries = 0; 854 /* Sanity check */ 855 856 if (inkey == NULL || !strlen(inkey) || inkeylen <= 0 || 857 inmap == NULL || !strlen(inmap) || 858 indomain == NULL || !strlen(indomain)) 859 return (YPERR_BADARGS); 860 861 *outkey = *outval = NULL; 862 *outkeylen = *outvallen = 0; 863 864 YPLOCK(); 865again: 866 if (retries > MAX_RETRIES) { 867 YPUNLOCK(); 868 return (YPERR_RPC); 869 } 870 871 if (_yp_dobind(indomain, &ysd) != 0) { 872 YPUNLOCK(); 873 return (YPERR_DOMAIN); 874 } 875 876 tv.tv_sec = _yplib_timeout; 877 tv.tv_usec = 0; 878 879 yprk.domain = indomain; 880 yprk.map = inmap; 881 yprk.key.keydat_val = inkey; 882 yprk.key.keydat_len = inkeylen; 883 bzero((char *)&yprkv, sizeof yprkv); 884 885 r = clnt_call(ysd->dom_client, YPPROC_NEXT, 886 (xdrproc_t)xdr_ypreq_key, &yprk, 887 (xdrproc_t)xdr_ypresp_key_val, &yprkv, tv); 888 if (r != RPC_SUCCESS) { 889 clnt_perror(ysd->dom_client, "yp_next: clnt_call"); 890 _yp_unbind(ysd); 891 retries++; 892 goto again; 893 } 894 if (!(r = ypprot_err(yprkv.stat))) { 895 *outkeylen = yprkv.key.keydat_len; 896 *outkey = (char *)malloc(*outkeylen+1); 897 if (*outkey == NULL) { 898 _yp_unbind(ysd); 899 *outkeylen = 0; 900 xdr_free((xdrproc_t)xdr_ypresp_key_val, &yprkv); 901 YPUNLOCK(); 902 return (YPERR_RESRC); 903 } 904 bcopy(yprkv.key.keydat_val, *outkey, *outkeylen); 905 (*outkey)[*outkeylen] = '\0'; 906 *outvallen = yprkv.val.valdat_len; 907 *outval = (char *)malloc(*outvallen+1); 908 if (*outval == NULL) { 909 free(*outkey); 910 _yp_unbind(ysd); 911 *outkeylen = *outvallen = 0; 912 xdr_free((xdrproc_t)xdr_ypresp_key_val, &yprkv); 913 YPUNLOCK(); 914 return (YPERR_RESRC); 915 } 916 bcopy(yprkv.val.valdat_val, *outval, *outvallen); 917 (*outval)[*outvallen] = '\0'; 918 } 919 920 xdr_free((xdrproc_t)xdr_ypresp_key_val, &yprkv); 921 YPUNLOCK(); 922 return (r); 923} 924 925int 926yp_all(char *indomain, char *inmap, struct ypall_callback *incallback) 927{ 928 struct ypreq_nokey yprnk; 929 struct dom_binding *ysd; 930 struct timeval tv; 931 struct sockaddr_in clnt_sin; 932 CLIENT *clnt; 933 u_long status, savstat; 934 int clnt_sock; 935 int retries = 0; 936 /* Sanity check */ 937 938 if (indomain == NULL || !strlen(indomain) || 939 inmap == NULL || !strlen(inmap)) 940 return (YPERR_BADARGS); 941 942 YPLOCK(); 943again: 944 if (retries > MAX_RETRIES) { 945 YPUNLOCK(); 946 return (YPERR_RPC); 947 } 948 949 if (_yp_dobind(indomain, &ysd) != 0) { 950 YPUNLOCK(); 951 return (YPERR_DOMAIN); 952 } 953 954 tv.tv_sec = _yplib_timeout; 955 tv.tv_usec = 0; 956 957 /* YPPROC_ALL manufactures its own channel to ypserv using TCP */ 958 959 clnt_sock = RPC_ANYSOCK; 960 clnt_sin = ysd->dom_server_addr; 961 clnt_sin.sin_port = 0; 962 clnt = clnttcp_create(&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0); 963 if (clnt == NULL) { 964 YPUNLOCK(); 965 printf("clnttcp_create failed\n"); 966 return (YPERR_PMAP); 967 } 968 969 yprnk.domain = indomain; 970 yprnk.map = inmap; 971 ypresp_allfn = incallback->foreach; 972 ypresp_data = (void *)incallback->data; 973 974 if (clnt_call(clnt, YPPROC_ALL, 975 (xdrproc_t)xdr_ypreq_nokey, &yprnk, 976 (xdrproc_t)xdr_ypresp_all_seq, &status, tv) != RPC_SUCCESS) { 977 clnt_perror(clnt, "yp_all: clnt_call"); 978 clnt_destroy(clnt); 979 _yp_unbind(ysd); 980 retries++; 981 goto again; 982 } 983 984 clnt_destroy(clnt); 985 savstat = status; 986 xdr_free((xdrproc_t)xdr_ypresp_all_seq, &status); /* not really needed... */ 987 YPUNLOCK(); 988 if (savstat != YP_NOMORE) 989 return (ypprot_err(savstat)); 990 return (0); 991} 992 993int 994yp_order(char *indomain, char *inmap, int *outorder) 995{ 996 struct dom_binding *ysd; 997 struct ypresp_order ypro; 998 struct ypreq_nokey yprnk; 999 struct timeval tv; 1000 int r; 1001 1002 /* Sanity check */ 1003 1004 if (indomain == NULL || !strlen(indomain) || 1005 inmap == NULL || !strlen(inmap)) 1006 return (YPERR_BADARGS); 1007 1008 YPLOCK(); 1009again: 1010 if (_yp_dobind(indomain, &ysd) != 0) { 1011 YPUNLOCK(); 1012 return (YPERR_DOMAIN); 1013 } 1014 1015 tv.tv_sec = _yplib_timeout; 1016 tv.tv_usec = 0; 1017 1018 yprnk.domain = indomain; 1019 yprnk.map = inmap; 1020 1021 bzero((char *)(char *)&ypro, sizeof ypro); 1022 1023 r = clnt_call(ysd->dom_client, YPPROC_ORDER, 1024 (xdrproc_t)xdr_ypreq_nokey, &yprnk, 1025 (xdrproc_t)xdr_ypresp_order, &ypro, tv); 1026 1027 /* 1028 * NIS+ in YP compat mode doesn't support the YPPROC_ORDER 1029 * procedure. 1030 */ 1031 if (r == RPC_PROCUNAVAIL) { 1032 YPUNLOCK(); 1033 return(YPERR_YPERR); 1034 } 1035 1036 if (r != RPC_SUCCESS) { 1037 clnt_perror(ysd->dom_client, "yp_order: clnt_call"); 1038 _yp_unbind(ysd); 1039 goto again; 1040 } 1041 1042 if (!(r = ypprot_err(ypro.stat))) { 1043 *outorder = ypro.ordernum; 1044 } 1045 1046 xdr_free((xdrproc_t)xdr_ypresp_order, &ypro); 1047 YPUNLOCK(); 1048 return (r); 1049} 1050 1051int 1052yp_master(char *indomain, char *inmap, char **outname) 1053{ 1054 struct dom_binding *ysd; 1055 struct ypresp_master yprm; 1056 struct ypreq_nokey yprnk; 1057 struct timeval tv; 1058 int r; 1059 1060 /* Sanity check */ 1061 1062 if (indomain == NULL || !strlen(indomain) || 1063 inmap == NULL || !strlen(inmap)) 1064 return (YPERR_BADARGS); 1065 YPLOCK(); 1066again: 1067 if (_yp_dobind(indomain, &ysd) != 0) { 1068 YPUNLOCK(); 1069 return (YPERR_DOMAIN); 1070 } 1071 1072 tv.tv_sec = _yplib_timeout; 1073 tv.tv_usec = 0; 1074 1075 yprnk.domain = indomain; 1076 yprnk.map = inmap; 1077 1078 bzero((char *)&yprm, sizeof yprm); 1079 1080 r = clnt_call(ysd->dom_client, YPPROC_MASTER, 1081 (xdrproc_t)xdr_ypreq_nokey, &yprnk, 1082 (xdrproc_t)xdr_ypresp_master, &yprm, tv); 1083 if (r != RPC_SUCCESS) { 1084 clnt_perror(ysd->dom_client, "yp_master: clnt_call"); 1085 _yp_unbind(ysd); 1086 goto again; 1087 } 1088 1089 if (!(r = ypprot_err(yprm.stat))) { 1090 *outname = (char *)strdup(yprm.peer); 1091 } 1092 1093 xdr_free((xdrproc_t)xdr_ypresp_master, &yprm); 1094 YPUNLOCK(); 1095 return (r); 1096} 1097 1098int 1099yp_maplist(char *indomain, struct ypmaplist **outmaplist) 1100{ 1101 struct dom_binding *ysd; 1102 struct ypresp_maplist ypml; 1103 struct timeval tv; 1104 int r; 1105 1106 /* Sanity check */ 1107 1108 if (indomain == NULL || !strlen(indomain)) 1109 return (YPERR_BADARGS); 1110 1111 YPLOCK(); 1112again: 1113 if (_yp_dobind(indomain, &ysd) != 0) { 1114 YPUNLOCK(); 1115 return (YPERR_DOMAIN); 1116 } 1117 1118 tv.tv_sec = _yplib_timeout; 1119 tv.tv_usec = 0; 1120 1121 bzero((char *)&ypml, sizeof ypml); 1122 1123 r = clnt_call(ysd->dom_client, YPPROC_MAPLIST, 1124 (xdrproc_t)xdr_domainname, &indomain, 1125 (xdrproc_t)xdr_ypresp_maplist, &ypml,tv); 1126 if (r != RPC_SUCCESS) { 1127 clnt_perror(ysd->dom_client, "yp_maplist: clnt_call"); 1128 _yp_unbind(ysd); 1129 goto again; 1130 } 1131 if (!(r = ypprot_err(ypml.stat))) { 1132 *outmaplist = ypml.maps; 1133 } 1134 1135 /* NO: xdr_free((xdrproc_t)xdr_ypresp_maplist, &ypml);*/ 1136 YPUNLOCK(); 1137 return (r); 1138} 1139 1140const char * 1141yperr_string(int incode) 1142{ 1143 static char err[80]; 1144 1145 switch (incode) { 1146 case 0: 1147 return ("Success"); 1148 case YPERR_BADARGS: 1149 return ("Request arguments bad"); 1150 case YPERR_RPC: 1151 return ("RPC failure"); 1152 case YPERR_DOMAIN: 1153 return ("Can't bind to server which serves this domain"); 1154 case YPERR_MAP: 1155 return ("No such map in server's domain"); 1156 case YPERR_KEY: 1157 return ("No such key in map"); 1158 case YPERR_YPERR: 1159 return ("YP server error"); 1160 case YPERR_RESRC: 1161 return ("Local resource allocation failure"); 1162 case YPERR_NOMORE: 1163 return ("No more records in map database"); 1164 case YPERR_PMAP: 1165 return ("Can't communicate with portmapper"); 1166 case YPERR_YPBIND: 1167 return ("Can't communicate with ypbind"); 1168 case YPERR_YPSERV: 1169 return ("Can't communicate with ypserv"); 1170 case YPERR_NODOM: 1171 return ("Local domain name not set"); 1172 case YPERR_BADDB: 1173 return ("Server data base is bad"); 1174 case YPERR_VERS: 1175 return ("YP server version mismatch - server can't supply service."); 1176 case YPERR_ACCESS: 1177 return ("Access violation"); 1178 case YPERR_BUSY: 1179 return ("Database is busy"); 1180 } 1181 sprintf(err, "YP unknown error %d\n", incode); 1182 return (err); 1183} 1184 1185int 1186ypprot_err(unsigned int incode) 1187{ 1188 switch (incode) { 1189 case YP_TRUE: 1190 return (0); 1191 case YP_FALSE: 1192 return (YPERR_YPBIND); 1193 case YP_NOMORE: 1194 return (YPERR_NOMORE); 1195 case YP_NOMAP: 1196 return (YPERR_MAP); 1197 case YP_NODOM: 1198 return (YPERR_DOMAIN); 1199 case YP_NOKEY: 1200 return (YPERR_KEY); 1201 case YP_BADOP: 1202 return (YPERR_YPERR); 1203 case YP_BADDB: 1204 return (YPERR_BADDB); 1205 case YP_YPERR: 1206 return (YPERR_YPERR); 1207 case YP_BADARGS: 1208 return (YPERR_BADARGS); 1209 case YP_VERS: 1210 return (YPERR_VERS); 1211 } 1212 return (YPERR_YPERR); 1213} 1214 1215int 1216_yp_check(char **dom) 1217{ 1218 char *unused; 1219 1220 YPLOCK(); 1221 if (_yp_domain[0]=='\0') 1222 if (yp_get_default_domain_locked(&unused)) { 1223 YPUNLOCK(); 1224 return (0); 1225 } 1226 1227 if (dom) 1228 *dom = _yp_domain; 1229 1230 if (yp_bind_locked(_yp_domain) == 0) { 1231 yp_unbind_locked(_yp_domain); 1232 YPUNLOCK(); 1233 return (1); 1234 } 1235 YPUNLOCK(); 1236 return (0); 1237} 1238