1 /* 2 * Copyright (c) 1992, 1993 Theo de Raadt <deraadt@fsa.ca> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Theo de Raadt. 16 * 4. The name of the author may not be used to endorse or promote 17 * products derived from this software without specific prior written 18 * permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 21 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 24 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #ifndef LINT 34 static char rcsid[] = "$Id: ypbind.c,v 1.13 1994/09/28 01:39:54 deraadt Exp $"; 35 #endif 36 37 #include <sys/param.h> 38 #include <sys/types.h> 39 #include <sys/ioctl.h> 40 #include <sys/signal.h> 41 #include <sys/socket.h> 42 #include <sys/file.h> 43 #include <sys/fcntl.h> 44 #include <sys/uio.h> 45 #include <sys/syslog.h> 46 #include <stdio.h> 47 #include <errno.h> 48 #include <ctype.h> 49 #include <dirent.h> 50 #include <netdb.h> 51 #include <string.h> 52 #include <rpc/rpc.h> 53 #include <rpc/xdr.h> 54 #include <net/if.h> 55 #include <arpa/inet.h> 56 #include <rpc/pmap_clnt.h> 57 #include <rpc/pmap_prot.h> 58 #include <rpc/pmap_rmt.h> 59 #include <unistd.h> 60 #include <rpcsvc/yp_prot.h> 61 #include <rpcsvc/ypclnt.h> 62 63 #define BINDINGDIR "/var/yp/binding" 64 #define YPBINDLOCK "/var/run/ypbind.lock" 65 66 struct _dom_binding { 67 struct _dom_binding *dom_pnext; 68 char dom_domain[YPMAXDOMAIN + 1]; 69 struct sockaddr_in dom_server_addr; 70 unsigned short int dom_server_port; 71 int dom_socket; 72 CLIENT *dom_client; 73 long int dom_vers; 74 time_t dom_check_t; 75 time_t dom_ask_t; 76 int dom_lockfd; 77 int dom_alive; 78 }; 79 80 extern bool_t xdr_domainname(), xdr_ypbind_resp(); 81 extern bool_t xdr_ypreq_key(), xdr_ypresp_val(); 82 extern bool_t xdr_ypbind_setdom(); 83 84 char *domainname; 85 86 struct _dom_binding *ypbindlist; 87 int check; 88 89 #define YPSET_NO 0 90 #define YPSET_LOCAL 1 91 #define YPSET_ALL 2 92 int ypsetmode = YPSET_NO; 93 94 int rpcsock, pingsock; 95 struct rmtcallargs rmtca; 96 struct rmtcallres rmtcr; 97 char rmtcr_outval; 98 u_long rmtcr_port; 99 SVCXPRT *udptransp, *tcptransp; 100 101 void * 102 ypbindproc_null_2(transp, argp, clnt) 103 SVCXPRT *transp; 104 void *argp; 105 CLIENT *clnt; 106 { 107 static char res; 108 109 bzero((char *)&res, sizeof(res)); 110 return (void *)&res; 111 } 112 113 struct ypbind_resp * 114 ypbindproc_domain_2(transp, argp, clnt) 115 SVCXPRT *transp; 116 char *argp; 117 CLIENT *clnt; 118 { 119 static struct ypbind_resp res; 120 struct _dom_binding *ypdb; 121 char path[MAXPATHLEN]; 122 time_t now; 123 124 bzero((char *)&res, sizeof res); 125 res.ypbind_status = YPBIND_FAIL_VAL; 126 127 for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) 128 if( strcmp(ypdb->dom_domain, argp) == 0) 129 break; 130 131 if(ypdb==NULL) { 132 ypdb = (struct _dom_binding *)malloc(sizeof *ypdb); 133 bzero((char *)ypdb, sizeof *ypdb); 134 strncpy(ypdb->dom_domain, argp, sizeof ypdb->dom_domain); 135 ypdb->dom_vers = YPVERS; 136 ypdb->dom_alive = 0; 137 ypdb->dom_lockfd = -1; 138 sprintf(path, "%s/%s.%d", BINDINGDIR, ypdb->dom_domain, ypdb->dom_vers); 139 unlink(path); 140 ypdb->dom_pnext = ypbindlist; 141 ypbindlist = ypdb; 142 check++; 143 return NULL; 144 } 145 146 if(ypdb->dom_alive==0) 147 return NULL; 148 149 #ifdef HEURISTIC 150 time(&now); 151 if (now < ypdb->dom_ask_t + 5) { 152 /* 153 * Hmm. More than 2 requests in 5 seconds have indicated 154 * that my binding is possibly incorrect. 155 * Ok, do an immediate poll of the server. 156 */ 157 if (ypdb->dom_check_t >= now) { 158 /* don't flood it */ 159 ypdb->dom_check_t = 0; 160 check++; 161 } 162 } 163 ypdb->dom_ask_t = now; 164 #endif 165 166 answer: 167 res.ypbind_status = YPBIND_SUCC_VAL; 168 res.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr.s_addr = 169 ypdb->dom_server_addr.sin_addr.s_addr; 170 res.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port = 171 ypdb->dom_server_port; 172 /*printf("domain %s at %s/%d\n", ypdb->dom_domain, 173 inet_ntoa(ypdb->dom_server_addr.sin_addr), 174 ntohs(ypdb->dom_server_addr.sin_port));*/ 175 return &res; 176 } 177 178 bool_t * 179 ypbindproc_setdom_2(transp, argp, clnt) 180 SVCXPRT *transp; 181 struct ypbind_setdom *argp; 182 CLIENT *clnt; 183 { 184 struct sockaddr_in *fromsin, bindsin; 185 static bool_t res; 186 187 bzero((char *)&res, sizeof(res)); 188 fromsin = svc_getcaller(transp); 189 190 switch(ypsetmode) { 191 case YPSET_LOCAL: 192 if( fromsin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) 193 return (bool_t *)NULL; 194 break; 195 case YPSET_ALL: 196 break; 197 case YPSET_NO: 198 default: 199 return (bool_t *)NULL; 200 } 201 202 if(ntohs(fromsin->sin_port) >= IPPORT_RESERVED) 203 return &res; 204 205 if(argp->ypsetdom_vers != YPVERS) 206 return &res; 207 208 bzero((char *)&bindsin, sizeof bindsin); 209 bindsin.sin_family = AF_INET; 210 bindsin.sin_addr.s_addr = argp->ypsetdom_addr.s_addr; 211 bindsin.sin_port = argp->ypsetdom_port; 212 rpc_received(argp->ypsetdom_domain, &bindsin, 1); 213 214 res = 1; 215 return &res; 216 } 217 218 static void 219 ypbindprog_2(rqstp, transp) 220 struct svc_req *rqstp; 221 register SVCXPRT *transp; 222 { 223 union { 224 char ypbindproc_domain_2_arg[MAXHOSTNAMELEN]; 225 struct ypbind_setdom ypbindproc_setdom_2_arg; 226 } argument; 227 struct authunix_parms *creds; 228 char *result; 229 bool_t (*xdr_argument)(), (*xdr_result)(); 230 char *(*local)(); 231 232 switch (rqstp->rq_proc) { 233 case YPBINDPROC_NULL: 234 xdr_argument = xdr_void; 235 xdr_result = xdr_void; 236 local = (char *(*)()) ypbindproc_null_2; 237 break; 238 239 case YPBINDPROC_DOMAIN: 240 xdr_argument = xdr_domainname; 241 xdr_result = xdr_ypbind_resp; 242 local = (char *(*)()) ypbindproc_domain_2; 243 break; 244 245 case YPBINDPROC_SETDOM: 246 switch(rqstp->rq_cred.oa_flavor) { 247 case AUTH_UNIX: 248 creds = (struct authunix_parms *)rqstp->rq_clntcred; 249 if( creds->aup_uid != 0) { 250 svcerr_auth(transp, AUTH_BADCRED); 251 return; 252 } 253 break; 254 default: 255 svcerr_auth(transp, AUTH_TOOWEAK); 256 return; 257 } 258 259 xdr_argument = xdr_ypbind_setdom; 260 xdr_result = xdr_void; 261 local = (char *(*)()) ypbindproc_setdom_2; 262 break; 263 264 default: 265 svcerr_noproc(transp); 266 return; 267 } 268 bzero((char *)&argument, sizeof(argument)); 269 if (!svc_getargs(transp, xdr_argument, &argument)) { 270 svcerr_decode(transp); 271 return; 272 } 273 result = (*local)(transp, &argument, rqstp); 274 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { 275 svcerr_systemerr(transp); 276 } 277 return; 278 } 279 280 main(argc, argv) 281 char **argv; 282 { 283 char path[MAXPATHLEN]; 284 struct timeval tv; 285 fd_set fdsr; 286 int width, lockfd; 287 int i; 288 289 yp_get_default_domain(&domainname); 290 if( domainname[0] == '\0') { 291 fprintf(stderr, "domainname not set. Aborting.\n"); 292 exit(1); 293 } 294 295 for(i=1; i<argc; i++) { 296 if( strcmp("-ypset", argv[i]) == 0) 297 ypsetmode = YPSET_ALL; 298 else if (strcmp("-ypsetme", argv[i]) == 0) 299 ypsetmode = YPSET_LOCAL; 300 } 301 302 /* blow away everything in BINDINGDIR */ 303 304 #ifdef O_SHLOCK 305 lockfd = open(YPBINDLOCK, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644); 306 if (lockfd == -1) { 307 fprintf(stderr, "ypbind: cannot create %s\n", YPBINDLOCK); 308 exit(1); 309 } 310 #else 311 lockfd = open(YPBINDLOCK, O_CREAT|O_RDWR|O_TRUNC, 0644); 312 if (lockfd == -1) { 313 fprintf(stderr, "ypbind: cannot create %s\n", YPBINDLOCK); 314 exit(1); 315 } 316 flock(lockfd, LOCK_SH); 317 #endif 318 319 #ifdef DAEMON 320 switch(fork()) { 321 case 0: 322 break; 323 case -1: 324 perror("fork"); 325 exit(1); 326 default: 327 exit(0); 328 } 329 setsid(); 330 #endif 331 332 pmap_unset(YPBINDPROG, YPBINDVERS); 333 334 udptransp = svcudp_create(RPC_ANYSOCK); 335 if (udptransp == NULL) { 336 fprintf(stderr, "cannot create udp service."); 337 exit(1); 338 } 339 if (!svc_register(udptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2, 340 IPPROTO_UDP)) { 341 fprintf(stderr, "unable to register (YPBINDPROG, YPBINDVERS, udp)."); 342 exit(1); 343 } 344 345 tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0); 346 if (tcptransp == NULL) { 347 fprintf(stderr, "cannot create tcp service."); 348 exit(1); 349 } 350 351 if (!svc_register(tcptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2, 352 IPPROTO_TCP)) { 353 fprintf(stderr, "unable to register (YPBINDPROG, YPBINDVERS, tcp)."); 354 exit(1); 355 } 356 357 if( (rpcsock=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { 358 perror("socket"); 359 return -1; 360 } 361 if( (pingsock=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { 362 perror("socket"); 363 return -1; 364 } 365 366 fcntl(rpcsock, F_SETFL, fcntl(rpcsock, F_GETFL, 0) | FNDELAY); 367 fcntl(pingsock, F_SETFL, fcntl(rpcsock, F_GETFL, 0) | FNDELAY); 368 i = 1; 369 setsockopt(rpcsock, SOL_SOCKET, SO_BROADCAST, &i, sizeof(i)); 370 rmtca.prog = YPPROG; 371 rmtca.vers = YPVERS; 372 rmtca.proc = YPPROC_DOMAIN_NONACK; 373 rmtca.xdr_args = NULL; /* set at call time */ 374 rmtca.args_ptr = NULL; /* set at call time */ 375 rmtcr.port_ptr = &rmtcr_port; 376 rmtcr.xdr_results = xdr_bool; 377 rmtcr.results_ptr = (caddr_t)&rmtcr_outval; 378 379 /* build initial domain binding, make it "unsuccessful" */ 380 ypbindlist = (struct _dom_binding *)malloc(sizeof *ypbindlist); 381 bzero((char *)ypbindlist, sizeof *ypbindlist); 382 strncpy(ypbindlist->dom_domain, domainname, sizeof ypbindlist->dom_domain); 383 ypbindlist->dom_vers = YPVERS; 384 ypbindlist->dom_alive = 0; 385 ypbindlist->dom_lockfd = -1; 386 sprintf(path, "%s/%s.%d", BINDINGDIR, ypbindlist->dom_domain, 387 ypbindlist->dom_vers); 388 (void)unlink(path); 389 390 checkwork(); 391 392 width = getdtablesize(); 393 while(1) { 394 fdsr = svc_fdset; 395 FD_SET(rpcsock, &fdsr); 396 FD_SET(pingsock, &fdsr); 397 tv.tv_sec = 1; 398 tv.tv_usec = 0; 399 400 switch(select(width, &fdsr, NULL, NULL, &tv)) { 401 case 0: 402 checkwork(); 403 break; 404 case -1: 405 perror("select\n"); 406 break; 407 default: 408 if(FD_ISSET(rpcsock, &fdsr)) { 409 FD_CLR(rpcsock, &fdsr); 410 handle_replies(); 411 } 412 if (FD_ISSET(pingsock, &fdsr)) { 413 FD_CLR(pingsock, &fdsr); 414 handle_ping(); 415 } 416 svc_getreqset(&fdsr); 417 if(check) 418 checkwork(); 419 break; 420 } 421 } 422 } 423 424 /* 425 * State transition is done like this: 426 * 427 * STATE EVENT ACTION NEWSTATE TIMEOUT 428 * no binding timeout broadcast no binding 5 sec 429 * no binding answer -- binding 60 sec 430 * binding timeout ping server checking 5 sec 431 * checking timeout ping server + broadcast checking 5 sec 432 * checking answer -- binding 60 sec 433 */ 434 checkwork() 435 { 436 struct _dom_binding *ypdb; 437 time_t t; 438 439 check = 0; 440 441 time(&t); 442 for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) { 443 if(ypdb->dom_check_t < t) { 444 if (ypdb->dom_alive == 1) 445 ping(ypdb); 446 else 447 broadcast(ypdb); 448 time(&t); 449 ypdb->dom_check_t = t + 5; 450 } 451 } 452 } 453 454 ping(ypdb) 455 struct _dom_binding *ypdb; 456 { 457 char *dom = ypdb->dom_domain; 458 struct rpc_msg rpcmsg; 459 char buf[1400]; 460 enum clnt_stat st; 461 int outlen; 462 AUTH *rpcua; 463 XDR rpcxdr; 464 465 bzero((char *)&rpcxdr, sizeof rpcxdr); 466 bzero((char *)&rpcmsg, sizeof rpcmsg); 467 468 rpcua = authunix_create_default(); 469 if( rpcua == (AUTH *)NULL) { 470 /*printf("cannot get unix auth\n");*/ 471 return RPC_SYSTEMERROR; 472 } 473 rpcmsg.rm_direction = CALL; 474 rpcmsg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 475 rpcmsg.rm_call.cb_prog = YPPROG; 476 rpcmsg.rm_call.cb_vers = YPVERS; 477 rpcmsg.rm_call.cb_proc = YPPROC_DOMAIN_NONACK; 478 rpcmsg.rm_call.cb_cred = rpcua->ah_cred; 479 rpcmsg.rm_call.cb_verf = rpcua->ah_verf; 480 481 rpcmsg.rm_xid = (int)dom; 482 xdrmem_create(&rpcxdr, buf, sizeof buf, XDR_ENCODE); 483 if( (!xdr_callmsg(&rpcxdr, &rpcmsg)) ) { 484 st = RPC_CANTENCODEARGS; 485 AUTH_DESTROY(rpcua); 486 return st; 487 } 488 if( (!xdr_domainname(&rpcxdr, dom)) ) { 489 st = RPC_CANTENCODEARGS; 490 AUTH_DESTROY(rpcua); 491 return st; 492 } 493 outlen = (int)xdr_getpos(&rpcxdr); 494 xdr_destroy(&rpcxdr); 495 if(outlen<1) { 496 st = RPC_CANTENCODEARGS; 497 AUTH_DESTROY(rpcua); 498 return st; 499 } 500 AUTH_DESTROY(rpcua); 501 502 ypdb->dom_alive = 2; 503 if (sendto(pingsock, buf, outlen, 0, 504 (struct sockaddr *)&ypdb->dom_server_addr, 505 sizeof ypdb->dom_server_addr) < 0) 506 perror("sendto"); 507 return 0; 508 509 } 510 511 broadcast(ypdb) 512 struct _dom_binding *ypdb; 513 { 514 char *dom = ypdb->dom_domain; 515 struct rpc_msg rpcmsg; 516 char buf[1400], inbuf[8192]; 517 char path[MAXPATHLEN]; 518 enum clnt_stat st; 519 int outlen, i, sock, len; 520 struct sockaddr_in bsin; 521 struct ifconf ifc; 522 struct ifreq ifreq, *ifr; 523 struct in_addr in; 524 AUTH *rpcua; 525 XDR rpcxdr; 526 527 rmtca.xdr_args = xdr_domainname; 528 rmtca.args_ptr = dom; 529 530 bzero((char *)&rpcxdr, sizeof rpcxdr); 531 bzero((char *)&rpcmsg, sizeof rpcmsg); 532 533 rpcua = authunix_create_default(); 534 if( rpcua == (AUTH *)NULL) { 535 /*printf("cannot get unix auth\n");*/ 536 return RPC_SYSTEMERROR; 537 } 538 rpcmsg.rm_direction = CALL; 539 rpcmsg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 540 rpcmsg.rm_call.cb_prog = PMAPPROG; 541 rpcmsg.rm_call.cb_vers = PMAPVERS; 542 rpcmsg.rm_call.cb_proc = PMAPPROC_CALLIT; 543 rpcmsg.rm_call.cb_cred = rpcua->ah_cred; 544 rpcmsg.rm_call.cb_verf = rpcua->ah_verf; 545 546 rpcmsg.rm_xid = (int)dom; 547 xdrmem_create(&rpcxdr, buf, sizeof buf, XDR_ENCODE); 548 if( (!xdr_callmsg(&rpcxdr, &rpcmsg)) ) { 549 st = RPC_CANTENCODEARGS; 550 AUTH_DESTROY(rpcua); 551 return st; 552 } 553 if( (!xdr_rmtcall_args(&rpcxdr, &rmtca)) ) { 554 st = RPC_CANTENCODEARGS; 555 AUTH_DESTROY(rpcua); 556 return st; 557 } 558 outlen = (int)xdr_getpos(&rpcxdr); 559 xdr_destroy(&rpcxdr); 560 if(outlen<1) { 561 st = RPC_CANTENCODEARGS; 562 AUTH_DESTROY(rpcua); 563 return st; 564 } 565 AUTH_DESTROY(rpcua); 566 567 if(ypdb->dom_lockfd!=-1) { 568 close(ypdb->dom_lockfd); 569 ypdb->dom_lockfd = -1; 570 sprintf(path, "%s/%s.%d", BINDINGDIR, 571 ypdb->dom_domain, ypdb->dom_vers); 572 unlink(path); 573 } 574 575 bzero((char *)&bsin, sizeof bsin); 576 bsin.sin_family = AF_INET; 577 bsin.sin_port = htons(PMAPPORT); 578 579 if (ypdb->dom_alive == 2) { 580 /* 581 * This resolves the following situation: 582 * ypserver on other subnet was once bound, 583 * but rebooted and is now using a different port 584 */ 585 bsin.sin_addr = ypdb->dom_server_addr.sin_addr; 586 if (sendto(rpcsock, buf, outlen, 0, (struct sockaddr *)&bsin, 587 sizeof bsin) < 0) 588 perror("sendto"); 589 } 590 /* find all networks and send the RPC packet out them all */ 591 if( (sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { 592 perror("socket"); 593 return -1; 594 } 595 596 ifc.ifc_len = sizeof inbuf; 597 ifc.ifc_buf = inbuf; 598 if( ioctl(sock, SIOCGIFCONF, &ifc) < 0) { 599 close(sock); 600 perror("ioctl(SIOCGIFCONF)"); 601 return -1; 602 } 603 ifr = ifc.ifc_req; 604 ifreq.ifr_name[0] = '\0'; 605 for(i=0; i<ifc.ifc_len; i+=len, ifr=(struct ifreq *)((caddr_t)ifr+len)) { 606 #if defined(BSD) && BSD >= 199103 607 len = sizeof ifr->ifr_name + ifr->ifr_addr.sa_len; 608 #else 609 len = sizeof ifc.ifc_len / sizeof(struct ifreq); 610 #endif 611 ifreq = *ifr; 612 if( ifreq.ifr_addr.sa_family != AF_INET) 613 continue; 614 if( ioctl(sock, SIOCGIFFLAGS, &ifreq) < 0) { 615 perror("ioctl(SIOCGIFFLAGS)"); 616 continue; 617 } 618 if( (ifreq.ifr_flags & IFF_UP) == 0) 619 continue; 620 621 ifreq.ifr_flags &= (IFF_LOOPBACK | IFF_BROADCAST); 622 if( ifreq.ifr_flags==IFF_BROADCAST ) { 623 if( ioctl(sock, SIOCGIFBRDADDR, &ifreq) < 0 ) { 624 perror("ioctl(SIOCGIFBRDADDR)"); 625 continue; 626 } 627 } else if( ifreq.ifr_flags==IFF_LOOPBACK ) { 628 if( ioctl(sock, SIOCGIFADDR, &ifreq) < 0 ) { 629 perror("ioctl(SIOCGIFADDR)"); 630 continue; 631 } 632 } else 633 continue; 634 635 in = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr; 636 bsin.sin_addr = in; 637 if( sendto(rpcsock, buf, outlen, 0, (struct sockaddr *)&bsin, 638 sizeof bsin) < 0 ) 639 perror("sendto"); 640 } 641 close(sock); 642 return 0; 643 } 644 645 /*enum clnt_stat*/ 646 handle_replies() 647 { 648 char buf[1400]; 649 int fromlen, inlen; 650 struct sockaddr_in raddr; 651 struct rpc_msg msg; 652 XDR xdr; 653 654 recv_again: 655 bzero((char *)&xdr, sizeof(xdr)); 656 bzero((char *)&msg, sizeof(msg)); 657 msg.acpted_rply.ar_verf = _null_auth; 658 msg.acpted_rply.ar_results.where = (caddr_t)&rmtcr; 659 msg.acpted_rply.ar_results.proc = xdr_rmtcallres; 660 661 try_again: 662 fromlen = sizeof (struct sockaddr); 663 inlen = recvfrom(rpcsock, buf, sizeof buf, 0, 664 (struct sockaddr *)&raddr, &fromlen); 665 if(inlen<0) { 666 if(errno==EINTR) 667 goto try_again; 668 return RPC_CANTRECV; 669 } 670 if(inlen<sizeof(u_long)) 671 goto recv_again; 672 673 /* 674 * see if reply transaction id matches sent id. 675 * If so, decode the results. 676 */ 677 xdrmem_create(&xdr, buf, (u_int)inlen, XDR_DECODE); 678 if( xdr_replymsg(&xdr, &msg)) { 679 if( (msg.rm_reply.rp_stat == MSG_ACCEPTED) && 680 (msg.acpted_rply.ar_stat == SUCCESS)) { 681 raddr.sin_port = htons((u_short)rmtcr_port); 682 rpc_received(msg.rm_xid, &raddr, 0); 683 } 684 } 685 xdr.x_op = XDR_FREE; 686 msg.acpted_rply.ar_results.proc = xdr_void; 687 xdr_destroy(&xdr); 688 689 return RPC_SUCCESS; 690 } 691 692 /*enum clnt_stat*/ 693 handle_ping() 694 { 695 char buf[1400]; 696 int fromlen, inlen; 697 struct sockaddr_in raddr; 698 struct rpc_msg msg; 699 XDR xdr; 700 bool_t res; 701 702 recv_again: 703 bzero((char *)&xdr, sizeof(xdr)); 704 bzero((char *)&msg, sizeof(msg)); 705 msg.acpted_rply.ar_verf = _null_auth; 706 msg.acpted_rply.ar_results.where = (caddr_t)&res; 707 msg.acpted_rply.ar_results.proc = xdr_bool; 708 709 try_again: 710 fromlen = sizeof (struct sockaddr); 711 inlen = recvfrom(pingsock, buf, sizeof buf, 0, 712 (struct sockaddr *)&raddr, &fromlen); 713 if(inlen<0) { 714 if(errno==EINTR) 715 goto try_again; 716 return RPC_CANTRECV; 717 } 718 if(inlen<sizeof(u_long)) 719 goto recv_again; 720 721 /* 722 * see if reply transaction id matches sent id. 723 * If so, decode the results. 724 */ 725 xdrmem_create(&xdr, buf, (u_int)inlen, XDR_DECODE); 726 if( xdr_replymsg(&xdr, &msg)) { 727 if( (msg.rm_reply.rp_stat == MSG_ACCEPTED) && 728 (msg.acpted_rply.ar_stat == SUCCESS)) { 729 rpc_received(msg.rm_xid, &raddr, 0); 730 } 731 } 732 xdr.x_op = XDR_FREE; 733 msg.acpted_rply.ar_results.proc = xdr_void; 734 xdr_destroy(&xdr); 735 736 return RPC_SUCCESS; 737 } 738 739 /* 740 * LOOPBACK IS MORE IMPORTANT: PUT IN HACK 741 */ 742 rpc_received(dom, raddrp, force) 743 char *dom; 744 struct sockaddr_in *raddrp; 745 int force; 746 { 747 struct _dom_binding *ypdb; 748 struct iovec iov[2]; 749 struct ypbind_resp ybr; 750 char path[MAXPATHLEN]; 751 int fd; 752 753 /*printf("returned from %s about %s\n", inet_ntoa(raddrp->sin_addr), dom);*/ 754 755 if(dom==NULL) 756 return; 757 758 for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) 759 if( strcmp(ypdb->dom_domain, dom) == 0) 760 break; 761 762 if(ypdb==NULL) { 763 if(force==0) 764 return; 765 ypdb = (struct _dom_binding *)malloc(sizeof *ypdb); 766 bzero((char *)ypdb, sizeof *ypdb); 767 strncpy(ypdb->dom_domain, dom, sizeof ypdb->dom_domain); 768 ypdb->dom_lockfd = -1; 769 ypdb->dom_pnext = ypbindlist; 770 ypbindlist = ypdb; 771 } 772 773 /* soft update, alive */ 774 if(ypdb->dom_alive==1 && force==0) { 775 if (bcmp((char *)raddrp, (char *)&ypdb->dom_server_addr, 776 sizeof ypdb->dom_server_addr) == 0) { 777 ypdb->dom_alive = 1; 778 ypdb->dom_check_t = time(NULL) + 60; /* recheck binding in 60 sec */ 779 } 780 return; 781 } 782 783 bcopy((char *)raddrp, (char *)&ypdb->dom_server_addr, 784 sizeof ypdb->dom_server_addr); 785 ypdb->dom_check_t = time(NULL) + 60; /* recheck binding in 60 seconds */ 786 ypdb->dom_vers = YPVERS; 787 ypdb->dom_alive = 1; 788 789 if(ypdb->dom_lockfd != -1) 790 close(ypdb->dom_lockfd); 791 792 sprintf(path, "%s/%s.%d", BINDINGDIR, 793 ypdb->dom_domain, ypdb->dom_vers); 794 #ifdef O_SHLOCK 795 if( (fd=open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1) { 796 (void)mkdir(BINDINGDIR, 0755); 797 if( (fd=open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1) 798 return; 799 } 800 #else 801 if( (fd=open(path, O_CREAT|O_RDWR|O_TRUNC, 0644)) == -1) { 802 (void)mkdir(BINDINGDIR, 0755); 803 if( (fd=open(path, O_CREAT|O_RDWR|O_TRUNC, 0644)) == -1) 804 return; 805 } 806 flock(fd, LOCK_SH); 807 #endif 808 809 /* 810 * ok, if BINDINGDIR exists, and we can create the binding file, 811 * then write to it.. 812 */ 813 ypdb->dom_lockfd = fd; 814 815 iov[0].iov_base = (caddr_t)&(udptransp->xp_port); 816 iov[0].iov_len = sizeof udptransp->xp_port; 817 iov[1].iov_base = (caddr_t)&ybr; 818 iov[1].iov_len = sizeof ybr; 819 820 bzero(&ybr, sizeof ybr); 821 ybr.ypbind_status = YPBIND_SUCC_VAL; 822 ybr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr = raddrp->sin_addr; 823 ybr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port = raddrp->sin_port; 824 825 if( writev(ypdb->dom_lockfd, iov, 2) != iov[0].iov_len + iov[1].iov_len) { 826 perror("write"); 827 close(ypdb->dom_lockfd); 828 unlink(path); 829 ypdb->dom_lockfd = -1; 830 return; 831 } 832 } 833