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