1 /* $NetBSD: ypbind.c,v 1.60 2009/11/06 15:36:55 christos Exp $ */
4 * Copyright (c) 1992, 1993 Theo de Raadt <deraadt@fsa.ca>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
17 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/cdefs.h>
31 __RCSID("$NetBSD: ypbind.c,v 1.60 2009/11/06 15:36:55 christos Exp $");
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>
41 #include <sys/syslog.h>
58 #include <arpa/inet.h>
59 #include <rpc/pmap_clnt.h>
60 #include <rpc/pmap_prot.h>
61 #include <rpc/pmap_rmt.h>
64 #include <rpcsvc/yp_prot.h>
65 #include <rpcsvc/ypclnt.h>
68 #include "pathnames.h"
76 #define YPSERVERSSUFF ".ypservers"
77 #define BINDINGDIR (_PATH_VAR_YP "binding")
80 struct _dom_binding
*dom_pnext
;
81 char dom_domain
[YPMAXDOMAIN
+ 1];
82 struct sockaddr_in dom_server_addr
;
93 static char *domainname
;
95 static struct _dom_binding
*ypbindlist
;
99 YPBIND_DIRECT
, YPBIND_BROADCAST
, YPBIND_SETLOCAL
, YPBIND_SETALL
102 ypbind_mode_t ypbindmode
;
105 * If ypbindmode is YPBIND_SETLOCAL or YPBIND_SETALL, this indicates
106 * whether or not we've been "ypset". If we haven't, we behave like
107 * YPBIND_BROADCAST. If we have, we behave like YPBIND_DIRECT.
116 static int rpcsock
, pingsock
;
117 static struct rmtcallargs rmtca
;
118 static struct rmtcallres rmtcr
;
119 static bool_t rmtcr_outval
;
120 static u_long rmtcr_port
;
121 static SVCXPRT
*udptransp
, *tcptransp
;
123 int _yp_invalid_domain(const char *); /* from libc */
124 int main(int, char *[]);
126 static void usage(void);
127 static void yp_log(int, const char *, ...)
128 __attribute__((__format__(__printf__
, 2, 3)));
129 static struct _dom_binding
*makebinding(const char *);
130 static int makelock(struct _dom_binding
*);
131 static void removelock(struct _dom_binding
*);
132 static int purge_bindingdir(const char *);
133 static void *ypbindproc_null_2(SVCXPRT
*, void *);
134 static void *ypbindproc_domain_2(SVCXPRT
*, void *);
135 static void *ypbindproc_setdom_2(SVCXPRT
*, void *);
136 static void ypbindprog_2(struct svc_req
*, SVCXPRT
*);
137 static void checkwork(void);
138 static int ping(struct _dom_binding
*);
139 static int nag_servers(struct _dom_binding
*);
140 static enum clnt_stat
handle_replies(void);
141 static enum clnt_stat
handle_ping(void);
142 static void rpc_received(char *, struct sockaddr_in
*, int);
143 static struct _dom_binding
*xid2ypdb(u_int32_t
);
144 static u_int32_t
unique_xid(struct _dom_binding
*);
145 static int broadcast(char *, int);
146 static int direct(char *, int);
147 static int direct_set(char *, int, struct _dom_binding
*);
152 const char *opt
= "";
157 (void)fprintf(stderr
,
158 "Usage: %s [-broadcast] [-insecure] [-ypset] [-ypsetme]%s\n",
164 yp_log(int pri
, const char *fmt
, ...)
172 (void)vprintf(fmt
, ap
);
175 vsyslog(pri
, fmt
, ap
);
179 static struct _dom_binding
*
180 makebinding(const char *dm
)
182 struct _dom_binding
*ypdb
;
184 if ((ypdb
= (struct _dom_binding
*)malloc(sizeof *ypdb
)) == NULL
) {
185 yp_log(LOG_ERR
, "makebinding");
189 (void)memset(ypdb
, 0, sizeof *ypdb
);
190 (void)strlcpy(ypdb
->dom_domain
, dm
, sizeof ypdb
->dom_domain
);
195 makelock(struct _dom_binding
*ypdb
)
198 char path
[MAXPATHLEN
];
200 (void)snprintf(path
, sizeof(path
), "%s/%s.%ld", BINDINGDIR
,
201 ypdb
->dom_domain
, ypdb
->dom_vers
);
203 if ((fd
= open(path
, O_CREAT
|O_SHLOCK
|O_RDWR
|O_TRUNC
, 0644)) == -1) {
204 (void)mkdir(BINDINGDIR
, 0755);
205 if ((fd
= open(path
, O_CREAT
|O_SHLOCK
|O_RDWR
|O_TRUNC
, 0644)) == -1)
210 (void)flock(fd
, LOCK_SH
);
216 removelock(struct _dom_binding
*ypdb
)
218 char path
[MAXPATHLEN
];
220 (void)snprintf(path
, sizeof(path
), "%s/%s.%ld",
221 BINDINGDIR
, ypdb
->dom_domain
, ypdb
->dom_vers
);
226 * purge_bindingdir: remove old binding files (i.e. "rm BINDINGDIR\/\*.[0-9]")
228 * local YP functions [e.g. yp_master()] will fail without even talking
229 * to ypbind if there is a stale (non-flock'd) binding file present.
230 * we have to scan the entire BINDINGDIR for binding files, because
231 * ypbind may bind more than just the yp_get_default_domain() domain.
234 purge_bindingdir(const char *dirpath
)
237 int unlinkedfiles
, l
;
239 char pathname
[MAXPATHLEN
];
241 if ((dirp
= opendir(dirpath
)) == NULL
)
242 return(-1); /* at this point, shouldn't ever happen */
246 while ((dp
= readdir(dirp
)) != NULL
) {
249 if (l
> 2 && dp
->d_name
[l
-2] == '.' &&
250 dp
->d_name
[l
-1] >= '0' && dp
->d_name
[l
-1] <= '9') {
251 (void)snprintf(pathname
, sizeof(pathname
),
252 "%s/%s", dirpath
, dp
->d_name
);
253 if (unlink(pathname
) < 0 && errno
!= ENOENT
)
259 /* rescan dir if we removed it */
263 } while (unlinkedfiles
);
271 ypbindproc_null_2(SVCXPRT
*transp
, void *argp
)
277 (void)printf("ypbindproc_null_2\n");
279 (void)memset(&res
, 0, sizeof(res
));
285 ypbindproc_domain_2(SVCXPRT
*transp
, void *argp
)
287 static struct ypbind_resp res
;
288 struct _dom_binding
*ypdb
;
289 char *arg
= *(char **) argp
;
295 (void)printf("ypbindproc_domain_2 %s\n", arg
);
297 if (_yp_invalid_domain(arg
))
300 (void)memset(&res
, 0, sizeof res
);
301 res
.ypbind_status
= YPBIND_FAIL_VAL
;
303 for (count
= 0, ypdb
= ypbindlist
;
305 ypdb
= ypdb
->dom_pnext
, count
++) {
307 return NULL
; /* prevent denial of service */
308 if (!strcmp(ypdb
->dom_domain
, arg
))
313 ypdb
= makebinding(arg
);
314 ypdb
->dom_vers
= YPVERS
;
316 ypdb
->dom_lockfd
= -1;
318 ypdb
->dom_xid
= unique_xid(ypdb
);
319 ypdb
->dom_pnext
= ypbindlist
;
324 (void)printf("unknown domain %s\n", arg
);
329 if (ypdb
->dom_alive
== 0) {
332 (void)printf("dead domain %s\n", arg
);
339 if (now
< ypdb
->dom_ask_t
+ 5) {
341 * Hmm. More than 2 requests in 5 seconds have indicated
342 * that my binding is possibly incorrect.
343 * Ok, do an immediate poll of the server.
345 if (ypdb
->dom_check_t
>= now
) {
347 ypdb
->dom_check_t
= 0;
351 ypdb
->dom_ask_t
= now
;
354 res
.ypbind_status
= YPBIND_SUCC_VAL
;
355 res
.ypbind_respbody
.ypbind_bindinfo
.ypbind_binding_addr
.s_addr
=
356 ypdb
->dom_server_addr
.sin_addr
.s_addr
;
357 res
.ypbind_respbody
.ypbind_bindinfo
.ypbind_binding_port
=
358 ypdb
->dom_server_addr
.sin_port
;
361 (void)printf("domain %s at %s/%d\n", ypdb
->dom_domain
,
362 inet_ntoa(ypdb
->dom_server_addr
.sin_addr
),
363 ntohs(ypdb
->dom_server_addr
.sin_port
));
369 ypbindproc_setdom_2(SVCXPRT
*transp
, void *argp
)
371 struct ypbind_setdom
*sd
= argp
;
372 struct sockaddr_in
*fromsin
, bindsin
;
377 (void)printf("ypbindproc_setdom_2 %s\n", inet_ntoa(bindsin
.sin_addr
));
379 (void)memset(&res
, 0, sizeof(res
));
380 fromsin
= svc_getcaller(transp
);
382 switch (ypbindmode
) {
383 case YPBIND_SETLOCAL
:
384 if (fromsin
->sin_addr
.s_addr
!= htonl(INADDR_LOOPBACK
)) {
387 (void)printf("ypset from %s denied\n",
388 inet_ntoa(fromsin
->sin_addr
));
399 case YPBIND_BROADCAST
:
403 (void)printf("ypset denied\n");
408 if (ntohs(fromsin
->sin_port
) >= IPPORT_RESERVED
) {
411 (void)printf("ypset from unprivileged port denied\n");
416 if (sd
->ypsetdom_vers
!= YPVERS
) {
419 (void)printf("ypset with wrong version denied\n");
424 (void)memset(&bindsin
, 0, sizeof bindsin
);
425 bindsin
.sin_family
= AF_INET
;
426 bindsin
.sin_len
= sizeof(bindsin
);
427 bindsin
.sin_addr
= sd
->ypsetdom_addr
;
428 bindsin
.sin_port
= sd
->ypsetdom_port
;
429 rpc_received(sd
->ypsetdom_domain
, &bindsin
, 1);
433 (void)printf("ypset to %s succeeded\n", inet_ntoa(bindsin
.sin_addr
));
440 ypbindprog_2(struct svc_req
*rqstp
, register SVCXPRT
*transp
)
443 char ypbindproc_domain_2_arg
[YPMAXDOMAIN
+ 1];
444 struct ypbind_setdom ypbindproc_setdom_2_arg
;
447 struct authunix_parms
*creds
;
449 xdrproc_t xdr_argument
, xdr_result
;
450 void *(*local
)(SVCXPRT
*, void *);
452 switch (rqstp
->rq_proc
) {
453 case YPBINDPROC_NULL
:
454 xdr_argument
= xdr_void
;
455 xdr_result
= xdr_void
;
456 local
= ypbindproc_null_2
;
459 case YPBINDPROC_DOMAIN
:
460 xdr_argument
= xdr_ypdomain_wrap_string
;
461 xdr_result
= xdr_ypbind_resp
;
462 local
= ypbindproc_domain_2
;
465 case YPBINDPROC_SETDOM
:
466 switch (rqstp
->rq_cred
.oa_flavor
) {
468 creds
= (struct authunix_parms
*)rqstp
->rq_clntcred
;
469 if (creds
->aup_uid
!= 0) {
470 svcerr_auth(transp
, AUTH_BADCRED
);
475 svcerr_auth(transp
, AUTH_TOOWEAK
);
479 xdr_argument
= xdr_ypbind_setdom
;
480 xdr_result
= xdr_void
;
481 local
= ypbindproc_setdom_2
;
485 svcerr_noproc(transp
);
488 (void)memset(&argument
, 0, sizeof(argument
));
489 if (!svc_getargs(transp
, xdr_argument
, (caddr_t
)(void *)&argument
)) {
490 svcerr_decode(transp
);
493 result
= (*local
)(transp
, &argument
);
494 if (result
!= NULL
&& !svc_sendreply(transp
, xdr_result
, result
)) {
495 svcerr_systemerr(transp
);
501 main(int argc
, char *argv
[])
507 char pathname
[MAXPATHLEN
];
510 setprogname(argv
[0]);
511 (void)yp_get_default_domain(&domainname
);
512 if (domainname
[0] == '\0')
513 errx(1, "Domainname not set. Aborting.");
516 * Per traditional ypbind(8) semantics, if a ypservers
517 * file does not exist, we default to broadcast mode.
518 * If the file does exist, we default to direct mode.
519 * Note that we can still override direct mode by passing
520 * the -broadcast flag.
522 (void)snprintf(pathname
, sizeof(pathname
), "%s/%s%s", BINDINGDIR
,
523 domainname
, YPSERVERSSUFF
);
524 if (stat(pathname
, &st
) < 0) {
527 (void)printf("%s does not exist, defaulting to "
528 "broadcast\n", pathname
);
530 ypbindmode
= YPBIND_BROADCAST
;
532 ypbindmode
= YPBIND_DIRECT
;
536 if (!strcmp("-insecure", *argv
))
538 else if (!strcmp("-ypset", *argv
))
539 ypbindmode
= YPBIND_SETALL
;
540 else if (!strcmp("-ypsetme", *argv
))
541 ypbindmode
= YPBIND_SETLOCAL
;
542 else if (!strcmp("-broadcast", *argv
))
543 ypbindmode
= YPBIND_BROADCAST
;
545 else if (!strcmp("-d", *argv
))
552 /* initialise syslog */
553 openlog("ypbind", LOG_PERROR
| LOG_PID
, LOG_DAEMON
);
555 lockfd
= open(_PATH_YPBIND_LOCK
, O_CREAT
|O_SHLOCK
|O_RDWR
|O_TRUNC
, 0644);
557 err(1, "Cannot create %s", _PATH_YPBIND_LOCK
);
560 (void)flock(lockfd
, LOCK_SH
);
563 (void)pmap_unset(YPBINDPROG
, YPBINDVERS
);
565 udptransp
= svcudp_create(RPC_ANYSOCK
);
566 if (udptransp
== NULL
)
567 errx(1, "Cannot create udp service.");
569 if (!svc_register(udptransp
, YPBINDPROG
, YPBINDVERS
, ypbindprog_2
,
571 errx(1, "Unable to register (YPBINDPROG, YPBINDVERS, udp).");
573 tcptransp
= svctcp_create(RPC_ANYSOCK
, 0, 0);
574 if (tcptransp
== NULL
)
575 errx(1, "Cannot create tcp service.");
577 if (!svc_register(tcptransp
, YPBINDPROG
, YPBINDVERS
, ypbindprog_2
,
579 errx(1, "Unable to register (YPBINDPROG, YPBINDVERS, tcp).");
581 /* XXX use SOCK_STREAM for direct queries? */
582 if ((rpcsock
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
)) == -1)
583 err(1, "rpc socket");
584 if ((pingsock
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
)) == -1)
585 err(1, "ping socket");
587 (void)fcntl(rpcsock
, F_SETFL
, fcntl(rpcsock
, F_GETFL
, 0) | FNDELAY
);
588 (void)fcntl(pingsock
, F_SETFL
, fcntl(pingsock
, F_GETFL
, 0) | FNDELAY
);
591 (void)setsockopt(rpcsock
, SOL_SOCKET
, SO_BROADCAST
, &one
,
592 (socklen_t
)sizeof(one
));
595 rmtca
.proc
= YPPROC_DOMAIN_NONACK
;
596 rmtca
.xdr_args
= NULL
; /* set at call time */
597 rmtca
.args_ptr
= NULL
; /* set at call time */
598 rmtcr
.port_ptr
= &rmtcr_port
;
599 rmtcr
.xdr_results
= xdr_bool
;
600 rmtcr
.results_ptr
= (caddr_t
)(void *)&rmtcr_outval
;
602 if (_yp_invalid_domain(domainname
))
603 errx(1, "bad domainname: %s", domainname
);
605 /* blow away old bindings in BINDINGDIR */
606 if (purge_bindingdir(BINDINGDIR
) < 0)
607 errx(1, "unable to purge old bindings from %s", BINDINGDIR
);
609 /* build initial domain binding, make it "unsuccessful" */
610 ypbindlist
= makebinding(domainname
);
611 ypbindlist
->dom_vers
= YPVERS
;
612 ypbindlist
->dom_alive
= 0;
613 ypbindlist
->dom_lockfd
= -1;
614 removelock(ypbindlist
);
622 if (pingsock
> width
)
626 FD_SET(rpcsock
, &fdsr
);
627 FD_SET(pingsock
, &fdsr
);
631 switch (select(width
, &fdsr
, NULL
, NULL
, &tv
)) {
636 yp_log(LOG_WARNING
, "select: %m");
639 if (FD_ISSET(rpcsock
, &fdsr
))
640 (void)handle_replies();
641 if (FD_ISSET(pingsock
, &fdsr
))
643 svc_getreqset(&fdsr
);
649 if (!evil
&& ypbindlist
->dom_alive
) {
661 * State transition is done like this:
663 * STATE EVENT ACTION NEWSTATE TIMEOUT
664 * no binding timeout broadcast no binding 5 sec
665 * no binding answer -- binding 60 sec
666 * binding timeout ping server checking 5 sec
667 * checking timeout ping server + broadcast checking 5 sec
668 * checking answer -- binding 60 sec
673 struct _dom_binding
*ypdb
;
679 for (ypdb
= ypbindlist
; ypdb
; ypdb
= ypdb
->dom_pnext
) {
680 if (ypdb
->dom_check_t
< t
) {
681 if (ypdb
->dom_alive
== 1)
684 (void)nag_servers(ypdb
);
686 ypdb
->dom_check_t
= t
+ 5;
692 ping(struct _dom_binding
*ypdb
)
694 char *dom
= ypdb
->dom_domain
;
702 (void)memset(&xdr
, 0, sizeof xdr
);
703 (void)memset(&msg
, 0, sizeof msg
);
705 rpcua
= authunix_create_default();
709 (void)printf("cannot get unix auth\n");
711 return RPC_SYSTEMERROR
;
714 msg
.rm_direction
= CALL
;
715 msg
.rm_call
.cb_rpcvers
= RPC_MSG_VERSION
;
716 msg
.rm_call
.cb_prog
= YPPROG
;
717 msg
.rm_call
.cb_vers
= YPVERS
;
718 msg
.rm_call
.cb_proc
= YPPROC_DOMAIN_NONACK
;
719 msg
.rm_call
.cb_cred
= rpcua
->ah_cred
;
720 msg
.rm_call
.cb_verf
= rpcua
->ah_verf
;
722 msg
.rm_xid
= ypdb
->dom_xid
;
723 xdrmem_create(&xdr
, buf
, (u_int
)sizeof(buf
), XDR_ENCODE
);
724 if (!xdr_callmsg(&xdr
, &msg
)) {
725 st
= RPC_CANTENCODEARGS
;
729 if (!xdr_ypdomain_wrap_string(&xdr
, &dom
)) {
730 st
= RPC_CANTENCODEARGS
;
734 outlen
= (int)xdr_getpos(&xdr
);
737 st
= RPC_CANTENCODEARGS
;
746 (void)printf("ping %x\n",
747 ypdb
->dom_server_addr
.sin_addr
.s_addr
);
749 if (sendto(pingsock
, buf
, outlen
, 0,
750 (struct sockaddr
*)(void *)&ypdb
->dom_server_addr
,
751 (socklen_t
)sizeof ypdb
->dom_server_addr
) == -1)
752 yp_log(LOG_WARNING
, "ping: sendto: %m");
758 nag_servers(struct _dom_binding
*ypdb
)
760 char *dom
= ypdb
->dom_domain
;
770 (void)printf("nag_servers\n");
772 rmtca
.xdr_args
= xdr_ypdomain_wrap_string
;
773 rmtca
.args_ptr
= (caddr_t
)(void *)&dom
;
775 (void)memset(&xdr
, 0, sizeof xdr
);
776 (void)memset(&msg
, 0, sizeof msg
);
778 rpcua
= authunix_create_default();
782 (void)printf("cannot get unix auth\n");
784 return RPC_SYSTEMERROR
;
786 msg
.rm_direction
= CALL
;
787 msg
.rm_call
.cb_rpcvers
= RPC_MSG_VERSION
;
788 msg
.rm_call
.cb_prog
= PMAPPROG
;
789 msg
.rm_call
.cb_vers
= PMAPVERS
;
790 msg
.rm_call
.cb_proc
= PMAPPROC_CALLIT
;
791 msg
.rm_call
.cb_cred
= rpcua
->ah_cred
;
792 msg
.rm_call
.cb_verf
= rpcua
->ah_verf
;
794 msg
.rm_xid
= ypdb
->dom_xid
;
795 xdrmem_create(&xdr
, buf
, (u_int
)sizeof(buf
), XDR_ENCODE
);
796 if (!xdr_callmsg(&xdr
, &msg
)) {
797 st
= RPC_CANTENCODEARGS
;
801 if (!xdr_rmtcall_args(&xdr
, &rmtca
)) {
802 st
= RPC_CANTENCODEARGS
;
806 outlen
= (int)xdr_getpos(&xdr
);
809 st
= RPC_CANTENCODEARGS
;
815 if (ypdb
->dom_lockfd
!= -1) {
816 (void)close(ypdb
->dom_lockfd
);
817 ypdb
->dom_lockfd
= -1;
821 if (ypdb
->dom_alive
== 2) {
823 * This resolves the following situation:
824 * ypserver on other subnet was once bound,
825 * but rebooted and is now using a different port
827 struct sockaddr_in bindsin
;
829 (void)memset(&bindsin
, 0, sizeof bindsin
);
830 bindsin
.sin_family
= AF_INET
;
831 bindsin
.sin_len
= sizeof(bindsin
);
832 bindsin
.sin_port
= htons(PMAPPORT
);
833 bindsin
.sin_addr
= ypdb
->dom_server_addr
.sin_addr
;
835 if (sendto(rpcsock
, buf
, outlen
, 0,
836 (struct sockaddr
*)(void *)&bindsin
,
837 (socklen_t
)sizeof bindsin
) == -1)
838 yp_log(LOG_WARNING
, "nag_servers: sendto: %m");
841 switch (ypbindmode
) {
843 case YPBIND_SETLOCAL
:
845 return direct_set(buf
, outlen
, ypdb
);
848 case YPBIND_BROADCAST
:
849 return broadcast(buf
, outlen
);
852 return direct(buf
, outlen
);
859 broadcast(char *buf
, int outlen
)
861 struct ifaddrs
*ifap
, *ifa
;
862 struct sockaddr_in bindsin
;
865 (void)memset(&bindsin
, 0, sizeof bindsin
);
866 bindsin
.sin_family
= AF_INET
;
867 bindsin
.sin_len
= sizeof(bindsin
);
868 bindsin
.sin_port
= htons(PMAPPORT
);
870 if (getifaddrs(&ifap
) != 0) {
871 yp_log(LOG_WARNING
, "broadcast: getifaddrs: %m");
874 for (ifa
= ifap
; ifa
; ifa
= ifa
->ifa_next
) {
875 if (ifa
->ifa_addr
->sa_family
!= AF_INET
)
877 if ((ifa
->ifa_flags
& IFF_UP
) == 0)
880 switch (ifa
->ifa_flags
& (IFF_LOOPBACK
| IFF_BROADCAST
)) {
882 if (!ifa
->ifa_broadaddr
)
884 if (ifa
->ifa_broadaddr
->sa_family
!= AF_INET
)
886 in
= ((struct sockaddr_in
*)(void *)ifa
->ifa_broadaddr
)->sin_addr
;
889 in
= ((struct sockaddr_in
*)(void *)ifa
->ifa_addr
)->sin_addr
;
895 bindsin
.sin_addr
= in
;
898 (void)printf("broadcast %x\n",
899 bindsin
.sin_addr
.s_addr
);
901 if (sendto(rpcsock
, buf
, outlen
, 0,
902 (struct sockaddr
*)(void *)&bindsin
,
903 (socklen_t
)bindsin
.sin_len
) == -1)
904 yp_log(LOG_WARNING
, "broadcast: sendto: %m");
911 direct(char *buf
, int outlen
)
914 static char ypservers_path
[MAXPATHLEN
];
915 char line
[_POSIX2_LINE_MAX
];
918 struct sockaddr_in bindsin
;
924 (void)snprintf(ypservers_path
, sizeof(ypservers_path
),
925 "%s/%s%s", BINDINGDIR
, domainname
, YPSERVERSSUFF
);
926 df
= fopen(ypservers_path
, "r");
928 yp_log(LOG_ERR
, "%s: ", ypservers_path
);
933 (void)memset(&bindsin
, 0, sizeof bindsin
);
934 bindsin
.sin_family
= AF_INET
;
935 bindsin
.sin_len
= sizeof(bindsin
);
936 bindsin
.sin_port
= htons(PMAPPORT
);
938 while(fgets(line
, (int)sizeof(line
), df
) != NULL
) {
939 /* skip lines that are too big */
940 p
= strchr(line
, '\n');
944 while ((c
= getc(df
)) != '\n' && c
!= EOF
)
950 while (isspace((unsigned char)*p
))
954 hp
= gethostbyname(p
);
956 yp_log(LOG_WARNING
, "%s: %s", p
, hstrerror(h_errno
));
959 /* step through all addresses in case first is unavailable */
960 for (i
= 0; hp
->h_addr_list
[i
]; i
++) {
961 (void)memcpy(&bindsin
.sin_addr
, hp
->h_addr_list
[0],
963 if (sendto(rpcsock
, buf
, outlen
, 0,
964 (struct sockaddr
*)(void *)&bindsin
,
965 (socklen_t
)sizeof(bindsin
)) < 0) {
966 yp_log(LOG_WARNING
, "direct: sendto: %m");
973 yp_log(LOG_WARNING
, "no contactable servers found in %s",
981 direct_set(char *buf
, int outlen
, struct _dom_binding
*ypdb
)
983 struct sockaddr_in bindsin
;
984 char path
[MAXPATHLEN
];
986 struct ypbind_resp ybr
;
992 * Gack, we lose if binding file went away. We reset
993 * "been_set" if this happens, otherwise we'll never
996 (void)snprintf(path
, sizeof(path
), "%s/%s.%ld", BINDINGDIR
,
997 ypdb
->dom_domain
, ypdb
->dom_vers
);
999 if ((fd
= open(path
, O_SHLOCK
|O_RDONLY
, 0644)) == -1) {
1000 yp_log(LOG_WARNING
, "%s: %m", path
);
1006 (void)flock(fd
, LOCK_SH
);
1009 /* Read the binding file... */
1010 iov
[0].iov_base
= &(dummy_svc
.xp_port
);
1011 iov
[0].iov_len
= sizeof(dummy_svc
.xp_port
);
1012 iov
[1].iov_base
= &ybr
;
1013 iov
[1].iov_len
= sizeof(ybr
);
1014 bytes
= readv(fd
, iov
, 2);
1016 if ((size_t)bytes
!= (iov
[0].iov_len
+ iov
[1].iov_len
)) {
1017 /* Binding file corrupt? */
1018 yp_log(LOG_WARNING
, "%s: %m", path
);
1024 ybr
.ypbind_respbody
.ypbind_bindinfo
.ypbind_binding_addr
;
1026 if (sendto(rpcsock
, buf
, outlen
, 0,
1027 (struct sockaddr
*)(void *)&bindsin
,
1028 (socklen_t
)sizeof(bindsin
)) < 0) {
1029 yp_log(LOG_WARNING
, "direct_set: sendto: %m");
1036 static enum clnt_stat
1037 handle_replies(void)
1042 struct _dom_binding
*ypdb
;
1043 struct sockaddr_in raddr
;
1050 printf("handle_replies receiving\n");
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
)(void *)&rmtcr
;
1056 msg
.acpted_rply
.ar_results
.proc
= xdr_rmtcallres
;
1059 fromlen
= sizeof(struct sockaddr
);
1060 inlen
= recvfrom(rpcsock
, buf
, sizeof buf
, 0,
1061 (struct sockaddr
*)(void *)&raddr
, &fromlen
);
1067 printf("handle_replies: recvfrom failed (%s)\n",
1070 return RPC_CANTRECV
;
1072 if ((size_t)inlen
< sizeof(u_int32_t
))
1076 * see if reply transaction id matches sent id.
1077 * If so, decode the results.
1079 xdrmem_create(&xdr
, buf
, (u_int
)inlen
, XDR_DECODE
);
1080 if (xdr_replymsg(&xdr
, &msg
)) {
1081 if ((msg
.rm_reply
.rp_stat
== MSG_ACCEPTED
) &&
1082 (msg
.acpted_rply
.ar_stat
== SUCCESS
)) {
1083 raddr
.sin_port
= htons((u_short
)rmtcr_port
);
1084 ypdb
= xid2ypdb(msg
.rm_xid
);
1086 rpc_received(ypdb
->dom_domain
, &raddr
, 0);
1089 xdr
.x_op
= XDR_FREE
;
1090 msg
.acpted_rply
.ar_results
.proc
= xdr_void
;
1096 static enum clnt_stat
1102 struct _dom_binding
*ypdb
;
1103 struct sockaddr_in raddr
;
1111 printf("handle_ping receiving\n");
1113 (void)memset(&xdr
, 0, sizeof(xdr
));
1114 (void)memset(&msg
, 0, sizeof(msg
));
1115 msg
.acpted_rply
.ar_verf
= _null_auth
;
1116 msg
.acpted_rply
.ar_results
.where
= (caddr_t
)(void *)&res
;
1117 msg
.acpted_rply
.ar_results
.proc
= xdr_bool
;
1120 fromlen
= sizeof (struct sockaddr
);
1121 inlen
= recvfrom(pingsock
, buf
, sizeof buf
, 0,
1122 (struct sockaddr
*)(void *)&raddr
, &fromlen
);
1128 printf("handle_ping: recvfrom failed (%s)\n",
1131 return RPC_CANTRECV
;
1133 if ((size_t)inlen
< sizeof(u_int32_t
))
1137 * see if reply transaction id matches sent id.
1138 * If so, decode the results.
1140 xdrmem_create(&xdr
, buf
, (u_int
)inlen
, XDR_DECODE
);
1141 if (xdr_replymsg(&xdr
, &msg
)) {
1142 if ((msg
.rm_reply
.rp_stat
== MSG_ACCEPTED
) &&
1143 (msg
.acpted_rply
.ar_stat
== SUCCESS
)) {
1144 ypdb
= xid2ypdb(msg
.rm_xid
);
1146 rpc_received(ypdb
->dom_domain
, &raddr
, 0);
1149 xdr
.x_op
= XDR_FREE
;
1150 msg
.acpted_rply
.ar_results
.proc
= xdr_void
;
1157 * LOOPBACK IS MORE IMPORTANT: PUT IN HACK
1160 rpc_received(char *dom
, struct sockaddr_in
*raddrp
, int force
)
1162 struct _dom_binding
*ypdb
;
1163 struct iovec iov
[2];
1164 struct ypbind_resp ybr
;
1169 (void)printf("returned from %s about %s\n",
1170 inet_ntoa(raddrp
->sin_addr
), dom
);
1176 if (_yp_invalid_domain(dom
))
1179 /* don't support insecure servers by default */
1180 if (!insecure
&& ntohs(raddrp
->sin_port
) >= IPPORT_RESERVED
)
1183 for (ypdb
= ypbindlist
; ypdb
; ypdb
= ypdb
->dom_pnext
)
1184 if (!strcmp(ypdb
->dom_domain
, dom
))
1190 ypdb
= makebinding(dom
);
1191 ypdb
->dom_lockfd
= -1;
1192 ypdb
->dom_pnext
= ypbindlist
;
1196 /* soft update, alive */
1197 if (ypdb
->dom_alive
== 1 && force
== 0) {
1198 if (!memcmp(&ypdb
->dom_server_addr
, raddrp
,
1199 sizeof ypdb
->dom_server_addr
)) {
1200 ypdb
->dom_alive
= 1;
1201 /* recheck binding in 60 sec */
1202 ypdb
->dom_check_t
= time(NULL
) + 60;
1207 (void)memcpy(&ypdb
->dom_server_addr
, raddrp
,
1208 sizeof ypdb
->dom_server_addr
);
1209 /* recheck binding in 60 seconds */
1210 ypdb
->dom_check_t
= time(NULL
) + 60;
1211 ypdb
->dom_vers
= YPVERS
;
1212 ypdb
->dom_alive
= 1;
1214 if (ypdb
->dom_lockfd
!= -1)
1215 (void)close(ypdb
->dom_lockfd
);
1217 if ((fd
= makelock(ypdb
)) == -1)
1221 * ok, if BINDINGDIR exists, and we can create the binding file,
1222 * then write to it..
1224 ypdb
->dom_lockfd
= fd
;
1226 iov
[0].iov_base
= &(udptransp
->xp_port
);
1227 iov
[0].iov_len
= sizeof udptransp
->xp_port
;
1228 iov
[1].iov_base
= &ybr
;
1229 iov
[1].iov_len
= sizeof ybr
;
1231 (void)memset(&ybr
, 0, sizeof ybr
);
1232 ybr
.ypbind_status
= YPBIND_SUCC_VAL
;
1233 ybr
.ypbind_respbody
.ypbind_bindinfo
.ypbind_binding_addr
=
1235 ybr
.ypbind_respbody
.ypbind_bindinfo
.ypbind_binding_port
=
1238 if ((size_t)writev(ypdb
->dom_lockfd
, iov
, 2) !=
1239 iov
[0].iov_len
+ iov
[1].iov_len
) {
1240 yp_log(LOG_WARNING
, "writev: %m");
1241 (void)close(ypdb
->dom_lockfd
);
1243 ypdb
->dom_lockfd
= -1;
1247 static struct _dom_binding
*
1248 xid2ypdb(u_int32_t xid
)
1250 struct _dom_binding
*ypdb
;
1252 for (ypdb
= ypbindlist
; ypdb
; ypdb
= ypdb
->dom_pnext
)
1253 if (ypdb
->dom_xid
== xid
)
1259 unique_xid(struct _dom_binding
*ypdb
)
1263 tmp_xid
= ((u_int32_t
)(u_long
)ypdb
) & 0xffffffff;
1264 while (xid2ypdb(tmp_xid
) != NULL
)