1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1992/3 Theo de Raadt <deraadt@fsa.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote 16 * products derived from this software without specific prior written 17 * permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 20 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #include <sys/param.h> 34 #include <sys/types.h> 35 #include <sys/wait.h> 36 #include <sys/ioctl.h> 37 #include <sys/mman.h> 38 #include <sys/signal.h> 39 #include <sys/socket.h> 40 #include <sys/file.h> 41 #include <sys/fcntl.h> 42 #include <sys/stat.h> 43 #include <sys/uio.h> 44 #include <ctype.h> 45 #include <dirent.h> 46 #include <err.h> 47 #include <errno.h> 48 #include <netdb.h> 49 #include <signal.h> 50 #include <stdio.h> 51 #include <stdlib.h> 52 #include <string.h> 53 #include <syslog.h> 54 #include <unistd.h> 55 #include <rpc/rpc.h> 56 #include <rpc/xdr.h> 57 #include <net/if.h> 58 #include <netinet/in.h> 59 #include <arpa/inet.h> 60 #include <rpc/pmap_clnt.h> 61 #include <rpc/pmap_prot.h> 62 #include <rpc/pmap_rmt.h> 63 #include <rpc/rpc_com.h> 64 #include <rpcsvc/yp.h> 65 #include <rpcsvc/ypclnt.h> 66 #include "yp_ping.h" 67 68 #ifndef BINDINGDIR 69 #define BINDINGDIR "/var/yp/binding" 70 #endif 71 72 #ifndef YPBINDLOCK 73 #define YPBINDLOCK "/var/run/ypbind.lock" 74 #endif 75 76 struct _dom_binding { 77 struct _dom_binding *dom_pnext; 78 char dom_domain[YPMAXDOMAIN + 1]; 79 struct sockaddr_in dom_server_addr; 80 long int dom_vers; 81 int dom_lockfd; 82 int dom_alive; 83 int dom_broadcast_pid; 84 int dom_pipe_fds[2]; 85 int dom_default; 86 }; 87 88 #define READFD ypdb->dom_pipe_fds[0] 89 #define WRITEFD ypdb->dom_pipe_fds[1] 90 #define BROADFD broad_domain->dom_pipe_fds[1] 91 92 void checkwork(void); 93 void *ypbindproc_null_2_yp(SVCXPRT *, void *, CLIENT *); 94 void *ypbindproc_setdom_2_yp(SVCXPRT *, struct ypbind_setdom *, CLIENT *); 95 void rpc_received(char *, struct sockaddr_in *, int); 96 void broadcast(struct _dom_binding *); 97 int ping(struct _dom_binding *); 98 int tell_parent(char *, struct sockaddr_in *); 99 void handle_children(struct _dom_binding *); 100 void reaper(int); 101 void terminate(int); 102 void yp_restricted_mode(char *); 103 int verify(struct in_addr); 104 105 static char *domain_name; 106 static struct _dom_binding *ypbindlist; 107 static struct _dom_binding *broad_domain; 108 109 #define YPSET_NO 0 110 #define YPSET_LOCAL 1 111 #define YPSET_ALL 2 112 static int ypsetmode = YPSET_NO; 113 static int ypsecuremode = 0; 114 static int ppid; 115 116 #define NOT_RESPONDING_HYSTERESIS 10 117 static int not_responding_count = 0; 118 119 /* 120 * Special restricted mode variables: when in restricted mode, only the 121 * specified restricted_domain will be bound, and only the servers listed 122 * in restricted_addrs will be used for binding. 123 */ 124 #define RESTRICTED_SERVERS 10 125 static int yp_restricted = 0; 126 static int yp_manycast = 0; 127 static struct in_addr restricted_addrs[RESTRICTED_SERVERS]; 128 129 /* No more than MAX_CHILDREN child broadcasters at a time. */ 130 #ifndef MAX_CHILDREN 131 #define MAX_CHILDREN 5 132 #endif 133 /* No more than MAX_DOMAINS simultaneous domains */ 134 #ifndef MAX_DOMAINS 135 #define MAX_DOMAINS 200 136 #endif 137 /* RPC timeout value */ 138 #ifndef FAIL_THRESHOLD 139 #define FAIL_THRESHOLD 20 140 #endif 141 142 /* Number of times to fish for a response froma particular set of hosts */ 143 #ifndef MAX_RETRIES 144 #define MAX_RETRIES 30 145 #endif 146 147 static int retries = 0; 148 static int children = 0; 149 static int domains = 0; 150 static int yplockfd; 151 static fd_set fdsr; 152 153 static SVCXPRT *udptransp, *tcptransp; 154 155 void * 156 ypbindproc_null_2_yp(SVCXPRT *transp, void *argp, CLIENT *clnt) 157 { 158 static char res; 159 160 bzero(&res, sizeof(res)); 161 return &res; 162 } 163 164 static struct ypbind_resp * 165 ypbindproc_domain_2_yp(SVCXPRT *transp, domainname *argp, CLIENT *clnt) 166 { 167 static struct ypbind_resp res; 168 struct _dom_binding *ypdb; 169 char path[MAXPATHLEN]; 170 171 bzero(&res, sizeof res); 172 res.ypbind_status = YPBIND_FAIL_VAL; 173 res.ypbind_resp_u.ypbind_error = YPBIND_ERR_NOSERV; 174 175 if (strchr(*argp, '/')) { 176 syslog(LOG_WARNING, "Domain name '%s' has embedded slash -- \ 177 rejecting.", *argp); 178 return(&res); 179 } 180 181 for (ypdb = ypbindlist; ypdb; ypdb = ypdb->dom_pnext) { 182 if (strcmp(ypdb->dom_domain, *argp) == 0) 183 break; 184 } 185 186 if (ypdb == NULL) { 187 if (yp_restricted) { 188 syslog(LOG_NOTICE, "Running in restricted mode -- request to bind domain \"%s\" rejected.\n", *argp); 189 return (&res); 190 } 191 192 if (domains >= MAX_DOMAINS) { 193 syslog(LOG_WARNING, "domain limit (%d) exceeded", 194 MAX_DOMAINS); 195 res.ypbind_resp_u.ypbind_error = YPBIND_ERR_RESC; 196 return (&res); 197 } 198 if (strlen(*argp) > YPMAXDOMAIN) { 199 syslog(LOG_WARNING, "domain %s too long", *argp); 200 res.ypbind_resp_u.ypbind_error = YPBIND_ERR_RESC; 201 return (&res); 202 } 203 ypdb = malloc(sizeof *ypdb); 204 if (ypdb == NULL) { 205 syslog(LOG_WARNING, "malloc: %m"); 206 res.ypbind_resp_u.ypbind_error = YPBIND_ERR_RESC; 207 return (&res); 208 } 209 bzero(ypdb, sizeof *ypdb); 210 strlcpy(ypdb->dom_domain, *argp, sizeof ypdb->dom_domain); 211 ypdb->dom_vers = YPVERS; 212 ypdb->dom_alive = 0; 213 ypdb->dom_default = 0; 214 ypdb->dom_lockfd = -1; 215 sprintf(path, "%s/%s.%ld", BINDINGDIR, 216 ypdb->dom_domain, ypdb->dom_vers); 217 unlink(path); 218 ypdb->dom_pnext = ypbindlist; 219 ypbindlist = ypdb; 220 domains++; 221 } 222 223 if (ping(ypdb)) { 224 return (&res); 225 } 226 227 res.ypbind_status = YPBIND_SUCC_VAL; 228 res.ypbind_resp_u.ypbind_error = 0; /* Success */ 229 memcpy(&res.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr, 230 &ypdb->dom_server_addr.sin_addr.s_addr, sizeof(u_int32_t)); 231 memcpy(&res.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port, 232 &ypdb->dom_server_addr.sin_port, sizeof(u_short)); 233 /*printf("domain %s at %s/%d\n", ypdb->dom_domain, 234 inet_ntoa(ypdb->dom_server_addr.sin_addr), 235 ntohs(ypdb->dom_server_addr.sin_port));*/ 236 return (&res); 237 } 238 239 void * 240 ypbindproc_setdom_2_yp(SVCXPRT *transp, ypbind_setdom *argp, CLIENT *clnt) 241 { 242 struct sockaddr_in *fromsin, bindsin; 243 static char *result = NULL; 244 245 if (strchr(argp->ypsetdom_domain, '/')) { 246 syslog(LOG_WARNING, "Domain name '%s' has embedded slash -- \ 247 rejecting.", argp->ypsetdom_domain); 248 return(NULL); 249 } 250 fromsin = svc_getcaller(transp); 251 252 switch (ypsetmode) { 253 case YPSET_LOCAL: 254 if (fromsin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) { 255 svcerr_noprog(transp); 256 return(NULL); 257 } 258 break; 259 case YPSET_ALL: 260 break; 261 case YPSET_NO: 262 default: 263 svcerr_noprog(transp); 264 return(NULL); 265 } 266 267 if (ntohs(fromsin->sin_port) >= IPPORT_RESERVED) { 268 svcerr_noprog(transp); 269 return(NULL); 270 } 271 272 if (argp->ypsetdom_vers != YPVERS) { 273 svcerr_noprog(transp); 274 return(NULL); 275 } 276 277 bzero(&bindsin, sizeof bindsin); 278 bindsin.sin_family = AF_INET; 279 memcpy(&bindsin.sin_addr.s_addr, 280 &argp->ypsetdom_binding.ypbind_binding_addr, 281 sizeof(u_int32_t)); 282 memcpy(&bindsin.sin_port, 283 &argp->ypsetdom_binding.ypbind_binding_port, 284 sizeof(u_short)); 285 rpc_received(argp->ypsetdom_domain, &bindsin, 1); 286 287 return((void *) &result); 288 } 289 290 void 291 ypbindprog_2(struct svc_req *rqstp, register SVCXPRT *transp) 292 { 293 union { 294 domainname ypbindproc_domain_2_arg; 295 struct ypbind_setdom ypbindproc_setdom_2_arg; 296 } argument; 297 struct authunix_parms *creds; 298 void *result; 299 xdrproc_t xdr_argument, xdr_result; 300 typedef void *(svc_cb)(SVCXPRT *transp, void *arg, 301 struct svc_req *rqstp); 302 svc_cb *local; 303 304 switch (rqstp->rq_proc) { 305 case YPBINDPROC_NULL: 306 xdr_argument = (xdrproc_t)xdr_void; 307 xdr_result = (xdrproc_t)xdr_void; 308 local = (svc_cb *)ypbindproc_null_2_yp; 309 break; 310 311 case YPBINDPROC_DOMAIN: 312 xdr_argument = (xdrproc_t)xdr_domainname; 313 xdr_result = (xdrproc_t)xdr_ypbind_resp; 314 local = (svc_cb *)ypbindproc_domain_2_yp; 315 break; 316 317 case YPBINDPROC_SETDOM: 318 switch (rqstp->rq_cred.oa_flavor) { 319 case AUTH_UNIX: 320 creds = (struct authunix_parms *)rqstp->rq_clntcred; 321 if (creds->aup_uid != 0) { 322 svcerr_auth(transp, AUTH_BADCRED); 323 return; 324 } 325 break; 326 default: 327 svcerr_auth(transp, AUTH_TOOWEAK); 328 return; 329 } 330 331 xdr_argument = (xdrproc_t)xdr_ypbind_setdom; 332 xdr_result = (xdrproc_t)xdr_void; 333 local = (svc_cb *)ypbindproc_setdom_2_yp; 334 break; 335 336 default: 337 svcerr_noproc(transp); 338 return; 339 } 340 bzero(&argument, sizeof(argument)); 341 if (!svc_getargs(transp, xdr_argument, &argument)) { 342 svcerr_decode(transp); 343 return; 344 } 345 result = (*local)(transp, &argument, rqstp); 346 if (result != NULL && 347 !svc_sendreply(transp, xdr_result, result)) { 348 svcerr_systemerr(transp); 349 } 350 return; 351 } 352 353 /* Jack the reaper */ 354 void 355 reaper(int sig) 356 { 357 int st; 358 359 while (wait3(&st, WNOHANG, NULL) > 0) 360 children--; 361 } 362 363 void 364 terminate(int sig) 365 { 366 struct _dom_binding *ypdb; 367 char path[MAXPATHLEN]; 368 369 if (ppid != getpid()) 370 exit(0); 371 372 for (ypdb = ypbindlist; ypdb; ypdb = ypdb->dom_pnext) { 373 close(ypdb->dom_lockfd); 374 if (ypdb->dom_broadcast_pid) 375 kill(ypdb->dom_broadcast_pid, SIGINT); 376 sprintf(path, "%s/%s.%ld", BINDINGDIR, 377 ypdb->dom_domain, ypdb->dom_vers); 378 unlink(path); 379 } 380 close(yplockfd); 381 unlink(YPBINDLOCK); 382 pmap_unset(YPBINDPROG, YPBINDVERS); 383 exit(0); 384 } 385 386 int 387 main(int argc, char *argv[]) 388 { 389 struct timeval tv; 390 int i; 391 DIR *dird; 392 struct dirent *dirp; 393 struct _dom_binding *ypdb, *next; 394 395 /* Check that another ypbind isn't already running. */ 396 if ((yplockfd = (open(YPBINDLOCK, O_RDONLY|O_CREAT, 0444))) == -1) 397 err(1, "%s", YPBINDLOCK); 398 399 if (flock(yplockfd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK) 400 errx(1, "another ypbind is already running. Aborting"); 401 402 /* XXX domainname will be overridden if we use restricted mode */ 403 yp_get_default_domain(&domain_name); 404 if (domain_name[0] == '\0') 405 errx(1, "domainname not set. Aborting"); 406 407 for (i = 1; i<argc; i++) { 408 if (strcmp("-ypset", argv[i]) == 0) 409 ypsetmode = YPSET_ALL; 410 else if (strcmp("-ypsetme", argv[i]) == 0) 411 ypsetmode = YPSET_LOCAL; 412 else if (strcmp("-s", argv[i]) == 0) 413 ypsecuremode++; 414 else if (strcmp("-S", argv[i]) == 0 && argc > i) 415 yp_restricted_mode(argv[++i]); 416 else if (strcmp("-m", argv[i]) == 0) 417 yp_manycast++; 418 else 419 errx(1, "unknown option: %s", argv[i]); 420 } 421 422 if (strlen(domain_name) > YPMAXDOMAIN) 423 warnx("truncating domain name %s", domain_name); 424 425 /* blow away everything in BINDINGDIR (if it exists) */ 426 427 if ((dird = opendir(BINDINGDIR)) != NULL) { 428 char path[MAXPATHLEN]; 429 while ((dirp = readdir(dird)) != NULL) 430 if (strcmp(dirp->d_name, ".") && 431 strcmp(dirp->d_name, "..")) { 432 sprintf(path,"%s/%s",BINDINGDIR,dirp->d_name); 433 unlink(path); 434 } 435 closedir(dird); 436 } 437 438 #ifdef DAEMON 439 if (daemon(0,0)) 440 err(1, "fork"); 441 #endif 442 443 pmap_unset(YPBINDPROG, YPBINDVERS); 444 445 udptransp = svcudp_create(RPC_ANYSOCK); 446 if (udptransp == NULL) 447 errx(1, "cannot create udp service"); 448 if (!svc_register(udptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2, 449 IPPROTO_UDP)) 450 errx(1, "unable to register (YPBINDPROG, YPBINDVERS, udp)"); 451 452 tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0); 453 if (tcptransp == NULL) 454 errx(1, "cannot create tcp service"); 455 456 if (!svc_register(tcptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2, 457 IPPROTO_TCP)) 458 errx(1, "unable to register (YPBINDPROG, YPBINDVERS, tcp)"); 459 460 /* build initial domain binding, make it "unsuccessful" */ 461 ypbindlist = malloc(sizeof *ypbindlist); 462 if (ypbindlist == NULL) 463 errx(1, "malloc"); 464 bzero(ypbindlist, sizeof *ypbindlist); 465 strlcpy(ypbindlist->dom_domain, domain_name, sizeof ypbindlist->dom_domain); 466 ypbindlist->dom_vers = YPVERS; 467 ypbindlist->dom_alive = 0; 468 ypbindlist->dom_lockfd = -1; 469 ypbindlist->dom_default = 1; 470 domains++; 471 472 signal(SIGCHLD, reaper); 473 signal(SIGTERM, terminate); 474 475 ppid = getpid(); /* Remember who we are. */ 476 477 openlog(argv[0], LOG_PID, LOG_DAEMON); 478 479 if (madvise(NULL, 0, MADV_PROTECT) != 0) 480 syslog(LOG_WARNING, "madvise(): %m"); 481 482 /* Kick off the default domain */ 483 broadcast(ypbindlist); 484 485 while (1) { 486 fdsr = svc_fdset; 487 488 tv.tv_sec = 60; 489 tv.tv_usec = 0; 490 491 switch (select(_rpc_dtablesize(), &fdsr, NULL, NULL, &tv)) { 492 case 0: 493 checkwork(); 494 break; 495 case -1: 496 if (errno != EINTR) 497 syslog(LOG_WARNING, "select: %m"); 498 break; 499 default: 500 for (ypdb = ypbindlist; ypdb; ypdb = next) { 501 next = ypdb->dom_pnext; 502 if (READFD > 0 && FD_ISSET(READFD, &fdsr)) { 503 handle_children(ypdb); 504 if (children == (MAX_CHILDREN - 1)) 505 checkwork(); 506 } 507 } 508 svc_getreqset(&fdsr); 509 break; 510 } 511 } 512 513 /* NOTREACHED */ 514 exit(1); 515 } 516 517 void 518 checkwork(void) 519 { 520 struct _dom_binding *ypdb; 521 522 for (ypdb = ypbindlist; ypdb; ypdb = ypdb->dom_pnext) 523 ping(ypdb); 524 } 525 526 /* The clnt_broadcast() callback mechanism sucks. */ 527 528 /* 529 * Receive results from broadcaster. Don't worry about passing 530 * bogus info to rpc_received() -- it can handle it. Note that we 531 * must be sure to invalidate the dom_pipe_fds descriptors here: 532 * since descriptors can be re-used, we have to make sure we 533 * don't mistake one of the RPC descriptors for one of the pipes. 534 * What's weird is that forgetting to invalidate the pipe descriptors 535 * doesn't always result in an error (otherwise I would have caught 536 * the mistake much sooner), even though logically it should. 537 */ 538 void 539 handle_children(struct _dom_binding *ypdb) 540 { 541 char buf[YPMAXDOMAIN + 1]; 542 struct sockaddr_in addr; 543 int d = 0, a = 0; 544 struct _dom_binding *y, *prev = NULL; 545 char path[MAXPATHLEN]; 546 547 if ((d = read(READFD, &buf, sizeof(buf))) <= 0) 548 syslog(LOG_WARNING, "could not read from child: %m"); 549 550 if ((a = read(READFD, &addr, sizeof(struct sockaddr_in))) < 0) 551 syslog(LOG_WARNING, "could not read from child: %m"); 552 553 close(READFD); 554 FD_CLR(READFD, &fdsr); 555 FD_CLR(READFD, &svc_fdset); 556 READFD = WRITEFD = -1; 557 if (d > 0 && a > 0) 558 rpc_received(buf, &addr, 0); 559 else { 560 for (y = ypbindlist; y; y = y->dom_pnext) { 561 if (y == ypdb) 562 break; 563 prev = y; 564 } 565 switch (ypdb->dom_default) { 566 case 0: 567 if (prev == NULL) 568 ypbindlist = y->dom_pnext; 569 else 570 prev->dom_pnext = y->dom_pnext; 571 sprintf(path, "%s/%s.%ld", BINDINGDIR, 572 ypdb->dom_domain, YPVERS); 573 close(ypdb->dom_lockfd); 574 unlink(path); 575 free(ypdb); 576 domains--; 577 return; 578 case 1: 579 ypdb->dom_broadcast_pid = 0; 580 ypdb->dom_alive = 0; 581 broadcast(ypdb); 582 return; 583 default: 584 break; 585 } 586 } 587 588 return; 589 } 590 591 /* 592 * Send our dying words back to our parent before we perish. 593 */ 594 int 595 tell_parent(char *dom, struct sockaddr_in *addr) 596 { 597 char buf[YPMAXDOMAIN + 1]; 598 struct timeval timeout; 599 fd_set fds; 600 601 timeout.tv_sec = 5; 602 timeout.tv_usec = 0; 603 604 sprintf(buf, "%s", broad_domain->dom_domain); 605 if (write(BROADFD, &buf, sizeof(buf)) < 0) 606 return(1); 607 608 /* 609 * Stay in sync with parent: wait for it to read our first 610 * message before sending the second. 611 */ 612 613 FD_ZERO(&fds); 614 FD_SET(BROADFD, &fds); 615 if (select(FD_SETSIZE, NULL, &fds, NULL, &timeout) == -1) 616 return(1); 617 if (FD_ISSET(BROADFD, &fds)) { 618 if (write(BROADFD, addr, sizeof(struct sockaddr_in)) < 0) 619 return(1); 620 } else { 621 return(1); 622 } 623 624 close(BROADFD); 625 return (0); 626 } 627 628 static bool_t 629 broadcast_result(bool_t *out, struct sockaddr_in *addr) 630 { 631 if (retries >= MAX_RETRIES) { 632 bzero(addr, sizeof(struct sockaddr_in)); 633 if (tell_parent(broad_domain->dom_domain, addr)) 634 syslog(LOG_WARNING, "lost connection to parent"); 635 return (TRUE); 636 } 637 638 if (yp_restricted && verify(addr->sin_addr)) { 639 retries++; 640 syslog(LOG_NOTICE, "NIS server at %s not in restricted mode access list -- rejecting.\n",inet_ntoa(addr->sin_addr)); 641 return (FALSE); 642 } else { 643 if (tell_parent(broad_domain->dom_domain, addr)) 644 syslog(LOG_WARNING, "lost connection to parent"); 645 return (TRUE); 646 } 647 } 648 649 /* 650 * The right way to send RPC broadcasts. 651 * Use the clnt_broadcast() RPC service. Unfortunately, clnt_broadcast() 652 * blocks while waiting for replies, so we have to fork off separate 653 * broadcaster processes that do the waiting and then transmit their 654 * results back to the parent for processing. We also have to remember 655 * to save the name of the domain we're trying to bind in a global 656 * variable since clnt_broadcast() provides no way to pass things to 657 * the 'eachresult' callback function. 658 */ 659 void 660 broadcast(struct _dom_binding *ypdb) 661 { 662 bool_t out = FALSE; 663 enum clnt_stat stat; 664 665 if (children >= MAX_CHILDREN || ypdb->dom_broadcast_pid) 666 return; 667 668 if (pipe(ypdb->dom_pipe_fds) < 0) { 669 syslog(LOG_WARNING, "pipe: %m"); 670 return; 671 } 672 673 if (ypdb->dom_vers == -1 && (long)ypdb->dom_server_addr.sin_addr.s_addr) { 674 if (not_responding_count++ >= NOT_RESPONDING_HYSTERESIS) { 675 not_responding_count = NOT_RESPONDING_HYSTERESIS; 676 syslog(LOG_WARNING, "NIS server [%s] for domain \"%s\" not responding", 677 inet_ntoa(ypdb->dom_server_addr.sin_addr), ypdb->dom_domain); 678 } 679 } 680 681 broad_domain = ypdb; 682 flock(ypdb->dom_lockfd, LOCK_UN); 683 684 switch ((ypdb->dom_broadcast_pid = fork())) { 685 case 0: 686 close(READFD); 687 signal(SIGCHLD, SIG_DFL); 688 signal(SIGTERM, SIG_DFL); 689 break; 690 case -1: 691 syslog(LOG_WARNING, "fork: %m"); 692 close(READFD); 693 close(WRITEFD); 694 return; 695 default: 696 close(WRITEFD); 697 FD_SET(READFD, &svc_fdset); 698 children++; 699 return; 700 } 701 702 /* Release all locks before doing anything else. */ 703 while (ypbindlist) { 704 close(ypbindlist->dom_lockfd); 705 ypbindlist = ypbindlist->dom_pnext; 706 } 707 close(yplockfd); 708 709 /* 710 * Special 'many-cast' behavior. If we're in restricted mode, 711 * we have a list of possible server addresses to try. What 712 * we can do is transmit to each ypserv's YPPROC_DOMAIN_NONACK 713 * procedure and time the replies. Whoever replies fastest 714 * gets to be our server. Note that this is not a broadcast 715 * operation: we transmit uni-cast datagrams only. 716 */ 717 if (yp_restricted && yp_manycast) { 718 short port; 719 int i; 720 struct sockaddr_in sin; 721 722 i = __yp_ping(restricted_addrs, yp_restricted, 723 ypdb->dom_domain, &port); 724 if (i == -1) { 725 bzero(&ypdb->dom_server_addr, 726 sizeof(struct sockaddr_in)); 727 if (tell_parent(ypdb->dom_domain, 728 &ypdb->dom_server_addr)) 729 syslog(LOG_WARNING, "lost connection to parent"); 730 } else { 731 bzero(&sin, sizeof(struct sockaddr_in)); 732 bcopy(&restricted_addrs[i], 733 &sin.sin_addr, sizeof(struct in_addr)); 734 sin.sin_family = AF_INET; 735 sin.sin_port = port; 736 if (tell_parent(broad_domain->dom_domain, &sin)) 737 syslog(LOG_WARNING, 738 "lost connection to parent"); 739 } 740 _exit(0); 741 } 742 743 retries = 0; 744 745 { 746 char *ptr; 747 748 ptr = ypdb->dom_domain; 749 stat = clnt_broadcast(YPPROG, YPVERS, YPPROC_DOMAIN_NONACK, 750 (xdrproc_t)xdr_domainname, &ptr, 751 (xdrproc_t)xdr_bool, &out, 752 (resultproc_t)broadcast_result); 753 } 754 755 if (stat != RPC_SUCCESS) { 756 bzero(&ypdb->dom_server_addr, 757 sizeof(struct sockaddr_in)); 758 if (tell_parent(ypdb->dom_domain, &ypdb->dom_server_addr)) 759 syslog(LOG_WARNING, "lost connection to parent"); 760 } 761 762 _exit(0); 763 } 764 765 /* 766 * The right way to check if a server is alive. 767 * Attempt to get a client handle pointing to the server and send a 768 * YPPROC_DOMAIN. If we can't get a handle or we get a reply of FALSE, 769 * we invalidate this binding entry and send out a broadcast to try to 770 * establish a new binding. Note that we treat non-default domains 771 * specially: once bound, we keep tabs on our server, but if it 772 * goes away and fails to respond after one round of broadcasting, we 773 * abandon it until a client specifically references it again. We make 774 * every effort to keep our default domain bound, however, since we 775 * need it to keep the system on its feet. 776 */ 777 int 778 ping(struct _dom_binding *ypdb) 779 { 780 bool_t out; 781 struct timeval interval, timeout; 782 enum clnt_stat stat; 783 int rpcsock = RPC_ANYSOCK; 784 CLIENT *client_handle; 785 786 interval.tv_sec = FAIL_THRESHOLD; 787 interval.tv_usec = 0; 788 timeout.tv_sec = FAIL_THRESHOLD; 789 timeout.tv_usec = 0; 790 791 if (ypdb->dom_broadcast_pid) 792 return(1); 793 794 if ((client_handle = clntudp_bufcreate(&ypdb->dom_server_addr, 795 YPPROG, YPVERS, interval, &rpcsock, RPCSMALLMSGSIZE, 796 RPCSMALLMSGSIZE)) == (CLIENT *)NULL) { 797 /* Can't get a handle: we're dead. */ 798 ypdb->dom_alive = 0; 799 ypdb->dom_vers = -1; 800 broadcast(ypdb); 801 return(1); 802 } 803 804 { 805 char *ptr; 806 807 ptr = ypdb->dom_domain; 808 809 stat = clnt_call(client_handle, YPPROC_DOMAIN, 810 (xdrproc_t)xdr_domainname, &ptr, 811 (xdrproc_t)xdr_bool, &out, timeout); 812 if (stat != RPC_SUCCESS || out == FALSE) { 813 ypdb->dom_alive = 0; 814 ypdb->dom_vers = -1; 815 clnt_destroy(client_handle); 816 broadcast(ypdb); 817 return(1); 818 } 819 } 820 821 clnt_destroy(client_handle); 822 return(0); 823 } 824 825 void 826 rpc_received(char *dom, struct sockaddr_in *raddrp, int force) 827 { 828 struct _dom_binding *ypdb, *prev = NULL; 829 struct iovec iov[2]; 830 struct ypbind_resp ybr; 831 char path[MAXPATHLEN]; 832 int fd; 833 834 /*printf("returned from %s/%d about %s\n", inet_ntoa(raddrp->sin_addr), 835 ntohs(raddrp->sin_port), dom);*/ 836 837 if (dom == NULL) 838 return; 839 840 for (ypdb = ypbindlist; ypdb; ypdb = ypdb->dom_pnext) { 841 if (strcmp(ypdb->dom_domain, dom) == 0) 842 break; 843 prev = ypdb; 844 } 845 846 if (ypdb && force) { 847 if (ypdb->dom_broadcast_pid) { 848 kill(ypdb->dom_broadcast_pid, SIGINT); 849 close(READFD); 850 FD_CLR(READFD, &fdsr); 851 FD_CLR(READFD, &svc_fdset); 852 READFD = WRITEFD = -1; 853 } 854 } 855 856 /* if in secure mode, check originating port number */ 857 if ((ypsecuremode && (ntohs(raddrp->sin_port) >= IPPORT_RESERVED))) { 858 syslog(LOG_WARNING, "Rejected NIS server on [%s/%d] for domain %s.", 859 inet_ntoa(raddrp->sin_addr), ntohs(raddrp->sin_port), 860 dom); 861 if (ypdb != NULL) { 862 ypdb->dom_broadcast_pid = 0; 863 ypdb->dom_alive = 0; 864 } 865 return; 866 } 867 868 if (raddrp->sin_addr.s_addr == (long)0) { 869 switch (ypdb->dom_default) { 870 case 0: 871 if (prev == NULL) 872 ypbindlist = ypdb->dom_pnext; 873 else 874 prev->dom_pnext = ypdb->dom_pnext; 875 sprintf(path, "%s/%s.%ld", BINDINGDIR, 876 ypdb->dom_domain, YPVERS); 877 close(ypdb->dom_lockfd); 878 unlink(path); 879 free(ypdb); 880 domains--; 881 return; 882 case 1: 883 ypdb->dom_broadcast_pid = 0; 884 ypdb->dom_alive = 0; 885 broadcast(ypdb); 886 return; 887 default: 888 break; 889 } 890 } 891 892 if (ypdb == NULL) { 893 if (force == 0) 894 return; 895 if (strlen(dom) > YPMAXDOMAIN) { 896 syslog(LOG_WARNING, "domain %s too long", dom); 897 return; 898 } 899 ypdb = malloc(sizeof *ypdb); 900 if (ypdb == NULL) { 901 syslog(LOG_WARNING, "malloc: %m"); 902 return; 903 } 904 bzero(ypdb, sizeof *ypdb); 905 strlcpy(ypdb->dom_domain, dom, sizeof ypdb->dom_domain); 906 ypdb->dom_lockfd = -1; 907 ypdb->dom_default = 0; 908 ypdb->dom_pnext = ypbindlist; 909 ypbindlist = ypdb; 910 } 911 912 /* We've recovered from a crash: inform the world. */ 913 if (ypdb->dom_vers == -1 && ypdb->dom_server_addr.sin_addr.s_addr) { 914 if (not_responding_count >= NOT_RESPONDING_HYSTERESIS) { 915 not_responding_count = 0; 916 syslog(LOG_WARNING, "NIS server [%s] for domain \"%s\" OK", 917 inet_ntoa(raddrp->sin_addr), ypdb->dom_domain); 918 } 919 } 920 921 bcopy(raddrp, &ypdb->dom_server_addr, 922 sizeof ypdb->dom_server_addr); 923 924 ypdb->dom_vers = YPVERS; 925 ypdb->dom_alive = 1; 926 ypdb->dom_broadcast_pid = 0; 927 928 if (ypdb->dom_lockfd != -1) 929 close(ypdb->dom_lockfd); 930 931 sprintf(path, "%s/%s.%ld", BINDINGDIR, 932 ypdb->dom_domain, ypdb->dom_vers); 933 #ifdef O_SHLOCK 934 if ((fd = open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1) { 935 (void)mkdir(BINDINGDIR, 0755); 936 if ((fd = open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1) 937 return; 938 } 939 #else 940 if ((fd = open(path, O_CREAT|O_RDWR|O_TRUNC, 0644)) == -1) { 941 (void)mkdir(BINDINGDIR, 0755); 942 if ((fd = open(path, O_CREAT|O_RDWR|O_TRUNC, 0644)) == -1) 943 return; 944 } 945 flock(fd, LOCK_SH); 946 #endif 947 948 /* 949 * ok, if BINDINGDIR exists, and we can create the binding file, 950 * then write to it.. 951 */ 952 ypdb->dom_lockfd = fd; 953 954 iov[0].iov_base = (char *)&(udptransp->xp_port); 955 iov[0].iov_len = sizeof udptransp->xp_port; 956 iov[1].iov_base = (char *)&ybr; 957 iov[1].iov_len = sizeof ybr; 958 959 bzero(&ybr, sizeof ybr); 960 ybr.ypbind_status = YPBIND_SUCC_VAL; 961 memcpy(&ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr, 962 &raddrp->sin_addr.s_addr, sizeof(u_int32_t)); 963 memcpy(&ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port, 964 &raddrp->sin_port, sizeof(u_short)); 965 966 if (writev(ypdb->dom_lockfd, iov, 2) != iov[0].iov_len + iov[1].iov_len) { 967 syslog(LOG_WARNING, "write: %m"); 968 close(ypdb->dom_lockfd); 969 ypdb->dom_lockfd = -1; 970 return; 971 } 972 } 973 974 /* 975 * Check address against list of allowed servers. Return 0 if okay, 976 * 1 if not matched. 977 */ 978 int 979 verify(struct in_addr addr) 980 { 981 int i; 982 983 for (i = 0; i < RESTRICTED_SERVERS; i++) 984 if (!bcmp(&addr, &restricted_addrs[i], sizeof(struct in_addr))) 985 return(0); 986 987 return(1); 988 } 989 990 /* 991 * Try to set restricted mode. We default to normal mode if we can't 992 * resolve the specified hostnames. 993 */ 994 void 995 yp_restricted_mode(char *args) 996 { 997 struct hostent *h; 998 int i = 0; 999 char *s; 1000 1001 /* Find the restricted domain. */ 1002 if ((s = strsep(&args, ",")) == NULL) 1003 return; 1004 domain_name = s; 1005 1006 /* Get the addresses of the servers. */ 1007 while ((s = strsep(&args, ",")) != NULL && i < RESTRICTED_SERVERS) { 1008 if ((h = gethostbyname(s)) == NULL) 1009 return; 1010 bcopy (h->h_addr_list[0], &restricted_addrs[i], 1011 sizeof(struct in_addr)); 1012 i++; 1013 } 1014 1015 /* ypset and ypsetme not allowed with restricted mode */ 1016 ypsetmode = YPSET_NO; 1017 1018 yp_restricted = i; 1019 return; 1020 } 1021