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