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