1 /* $NetBSD: ypbind.c,v 1.98 2014/06/10 17:19:48 dholland Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 1993 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 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 17 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 #ifndef LINT 31 __RCSID("$NetBSD: ypbind.c,v 1.98 2014/06/10 17:19:48 dholland Exp $"); 32 #endif 33 34 #include <sys/types.h> 35 #include <sys/param.h> 36 #include <sys/file.h> 37 #include <sys/ioctl.h> 38 #include <sys/signal.h> 39 #include <sys/socket.h> 40 #include <sys/stat.h> 41 #include <sys/syslog.h> 42 #include <sys/uio.h> 43 #include <arpa/inet.h> 44 #include <net/if.h> 45 #include <ctype.h> 46 #include <dirent.h> 47 #include <err.h> 48 #include <errno.h> 49 #include <fcntl.h> 50 #include <ifaddrs.h> 51 #include <limits.h> 52 #include <netdb.h> 53 #include <signal.h> 54 #include <stdarg.h> 55 #include <stdio.h> 56 #include <stdlib.h> 57 #include <string.h> 58 #include <syslog.h> 59 #include <unistd.h> 60 #include <util.h> 61 62 #include <rpc/rpc.h> 63 #include <rpc/xdr.h> 64 #include <rpc/pmap_clnt.h> 65 #include <rpc/pmap_prot.h> 66 #include <rpc/pmap_rmt.h> 67 #include <rpcsvc/yp_prot.h> 68 #include <rpcsvc/ypclnt.h> 69 70 #include "pathnames.h" 71 72 #define YPSERVERSSUFF ".ypservers" 73 #define BINDINGDIR (_PATH_VAR_YP "binding") 74 75 #ifndef O_SHLOCK 76 #define O_SHLOCK 0 77 #endif 78 79 int _yp_invalid_domain(const char *); /* XXX libc internal */ 80 81 //////////////////////////////////////////////////////////// 82 // types and globals 83 84 typedef enum { 85 YPBIND_DIRECT, YPBIND_BROADCAST, 86 } ypbind_mode_t; 87 88 enum domainstates { 89 DOM_NEW, /* not yet bound */ 90 DOM_ALIVE, /* bound and healthy */ 91 DOM_PINGING, /* ping outstanding */ 92 DOM_LOST, /* binding timed out, looking for a new one */ 93 DOM_DEAD, /* long-term lost, in exponential backoff */ 94 }; 95 96 struct domain { 97 struct domain *dom_next; 98 99 char dom_name[YPMAXDOMAIN + 1]; 100 struct sockaddr_in dom_server_addr; 101 long dom_vers; 102 time_t dom_checktime; /* time of next check/contact */ 103 time_t dom_asktime; /* time we were last DOMAIN'd */ 104 time_t dom_losttime; /* time the binding was lost, or 0 */ 105 unsigned dom_backofftime; /* current backoff period, when DEAD */ 106 int dom_lockfd; 107 enum domainstates dom_state; 108 uint32_t dom_xid; 109 FILE *dom_serversfile; /* /var/yp/binding/foo.ypservers */ 110 int dom_been_ypset; /* ypset been done on this domain? */ 111 ypbind_mode_t dom_ypbindmode; /* broadcast or direct */ 112 }; 113 114 #define BUFSIZE 1400 115 116 /* the list of all domains */ 117 static struct domain *domains; 118 static int check; 119 120 /* option settings */ 121 static ypbind_mode_t default_ypbindmode; 122 static int allow_local_ypset = 0, allow_any_ypset = 0; 123 static int insecure; 124 125 /* the sockets we use to interact with servers */ 126 static int rpcsock, pingsock; 127 128 /* stuff used for manually interacting with servers */ 129 static struct rmtcallargs rmtca; 130 static struct rmtcallres rmtcr; 131 static bool_t rmtcr_outval; 132 static unsigned long rmtcr_port; 133 134 /* The ypbind service transports */ 135 static SVCXPRT *udptransp, *tcptransp; 136 137 /* set if we get SIGHUP */ 138 static sig_atomic_t hupped; 139 140 //////////////////////////////////////////////////////////// 141 // utilities 142 143 /* 144 * Combo of open() and flock(). 145 */ 146 static int 147 open_locked(const char *path, int flags, mode_t mode) 148 { 149 int fd; 150 151 fd = open(path, flags|O_SHLOCK, mode); 152 if (fd < 0) { 153 return -1; 154 } 155 #if O_SHLOCK == 0 156 /* dholland 20110522 wouldn't it be better to check this for error? */ 157 (void)flock(fd, LOCK_SH); 158 #endif 159 return fd; 160 } 161 162 /* 163 * Exponential backoff for pinging servers for a dead domain. 164 * 165 * We go 10 -> 20 -> 40 -> 60 seconds, then 2 -> 4 -> 8 -> 15 -> 30 -> 166 * 60 minutes, and stay at 60 minutes. This is overengineered. 167 * 168 * With a 60 minute max backoff the response time for when things come 169 * back is not awful, but we only try (and log) about 60 times even if 170 * things are down for a whole long weekend. This is an acceptable log 171 * load, I think. 172 */ 173 static void 174 backoff(unsigned *psecs) 175 { 176 unsigned secs; 177 178 secs = *psecs; 179 if (secs < 60) { 180 secs *= 2; 181 if (secs > 60) { 182 secs = 60; 183 } 184 } else if (secs < 60 * 15) { 185 secs *= 2; 186 if (secs > 60 * 15) { 187 secs = 60 * 15; 188 } 189 } else if (secs < 60 * 60) { 190 secs *= 2; 191 } 192 *psecs = secs; 193 } 194 195 //////////////////////////////////////////////////////////// 196 // logging 197 198 #ifdef DEBUG 199 #define DPRINTF(...) (debug ? (void)printf(__VA_ARGS__) : (void)0) 200 static int debug; 201 #else 202 #define DPRINTF(...) 203 #endif 204 205 static void yp_log(int, const char *, ...) __printflike(2, 3); 206 207 /* 208 * Log some stuff, to syslog or stderr depending on the debug setting. 209 */ 210 static void 211 yp_log(int pri, const char *fmt, ...) 212 { 213 va_list ap; 214 215 va_start(ap, fmt); 216 217 #if defined(DEBUG) 218 if (debug) { 219 (void)vprintf(fmt, ap); 220 (void)printf("\n"); 221 } else 222 #endif 223 vsyslog(pri, fmt, ap); 224 va_end(ap); 225 } 226 227 //////////////////////////////////////////////////////////// 228 // ypservers file 229 230 /* 231 * Get pathname for the ypservers file for a given domain 232 * (/var/yp/binding/DOMAIN.ypservers) 233 */ 234 static const char * 235 ypservers_filename(const char *domain) 236 { 237 static char ret[PATH_MAX]; 238 239 (void)snprintf(ret, sizeof(ret), "%s/%s%s", 240 BINDINGDIR, domain, YPSERVERSSUFF); 241 return ret; 242 } 243 244 //////////////////////////////////////////////////////////// 245 // struct domain 246 247 /* 248 * The state transitions of a domain work as follows: 249 * 250 * in state NEW: 251 * nag_servers every 5 seconds 252 * upon answer, state is ALIVE 253 * 254 * in state ALIVE: 255 * every 60 seconds, send ping and switch to state PINGING 256 * 257 * in state PINGING: 258 * upon answer, go to state ALIVE 259 * if no answer in 5 seconds, go to state LOST and do nag_servers 260 * 261 * in state LOST: 262 * do nag_servers every 5 seconds 263 * upon answer, go to state ALIVE 264 * if no answer in 60 seconds, go to state DEAD 265 * 266 * in state DEAD 267 * do nag_servers every backofftime seconds (starts at 10) 268 * upon answer go to state ALIVE 269 * backofftime doubles (approximately) each try, with a cap of 1 hour 270 */ 271 272 /* 273 * Look up a domain by the XID we assigned it. 274 */ 275 static struct domain * 276 domain_find(uint32_t xid) 277 { 278 struct domain *dom; 279 280 for (dom = domains; dom != NULL; dom = dom->dom_next) 281 if (dom->dom_xid == xid) 282 break; 283 return dom; 284 } 285 286 /* 287 * Pick an XID for a domain. 288 * 289 * XXX: this should just generate a random number. 290 */ 291 static uint32_t 292 unique_xid(struct domain *dom) 293 { 294 uint32_t tmp_xid; 295 296 tmp_xid = ((uint32_t)(unsigned long)dom) & 0xffffffff; 297 while (domain_find(tmp_xid) != NULL) 298 tmp_xid++; 299 300 return tmp_xid; 301 } 302 303 /* 304 * Construct a new domain. Adds it to the global linked list of all 305 * domains. 306 */ 307 static struct domain * 308 domain_create(const char *name) 309 { 310 struct domain *dom; 311 const char *pathname; 312 struct stat st; 313 314 dom = malloc(sizeof *dom); 315 if (dom == NULL) { 316 yp_log(LOG_ERR, "domain_create: Out of memory"); 317 exit(1); 318 } 319 320 dom->dom_next = NULL; 321 322 (void)strlcpy(dom->dom_name, name, sizeof(dom->dom_name)); 323 (void)memset(&dom->dom_server_addr, 0, sizeof(dom->dom_server_addr)); 324 dom->dom_vers = YPVERS; 325 dom->dom_checktime = 0; 326 dom->dom_asktime = 0; 327 dom->dom_losttime = 0; 328 dom->dom_backofftime = 10; 329 dom->dom_lockfd = -1; 330 dom->dom_state = DOM_NEW; 331 dom->dom_xid = unique_xid(dom); 332 dom->dom_been_ypset = 0; 333 dom->dom_serversfile = NULL; 334 335 /* 336 * Per traditional ypbind(8) semantics, if a ypservers 337 * file does not exist, we revert to broadcast mode. 338 * 339 * The sysadmin can force broadcast mode by passing the 340 * -broadcast flag. There is currently no way to fail and 341 * reject domains for which there is no ypservers file. 342 */ 343 dom->dom_ypbindmode = default_ypbindmode; 344 if (dom->dom_ypbindmode == YPBIND_DIRECT) { 345 pathname = ypservers_filename(dom->dom_name); 346 if (stat(pathname, &st) < 0) { 347 /* XXX syslog a warning here? */ 348 DPRINTF("%s does not exist, defaulting to broadcast\n", 349 pathname); 350 dom->dom_ypbindmode = YPBIND_BROADCAST; 351 } 352 } 353 354 /* add to global list */ 355 dom->dom_next = domains; 356 domains = dom; 357 358 return dom; 359 } 360 361 //////////////////////////////////////////////////////////// 362 // locks 363 364 /* 365 * Open a new binding file. Does not write the contents out; the 366 * caller (there's only one) does that. 367 */ 368 static int 369 makelock(struct domain *dom) 370 { 371 int fd; 372 char path[MAXPATHLEN]; 373 374 (void)snprintf(path, sizeof(path), "%s/%s.%ld", BINDINGDIR, 375 dom->dom_name, dom->dom_vers); 376 377 fd = open_locked(path, O_CREAT|O_RDWR|O_TRUNC, 0644); 378 if (fd == -1) { 379 (void)mkdir(BINDINGDIR, 0755); 380 fd = open_locked(path, O_CREAT|O_RDWR|O_TRUNC, 0644); 381 if (fd == -1) { 382 return -1; 383 } 384 } 385 386 return fd; 387 } 388 389 /* 390 * Remove a binding file. 391 */ 392 static void 393 removelock(struct domain *dom) 394 { 395 char path[MAXPATHLEN]; 396 397 (void)snprintf(path, sizeof(path), "%s/%s.%ld", 398 BINDINGDIR, dom->dom_name, dom->dom_vers); 399 (void)unlink(path); 400 } 401 402 /* 403 * purge_bindingdir: remove old binding files (i.e. "rm *.[0-9]" in BINDINGDIR) 404 * 405 * The local YP functions [e.g. yp_master()] will fail without even 406 * talking to ypbind if there is a stale (non-flock'd) binding file 407 * present. 408 * 409 * We have to remove all binding files in BINDINGDIR, not just the one 410 * for the default domain. 411 */ 412 static int 413 purge_bindingdir(const char *dirpath) 414 { 415 DIR *dirp; 416 int unlinkedfiles, l; 417 struct dirent *dp; 418 char pathname[MAXPATHLEN]; 419 420 if ((dirp = opendir(dirpath)) == NULL) 421 return(-1); /* at this point, shouldn't ever happen */ 422 423 do { 424 unlinkedfiles = 0; 425 while ((dp = readdir(dirp)) != NULL) { 426 l = dp->d_namlen; 427 /* 'rm *.[0-9]' */ 428 if (l > 2 && dp->d_name[l-2] == '.' && 429 dp->d_name[l-1] >= '0' && dp->d_name[l-1] <= '9') { 430 (void)snprintf(pathname, sizeof(pathname), 431 "%s/%s", dirpath, dp->d_name); 432 if (unlink(pathname) < 0 && errno != ENOENT) 433 return(-1); 434 unlinkedfiles++; 435 } 436 } 437 438 /* rescan dir if we removed it */ 439 if (unlinkedfiles) 440 rewinddir(dirp); 441 442 } while (unlinkedfiles); 443 444 closedir(dirp); 445 return(0); 446 } 447 448 //////////////////////////////////////////////////////////// 449 // sunrpc twaddle 450 451 /* 452 * Check if the info coming in is (at least somewhat) valid. 453 */ 454 static int 455 rpc_is_valid_response(char *name, struct sockaddr_in *addr) 456 { 457 if (name == NULL) { 458 return 0; 459 } 460 461 if (_yp_invalid_domain(name)) { 462 return 0; 463 } 464 465 /* don't support insecure servers by default */ 466 if (!insecure && ntohs(addr->sin_port) >= IPPORT_RESERVED) { 467 return 0; 468 } 469 470 return 1; 471 } 472 473 /* 474 * Take note of the fact that we've received a reply from a ypserver. 475 * Or, in the case of being ypset, that we've been ypset, which 476 * functions much the same. 477 * 478 * Note that FORCE is set if and only if IS_YPSET is set. 479 * 480 * This function has also for the past 20+ years carried the annotation 481 * 482 * LOOPBACK IS MORE IMPORTANT: PUT IN HACK 483 * 484 * whose meaning isn't entirely clear. 485 */ 486 static void 487 rpc_received(char *dom_name, struct sockaddr_in *raddrp, int force, 488 int is_ypset) 489 { 490 struct domain *dom; 491 struct iovec iov[2]; 492 struct ypbind_resp ybr; 493 ssize_t result; 494 int fd; 495 496 DPRINTF("returned from %s about %s\n", 497 inet_ntoa(raddrp->sin_addr), dom_name); 498 499 /* validate some stuff */ 500 if (!rpc_is_valid_response(dom_name, raddrp)) { 501 return; 502 } 503 504 /* look for the domain */ 505 for (dom = domains; dom != NULL; dom = dom->dom_next) 506 if (!strcmp(dom->dom_name, dom_name)) 507 break; 508 509 /* if not found, create it, but only if FORCE; otherwise ignore */ 510 if (dom == NULL) { 511 if (force == 0) 512 return; 513 dom = domain_create(dom_name); 514 } 515 516 /* the domain needs to know if it's been explicitly ypset */ 517 if (is_ypset) { 518 dom->dom_been_ypset = 1; 519 } 520 521 /* 522 * If the domain is alive and we aren't being called by ypset, 523 * we shouldn't be getting a response at all. Log it, as it 524 * might be hostile. 525 */ 526 if (dom->dom_state == DOM_ALIVE && force == 0) { 527 if (!memcmp(&dom->dom_server_addr, raddrp, 528 sizeof(dom->dom_server_addr))) { 529 yp_log(LOG_WARNING, 530 "Unexpected reply from server %s for domain %s", 531 inet_ntoa(dom->dom_server_addr.sin_addr), 532 dom->dom_name); 533 } else { 534 yp_log(LOG_WARNING, 535 "Falsified reply from %s for domain %s", 536 inet_ntoa(dom->dom_server_addr.sin_addr), 537 dom->dom_name); 538 } 539 return; 540 } 541 542 /* 543 * If we're expected a ping response, and we've got it 544 * (meaning we aren't being called by ypset), we don't need to 545 * do anything. 546 */ 547 if (dom->dom_state == DOM_PINGING && force == 0) { 548 /* 549 * If the reply came from the server we expect, set 550 * dom_state back to ALIVE and ping again in 60 551 * seconds. 552 * 553 * If it came from somewhere else, log it. 554 */ 555 if (!memcmp(&dom->dom_server_addr, raddrp, 556 sizeof(dom->dom_server_addr))) { 557 dom->dom_state = DOM_ALIVE; 558 /* recheck binding in 60 sec */ 559 dom->dom_checktime = time(NULL) + 60; 560 } else { 561 yp_log(LOG_WARNING, 562 "Falsified reply from %s for domain %s", 563 inet_ntoa(dom->dom_server_addr.sin_addr), 564 dom->dom_name); 565 } 566 return; 567 } 568 569 #ifdef HEURISTIC 570 /* 571 * If transitioning to the alive state from a non-alive state, 572 * clear dom_asktime. This will help prevent any requests that 573 * are still coming in from triggering unnecessary pings via 574 * the HEURISTIC code. 575 * 576 * XXX: this may not be an adequate measure; we may need to 577 * keep more state so we can disable the HEURISTIC code for 578 * the first few seconds after rebinding. 579 */ 580 if (dom->dom_state == DOM_NEW || 581 dom->dom_state == DOM_LOST || 582 dom->dom_state == DOM_DEAD) { 583 dom->dom_asktime = 0; 584 } 585 #endif 586 587 /* 588 * Take the address we got the message from (or in the case of 589 * ypset, the explicit address we were given) as the server 590 * address for this domain, mark the domain alive, and we'll 591 * check it again in 60 seconds. 592 * 593 * XXX: it looks like if we get a random unsolicited reply 594 * from somewhere, we'll silently switch to that server 595 * address, regardless of merit. 596 * 597 * 1. If we have a foo.ypservers file the address should be 598 * checked against it and rejected if it's not one of the 599 * addresses of one of the listed hostnames. Note that it 600 * might not be the same address we sent to; even fairly smart 601 * UDP daemons don't always handle multihomed hosts correctly 602 * and we can't expect sunrpc code to do anything intelligent 603 * at all. 604 * 605 * 2. If we're in broadcast mode the address should be 606 * checked against the local addresses and netmasks so we 607 * don't accept responses from Mars. 608 * 609 * 2a. If we're in broadcast mode and we've been ypset, we 610 * should not accept anything else until we drop the ypset 611 * state for not responding. 612 * 613 * 3. Either way we should not accept a response from an 614 * arbitrary host unless we don't currently have a binding. 615 * (This is now fixed above.) 616 * 617 * Note that for a random unsolicited reply to work it has to 618 * carry the XID of one of the domains we know about; but 619 * those values are predictable. 620 */ 621 (void)memcpy(&dom->dom_server_addr, raddrp, 622 sizeof(dom->dom_server_addr)); 623 /* recheck binding in 60 seconds */ 624 dom->dom_checktime = time(NULL) + 60; 625 dom->dom_state = DOM_ALIVE; 626 627 /* Clear the dead/backoff state. */ 628 dom->dom_losttime = 0; 629 dom->dom_backofftime = 10; 630 631 if (is_ypset == 0) { 632 yp_log(LOG_NOTICE, "Domain %s is alive; server %s", 633 dom->dom_name, 634 inet_ntoa(dom->dom_server_addr.sin_addr)); 635 } 636 637 /* 638 * Generate a new binding file. If this fails, forget about it. 639 * (But we keep the binding and we'll report it to anyone who 640 * asks via the ypbind service.) XXX: this will interact badly, 641 * maybe very badly, with the code in HEURISTIC. 642 * 643 * Note that makelock() doesn't log on failure. 644 */ 645 646 if (dom->dom_lockfd != -1) 647 (void)close(dom->dom_lockfd); 648 649 if ((fd = makelock(dom)) == -1) 650 return; 651 652 dom->dom_lockfd = fd; 653 654 iov[0].iov_base = &(udptransp->xp_port); 655 iov[0].iov_len = sizeof udptransp->xp_port; 656 iov[1].iov_base = &ybr; 657 iov[1].iov_len = sizeof ybr; 658 659 (void)memset(&ybr, 0, sizeof ybr); 660 ybr.ypbind_status = YPBIND_SUCC_VAL; 661 ybr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr = 662 raddrp->sin_addr; 663 ybr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port = 664 raddrp->sin_port; 665 666 result = writev(dom->dom_lockfd, iov, 2); 667 if (result < 0 || (size_t)result != iov[0].iov_len + iov[1].iov_len) { 668 if (result < 0) 669 yp_log(LOG_WARNING, "writev: %s", strerror(errno)); 670 else 671 yp_log(LOG_WARNING, "writev: short count"); 672 (void)close(dom->dom_lockfd); 673 removelock(dom); 674 dom->dom_lockfd = -1; 675 } 676 } 677 678 /* 679 * The NULL call: do nothing. This is obliged to exist because of 680 * sunrpc silliness. 681 */ 682 static void * 683 /*ARGSUSED*/ 684 ypbindproc_null_2(SVCXPRT *transp, void *argp) 685 { 686 static char res; 687 688 DPRINTF("ypbindproc_null_2\n"); 689 (void)memset(&res, 0, sizeof(res)); 690 return (void *)&res; 691 } 692 693 /* 694 * The DOMAIN call: look up the ypserver for a specified domain. 695 */ 696 static void * 697 /*ARGSUSED*/ 698 ypbindproc_domain_2(SVCXPRT *transp, void *argp) 699 { 700 static struct ypbind_resp res; 701 struct domain *dom; 702 char *arg = *(char **) argp; 703 time_t now; 704 int count; 705 706 DPRINTF("ypbindproc_domain_2 %s\n", arg); 707 708 /* Reject invalid domains. */ 709 if (_yp_invalid_domain(arg)) 710 return NULL; 711 712 (void)memset(&res, 0, sizeof res); 713 res.ypbind_status = YPBIND_FAIL_VAL; 714 715 /* 716 * Look for the domain. XXX: Behave erratically if we have 717 * more than 100 domains. The intent here is to avoid allowing 718 * arbitrary incoming requests to create more than 100 719 * domains; but this logic means that if we legitimately have 720 * more than 100 (e.g. via ypset) we'll only actually bind the 721 * first 100 and the rest will fail. The test on 'count' should 722 * be moved further down. 723 */ 724 for (count = 0, dom = domains; 725 dom != NULL; 726 dom = dom->dom_next, count++) { 727 if (count > 100) 728 return NULL; /* prevent denial of service */ 729 if (!strcmp(dom->dom_name, arg)) 730 break; 731 } 732 733 /* 734 * If the domain doesn't exist, create it, then fail the call 735 * because we have no information yet. 736 * 737 * Set "check" so that checkwork() will run and look for a 738 * server. 739 * 740 * XXX: like during startup there's a spurious call to 741 * removelock() after domain_create(). 742 */ 743 if (dom == NULL) { 744 dom = domain_create(arg); 745 removelock(dom); 746 check++; 747 DPRINTF("unknown domain %s\n", arg); 748 return NULL; 749 } 750 751 if (dom->dom_state == DOM_NEW) { 752 DPRINTF("new domain %s\n", arg); 753 return NULL; 754 } 755 756 #ifdef HEURISTIC 757 /* 758 * Keep track of the last time we were explicitly asked about 759 * this domain. If it happens a lot, force a ping. This works 760 * (or "works") because we only get asked specifically when 761 * things aren't going; otherwise the client code in libc and 762 * elsewhere uses the binding file. 763 * 764 * Note: HEURISTIC is enabled by default. 765 * 766 * dholland 20140609: I think this is part of the mechanism 767 * that causes ypbind to spam. I'm changing this logic so it 768 * only triggers when the state is DOM_ALIVE: if the domain 769 * is new, lost, or dead we shouldn't send more requests than 770 * the ones already scheduled, and if we're already in the 771 * middle of pinging there's no point doing it again. 772 */ 773 (void)time(&now); 774 if (dom->dom_state == DOM_ALIVE && now < dom->dom_asktime + 5) { 775 /* 776 * Hmm. More than 2 requests in 5 seconds have indicated 777 * that my binding is possibly incorrect. 778 * Ok, do an immediate poll of the server. 779 */ 780 if (dom->dom_checktime >= now) { 781 /* don't flood it */ 782 dom->dom_checktime = 0; 783 check++; 784 } 785 } 786 dom->dom_asktime = now; 787 #endif 788 789 res.ypbind_status = YPBIND_SUCC_VAL; 790 res.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr.s_addr = 791 dom->dom_server_addr.sin_addr.s_addr; 792 res.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port = 793 dom->dom_server_addr.sin_port; 794 DPRINTF("domain %s at %s/%d\n", dom->dom_name, 795 inet_ntoa(dom->dom_server_addr.sin_addr), 796 ntohs(dom->dom_server_addr.sin_port)); 797 return &res; 798 } 799 800 /* 801 * The SETDOM call: ypset. 802 * 803 * Unless -ypsetme was given on the command line, this is rejected; 804 * even then it's only allowed from localhost unless -ypset was 805 * given on the command line. 806 * 807 * Allowing anyone anywhere to ypset you (and therefore provide your 808 * password file and such) is a horrible thing and it isn't clear to 809 * me why this functionality even exists. 810 * 811 * ypset from localhost has some but limited utility. 812 */ 813 static void * 814 ypbindproc_setdom_2(SVCXPRT *transp, void *argp) 815 { 816 struct ypbind_setdom *sd = argp; 817 struct sockaddr_in *fromsin, bindsin; 818 static bool_t res; 819 820 (void)memset(&res, 0, sizeof(res)); 821 fromsin = svc_getcaller(transp); 822 DPRINTF("ypbindproc_setdom_2 from %s\n", inet_ntoa(fromsin->sin_addr)); 823 824 /* 825 * Reject unless enabled. 826 */ 827 828 if (allow_any_ypset) { 829 /* nothing */ 830 } else if (allow_local_ypset) { 831 if (fromsin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) { 832 DPRINTF("ypset denied from %s\n", 833 inet_ntoa(fromsin->sin_addr)); 834 return NULL; 835 } 836 } else { 837 DPRINTF("ypset denied\n"); 838 return NULL; 839 } 840 841 /* Make a "security" check. */ 842 if (ntohs(fromsin->sin_port) >= IPPORT_RESERVED) { 843 DPRINTF("ypset from unprivileged port denied\n"); 844 return &res; 845 } 846 847 /* Ignore requests we don't understand. */ 848 if (sd->ypsetdom_vers != YPVERS) { 849 DPRINTF("ypset with wrong version denied\n"); 850 return &res; 851 } 852 853 /* 854 * Fetch the arguments out of the xdr-decoded blob and call 855 * rpc_received(), setting FORCE so that the domain will be 856 * created if we don't already know about it, and also saying 857 * that it's actually a ypset. 858 * 859 * Effectively we're telilng rpc_received() that we got an 860 * RPC response from the server specified by ypset. 861 */ 862 (void)memset(&bindsin, 0, sizeof bindsin); 863 bindsin.sin_family = AF_INET; 864 bindsin.sin_len = sizeof(bindsin); 865 bindsin.sin_addr = sd->ypsetdom_addr; 866 bindsin.sin_port = sd->ypsetdom_port; 867 rpc_received(sd->ypsetdom_domain, &bindsin, 1, 1); 868 869 DPRINTF("ypset to %s for domain %s succeeded\n", 870 inet_ntoa(bindsin.sin_addr), sd->ypsetdom_domain); 871 res = 1; 872 return &res; 873 } 874 875 /* 876 * Dispatcher for the ypbind service. 877 * 878 * There are three calls: NULL, which does nothing, DOMAIN, which 879 * gets the binding for a particular domain, and SETDOM, which 880 * does ypset. 881 */ 882 static void 883 ypbindprog_2(struct svc_req *rqstp, register SVCXPRT *transp) 884 { 885 union { 886 char ypbindproc_domain_2_arg[YPMAXDOMAIN + 1]; 887 struct ypbind_setdom ypbindproc_setdom_2_arg; 888 void *alignment; 889 } argument; 890 struct authunix_parms *creds; 891 char *result; 892 xdrproc_t xdr_argument, xdr_result; 893 void *(*local)(SVCXPRT *, void *); 894 895 switch (rqstp->rq_proc) { 896 case YPBINDPROC_NULL: 897 xdr_argument = (xdrproc_t)xdr_void; 898 xdr_result = (xdrproc_t)xdr_void; 899 local = ypbindproc_null_2; 900 break; 901 902 case YPBINDPROC_DOMAIN: 903 xdr_argument = (xdrproc_t)xdr_ypdomain_wrap_string; 904 xdr_result = (xdrproc_t)xdr_ypbind_resp; 905 local = ypbindproc_domain_2; 906 break; 907 908 case YPBINDPROC_SETDOM: 909 switch (rqstp->rq_cred.oa_flavor) { 910 case AUTH_UNIX: 911 creds = (struct authunix_parms *)rqstp->rq_clntcred; 912 if (creds->aup_uid != 0) { 913 svcerr_auth(transp, AUTH_BADCRED); 914 return; 915 } 916 break; 917 default: 918 svcerr_auth(transp, AUTH_TOOWEAK); 919 return; 920 } 921 922 xdr_argument = (xdrproc_t)xdr_ypbind_setdom; 923 xdr_result = (xdrproc_t)xdr_void; 924 local = ypbindproc_setdom_2; 925 break; 926 927 default: 928 svcerr_noproc(transp); 929 return; 930 } 931 (void)memset(&argument, 0, sizeof(argument)); 932 if (!svc_getargs(transp, xdr_argument, (caddr_t)(void *)&argument)) { 933 svcerr_decode(transp); 934 return; 935 } 936 result = (*local)(transp, &argument); 937 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { 938 svcerr_systemerr(transp); 939 } 940 return; 941 } 942 943 /* 944 * Set up sunrpc stuff. 945 * 946 * This sets up the ypbind service (both TCP and UDP) and also opens 947 * the sockets we use for talking to ypservers. 948 */ 949 static void 950 sunrpc_setup(void) 951 { 952 int one; 953 954 (void)pmap_unset(YPBINDPROG, YPBINDVERS); 955 956 udptransp = svcudp_create(RPC_ANYSOCK); 957 if (udptransp == NULL) 958 errx(1, "Cannot create udp service."); 959 960 if (!svc_register(udptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2, 961 IPPROTO_UDP)) 962 errx(1, "Unable to register (YPBINDPROG, YPBINDVERS, udp)."); 963 964 tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0); 965 if (tcptransp == NULL) 966 errx(1, "Cannot create tcp service."); 967 968 if (!svc_register(tcptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2, 969 IPPROTO_TCP)) 970 errx(1, "Unable to register (YPBINDPROG, YPBINDVERS, tcp)."); 971 972 /* XXX use SOCK_STREAM for direct queries? */ 973 if ((rpcsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) 974 err(1, "rpc socket"); 975 if ((pingsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) 976 err(1, "ping socket"); 977 978 (void)fcntl(rpcsock, F_SETFL, fcntl(rpcsock, F_GETFL, 0) | FNDELAY); 979 (void)fcntl(pingsock, F_SETFL, fcntl(pingsock, F_GETFL, 0) | FNDELAY); 980 981 one = 1; 982 (void)setsockopt(rpcsock, SOL_SOCKET, SO_BROADCAST, &one, 983 (socklen_t)sizeof(one)); 984 rmtca.prog = YPPROG; 985 rmtca.vers = YPVERS; 986 rmtca.proc = YPPROC_DOMAIN_NONACK; 987 rmtca.xdr_args = NULL; /* set at call time */ 988 rmtca.args_ptr = NULL; /* set at call time */ 989 rmtcr.port_ptr = &rmtcr_port; 990 rmtcr.xdr_results = (xdrproc_t)xdr_bool; 991 rmtcr.results_ptr = (caddr_t)(void *)&rmtcr_outval; 992 } 993 994 //////////////////////////////////////////////////////////// 995 // operational logic 996 997 /* 998 * Broadcast an RPC packet to hopefully contact some servers for a 999 * domain. 1000 */ 1001 static int 1002 broadcast(char *buf, int outlen) 1003 { 1004 struct ifaddrs *ifap, *ifa; 1005 struct sockaddr_in bindsin; 1006 struct in_addr in; 1007 1008 (void)memset(&bindsin, 0, sizeof bindsin); 1009 bindsin.sin_family = AF_INET; 1010 bindsin.sin_len = sizeof(bindsin); 1011 bindsin.sin_port = htons(PMAPPORT); 1012 1013 if (getifaddrs(&ifap) != 0) { 1014 yp_log(LOG_WARNING, "broadcast: getifaddrs: %s", 1015 strerror(errno)); 1016 return (-1); 1017 } 1018 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 1019 if (ifa->ifa_addr->sa_family != AF_INET) 1020 continue; 1021 if ((ifa->ifa_flags & IFF_UP) == 0) 1022 continue; 1023 1024 switch (ifa->ifa_flags & (IFF_LOOPBACK | IFF_BROADCAST)) { 1025 case IFF_BROADCAST: 1026 if (!ifa->ifa_broadaddr) 1027 continue; 1028 if (ifa->ifa_broadaddr->sa_family != AF_INET) 1029 continue; 1030 in = ((struct sockaddr_in *)(void *)ifa->ifa_broadaddr)->sin_addr; 1031 break; 1032 case IFF_LOOPBACK: 1033 in = ((struct sockaddr_in *)(void *)ifa->ifa_addr)->sin_addr; 1034 break; 1035 default: 1036 continue; 1037 } 1038 1039 bindsin.sin_addr = in; 1040 DPRINTF("broadcast %x\n", bindsin.sin_addr.s_addr); 1041 if (sendto(rpcsock, buf, outlen, 0, 1042 (struct sockaddr *)(void *)&bindsin, 1043 (socklen_t)bindsin.sin_len) == -1) 1044 yp_log(LOG_WARNING, "broadcast: sendto: %s", 1045 strerror(errno)); 1046 } 1047 freeifaddrs(ifap); 1048 return (0); 1049 } 1050 1051 /* 1052 * Send an RPC packet to all the configured (in /var/yp/foo.ypservers) 1053 * servers for a domain. 1054 * 1055 * XXX: we should read and parse the file up front and reread it only 1056 * if it changes. 1057 */ 1058 static int 1059 direct(char *buf, int outlen, struct domain *dom) 1060 { 1061 const char *path; 1062 char line[_POSIX2_LINE_MAX]; 1063 char *p; 1064 struct hostent *hp; 1065 struct sockaddr_in bindsin; 1066 int i, count = 0; 1067 1068 /* 1069 * XXX what happens if someone's editor unlinks and replaces 1070 * the servers file? 1071 */ 1072 1073 if (dom->dom_serversfile != NULL) { 1074 rewind(dom->dom_serversfile); 1075 } else { 1076 path = ypservers_filename(dom->dom_name); 1077 dom->dom_serversfile = fopen(path, "r"); 1078 if (dom->dom_serversfile == NULL) { 1079 /* 1080 * XXX there should be a time restriction on 1081 * this (and/or on trying the open) so we 1082 * don't flood the log. Or should we fall back 1083 * to broadcast mode? 1084 */ 1085 yp_log(LOG_ERR, "%s: %s", path, 1086 strerror(errno)); 1087 return -1; 1088 } 1089 } 1090 1091 (void)memset(&bindsin, 0, sizeof bindsin); 1092 bindsin.sin_family = AF_INET; 1093 bindsin.sin_len = sizeof(bindsin); 1094 bindsin.sin_port = htons(PMAPPORT); 1095 1096 while (fgets(line, (int)sizeof(line), dom->dom_serversfile) != NULL) { 1097 /* skip lines that are too big */ 1098 p = strchr(line, '\n'); 1099 if (p == NULL) { 1100 int c; 1101 1102 while ((c = getc(dom->dom_serversfile)) != '\n' && c != EOF) 1103 ; 1104 continue; 1105 } 1106 *p = '\0'; 1107 p = line; 1108 while (isspace((unsigned char)*p)) 1109 p++; 1110 if (*p == '#') 1111 continue; 1112 hp = gethostbyname(p); 1113 if (!hp) { 1114 yp_log(LOG_WARNING, "%s: %s", p, hstrerror(h_errno)); 1115 continue; 1116 } 1117 /* step through all addresses in case first is unavailable */ 1118 for (i = 0; hp->h_addr_list[i]; i++) { 1119 (void)memcpy(&bindsin.sin_addr, hp->h_addr_list[0], 1120 hp->h_length); 1121 if (sendto(rpcsock, buf, outlen, 0, 1122 (struct sockaddr *)(void *)&bindsin, 1123 (socklen_t)sizeof(bindsin)) < 0) { 1124 yp_log(LOG_WARNING, "direct: sendto: %s", 1125 strerror(errno)); 1126 continue; 1127 } else 1128 count++; 1129 } 1130 } 1131 if (!count) { 1132 yp_log(LOG_WARNING, "No contactable servers found in %s", 1133 ypservers_filename(dom->dom_name)); 1134 return -1; 1135 } 1136 return 0; 1137 } 1138 1139 /* 1140 * Send an RPC packet to the server that's been selected with ypset. 1141 * (This is only used when in broadcast mode and when ypset is 1142 * allowed.) 1143 */ 1144 static int 1145 direct_set(char *buf, int outlen, struct domain *dom) 1146 { 1147 struct sockaddr_in bindsin; 1148 char path[MAXPATHLEN]; 1149 struct iovec iov[2]; 1150 struct ypbind_resp ybr; 1151 SVCXPRT dummy_svc; 1152 int fd; 1153 ssize_t bytes; 1154 1155 /* 1156 * Gack, we lose if binding file went away. We reset 1157 * "been_set" if this happens, otherwise we'll never 1158 * bind again. 1159 */ 1160 (void)snprintf(path, sizeof(path), "%s/%s.%ld", BINDINGDIR, 1161 dom->dom_name, dom->dom_vers); 1162 1163 fd = open_locked(path, O_RDONLY, 0644); 1164 if (fd == -1) { 1165 yp_log(LOG_WARNING, "%s: %s", path, strerror(errno)); 1166 dom->dom_been_ypset = 0; 1167 return -1; 1168 } 1169 1170 /* Read the binding file... */ 1171 iov[0].iov_base = &(dummy_svc.xp_port); 1172 iov[0].iov_len = sizeof(dummy_svc.xp_port); 1173 iov[1].iov_base = &ybr; 1174 iov[1].iov_len = sizeof(ybr); 1175 bytes = readv(fd, iov, 2); 1176 (void)close(fd); 1177 if (bytes <0 || (size_t)bytes != (iov[0].iov_len + iov[1].iov_len)) { 1178 /* Binding file corrupt? */ 1179 if (bytes < 0) 1180 yp_log(LOG_WARNING, "%s: %s", path, strerror(errno)); 1181 else 1182 yp_log(LOG_WARNING, "%s: short read", path); 1183 dom->dom_been_ypset = 0; 1184 return -1; 1185 } 1186 1187 bindsin.sin_addr = 1188 ybr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr; 1189 1190 if (sendto(rpcsock, buf, outlen, 0, 1191 (struct sockaddr *)(void *)&bindsin, 1192 (socklen_t)sizeof(bindsin)) < 0) { 1193 yp_log(LOG_WARNING, "direct_set: sendto: %s", strerror(errno)); 1194 return -1; 1195 } 1196 1197 return 0; 1198 } 1199 1200 /* 1201 * Receive and dispatch packets on the general RPC socket. 1202 */ 1203 static enum clnt_stat 1204 handle_replies(void) 1205 { 1206 char buf[BUFSIZE]; 1207 socklen_t fromlen; 1208 ssize_t inlen; 1209 struct domain *dom; 1210 struct sockaddr_in raddr; 1211 struct rpc_msg msg; 1212 XDR xdr; 1213 1214 recv_again: 1215 DPRINTF("handle_replies receiving\n"); 1216 (void)memset(&xdr, 0, sizeof(xdr)); 1217 (void)memset(&msg, 0, sizeof(msg)); 1218 msg.acpted_rply.ar_verf = _null_auth; 1219 msg.acpted_rply.ar_results.where = (caddr_t)(void *)&rmtcr; 1220 msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_rmtcallres; 1221 1222 try_again: 1223 fromlen = sizeof(struct sockaddr); 1224 inlen = recvfrom(rpcsock, buf, sizeof buf, 0, 1225 (struct sockaddr *)(void *)&raddr, &fromlen); 1226 if (inlen < 0) { 1227 if (errno == EINTR) 1228 goto try_again; 1229 DPRINTF("handle_replies: recvfrom failed (%s)\n", 1230 strerror(errno)); 1231 return RPC_CANTRECV; 1232 } 1233 if ((size_t)inlen < sizeof(uint32_t)) 1234 goto recv_again; 1235 1236 /* 1237 * see if reply transaction id matches sent id. 1238 * If so, decode the results. 1239 */ 1240 xdrmem_create(&xdr, buf, (unsigned)inlen, XDR_DECODE); 1241 if (xdr_replymsg(&xdr, &msg)) { 1242 if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) && 1243 (msg.acpted_rply.ar_stat == SUCCESS)) { 1244 raddr.sin_port = htons((uint16_t)rmtcr_port); 1245 dom = domain_find(msg.rm_xid); 1246 if (dom != NULL) 1247 rpc_received(dom->dom_name, &raddr, 0, 0); 1248 } 1249 } 1250 xdr.x_op = XDR_FREE; 1251 msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; 1252 xdr_destroy(&xdr); 1253 1254 return RPC_SUCCESS; 1255 } 1256 1257 /* 1258 * Receive and dispatch packets on the ping socket. 1259 */ 1260 static enum clnt_stat 1261 handle_ping(void) 1262 { 1263 char buf[BUFSIZE]; 1264 socklen_t fromlen; 1265 ssize_t inlen; 1266 struct domain *dom; 1267 struct sockaddr_in raddr; 1268 struct rpc_msg msg; 1269 XDR xdr; 1270 bool_t res; 1271 1272 recv_again: 1273 DPRINTF("handle_ping receiving\n"); 1274 (void)memset(&xdr, 0, sizeof(xdr)); 1275 (void)memset(&msg, 0, sizeof(msg)); 1276 msg.acpted_rply.ar_verf = _null_auth; 1277 msg.acpted_rply.ar_results.where = (caddr_t)(void *)&res; 1278 msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_bool; 1279 1280 try_again: 1281 fromlen = sizeof (struct sockaddr); 1282 inlen = recvfrom(pingsock, buf, sizeof buf, 0, 1283 (struct sockaddr *)(void *)&raddr, &fromlen); 1284 if (inlen < 0) { 1285 if (errno == EINTR) 1286 goto try_again; 1287 DPRINTF("handle_ping: recvfrom failed (%s)\n", 1288 strerror(errno)); 1289 return RPC_CANTRECV; 1290 } 1291 if ((size_t)inlen < sizeof(uint32_t)) 1292 goto recv_again; 1293 1294 /* 1295 * see if reply transaction id matches sent id. 1296 * If so, decode the results. 1297 */ 1298 xdrmem_create(&xdr, buf, (unsigned)inlen, XDR_DECODE); 1299 if (xdr_replymsg(&xdr, &msg)) { 1300 if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) && 1301 (msg.acpted_rply.ar_stat == SUCCESS)) { 1302 dom = domain_find(msg.rm_xid); 1303 if (dom != NULL) 1304 rpc_received(dom->dom_name, &raddr, 0, 0); 1305 } 1306 } 1307 xdr.x_op = XDR_FREE; 1308 msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; 1309 xdr_destroy(&xdr); 1310 1311 return RPC_SUCCESS; 1312 } 1313 1314 /* 1315 * Contact all known servers for a domain in the hopes that one of 1316 * them's awake. Also, if we previously had a binding but it timed 1317 * out, try the portmapper on that host in case ypserv moved ports for 1318 * some reason. 1319 * 1320 * As a side effect, wipe out any existing binding file. 1321 */ 1322 static int 1323 nag_servers(struct domain *dom) 1324 { 1325 char *dom_name = dom->dom_name; 1326 struct rpc_msg msg; 1327 char buf[BUFSIZE]; 1328 enum clnt_stat st; 1329 int outlen; 1330 AUTH *rpcua; 1331 XDR xdr; 1332 1333 DPRINTF("nag_servers\n"); 1334 rmtca.xdr_args = (xdrproc_t)xdr_ypdomain_wrap_string; 1335 rmtca.args_ptr = (caddr_t)(void *)&dom_name; 1336 1337 (void)memset(&xdr, 0, sizeof xdr); 1338 (void)memset(&msg, 0, sizeof msg); 1339 1340 rpcua = authunix_create_default(); 1341 if (rpcua == NULL) { 1342 DPRINTF("cannot get unix auth\n"); 1343 return RPC_SYSTEMERROR; 1344 } 1345 msg.rm_direction = CALL; 1346 msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 1347 msg.rm_call.cb_prog = PMAPPROG; 1348 msg.rm_call.cb_vers = PMAPVERS; 1349 msg.rm_call.cb_proc = PMAPPROC_CALLIT; 1350 msg.rm_call.cb_cred = rpcua->ah_cred; 1351 msg.rm_call.cb_verf = rpcua->ah_verf; 1352 1353 msg.rm_xid = dom->dom_xid; 1354 xdrmem_create(&xdr, buf, (unsigned)sizeof(buf), XDR_ENCODE); 1355 if (!xdr_callmsg(&xdr, &msg)) { 1356 st = RPC_CANTENCODEARGS; 1357 AUTH_DESTROY(rpcua); 1358 return st; 1359 } 1360 if (!xdr_rmtcall_args(&xdr, &rmtca)) { 1361 st = RPC_CANTENCODEARGS; 1362 AUTH_DESTROY(rpcua); 1363 return st; 1364 } 1365 outlen = (int)xdr_getpos(&xdr); 1366 xdr_destroy(&xdr); 1367 if (outlen < 1) { 1368 st = RPC_CANTENCODEARGS; 1369 AUTH_DESTROY(rpcua); 1370 return st; 1371 } 1372 AUTH_DESTROY(rpcua); 1373 1374 if (dom->dom_lockfd != -1) { 1375 (void)close(dom->dom_lockfd); 1376 dom->dom_lockfd = -1; 1377 removelock(dom); 1378 } 1379 1380 if (dom->dom_state == DOM_PINGING || dom->dom_state == DOM_LOST) { 1381 /* 1382 * This resolves the following situation: 1383 * ypserver on other subnet was once bound, 1384 * but rebooted and is now using a different port 1385 */ 1386 struct sockaddr_in bindsin; 1387 1388 (void)memset(&bindsin, 0, sizeof bindsin); 1389 bindsin.sin_family = AF_INET; 1390 bindsin.sin_len = sizeof(bindsin); 1391 bindsin.sin_port = htons(PMAPPORT); 1392 bindsin.sin_addr = dom->dom_server_addr.sin_addr; 1393 1394 if (sendto(rpcsock, buf, outlen, 0, 1395 (struct sockaddr *)(void *)&bindsin, 1396 (socklen_t)sizeof bindsin) == -1) 1397 yp_log(LOG_WARNING, "nag_servers: sendto: %s", 1398 strerror(errno)); 1399 } 1400 1401 switch (dom->dom_ypbindmode) { 1402 case YPBIND_BROADCAST: 1403 if (dom->dom_been_ypset) { 1404 return direct_set(buf, outlen, dom); 1405 } 1406 return broadcast(buf, outlen); 1407 1408 case YPBIND_DIRECT: 1409 return direct(buf, outlen, dom); 1410 } 1411 /*NOTREACHED*/ 1412 return -1; 1413 } 1414 1415 /* 1416 * Send a ping message to a domain's current ypserver. 1417 */ 1418 static int 1419 ping(struct domain *dom) 1420 { 1421 char *dom_name = dom->dom_name; 1422 struct rpc_msg msg; 1423 char buf[BUFSIZE]; 1424 enum clnt_stat st; 1425 int outlen; 1426 AUTH *rpcua; 1427 XDR xdr; 1428 1429 (void)memset(&xdr, 0, sizeof xdr); 1430 (void)memset(&msg, 0, sizeof msg); 1431 1432 rpcua = authunix_create_default(); 1433 if (rpcua == NULL) { 1434 DPRINTF("cannot get unix auth\n"); 1435 return RPC_SYSTEMERROR; 1436 } 1437 1438 msg.rm_direction = CALL; 1439 msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 1440 msg.rm_call.cb_prog = YPPROG; 1441 msg.rm_call.cb_vers = YPVERS; 1442 msg.rm_call.cb_proc = YPPROC_DOMAIN_NONACK; 1443 msg.rm_call.cb_cred = rpcua->ah_cred; 1444 msg.rm_call.cb_verf = rpcua->ah_verf; 1445 1446 msg.rm_xid = dom->dom_xid; 1447 xdrmem_create(&xdr, buf, (unsigned)sizeof(buf), XDR_ENCODE); 1448 if (!xdr_callmsg(&xdr, &msg)) { 1449 st = RPC_CANTENCODEARGS; 1450 AUTH_DESTROY(rpcua); 1451 return st; 1452 } 1453 if (!xdr_ypdomain_wrap_string(&xdr, &dom_name)) { 1454 st = RPC_CANTENCODEARGS; 1455 AUTH_DESTROY(rpcua); 1456 return st; 1457 } 1458 outlen = (int)xdr_getpos(&xdr); 1459 xdr_destroy(&xdr); 1460 if (outlen < 1) { 1461 st = RPC_CANTENCODEARGS; 1462 AUTH_DESTROY(rpcua); 1463 return st; 1464 } 1465 AUTH_DESTROY(rpcua); 1466 1467 DPRINTF("ping %x\n", dom->dom_server_addr.sin_addr.s_addr); 1468 1469 if (sendto(pingsock, buf, outlen, 0, 1470 (struct sockaddr *)(void *)&dom->dom_server_addr, 1471 (socklen_t)(sizeof dom->dom_server_addr)) == -1) 1472 yp_log(LOG_WARNING, "ping: sendto: %s", strerror(errno)); 1473 return 0; 1474 1475 } 1476 1477 /* 1478 * Scan for timer-based work to do. 1479 * 1480 * If the domain is currently alive, ping the server we're currently 1481 * bound to. Otherwise, try all known servers and/or broadcast for a 1482 * server via nag_servers. 1483 * 1484 * Try again in five seconds. 1485 * 1486 * If we get back here and the state is still DOM_PINGING, it means 1487 * we didn't receive a ping response within five seconds. Declare the 1488 * binding lost. If the binding is already lost, and it's been lost 1489 * for 60 seconds, switch to DOM_DEAD and begin exponential backoff. 1490 * The exponential backoff starts at 10 seconds and tops out at one 1491 * hour; see above. 1492 */ 1493 static void 1494 checkwork(void) 1495 { 1496 struct domain *dom; 1497 time_t t; 1498 1499 check = 0; 1500 1501 (void)time(&t); 1502 for (dom = domains; dom != NULL; dom = dom->dom_next) { 1503 if (dom->dom_checktime >= t) { 1504 continue; 1505 } 1506 switch (dom->dom_state) { 1507 case DOM_NEW: 1508 /* XXX should be a timeout for this state */ 1509 dom->dom_checktime = t + 5; 1510 (void)nag_servers(dom); 1511 break; 1512 1513 case DOM_ALIVE: 1514 dom->dom_state = DOM_PINGING; 1515 dom->dom_checktime = t + 5; 1516 (void)ping(dom); 1517 break; 1518 1519 case DOM_PINGING: 1520 dom->dom_state = DOM_LOST; 1521 dom->dom_losttime = t; 1522 dom->dom_checktime = t + 5; 1523 yp_log(LOG_NOTICE, "Domain %s lost its binding to " 1524 "server %s", dom->dom_name, 1525 inet_ntoa(dom->dom_server_addr.sin_addr)); 1526 (void)nag_servers(dom); 1527 break; 1528 1529 case DOM_LOST: 1530 if (t > dom->dom_losttime + 60) { 1531 dom->dom_state = DOM_DEAD; 1532 dom->dom_backofftime = 10; 1533 yp_log(LOG_NOTICE, "Domain %s dead; " 1534 "going to exponential backoff", 1535 dom->dom_name); 1536 } 1537 dom->dom_checktime = t + 5; 1538 (void)nag_servers(dom); 1539 break; 1540 1541 case DOM_DEAD: 1542 dom->dom_checktime = t + dom->dom_backofftime; 1543 backoff(&dom->dom_backofftime); 1544 (void)nag_servers(dom); 1545 break; 1546 } 1547 /* re-fetch the time in case we hung sending packets */ 1548 (void)time(&t); 1549 } 1550 } 1551 1552 /* 1553 * Process a hangup signal. 1554 * 1555 * Do an extra nag_servers() for any domains that are DEAD. This way 1556 * if you know things are back up you can restore service by sending 1557 * ypbind a SIGHUP rather than waiting for the timeout period. 1558 */ 1559 static void 1560 dohup(void) 1561 { 1562 struct domain *dom; 1563 1564 hupped = 0; 1565 for (dom = domains; dom != NULL; dom = dom->dom_next) { 1566 if (dom->dom_state == DOM_DEAD) { 1567 (void)nag_servers(dom); 1568 } 1569 } 1570 } 1571 1572 /* 1573 * Receive a hangup signal. 1574 */ 1575 static void 1576 hup(int __unused sig) 1577 { 1578 hupped = 1; 1579 } 1580 1581 /* 1582 * Initialize hangup processing. 1583 */ 1584 static void 1585 starthup(void) 1586 { 1587 struct sigaction sa; 1588 1589 sa.sa_handler = hup; 1590 sigemptyset(&sa.sa_mask); 1591 sa.sa_flags = SA_RESTART; 1592 if (sigaction(SIGHUP, &sa, NULL) == -1) { 1593 err(1, "sigaction"); 1594 } 1595 } 1596 1597 //////////////////////////////////////////////////////////// 1598 // main 1599 1600 /* 1601 * Usage message. 1602 */ 1603 __dead static void 1604 usage(void) 1605 { 1606 const char *opt = ""; 1607 #ifdef DEBUG 1608 opt = " [-d]"; 1609 #endif 1610 1611 (void)fprintf(stderr, 1612 "Usage: %s [-broadcast] [-insecure] [-ypset] [-ypsetme]%s\n", 1613 getprogname(), opt); 1614 exit(1); 1615 } 1616 1617 /* 1618 * Main. 1619 */ 1620 int 1621 main(int argc, char *argv[]) 1622 { 1623 struct timeval tv; 1624 fd_set fdsr; 1625 int width, lockfd; 1626 int started = 0; 1627 char *domainname; 1628 1629 setprogname(argv[0]); 1630 1631 /* 1632 * Process arguments. 1633 */ 1634 1635 default_ypbindmode = YPBIND_DIRECT; 1636 while (--argc) { 1637 ++argv; 1638 if (!strcmp("-insecure", *argv)) { 1639 insecure = 1; 1640 } else if (!strcmp("-ypset", *argv)) { 1641 allow_any_ypset = 1; 1642 allow_local_ypset = 1; 1643 } else if (!strcmp("-ypsetme", *argv)) { 1644 allow_any_ypset = 0; 1645 allow_local_ypset = 1; 1646 } else if (!strcmp("-broadcast", *argv)) { 1647 default_ypbindmode = YPBIND_BROADCAST; 1648 #ifdef DEBUG 1649 } else if (!strcmp("-d", *argv)) { 1650 debug = 1; 1651 #endif 1652 } else { 1653 usage(); 1654 } 1655 } 1656 1657 /* 1658 * Look up the name of the default domain. 1659 */ 1660 1661 (void)yp_get_default_domain(&domainname); 1662 if (domainname[0] == '\0') 1663 errx(1, "Domainname not set. Aborting."); 1664 if (_yp_invalid_domain(domainname)) 1665 errx(1, "Invalid domainname: %s", domainname); 1666 1667 /* 1668 * Start things up. 1669 */ 1670 1671 /* Open the system log. */ 1672 openlog("ypbind", LOG_PERROR | LOG_PID, LOG_DAEMON); 1673 1674 /* Acquire /var/run/ypbind.lock. */ 1675 lockfd = open_locked(_PATH_YPBIND_LOCK, O_CREAT|O_RDWR|O_TRUNC, 0644); 1676 if (lockfd == -1) 1677 err(1, "Cannot create %s", _PATH_YPBIND_LOCK); 1678 1679 /* Accept hangups. */ 1680 starthup(); 1681 1682 /* Initialize sunrpc stuff. */ 1683 sunrpc_setup(); 1684 1685 /* Clean out BINDINGDIR, deleting all existing (now stale) bindings */ 1686 if (purge_bindingdir(BINDINGDIR) < 0) 1687 errx(1, "Unable to purge old bindings from %s", BINDINGDIR); 1688 1689 /* 1690 * We start with one binding, for the default domain. It starts 1691 * out "unsuccessful". 1692 * 1693 * XXX: domain_create adds the new domain to 'domains' (the 1694 * global linked list) and therefore we shouldn't assign 1695 * 'domains' again on return. 1696 */ 1697 1698 domains = domain_create(domainname); 1699 1700 /* 1701 * Delete the lock for the default domain again, just in case something 1702 * magically caused it to appear since purge_bindingdir() was called. 1703 * XXX: this is useless and redundant; remove it. 1704 */ 1705 removelock(domains); 1706 1707 /* 1708 * Main loop. Wake up at least once a second and check for 1709 * timer-based work to do (checkwork) and also handle incoming 1710 * responses from ypservers and any RPCs made to the ypbind 1711 * service. 1712 * 1713 * There are two sockets used for ypserver traffic: one for 1714 * pings and one for everything else. These call XDR manually 1715 * for encoding and are *not* dispatched via the sunrpc 1716 * libraries. 1717 * 1718 * The ypbind serivce *is* dispatched via the sunrpc libraries. 1719 * svc_getreqset() does whatever internal muck and ultimately 1720 * ypbind service calls arrive at ypbindprog_2(). 1721 */ 1722 checkwork(); 1723 for (;;) { 1724 width = svc_maxfd; 1725 if (rpcsock > width) 1726 width = rpcsock; 1727 if (pingsock > width) 1728 width = pingsock; 1729 width++; 1730 fdsr = svc_fdset; 1731 FD_SET(rpcsock, &fdsr); 1732 FD_SET(pingsock, &fdsr); 1733 tv.tv_sec = 1; 1734 tv.tv_usec = 0; 1735 1736 switch (select(width, &fdsr, NULL, NULL, &tv)) { 1737 case 0: 1738 /* select timed out - check for timer-based work */ 1739 if (hupped) { 1740 dohup(); 1741 } 1742 checkwork(); 1743 break; 1744 case -1: 1745 if (hupped) { 1746 dohup(); 1747 } 1748 if (errno != EINTR) { 1749 yp_log(LOG_WARNING, "select: %s", 1750 strerror(errno)); 1751 } 1752 break; 1753 default: 1754 if (hupped) { 1755 dohup(); 1756 } 1757 /* incoming of our own; read it */ 1758 if (FD_ISSET(rpcsock, &fdsr)) 1759 (void)handle_replies(); 1760 if (FD_ISSET(pingsock, &fdsr)) 1761 (void)handle_ping(); 1762 1763 /* read any incoming packets for the ypbind service */ 1764 svc_getreqset(&fdsr); 1765 1766 /* 1767 * Only check for timer-based work if 1768 * something in the incoming RPC logic said 1769 * to. This might be just a hack to avoid 1770 * scanning the list unnecessarily, but I 1771 * suspect it's also a hack to cover wrong 1772 * state logic. - dholland 20140609 1773 */ 1774 if (check) 1775 checkwork(); 1776 break; 1777 } 1778 1779 /* 1780 * Defer daemonizing until the default domain binds 1781 * successfully. XXX: there seems to be no timeout 1782 * on this, which means that if the default domain 1783 * is dead upstream boot will hang indefinitely. 1784 */ 1785 if (!started && domains->dom_state == DOM_ALIVE) { 1786 started = 1; 1787 #ifdef DEBUG 1788 if (!debug) 1789 #endif 1790 (void)daemon(0, 0); 1791 (void)pidfile(NULL); 1792 } 1793 } 1794 } 1795