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