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