1 /* $NetBSD: ypbind.c,v 1.61 2009/11/06 15:41:58 skrll 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.61 2009/11/06 15:41:58 skrll Exp $"); 32 #endif 33 34 #include <sys/param.h> 35 #include <sys/types.h> 36 #include <sys/ioctl.h> 37 #include <sys/signal.h> 38 #include <sys/socket.h> 39 #include <sys/file.h> 40 #include <sys/uio.h> 41 #include <sys/syslog.h> 42 #include <sys/stat.h> 43 #include <fcntl.h> 44 #include <limits.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <errno.h> 48 #include <syslog.h> 49 #include <stdarg.h> 50 #include <ctype.h> 51 #include <dirent.h> 52 #include <netdb.h> 53 #include <string.h> 54 #include <err.h> 55 #include <rpc/rpc.h> 56 #include <rpc/xdr.h> 57 #include <net/if.h> 58 #include <arpa/inet.h> 59 #include <rpc/pmap_clnt.h> 60 #include <rpc/pmap_prot.h> 61 #include <rpc/pmap_rmt.h> 62 #include <unistd.h> 63 #include <util.h> 64 #include <rpcsvc/yp_prot.h> 65 #include <rpcsvc/ypclnt.h> 66 #include <ifaddrs.h> 67 68 #include "pathnames.h" 69 70 #ifndef O_SHLOCK 71 #define O_SHLOCK 0 72 #endif 73 74 #define BUFSIZE 1400 75 76 #define YPSERVERSSUFF ".ypservers" 77 #define BINDINGDIR (_PATH_VAR_YP "binding") 78 79 struct _dom_binding { 80 struct _dom_binding *dom_pnext; 81 char dom_domain[YPMAXDOMAIN + 1]; 82 struct sockaddr_in dom_server_addr; 83 int dom_socket; 84 CLIENT *dom_client; 85 long dom_vers; 86 time_t dom_check_t; 87 time_t dom_ask_t; 88 int dom_lockfd; 89 int dom_alive; 90 u_int32_t dom_xid; 91 }; 92 93 static char *domainname; 94 95 static struct _dom_binding *ypbindlist; 96 static int check; 97 98 typedef enum { 99 YPBIND_DIRECT, YPBIND_BROADCAST, YPBIND_SETLOCAL, YPBIND_SETALL 100 } ypbind_mode_t; 101 102 ypbind_mode_t ypbindmode; 103 104 /* 105 * If ypbindmode is YPBIND_SETLOCAL or YPBIND_SETALL, this indicates 106 * whether or not we've been "ypset". If we haven't, we behave like 107 * YPBIND_BROADCAST. If we have, we behave like YPBIND_DIRECT. 108 */ 109 int been_ypset; 110 111 #ifdef DEBUG 112 static int debug; 113 #endif 114 115 static int insecure; 116 static int rpcsock, pingsock; 117 static struct rmtcallargs rmtca; 118 static struct rmtcallres rmtcr; 119 static bool_t rmtcr_outval; 120 static u_long rmtcr_port; 121 static SVCXPRT *udptransp, *tcptransp; 122 123 int _yp_invalid_domain(const char *); /* from libc */ 124 int main(int, char *[]); 125 126 static void usage(void); 127 static void yp_log(int, const char *, ...) 128 __attribute__((__format__(__printf__, 2, 3))); 129 static struct _dom_binding *makebinding(const char *); 130 static int makelock(struct _dom_binding *); 131 static void removelock(struct _dom_binding *); 132 static int purge_bindingdir(const char *); 133 static void *ypbindproc_null_2(SVCXPRT *, void *); 134 static void *ypbindproc_domain_2(SVCXPRT *, void *); 135 static void *ypbindproc_setdom_2(SVCXPRT *, void *); 136 static void ypbindprog_2(struct svc_req *, SVCXPRT *); 137 static void checkwork(void); 138 static int ping(struct _dom_binding *); 139 static int nag_servers(struct _dom_binding *); 140 static enum clnt_stat handle_replies(void); 141 static enum clnt_stat handle_ping(void); 142 static void rpc_received(char *, struct sockaddr_in *, int); 143 static struct _dom_binding *xid2ypdb(u_int32_t); 144 static u_int32_t unique_xid(struct _dom_binding *); 145 static int broadcast(char *, int); 146 static int direct(char *, int); 147 static int direct_set(char *, int, struct _dom_binding *); 148 149 static void 150 usage(void) 151 { 152 const char *opt = ""; 153 #ifdef DEBUG 154 opt = " [-d]"; 155 #endif 156 157 (void)fprintf(stderr, 158 "Usage: %s [-broadcast] [-insecure] [-ypset] [-ypsetme]%s\n", 159 getprogname(), opt); 160 exit(1); 161 } 162 163 static void 164 yp_log(int pri, const char *fmt, ...) 165 { 166 va_list ap; 167 168 va_start(ap, fmt); 169 170 #if defined(DEBUG) 171 if (debug) 172 (void)vprintf(fmt, ap); 173 else 174 #endif 175 vsyslog(pri, fmt, ap); 176 va_end(ap); 177 } 178 179 static struct _dom_binding * 180 makebinding(const char *dm) 181 { 182 struct _dom_binding *ypdb; 183 184 if ((ypdb = (struct _dom_binding *)malloc(sizeof *ypdb)) == NULL) { 185 yp_log(LOG_ERR, "makebinding"); 186 exit(1); 187 } 188 189 (void)memset(ypdb, 0, sizeof *ypdb); 190 (void)strlcpy(ypdb->dom_domain, dm, sizeof ypdb->dom_domain); 191 return ypdb; 192 } 193 194 static int 195 makelock(struct _dom_binding *ypdb) 196 { 197 int fd; 198 char path[MAXPATHLEN]; 199 200 (void)snprintf(path, sizeof(path), "%s/%s.%ld", BINDINGDIR, 201 ypdb->dom_domain, ypdb->dom_vers); 202 203 if ((fd = open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1) { 204 (void)mkdir(BINDINGDIR, 0755); 205 if ((fd = open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1) 206 return -1; 207 } 208 209 #if O_SHLOCK == 0 210 (void)flock(fd, LOCK_SH); 211 #endif 212 return fd; 213 } 214 215 static void 216 removelock(struct _dom_binding *ypdb) 217 { 218 char path[MAXPATHLEN]; 219 220 (void)snprintf(path, sizeof(path), "%s/%s.%ld", 221 BINDINGDIR, ypdb->dom_domain, ypdb->dom_vers); 222 (void)unlink(path); 223 } 224 225 /* 226 * purge_bindingdir: remove old binding files (i.e. "rm BINDINGDIR\/\*.[0-9]") 227 * 228 * local YP functions [e.g. yp_master()] will fail without even talking 229 * to ypbind if there is a stale (non-flock'd) binding file present. 230 * we have to scan the entire BINDINGDIR for binding files, because 231 * ypbind may bind more than just the yp_get_default_domain() domain. 232 */ 233 static int 234 purge_bindingdir(const char *dirpath) 235 { 236 DIR *dirp; 237 int unlinkedfiles, l; 238 struct dirent *dp; 239 char pathname[MAXPATHLEN]; 240 241 if ((dirp = opendir(dirpath)) == NULL) 242 return(-1); /* at this point, shouldn't ever happen */ 243 244 do { 245 unlinkedfiles = 0; 246 while ((dp = readdir(dirp)) != NULL) { 247 l = dp->d_namlen; 248 /* 'rm *.[0-9]' */ 249 if (l > 2 && dp->d_name[l-2] == '.' && 250 dp->d_name[l-1] >= '0' && dp->d_name[l-1] <= '9') { 251 (void)snprintf(pathname, sizeof(pathname), 252 "%s/%s", dirpath, dp->d_name); 253 if (unlink(pathname) < 0 && errno != ENOENT) 254 return(-1); 255 unlinkedfiles++; 256 } 257 } 258 259 /* rescan dir if we removed it */ 260 if (unlinkedfiles) 261 rewinddir(dirp); 262 263 } while (unlinkedfiles); 264 265 closedir(dirp); 266 return(0); 267 } 268 269 static void * 270 /*ARGSUSED*/ 271 ypbindproc_null_2(SVCXPRT *transp, void *argp) 272 { 273 static char res; 274 275 #ifdef DEBUG 276 if (debug) 277 (void)printf("ypbindproc_null_2\n"); 278 #endif 279 (void)memset(&res, 0, sizeof(res)); 280 return (void *)&res; 281 } 282 283 static void * 284 /*ARGSUSED*/ 285 ypbindproc_domain_2(SVCXPRT *transp, void *argp) 286 { 287 static struct ypbind_resp res; 288 struct _dom_binding *ypdb; 289 char *arg = *(char **) argp; 290 time_t now; 291 int count; 292 293 #ifdef DEBUG 294 if (debug) 295 (void)printf("ypbindproc_domain_2 %s\n", arg); 296 #endif 297 if (_yp_invalid_domain(arg)) 298 return NULL; 299 300 (void)memset(&res, 0, sizeof res); 301 res.ypbind_status = YPBIND_FAIL_VAL; 302 303 for (count = 0, ypdb = ypbindlist; 304 ypdb != NULL; 305 ypdb = ypdb->dom_pnext, count++) { 306 if (count > 100) 307 return NULL; /* prevent denial of service */ 308 if (!strcmp(ypdb->dom_domain, arg)) 309 break; 310 } 311 312 if (ypdb == NULL) { 313 ypdb = makebinding(arg); 314 ypdb->dom_vers = YPVERS; 315 ypdb->dom_alive = 0; 316 ypdb->dom_lockfd = -1; 317 removelock(ypdb); 318 ypdb->dom_xid = unique_xid(ypdb); 319 ypdb->dom_pnext = ypbindlist; 320 ypbindlist = ypdb; 321 check++; 322 #ifdef DEBUG 323 if (debug) 324 (void)printf("unknown domain %s\n", arg); 325 #endif 326 return NULL; 327 } 328 329 if (ypdb->dom_alive == 0) { 330 #ifdef DEBUG 331 if (debug) 332 (void)printf("dead domain %s\n", arg); 333 #endif 334 return NULL; 335 } 336 337 #ifdef HEURISTIC 338 (void)time(&now); 339 if (now < ypdb->dom_ask_t + 5) { 340 /* 341 * Hmm. More than 2 requests in 5 seconds have indicated 342 * that my binding is possibly incorrect. 343 * Ok, do an immediate poll of the server. 344 */ 345 if (ypdb->dom_check_t >= now) { 346 /* don't flood it */ 347 ypdb->dom_check_t = 0; 348 check++; 349 } 350 } 351 ypdb->dom_ask_t = now; 352 #endif 353 354 res.ypbind_status = YPBIND_SUCC_VAL; 355 res.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr.s_addr = 356 ypdb->dom_server_addr.sin_addr.s_addr; 357 res.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port = 358 ypdb->dom_server_addr.sin_port; 359 #ifdef DEBUG 360 if (debug) 361 (void)printf("domain %s at %s/%d\n", ypdb->dom_domain, 362 inet_ntoa(ypdb->dom_server_addr.sin_addr), 363 ntohs(ypdb->dom_server_addr.sin_port)); 364 #endif 365 return &res; 366 } 367 368 static void * 369 ypbindproc_setdom_2(SVCXPRT *transp, void *argp) 370 { 371 struct ypbind_setdom *sd = argp; 372 struct sockaddr_in *fromsin, bindsin; 373 static bool_t res; 374 375 #ifdef DEBUG 376 if (debug) 377 (void)printf("ypbindproc_setdom_2 %s\n", inet_ntoa(bindsin.sin_addr)); 378 #endif 379 (void)memset(&res, 0, sizeof(res)); 380 fromsin = svc_getcaller(transp); 381 382 switch (ypbindmode) { 383 case YPBIND_SETLOCAL: 384 if (fromsin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) { 385 #ifdef DEBUG 386 if (debug) 387 (void)printf("ypset from %s denied\n", 388 inet_ntoa(fromsin->sin_addr)); 389 #endif 390 return NULL; 391 } 392 /* FALLTHROUGH */ 393 394 case YPBIND_SETALL: 395 been_ypset = 1; 396 break; 397 398 case YPBIND_DIRECT: 399 case YPBIND_BROADCAST: 400 default: 401 #ifdef DEBUG 402 if (debug) 403 (void)printf("ypset denied\n"); 404 #endif 405 return NULL; 406 } 407 408 if (ntohs(fromsin->sin_port) >= IPPORT_RESERVED) { 409 #ifdef DEBUG 410 if (debug) 411 (void)printf("ypset from unprivileged port denied\n"); 412 #endif 413 return &res; 414 } 415 416 if (sd->ypsetdom_vers != YPVERS) { 417 #ifdef DEBUG 418 if (debug) 419 (void)printf("ypset with wrong version denied\n"); 420 #endif 421 return &res; 422 } 423 424 (void)memset(&bindsin, 0, sizeof bindsin); 425 bindsin.sin_family = AF_INET; 426 bindsin.sin_len = sizeof(bindsin); 427 bindsin.sin_addr = sd->ypsetdom_addr; 428 bindsin.sin_port = sd->ypsetdom_port; 429 rpc_received(sd->ypsetdom_domain, &bindsin, 1); 430 431 #ifdef DEBUG 432 if (debug) 433 (void)printf("ypset to %s succeeded\n", inet_ntoa(bindsin.sin_addr)); 434 #endif 435 res = 1; 436 return &res; 437 } 438 439 static void 440 ypbindprog_2(struct svc_req *rqstp, register SVCXPRT *transp) 441 { 442 union { 443 char ypbindproc_domain_2_arg[YPMAXDOMAIN + 1]; 444 struct ypbind_setdom ypbindproc_setdom_2_arg; 445 void *alignment; 446 } argument; 447 struct authunix_parms *creds; 448 char *result; 449 xdrproc_t xdr_argument, xdr_result; 450 void *(*local)(SVCXPRT *, void *); 451 452 switch (rqstp->rq_proc) { 453 case YPBINDPROC_NULL: 454 xdr_argument = xdr_void; 455 xdr_result = xdr_void; 456 local = ypbindproc_null_2; 457 break; 458 459 case YPBINDPROC_DOMAIN: 460 xdr_argument = xdr_ypdomain_wrap_string; 461 xdr_result = xdr_ypbind_resp; 462 local = ypbindproc_domain_2; 463 break; 464 465 case YPBINDPROC_SETDOM: 466 switch (rqstp->rq_cred.oa_flavor) { 467 case AUTH_UNIX: 468 creds = (struct authunix_parms *)rqstp->rq_clntcred; 469 if (creds->aup_uid != 0) { 470 svcerr_auth(transp, AUTH_BADCRED); 471 return; 472 } 473 break; 474 default: 475 svcerr_auth(transp, AUTH_TOOWEAK); 476 return; 477 } 478 479 xdr_argument = xdr_ypbind_setdom; 480 xdr_result = xdr_void; 481 local = ypbindproc_setdom_2; 482 break; 483 484 default: 485 svcerr_noproc(transp); 486 return; 487 } 488 (void)memset(&argument, 0, sizeof(argument)); 489 if (!svc_getargs(transp, xdr_argument, (caddr_t)(void *)&argument)) { 490 svcerr_decode(transp); 491 return; 492 } 493 result = (*local)(transp, &argument); 494 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { 495 svcerr_systemerr(transp); 496 } 497 return; 498 } 499 500 int 501 main(int argc, char *argv[]) 502 { 503 struct timeval tv; 504 fd_set fdsr; 505 int width, lockfd; 506 int evil = 0, one; 507 char pathname[MAXPATHLEN]; 508 struct stat st; 509 510 setprogname(argv[0]); 511 (void)yp_get_default_domain(&domainname); 512 if (domainname[0] == '\0') 513 errx(1, "Domainname not set. Aborting."); 514 515 /* 516 * Per traditional ypbind(8) semantics, if a ypservers 517 * file does not exist, we default to broadcast mode. 518 * If the file does exist, we default to direct mode. 519 * Note that we can still override direct mode by passing 520 * the -broadcast flag. 521 */ 522 (void)snprintf(pathname, sizeof(pathname), "%s/%s%s", BINDINGDIR, 523 domainname, YPSERVERSSUFF); 524 if (stat(pathname, &st) < 0) { 525 #ifdef DEBUG 526 if (debug) 527 (void)printf("%s does not exist, defaulting to " 528 "broadcast\n", pathname); 529 #endif 530 ypbindmode = YPBIND_BROADCAST; 531 } else 532 ypbindmode = YPBIND_DIRECT; 533 534 while (--argc) { 535 ++argv; 536 if (!strcmp("-insecure", *argv)) 537 insecure = 1; 538 else if (!strcmp("-ypset", *argv)) 539 ypbindmode = YPBIND_SETALL; 540 else if (!strcmp("-ypsetme", *argv)) 541 ypbindmode = YPBIND_SETLOCAL; 542 else if (!strcmp("-broadcast", *argv)) 543 ypbindmode = YPBIND_BROADCAST; 544 #ifdef DEBUG 545 else if (!strcmp("-d", *argv)) 546 debug++; 547 #endif 548 else 549 usage(); 550 } 551 552 /* initialise syslog */ 553 openlog("ypbind", LOG_PERROR | LOG_PID, LOG_DAEMON); 554 555 lockfd = open(_PATH_YPBIND_LOCK, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644); 556 if (lockfd == -1) 557 err(1, "Cannot create %s", _PATH_YPBIND_LOCK); 558 559 #if O_SHLOCK == 0 560 (void)flock(lockfd, LOCK_SH); 561 #endif 562 563 (void)pmap_unset(YPBINDPROG, YPBINDVERS); 564 565 udptransp = svcudp_create(RPC_ANYSOCK); 566 if (udptransp == NULL) 567 errx(1, "Cannot create udp service."); 568 569 if (!svc_register(udptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2, 570 IPPROTO_UDP)) 571 errx(1, "Unable to register (YPBINDPROG, YPBINDVERS, udp)."); 572 573 tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0); 574 if (tcptransp == NULL) 575 errx(1, "Cannot create tcp service."); 576 577 if (!svc_register(tcptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2, 578 IPPROTO_TCP)) 579 errx(1, "Unable to register (YPBINDPROG, YPBINDVERS, tcp)."); 580 581 /* XXX use SOCK_STREAM for direct queries? */ 582 if ((rpcsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) 583 err(1, "rpc socket"); 584 if ((pingsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) 585 err(1, "ping socket"); 586 587 (void)fcntl(rpcsock, F_SETFL, fcntl(rpcsock, F_GETFL, 0) | FNDELAY); 588 (void)fcntl(pingsock, F_SETFL, fcntl(pingsock, F_GETFL, 0) | FNDELAY); 589 590 one = 1; 591 (void)setsockopt(rpcsock, SOL_SOCKET, SO_BROADCAST, &one, 592 (socklen_t)sizeof(one)); 593 rmtca.prog = YPPROG; 594 rmtca.vers = YPVERS; 595 rmtca.proc = YPPROC_DOMAIN_NONACK; 596 rmtca.xdr_args = NULL; /* set at call time */ 597 rmtca.args_ptr = NULL; /* set at call time */ 598 rmtcr.port_ptr = &rmtcr_port; 599 rmtcr.xdr_results = xdr_bool; 600 rmtcr.results_ptr = (caddr_t)(void *)&rmtcr_outval; 601 602 if (_yp_invalid_domain(domainname)) 603 errx(1, "bad domainname: %s", domainname); 604 605 /* blow away old bindings in BINDINGDIR */ 606 if (purge_bindingdir(BINDINGDIR) < 0) 607 errx(1, "unable to purge old bindings from %s", BINDINGDIR); 608 609 /* build initial domain binding, make it "unsuccessful" */ 610 ypbindlist = makebinding(domainname); 611 ypbindlist->dom_vers = YPVERS; 612 ypbindlist->dom_alive = 0; 613 ypbindlist->dom_lockfd = -1; 614 removelock(ypbindlist); 615 616 checkwork(); 617 618 for (;;) { 619 width = svc_maxfd; 620 if (rpcsock > width) 621 width = rpcsock; 622 if (pingsock > width) 623 width = pingsock; 624 width++; 625 fdsr = svc_fdset; 626 FD_SET(rpcsock, &fdsr); 627 FD_SET(pingsock, &fdsr); 628 tv.tv_sec = 1; 629 tv.tv_usec = 0; 630 631 switch (select(width, &fdsr, NULL, NULL, &tv)) { 632 case 0: 633 checkwork(); 634 break; 635 case -1: 636 yp_log(LOG_WARNING, "select: %m"); 637 break; 638 default: 639 if (FD_ISSET(rpcsock, &fdsr)) 640 (void)handle_replies(); 641 if (FD_ISSET(pingsock, &fdsr)) 642 (void)handle_ping(); 643 svc_getreqset(&fdsr); 644 if (check) 645 checkwork(); 646 break; 647 } 648 649 if (!evil && ypbindlist->dom_alive) { 650 evil = 1; 651 #ifdef DEBUG 652 if (!debug) 653 #endif 654 (void)daemon(0, 0); 655 (void)pidfile(NULL); 656 } 657 } 658 } 659 660 /* 661 * State transition is done like this: 662 * 663 * STATE EVENT ACTION NEWSTATE TIMEOUT 664 * no binding timeout broadcast no binding 5 sec 665 * no binding answer -- binding 60 sec 666 * binding timeout ping server checking 5 sec 667 * checking timeout ping server + broadcast checking 5 sec 668 * checking answer -- binding 60 sec 669 */ 670 void 671 checkwork(void) 672 { 673 struct _dom_binding *ypdb; 674 time_t t; 675 676 check = 0; 677 678 (void)time(&t); 679 for (ypdb = ypbindlist; ypdb; ypdb = ypdb->dom_pnext) { 680 if (ypdb->dom_check_t < t) { 681 if (ypdb->dom_alive == 1) 682 (void)ping(ypdb); 683 else 684 (void)nag_servers(ypdb); 685 (void)time(&t); 686 ypdb->dom_check_t = t + 5; 687 } 688 } 689 } 690 691 int 692 ping(struct _dom_binding *ypdb) 693 { 694 char *dom = ypdb->dom_domain; 695 struct rpc_msg msg; 696 char buf[BUFSIZE]; 697 enum clnt_stat st; 698 int outlen; 699 AUTH *rpcua; 700 XDR xdr; 701 702 (void)memset(&xdr, 0, sizeof xdr); 703 (void)memset(&msg, 0, sizeof msg); 704 705 rpcua = authunix_create_default(); 706 if (rpcua == NULL) { 707 #ifdef DEBUG 708 if (debug) 709 (void)printf("cannot get unix auth\n"); 710 #endif 711 return RPC_SYSTEMERROR; 712 } 713 714 msg.rm_direction = CALL; 715 msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 716 msg.rm_call.cb_prog = YPPROG; 717 msg.rm_call.cb_vers = YPVERS; 718 msg.rm_call.cb_proc = YPPROC_DOMAIN_NONACK; 719 msg.rm_call.cb_cred = rpcua->ah_cred; 720 msg.rm_call.cb_verf = rpcua->ah_verf; 721 722 msg.rm_xid = ypdb->dom_xid; 723 xdrmem_create(&xdr, buf, (u_int)sizeof(buf), XDR_ENCODE); 724 if (!xdr_callmsg(&xdr, &msg)) { 725 st = RPC_CANTENCODEARGS; 726 AUTH_DESTROY(rpcua); 727 return st; 728 } 729 if (!xdr_ypdomain_wrap_string(&xdr, &dom)) { 730 st = RPC_CANTENCODEARGS; 731 AUTH_DESTROY(rpcua); 732 return st; 733 } 734 outlen = (int)xdr_getpos(&xdr); 735 xdr_destroy(&xdr); 736 if (outlen < 1) { 737 st = RPC_CANTENCODEARGS; 738 AUTH_DESTROY(rpcua); 739 return st; 740 } 741 AUTH_DESTROY(rpcua); 742 743 ypdb->dom_alive = 2; 744 #ifdef DEBUG 745 if (debug) 746 (void)printf("ping %x\n", 747 ypdb->dom_server_addr.sin_addr.s_addr); 748 #endif 749 if (sendto(pingsock, buf, outlen, 0, 750 (struct sockaddr *)(void *)&ypdb->dom_server_addr, 751 (socklen_t)sizeof ypdb->dom_server_addr) == -1) 752 yp_log(LOG_WARNING, "ping: sendto: %m"); 753 return 0; 754 755 } 756 757 static int 758 nag_servers(struct _dom_binding *ypdb) 759 { 760 char *dom = ypdb->dom_domain; 761 struct rpc_msg msg; 762 char buf[BUFSIZE]; 763 enum clnt_stat st; 764 int outlen; 765 AUTH *rpcua; 766 XDR xdr; 767 768 #ifdef DEBUG 769 if (debug) 770 (void)printf("nag_servers\n"); 771 #endif 772 rmtca.xdr_args = xdr_ypdomain_wrap_string; 773 rmtca.args_ptr = (caddr_t)(void *)&dom; 774 775 (void)memset(&xdr, 0, sizeof xdr); 776 (void)memset(&msg, 0, sizeof msg); 777 778 rpcua = authunix_create_default(); 779 if (rpcua == NULL) { 780 #ifdef DEBUG 781 if (debug) 782 (void)printf("cannot get unix auth\n"); 783 #endif 784 return RPC_SYSTEMERROR; 785 } 786 msg.rm_direction = CALL; 787 msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 788 msg.rm_call.cb_prog = PMAPPROG; 789 msg.rm_call.cb_vers = PMAPVERS; 790 msg.rm_call.cb_proc = PMAPPROC_CALLIT; 791 msg.rm_call.cb_cred = rpcua->ah_cred; 792 msg.rm_call.cb_verf = rpcua->ah_verf; 793 794 msg.rm_xid = ypdb->dom_xid; 795 xdrmem_create(&xdr, buf, (u_int)sizeof(buf), XDR_ENCODE); 796 if (!xdr_callmsg(&xdr, &msg)) { 797 st = RPC_CANTENCODEARGS; 798 AUTH_DESTROY(rpcua); 799 return st; 800 } 801 if (!xdr_rmtcall_args(&xdr, &rmtca)) { 802 st = RPC_CANTENCODEARGS; 803 AUTH_DESTROY(rpcua); 804 return st; 805 } 806 outlen = (int)xdr_getpos(&xdr); 807 xdr_destroy(&xdr); 808 if (outlen < 1) { 809 st = RPC_CANTENCODEARGS; 810 AUTH_DESTROY(rpcua); 811 return st; 812 } 813 AUTH_DESTROY(rpcua); 814 815 if (ypdb->dom_lockfd != -1) { 816 (void)close(ypdb->dom_lockfd); 817 ypdb->dom_lockfd = -1; 818 removelock(ypdb); 819 } 820 821 if (ypdb->dom_alive == 2) { 822 /* 823 * This resolves the following situation: 824 * ypserver on other subnet was once bound, 825 * but rebooted and is now using a different port 826 */ 827 struct sockaddr_in bindsin; 828 829 (void)memset(&bindsin, 0, sizeof bindsin); 830 bindsin.sin_family = AF_INET; 831 bindsin.sin_len = sizeof(bindsin); 832 bindsin.sin_port = htons(PMAPPORT); 833 bindsin.sin_addr = ypdb->dom_server_addr.sin_addr; 834 835 if (sendto(rpcsock, buf, outlen, 0, 836 (struct sockaddr *)(void *)&bindsin, 837 (socklen_t)sizeof bindsin) == -1) 838 yp_log(LOG_WARNING, "nag_servers: sendto: %m"); 839 } 840 841 switch (ypbindmode) { 842 case YPBIND_SETALL: 843 case YPBIND_SETLOCAL: 844 if (been_ypset) 845 return direct_set(buf, outlen, ypdb); 846 /* FALLTHROUGH */ 847 848 case YPBIND_BROADCAST: 849 return broadcast(buf, outlen); 850 851 case YPBIND_DIRECT: 852 return direct(buf, outlen); 853 } 854 /*NOTREACHED*/ 855 return -1; 856 } 857 858 static int 859 broadcast(char *buf, int outlen) 860 { 861 struct ifaddrs *ifap, *ifa; 862 struct sockaddr_in bindsin; 863 struct in_addr in; 864 865 (void)memset(&bindsin, 0, sizeof bindsin); 866 bindsin.sin_family = AF_INET; 867 bindsin.sin_len = sizeof(bindsin); 868 bindsin.sin_port = htons(PMAPPORT); 869 870 if (getifaddrs(&ifap) != 0) { 871 yp_log(LOG_WARNING, "broadcast: getifaddrs: %m"); 872 return (-1); 873 } 874 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 875 if (ifa->ifa_addr->sa_family != AF_INET) 876 continue; 877 if ((ifa->ifa_flags & IFF_UP) == 0) 878 continue; 879 880 switch (ifa->ifa_flags & (IFF_LOOPBACK | IFF_BROADCAST)) { 881 case IFF_BROADCAST: 882 if (!ifa->ifa_broadaddr) 883 continue; 884 if (ifa->ifa_broadaddr->sa_family != AF_INET) 885 continue; 886 in = ((struct sockaddr_in *)(void *)ifa->ifa_broadaddr)->sin_addr; 887 break; 888 case IFF_LOOPBACK: 889 in = ((struct sockaddr_in *)(void *)ifa->ifa_addr)->sin_addr; 890 break; 891 default: 892 continue; 893 } 894 895 bindsin.sin_addr = in; 896 #ifdef DEBUG 897 if (debug) 898 (void)printf("broadcast %x\n", 899 bindsin.sin_addr.s_addr); 900 #endif 901 if (sendto(rpcsock, buf, outlen, 0, 902 (struct sockaddr *)(void *)&bindsin, 903 (socklen_t)bindsin.sin_len) == -1) 904 yp_log(LOG_WARNING, "broadcast: sendto: %m"); 905 } 906 freeifaddrs(ifap); 907 return (0); 908 } 909 910 static int 911 direct(char *buf, int outlen) 912 { 913 static FILE *df; 914 static char ypservers_path[MAXPATHLEN]; 915 char line[_POSIX2_LINE_MAX]; 916 char *p; 917 struct hostent *hp; 918 struct sockaddr_in bindsin; 919 int i, count = 0; 920 921 if (df) 922 rewind(df); 923 else { 924 (void)snprintf(ypservers_path, sizeof(ypservers_path), 925 "%s/%s%s", BINDINGDIR, domainname, YPSERVERSSUFF); 926 df = fopen(ypservers_path, "r"); 927 if (df == NULL) { 928 yp_log(LOG_ERR, "%s: ", ypservers_path); 929 exit(1); 930 } 931 } 932 933 (void)memset(&bindsin, 0, sizeof bindsin); 934 bindsin.sin_family = AF_INET; 935 bindsin.sin_len = sizeof(bindsin); 936 bindsin.sin_port = htons(PMAPPORT); 937 938 while(fgets(line, (int)sizeof(line), df) != NULL) { 939 /* skip lines that are too big */ 940 p = strchr(line, '\n'); 941 if (p == NULL) { 942 int c; 943 944 while ((c = getc(df)) != '\n' && c != EOF) 945 ; 946 continue; 947 } 948 *p = '\0'; 949 p = line; 950 while (isspace((unsigned char)*p)) 951 p++; 952 if (*p == '#') 953 continue; 954 hp = gethostbyname(p); 955 if (!hp) { 956 yp_log(LOG_WARNING, "%s: %s", p, hstrerror(h_errno)); 957 continue; 958 } 959 /* step through all addresses in case first is unavailable */ 960 for (i = 0; hp->h_addr_list[i]; i++) { 961 (void)memcpy(&bindsin.sin_addr, hp->h_addr_list[0], 962 hp->h_length); 963 if (sendto(rpcsock, buf, outlen, 0, 964 (struct sockaddr *)(void *)&bindsin, 965 (socklen_t)sizeof(bindsin)) < 0) { 966 yp_log(LOG_WARNING, "direct: sendto: %m"); 967 continue; 968 } else 969 count++; 970 } 971 } 972 if (!count) { 973 yp_log(LOG_WARNING, "no contactable servers found in %s", 974 ypservers_path); 975 return -1; 976 } 977 return 0; 978 } 979 980 static int 981 direct_set(char *buf, int outlen, struct _dom_binding *ypdb) 982 { 983 struct sockaddr_in bindsin; 984 char path[MAXPATHLEN]; 985 struct iovec iov[2]; 986 struct ypbind_resp ybr; 987 SVCXPRT dummy_svc; 988 int fd; 989 ssize_t bytes; 990 991 /* 992 * Gack, we lose if binding file went away. We reset 993 * "been_set" if this happens, otherwise we'll never 994 * bind again. 995 */ 996 (void)snprintf(path, sizeof(path), "%s/%s.%ld", BINDINGDIR, 997 ypdb->dom_domain, ypdb->dom_vers); 998 999 if ((fd = open(path, O_SHLOCK|O_RDONLY, 0644)) == -1) { 1000 yp_log(LOG_WARNING, "%s: %m", path); 1001 been_ypset = 0; 1002 return -1; 1003 } 1004 1005 #if O_SHLOCK == 0 1006 (void)flock(fd, LOCK_SH); 1007 #endif 1008 1009 /* Read the binding file... */ 1010 iov[0].iov_base = &(dummy_svc.xp_port); 1011 iov[0].iov_len = sizeof(dummy_svc.xp_port); 1012 iov[1].iov_base = &ybr; 1013 iov[1].iov_len = sizeof(ybr); 1014 bytes = readv(fd, iov, 2); 1015 (void)close(fd); 1016 if ((size_t)bytes != (iov[0].iov_len + iov[1].iov_len)) { 1017 /* Binding file corrupt? */ 1018 yp_log(LOG_WARNING, "%s: %m", path); 1019 been_ypset = 0; 1020 return -1; 1021 } 1022 1023 bindsin.sin_addr = 1024 ybr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr; 1025 1026 if (sendto(rpcsock, buf, outlen, 0, 1027 (struct sockaddr *)(void *)&bindsin, 1028 (socklen_t)sizeof(bindsin)) < 0) { 1029 yp_log(LOG_WARNING, "direct_set: sendto: %m"); 1030 return -1; 1031 } 1032 1033 return 0; 1034 } 1035 1036 static enum clnt_stat 1037 handle_replies(void) 1038 { 1039 char buf[BUFSIZE]; 1040 socklen_t fromlen; 1041 ssize_t inlen; 1042 struct _dom_binding *ypdb; 1043 struct sockaddr_in raddr; 1044 struct rpc_msg msg; 1045 XDR xdr; 1046 1047 recv_again: 1048 #ifdef DEBUG 1049 if (debug) 1050 printf("handle_replies receiving\n"); 1051 #endif 1052 (void)memset(&xdr, 0, sizeof(xdr)); 1053 (void)memset(&msg, 0, sizeof(msg)); 1054 msg.acpted_rply.ar_verf = _null_auth; 1055 msg.acpted_rply.ar_results.where = (caddr_t)(void *)&rmtcr; 1056 msg.acpted_rply.ar_results.proc = xdr_rmtcallres; 1057 1058 try_again: 1059 fromlen = sizeof(struct sockaddr); 1060 inlen = recvfrom(rpcsock, buf, sizeof buf, 0, 1061 (struct sockaddr *)(void *)&raddr, &fromlen); 1062 if (inlen < 0) { 1063 if (errno == EINTR) 1064 goto try_again; 1065 #ifdef DEBUG 1066 if (debug) 1067 printf("handle_replies: recvfrom failed (%s)\n", 1068 strerror(errno)); 1069 #endif 1070 return RPC_CANTRECV; 1071 } 1072 if ((size_t)inlen < sizeof(u_int32_t)) 1073 goto recv_again; 1074 1075 /* 1076 * see if reply transaction id matches sent id. 1077 * If so, decode the results. 1078 */ 1079 xdrmem_create(&xdr, buf, (u_int)inlen, XDR_DECODE); 1080 if (xdr_replymsg(&xdr, &msg)) { 1081 if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) && 1082 (msg.acpted_rply.ar_stat == SUCCESS)) { 1083 raddr.sin_port = htons((u_short)rmtcr_port); 1084 ypdb = xid2ypdb(msg.rm_xid); 1085 if (ypdb != NULL) 1086 rpc_received(ypdb->dom_domain, &raddr, 0); 1087 } 1088 } 1089 xdr.x_op = XDR_FREE; 1090 msg.acpted_rply.ar_results.proc = xdr_void; 1091 xdr_destroy(&xdr); 1092 1093 return RPC_SUCCESS; 1094 } 1095 1096 static enum clnt_stat 1097 handle_ping(void) 1098 { 1099 char buf[BUFSIZE]; 1100 socklen_t fromlen; 1101 ssize_t inlen; 1102 struct _dom_binding *ypdb; 1103 struct sockaddr_in raddr; 1104 struct rpc_msg msg; 1105 XDR xdr; 1106 bool_t res; 1107 1108 recv_again: 1109 #ifdef DEBUG 1110 if (debug) 1111 printf("handle_ping receiving\n"); 1112 #endif 1113 (void)memset(&xdr, 0, sizeof(xdr)); 1114 (void)memset(&msg, 0, sizeof(msg)); 1115 msg.acpted_rply.ar_verf = _null_auth; 1116 msg.acpted_rply.ar_results.where = (caddr_t)(void *)&res; 1117 msg.acpted_rply.ar_results.proc = xdr_bool; 1118 1119 try_again: 1120 fromlen = sizeof (struct sockaddr); 1121 inlen = recvfrom(pingsock, buf, sizeof buf, 0, 1122 (struct sockaddr *)(void *)&raddr, &fromlen); 1123 if (inlen < 0) { 1124 if (errno == EINTR) 1125 goto try_again; 1126 #ifdef DEBUG 1127 if (debug) 1128 printf("handle_ping: recvfrom failed (%s)\n", 1129 strerror(errno)); 1130 #endif 1131 return RPC_CANTRECV; 1132 } 1133 if ((size_t)inlen < sizeof(u_int32_t)) 1134 goto recv_again; 1135 1136 /* 1137 * see if reply transaction id matches sent id. 1138 * If so, decode the results. 1139 */ 1140 xdrmem_create(&xdr, buf, (u_int)inlen, XDR_DECODE); 1141 if (xdr_replymsg(&xdr, &msg)) { 1142 if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) && 1143 (msg.acpted_rply.ar_stat == SUCCESS)) { 1144 ypdb = xid2ypdb(msg.rm_xid); 1145 if (ypdb != NULL) 1146 rpc_received(ypdb->dom_domain, &raddr, 0); 1147 } 1148 } 1149 xdr.x_op = XDR_FREE; 1150 msg.acpted_rply.ar_results.proc = xdr_void; 1151 xdr_destroy(&xdr); 1152 1153 return RPC_SUCCESS; 1154 } 1155 1156 /* 1157 * LOOPBACK IS MORE IMPORTANT: PUT IN HACK 1158 */ 1159 void 1160 rpc_received(char *dom, struct sockaddr_in *raddrp, int force) 1161 { 1162 struct _dom_binding *ypdb; 1163 struct iovec iov[2]; 1164 struct ypbind_resp ybr; 1165 int fd; 1166 1167 #ifdef DEBUG 1168 if (debug) 1169 (void)printf("returned from %s about %s\n", 1170 inet_ntoa(raddrp->sin_addr), dom); 1171 #endif 1172 1173 if (dom == NULL) 1174 return; 1175 1176 if (_yp_invalid_domain(dom)) 1177 return; 1178 1179 /* don't support insecure servers by default */ 1180 if (!insecure && ntohs(raddrp->sin_port) >= IPPORT_RESERVED) 1181 return; 1182 1183 for (ypdb = ypbindlist; ypdb; ypdb = ypdb->dom_pnext) 1184 if (!strcmp(ypdb->dom_domain, dom)) 1185 break; 1186 1187 if (ypdb == NULL) { 1188 if (force == 0) 1189 return; 1190 ypdb = makebinding(dom); 1191 ypdb->dom_lockfd = -1; 1192 ypdb->dom_pnext = ypbindlist; 1193 ypbindlist = ypdb; 1194 } 1195 1196 /* soft update, alive */ 1197 if (ypdb->dom_alive == 1 && force == 0) { 1198 if (!memcmp(&ypdb->dom_server_addr, raddrp, 1199 sizeof ypdb->dom_server_addr)) { 1200 ypdb->dom_alive = 1; 1201 /* recheck binding in 60 sec */ 1202 ypdb->dom_check_t = time(NULL) + 60; 1203 } 1204 return; 1205 } 1206 1207 (void)memcpy(&ypdb->dom_server_addr, raddrp, 1208 sizeof ypdb->dom_server_addr); 1209 /* recheck binding in 60 seconds */ 1210 ypdb->dom_check_t = time(NULL) + 60; 1211 ypdb->dom_vers = YPVERS; 1212 ypdb->dom_alive = 1; 1213 1214 if (ypdb->dom_lockfd != -1) 1215 (void)close(ypdb->dom_lockfd); 1216 1217 if ((fd = makelock(ypdb)) == -1) 1218 return; 1219 1220 /* 1221 * ok, if BINDINGDIR exists, and we can create the binding file, 1222 * then write to it.. 1223 */ 1224 ypdb->dom_lockfd = fd; 1225 1226 iov[0].iov_base = &(udptransp->xp_port); 1227 iov[0].iov_len = sizeof udptransp->xp_port; 1228 iov[1].iov_base = &ybr; 1229 iov[1].iov_len = sizeof ybr; 1230 1231 (void)memset(&ybr, 0, sizeof ybr); 1232 ybr.ypbind_status = YPBIND_SUCC_VAL; 1233 ybr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr = 1234 raddrp->sin_addr; 1235 ybr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port = 1236 raddrp->sin_port; 1237 1238 if ((size_t)writev(ypdb->dom_lockfd, iov, 2) != 1239 iov[0].iov_len + iov[1].iov_len) { 1240 yp_log(LOG_WARNING, "writev: %m"); 1241 (void)close(ypdb->dom_lockfd); 1242 removelock(ypdb); 1243 ypdb->dom_lockfd = -1; 1244 } 1245 } 1246 1247 static struct _dom_binding * 1248 xid2ypdb(u_int32_t xid) 1249 { 1250 struct _dom_binding *ypdb; 1251 1252 for (ypdb = ypbindlist; ypdb; ypdb = ypdb->dom_pnext) 1253 if (ypdb->dom_xid == xid) 1254 break; 1255 return (ypdb); 1256 } 1257 1258 static u_int32_t 1259 unique_xid(struct _dom_binding *ypdb) 1260 { 1261 u_int32_t tmp_xid; 1262 1263 tmp_xid = ((u_int32_t)(u_long)ypdb) & 0xffffffff; 1264 while (xid2ypdb(tmp_xid) != NULL) 1265 tmp_xid++; 1266 1267 return tmp_xid; 1268 } 1269