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.5 1993/11/15 21:51:30 cgd 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/syslog.h> 42 #include <stdio.h> 43 #include <errno.h> 44 #include <ctype.h> 45 #include <dirent.h> 46 #include <netdb.h> 47 #include <string.h> 48 #include <rpc/rpc.h> 49 #include <rpc/xdr.h> 50 #include <net/if.h> 51 #include <arpa/inet.h> 52 #include <rpc/pmap_clnt.h> 53 #include <rpc/pmap_prot.h> 54 #include <rpc/pmap_rmt.h> 55 #include <unistd.h> 56 #include <rpcsvc/yp_prot.h> 57 #include <rpcsvc/ypclnt.h> 58 59 #ifndef BINDINGDIR 60 #define BINDINGDIR "/var/yp/binding" 61 #endif 62 63 struct _dom_binding { 64 struct _dom_binding *dom_pnext; 65 char dom_domain[YPMAXDOMAIN + 1]; 66 struct sockaddr_in dom_server_addr; 67 unsigned short int dom_server_port; 68 int dom_socket; 69 CLIENT *dom_client; 70 long int dom_vers; 71 time_t dom_check_t; 72 int dom_lockfd; 73 int dom_alive; 74 }; 75 76 extern bool_t xdr_domainname(), xdr_ypbind_resp(); 77 extern bool_t xdr_ypreq_key(), xdr_ypresp_val(); 78 extern bool_t xdr_ypbind_setdom(); 79 80 char *domainname; 81 82 struct _dom_binding *ypbindlist; 83 int check; 84 85 #define YPSET_NO 0 86 #define YPSET_LOCAL 1 87 #define YPSET_ALL 2 88 int ypsetmode = YPSET_NO; 89 90 int rpcsock; 91 struct rmtcallargs rmtca; 92 struct rmtcallres rmtcr; 93 char rmtcr_outval; 94 u_long rmtcr_port; 95 96 void * 97 ypbindproc_null_2(transp, argp, clnt) 98 SVCXPRT *transp; 99 void *argp; 100 CLIENT *clnt; 101 { 102 static char res; 103 104 bzero((char *)&res, sizeof(res)); 105 return (void *)&res; 106 } 107 108 struct ypbind_resp * 109 ypbindproc_domain_2(transp, argp, clnt) 110 SVCXPRT *transp; 111 char *argp; 112 CLIENT *clnt; 113 { 114 static struct ypbind_resp res; 115 struct _dom_binding *ypdb; 116 char path[MAXPATHLEN]; 117 118 bzero((char *)&res, sizeof res); 119 res.ypbind_status = YPBIND_FAIL_VAL; 120 121 for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) 122 if( strcmp(ypdb->dom_domain, argp) == 0) 123 break; 124 125 if(ypdb==NULL) { 126 ypdb = (struct _dom_binding *)malloc(sizeof *ypdb); 127 bzero((char *)ypdb, sizeof *ypdb); 128 strncpy(ypdb->dom_domain, argp, sizeof ypdb->dom_domain); 129 ypdb->dom_vers = YPVERS; 130 ypdb->dom_alive = 0; 131 ypdb->dom_lockfd = -1; 132 sprintf(path, "%s/%s.%d", BINDINGDIR, ypdb->dom_domain, ypdb->dom_vers); 133 unlink(path); 134 ypdb->dom_pnext = ypbindlist; 135 ypbindlist = ypdb; 136 check++; 137 return NULL; 138 } 139 140 if(ypdb->dom_alive==0) 141 return NULL; 142 143 #if 0 144 delta = ypdb->dom_check_t - ypdb->dom_ask_t; 145 if( !(ypdb->dom_ask_t==0 || delta > 5)) { 146 ypdb->dom_ask_t = time(NULL); 147 /* 148 * Hmm. More than 2 requests in 5 seconds have indicated that my 149 * binding is possibly incorrect. Ok, make myself unalive, and 150 * find out what the actual state is. 151 */ 152 if(ypdb->dom_lockfd!=-1) 153 close(ypdb->dom_lockfd); 154 ypdb->dom_lockfd = -1; 155 ypdb->dom_alive = 0; 156 ypdb->dom_lockfd = -1; 157 sprintf(path, "%s/%s.%d", BINDINGDIR, ypdb->dom_domain, ypdb->dom_vers); 158 unlink(path); 159 check++; 160 return NULL; 161 } 162 #endif 163 164 answer: 165 res.ypbind_status = YPBIND_SUCC_VAL; 166 res.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr.s_addr = 167 ypdb->dom_server_addr.sin_addr.s_addr; 168 res.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port = 169 ypdb->dom_server_port; 170 /*printf("domain %s at %s/%d\n", ypdb->dom_domain, 171 inet_ntoa(ypdb->dom_server_addr.sin_addr), 172 ntohs(ypdb->dom_server_addr.sin_port));*/ 173 return &res; 174 } 175 176 bool_t * 177 ypbindproc_setdom_2(transp, argp, clnt) 178 SVCXPRT *transp; 179 struct ypbind_setdom *argp; 180 CLIENT *clnt; 181 { 182 struct sockaddr_in *fromsin, bindsin; 183 char res; 184 185 bzero((char *)&res, sizeof(res)); 186 fromsin = svc_getcaller(transp); 187 188 switch(ypsetmode) { 189 case YPSET_LOCAL: 190 if( fromsin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) 191 return (void *)NULL; 192 break; 193 case YPSET_ALL: 194 break; 195 case YPSET_NO: 196 default: 197 return (void *)NULL; 198 } 199 200 if(ntohs(fromsin->sin_port) >= IPPORT_RESERVED) 201 return (void *)&res; 202 203 if(argp->ypsetdom_vers != YPVERS) 204 return (void *)&res; 205 206 bzero((char *)&bindsin, sizeof bindsin); 207 bindsin.sin_family = AF_INET; 208 bindsin.sin_addr.s_addr = argp->ypsetdom_addr.s_addr; 209 bindsin.sin_port = argp->ypsetdom_port; 210 rpc_received(argp->ypsetdom_domain, &bindsin, 1); 211 212 res = 1; 213 return (void *)&res; 214 } 215 216 static void 217 ypbindprog_2(rqstp, transp) 218 struct svc_req *rqstp; 219 register SVCXPRT *transp; 220 { 221 union { 222 char ypbindproc_domain_2_arg[MAXHOSTNAMELEN]; 223 struct ypbind_setdom ypbindproc_setdom_2_arg; 224 } argument; 225 struct authunix_parms *creds; 226 char *result; 227 bool_t (*xdr_argument)(), (*xdr_result)(); 228 char *(*local)(); 229 230 switch (rqstp->rq_proc) { 231 case YPBINDPROC_NULL: 232 xdr_argument = xdr_void; 233 xdr_result = xdr_void; 234 local = (char *(*)()) ypbindproc_null_2; 235 break; 236 237 case YPBINDPROC_DOMAIN: 238 xdr_argument = xdr_domainname; 239 xdr_result = xdr_ypbind_resp; 240 local = (char *(*)()) ypbindproc_domain_2; 241 break; 242 243 case YPBINDPROC_SETDOM: 244 switch(rqstp->rq_cred.oa_flavor) { 245 case AUTH_UNIX: 246 creds = (struct authunix_parms *)rqstp->rq_clntcred; 247 if( creds->aup_uid != 0) { 248 svcerr_auth(transp, AUTH_BADCRED); 249 return; 250 } 251 break; 252 default: 253 svcerr_auth(transp, AUTH_TOOWEAK); 254 return; 255 } 256 257 xdr_argument = xdr_ypbind_setdom; 258 xdr_result = xdr_void; 259 local = (char *(*)()) ypbindproc_setdom_2; 260 break; 261 262 default: 263 svcerr_noproc(transp); 264 return; 265 } 266 bzero((char *)&argument, sizeof(argument)); 267 if (!svc_getargs(transp, xdr_argument, &argument)) { 268 svcerr_decode(transp); 269 return; 270 } 271 result = (*local)(transp, &argument, rqstp); 272 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { 273 svcerr_systemerr(transp); 274 } 275 return; 276 } 277 278 main(argc, argv) 279 char **argv; 280 { 281 char path[MAXPATHLEN]; 282 struct timeval tv; 283 SVCXPRT *transp; 284 fd_set fdsr; 285 int width; 286 int i; 287 288 yp_get_default_domain(&domainname); 289 if( domainname[0] == '\0') { 290 fprintf(stderr, "domainname not set. Aborting.\n"); 291 exit(1); 292 } 293 294 for(i=1; i<argc; i++) { 295 if( strcmp("-ypset", argv[i]) == 0) 296 ypsetmode = YPSET_ALL; 297 else if (strcmp("-ypsetme", argv[i]) == 0) 298 ypsetmode = YPSET_LOCAL; 299 } 300 301 /* blow away everything in BINDINGDIR */ 302 303 304 305 #ifdef DAEMON 306 switch(fork()) { 307 case 0: 308 break; 309 case -1: 310 perror("fork"); 311 exit(1); 312 default: 313 exit(0); 314 } 315 setsid(); 316 #endif 317 318 pmap_unset(YPBINDPROG, YPBINDVERS); 319 320 transp = svcudp_create(RPC_ANYSOCK); 321 if (transp == NULL) { 322 fprintf(stderr, "cannot create udp service."); 323 exit(1); 324 } 325 if (!svc_register(transp, YPBINDPROG, YPBINDVERS, ypbindprog_2, IPPROTO_UDP)) { 326 fprintf(stderr, "unable to register (YPBINDPROG, YPBINDVERS, udp)."); 327 exit(1); 328 } 329 330 transp = svctcp_create(RPC_ANYSOCK, 0, 0); 331 if (transp == NULL) { 332 fprintf(stderr, "cannot create tcp service."); 333 exit(1); 334 } 335 336 if (!svc_register(transp, YPBINDPROG, YPBINDVERS, ypbindprog_2, IPPROTO_TCP)) { 337 fprintf(stderr, "unable to register (YPBINDPROG, YPBINDVERS, tcp)."); 338 exit(1); 339 } 340 341 if( (rpcsock=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { 342 perror("socket"); 343 return -1; 344 } 345 fcntl(rpcsock, F_SETFL, fcntl(rpcsock, F_GETFL, 0) | FNDELAY); 346 i = 1; 347 setsockopt(rpcsock, SOL_SOCKET, SO_BROADCAST, &i, sizeof(i)); 348 rmtca.prog = YPPROG; 349 rmtca.vers = YPVERS; 350 rmtca.proc = YPPROC_DOMAIN_NONACK; 351 rmtca.xdr_args = NULL; /* set at call time */ 352 rmtca.args_ptr = NULL; /* set at call time */ 353 rmtcr.port_ptr = &rmtcr_port; 354 rmtcr.xdr_results = xdr_bool; 355 rmtcr.results_ptr = (caddr_t)&rmtcr_outval; 356 357 /* build initial domain binding, make it "unsuccessful" */ 358 ypbindlist = (struct _dom_binding *)malloc(sizeof *ypbindlist); 359 bzero((char *)ypbindlist, sizeof *ypbindlist); 360 strncpy(ypbindlist->dom_domain, domainname, sizeof ypbindlist->dom_domain); 361 ypbindlist->dom_vers = YPVERS; 362 ypbindlist->dom_alive = 0; 363 ypbindlist->dom_lockfd = -1; 364 sprintf(path, "%s/%s.%d", BINDINGDIR, ypbindlist->dom_domain, 365 ypbindlist->dom_vers); 366 (void)unlink(path); 367 368 width = getdtablesize(); 369 while(1) { 370 fdsr = svc_fdset; 371 FD_SET(rpcsock, &fdsr); 372 tv.tv_sec = 1; 373 tv.tv_usec = 0; 374 375 switch(select(width, &fdsr, NULL, NULL, &tv)) { 376 case 0: 377 checkwork(); 378 break; 379 case -1: 380 perror("select\n"); 381 break; 382 default: 383 if(FD_ISSET(rpcsock, &fdsr)) { 384 FD_CLR(rpcsock, &fdsr); 385 handle_replies(); 386 } 387 svc_getreqset(&fdsr); 388 if(check) 389 checkwork(); 390 break; 391 } 392 } 393 } 394 395 /* 396 * change to do something like this: 397 * 398 * STATE TIME ACTION NEWTIME NEWSTATE 399 * no binding t==* broadcast t=2 no binding 400 * binding t==60 check server t=10 binding 401 * binding t=10 broadcast t=2 no binding 402 */ 403 checkwork() 404 { 405 struct _dom_binding *ypdb; 406 time_t t; 407 408 check = 0; 409 410 time(&t); 411 for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) { 412 if(ypdb->dom_alive==0 || ypdb->dom_check_t < t) { 413 broadcast(ypdb->dom_domain); 414 time(&t); 415 ypdb->dom_check_t = t + 5; 416 } 417 } 418 } 419 420 broadcast(dom) 421 char *dom; 422 { 423 struct rpc_msg rpcmsg; 424 char buf[1400], inbuf[8192]; 425 enum clnt_stat st; 426 struct timeval tv; 427 int outlen, i, sock, len; 428 struct sockaddr_in bsin; 429 struct ifconf ifc; 430 struct ifreq ifreq, *ifr; 431 struct in_addr in; 432 AUTH *rpcua; 433 XDR rpcxdr; 434 435 rmtca.xdr_args = xdr_domainname; 436 rmtca.args_ptr = dom; 437 438 bzero((char *)&bsin, sizeof bsin); 439 bsin.sin_family = AF_INET; 440 bsin.sin_port = htons(PMAPPORT); 441 442 bzero((char *)&rpcxdr, sizeof rpcxdr); 443 bzero((char *)&rpcmsg, sizeof rpcmsg); 444 445 rpcua = authunix_create_default(); 446 if( rpcua == (AUTH *)NULL) { 447 /*printf("cannot get unix auth\n");*/ 448 return RPC_SYSTEMERROR; 449 } 450 rpcmsg.rm_direction = CALL; 451 rpcmsg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 452 rpcmsg.rm_call.cb_prog = PMAPPROG; 453 rpcmsg.rm_call.cb_vers = PMAPVERS; 454 rpcmsg.rm_call.cb_proc = PMAPPROC_CALLIT; 455 rpcmsg.rm_call.cb_cred = rpcua->ah_cred; 456 rpcmsg.rm_call.cb_verf = rpcua->ah_verf; 457 458 gettimeofday(&tv, (struct timezone *)0); 459 rpcmsg.rm_xid = (int)dom; 460 tv.tv_usec = 0; 461 xdrmem_create(&rpcxdr, buf, sizeof buf, XDR_ENCODE); 462 if( (!xdr_callmsg(&rpcxdr, &rpcmsg)) ) { 463 st = RPC_CANTENCODEARGS; 464 AUTH_DESTROY(rpcua); 465 return st; 466 } 467 if( (!xdr_rmtcall_args(&rpcxdr, &rmtca)) ) { 468 st = RPC_CANTENCODEARGS; 469 AUTH_DESTROY(rpcua); 470 return st; 471 } 472 outlen = (int)xdr_getpos(&rpcxdr); 473 xdr_destroy(&rpcxdr); 474 if(outlen<1) { 475 AUTH_DESTROY(rpcua); 476 return st; 477 } 478 AUTH_DESTROY(rpcua); 479 480 /* find all networks and send the RPC packet out them all */ 481 if( (sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { 482 perror("socket"); 483 return -1; 484 } 485 486 ifc.ifc_len = sizeof inbuf; 487 ifc.ifc_buf = inbuf; 488 if( ioctl(sock, SIOCGIFCONF, &ifc) < 0) { 489 close(sock); 490 perror("ioctl(SIOCGIFCONF)"); 491 return -1; 492 } 493 ifr = ifc.ifc_req; 494 ifreq.ifr_name[0] = '\0'; 495 for(i=0; i<ifc.ifc_len; i+=len, ifr=(struct ifreq *)((caddr_t)ifr+len)) { 496 #if defined(BSD) && BSD >= 199103 497 len = sizeof ifr->ifr_name + ifr->ifr_addr.sa_len; 498 #else 499 len = sizeof ifc.ifc_len / sizeof(struct ifreq); 500 #endif 501 ifreq = *ifr; 502 if( ifreq.ifr_addr.sa_family != AF_INET) 503 continue; 504 if( ioctl(sock, SIOCGIFFLAGS, &ifreq) < 0) { 505 perror("ioctl(SIOCGIFFLAGS)"); 506 continue; 507 } 508 if( (ifreq.ifr_flags & IFF_UP) == 0) 509 continue; 510 511 ifreq.ifr_flags &= (IFF_LOOPBACK | IFF_BROADCAST); 512 if( ifreq.ifr_flags==IFF_BROADCAST ) { 513 if( ioctl(sock, SIOCGIFBRDADDR, &ifreq) < 0 ) { 514 perror("ioctl(SIOCGIFBRDADDR)"); 515 continue; 516 } 517 } else if( ifreq.ifr_flags==IFF_LOOPBACK ) { 518 if( ioctl(sock, SIOCGIFADDR, &ifreq) < 0 ) { 519 perror("ioctl(SIOCGIFADDR)"); 520 continue; 521 } 522 } else 523 continue; 524 525 in = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr; 526 bsin.sin_addr = in; 527 if( sendto(rpcsock, buf, outlen, 0, (struct sockaddr *)&bsin, 528 sizeof bsin) < 0 ) 529 perror("sendto"); 530 } 531 close(sock); 532 return 0; 533 } 534 535 /*enum clnt_stat*/ 536 handle_replies() 537 { 538 char buf[1400]; 539 int fromlen, inlen; 540 struct sockaddr_in raddr; 541 struct rpc_msg msg; 542 XDR xdr; 543 544 recv_again: 545 bzero((char *)&xdr, sizeof(xdr)); 546 bzero((char *)&msg, sizeof(msg)); 547 msg.acpted_rply.ar_verf = _null_auth; 548 msg.acpted_rply.ar_results.where = (caddr_t)&rmtcr; 549 msg.acpted_rply.ar_results.proc = xdr_rmtcallres; 550 551 try_again: 552 fromlen = sizeof (struct sockaddr); 553 inlen = recvfrom(rpcsock, buf, sizeof buf, 0, 554 (struct sockaddr *)&raddr, &fromlen); 555 if(inlen<0) { 556 if(errno==EINTR) 557 goto try_again; 558 return RPC_CANTRECV; 559 } 560 if(inlen<sizeof(u_long)) 561 goto recv_again; 562 563 /* 564 * see if reply transaction id matches sent id. 565 * If so, decode the results. 566 */ 567 xdrmem_create(&xdr, buf, (u_int)inlen, XDR_DECODE); 568 if( xdr_replymsg(&xdr, &msg)) { 569 if( (msg.rm_reply.rp_stat == MSG_ACCEPTED) && 570 (msg.acpted_rply.ar_stat == SUCCESS)) { 571 raddr.sin_port = htons((u_short)rmtcr_port); 572 rpc_received(msg.rm_xid, &raddr, 0); 573 } 574 } 575 xdr.x_op = XDR_FREE; 576 msg.acpted_rply.ar_results.proc = xdr_void; 577 xdr_destroy(&xdr); 578 579 return RPC_SUCCESS; 580 } 581 582 /* 583 * LOOPBACK IS MORE IMPORTANT: PUT IN HACK 584 */ 585 rpc_received(dom, raddrp, force) 586 char *dom; 587 struct sockaddr_in *raddrp; 588 int force; 589 { 590 struct _dom_binding *ypdb; 591 char path[MAXPATHLEN]; 592 int fd; 593 594 /*printf("returned from %s about %s\n", inet_ntoa(raddrp->sin_addr), dom);*/ 595 596 if(dom==NULL) 597 return; 598 599 for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) 600 if( strcmp(ypdb->dom_domain, dom) == 0) 601 break; 602 603 if(ypdb==NULL) { 604 if(force==0) 605 return; 606 ypdb = (struct _dom_binding *)malloc(sizeof *ypdb); 607 bzero((char *)ypdb, sizeof *ypdb); 608 strncpy(ypdb->dom_domain, dom, sizeof ypdb->dom_domain); 609 ypdb->dom_lockfd = -1; 610 ypdb->dom_pnext = ypbindlist; 611 ypbindlist = ypdb; 612 } 613 614 /* soft update, alive, less than 30 seconds old */ 615 if(ypdb->dom_alive==1 && force==0 && ypdb->dom_check_t<time(NULL)+30) 616 return; 617 618 bcopy((char *)raddrp, (char *)&ypdb->dom_server_addr, 619 sizeof ypdb->dom_server_addr); 620 ypdb->dom_check_t = time(NULL) + 60; /* recheck binding in 60 seconds */ 621 ypdb->dom_vers = YPVERS; 622 ypdb->dom_alive = 1; 623 624 if(ypdb->dom_lockfd != -1) 625 close(ypdb->dom_lockfd); 626 627 sprintf(path, "%s/%s.%d", BINDINGDIR, 628 ypdb->dom_domain, ypdb->dom_vers); 629 #ifdef O_SHLOCK 630 if( (fd=open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1) { 631 (void)mkdir(BINDINGDIR, 0755); 632 if( (fd=open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1) 633 return; 634 } 635 #else 636 if( (fd=open(path, O_CREAT|O_RDWR|O_TRUNC, 0644)) == -1) { 637 (void)mkdir(BINDINGDIR, 0755); 638 if( (fd=open(path, O_CREAT|O_RDWR|O_TRUNC, 0644)) == -1) 639 return; 640 } 641 flock(fd, LOCK_SH); 642 #endif 643 644 /* 645 * ok, if BINDINGDIR exists, and we can create the binding file, 646 * then write to it.. 647 */ 648 ypdb->dom_lockfd = fd; 649 if( write(ypdb->dom_lockfd, raddrp, sizeof *raddrp) != sizeof *raddrp) { 650 perror("write"); 651 close(ypdb->dom_lockfd); 652 ypdb->dom_lockfd = -1; 653 return; 654 } 655 } 656