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