2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
25 * Copyright (c) 1992, 1993 Theo de Raadt <deraadt@fsa.ca>
26 * All rights reserved.
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. All advertising materials mentioning features or use of this software
37 * must display the following acknowledgement:
38 * This product includes software developed by Theo de Raadt.
39 * 4. The name of the author may not be used to endorse or promote
40 * products derived from this software without specific prior written
43 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
44 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
45 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
47 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 static char rcsid
[] = "$Id: ypbind.c,v 1.1.1.1 1999/05/02 03:59:00 wsanchez Exp $";
59 #include <sys/cdefs.h>
61 #include <sys/param.h>
62 #include <sys/types.h>
63 #include <sys/ioctl.h>
64 #include <sys/signal.h>
65 #include <sys/socket.h>
67 #include <sys/fcntl.h>
84 #include <arpa/inet.h>
85 #include <rpc/pmap_clnt.h>
86 #include <rpc/pmap_prot.h>
87 #include <rpc/pmap_rmt.h>
89 #include <rpcsvc/yp.h>
90 // #include <rpcsvc/yp_prot.h>
91 // #include <rpcsvc/ypclnt.h>
93 #define _PATH_YPBIND_LOCK "/var/run/ypbind.lock"
94 #define YPSERVERSSUFF ".ypservers"
95 #define BINDINGDIR "/var/yp/binding"
105 struct _dom_binding
*dom_pnext
;
106 char dom_domain
[YPMAXDOMAIN
+ 1];
107 struct sockaddr_in dom_server_addr
;
108 unsigned short int dom_server_port
;
121 static struct _dom_binding
*ypbindlist
;
132 ypbind_mode_t ypbindmode
;
135 * If ypbindmode is YPBIND_SETLOCAL or YPBIND_SETALL, this indicates
136 * whether or not we've been "ypset". If we haven't, we behave like
137 * YPBIND_BROADCAST. If we have, we behave like YPBIND_DIRECT.
142 static int rpcsock
, pingsock
;
143 static struct rmtcallargs rmtca
;
144 static struct rmtcallres rmtcr
;
145 static bool_t rmtcr_outval
;
146 static u_long rmtcr_port
;
147 static SVCXPRT
*udptransp
, *tcptransp
;
149 int main
__P((int, char *[]));
151 static void usage
__P((void));
152 static struct _dom_binding
*makebinding
__P((const char *));
153 static int makelock
__P((struct _dom_binding
*));
154 static void removelock
__P((struct _dom_binding
*));
155 static void checkwork
__P((void));
156 static int ping
__P((struct _dom_binding
*));
157 static int nag_servers
__P((struct _dom_binding
*));
158 static enum clnt_stat handle_replies
__P((void));
159 static enum clnt_stat handle_ping
__P((void));
160 static void rpc_received
__P((char *, struct sockaddr_in
*, int));
161 static struct _dom_binding
*xid2ypdb
__P((u_int32_t
));
162 static u_int32_t unique_xid
__P((struct _dom_binding
*));
163 static int broadcast
__P((char *, int));
164 static int direct
__P((char *, int));
165 static int direct_set
__P((char *, int, struct _dom_binding
*));
168 #define DEBUG_STDERR 1
169 #define DEBUG_SYSLOG 2
172 static char *msg_str
= NULL
;
175 sys_openlog(int debug
, char *str
, int flags
, int facility
)
177 if (msg_str
!= NULL
) free(msg_str
);
181 msg_str
= malloc(strlen(str
) + 1);
182 strcpy(msg_str
, str
);
185 if (debug
& DEBUG_SYSLOG
) openlog(msg_str
, flags
, facility
);
189 sys_msg(int debug
, int priority
, char *message
, ...)
193 va_start(ap
, message
);
195 if (debug
& DEBUG_SYSLOG
) vsyslog(priority
, message
, ap
);
197 if (debug
& DEBUG_STDERR
)
199 if (msg_str
!= NULL
) fprintf(stderr
, "%s: ", msg_str
);
200 vfprintf(stderr
, message
, ap
);
201 fprintf(stderr
, "\n");
212 "Usage: ypbind [-broadcast] [-insecure] [-ypset] [-ypsetme] [-d]\n");
216 static struct _dom_binding
*
217 makebinding(const char *dm
)
219 struct _dom_binding
*ypdb
;
221 ypdb
= (struct _dom_binding
*)malloc(sizeof *ypdb
);
222 memset(ypdb
, 0, sizeof *ypdb
);
223 strncpy(ypdb
->dom_domain
, dm
, sizeof ypdb
->dom_domain
);
224 ypdb
->dom_domain
[sizeof(ypdb
->dom_domain
) - 1] = '\0';
230 makelock(struct _dom_binding
*ypdb
)
233 char path
[MAXPATHLEN
];
235 snprintf(path
, sizeof(path
), "%s/%s.%ld", BINDINGDIR
,
236 ypdb
->dom_domain
, ypdb
->dom_vers
);
238 fd
= open(path
, O_CREAT
|O_SHLOCK
|O_RDWR
|O_TRUNC
, 0644);
241 mkdir(BINDINGDIR
, 0755);
242 fd
= open(path
, O_CREAT
|O_SHLOCK
|O_RDWR
|O_TRUNC
, 0644);
243 if (fd
== -1) return -1;
253 removelock(struct _dom_binding
*ypdb
)
255 char path
[MAXPATHLEN
];
257 snprintf(path
, sizeof(path
), "%s/%s.%ld",
258 BINDINGDIR
, ypdb
->dom_domain
, ypdb
->dom_vers
);
263 svc_ypbindproc_null_2(void *argp
, SVCXPRT
*transp
)
267 sys_msg(debug
, LOG_DEBUG
, "ypbindproc_null_2");
269 memset(&res
, 0, sizeof(res
));
274 svc_ypbindproc_domain_2(void *argp
, SVCXPRT
*transp
)
276 static struct ypbind_resp res
;
277 struct _dom_binding
*ypdb
;
278 char *arg
= *(char **) argp
;
281 sys_msg(debug
, LOG_DEBUG
, "ypbindproc_domain_2 %s", arg
);
283 memset(&res
, 0, sizeof res
);
284 res
.ypbind_status
= YPBIND_FAIL_VAL
;
286 for (count
= 0, ypdb
= ypbindlist
;
288 ypdb
= ypdb
->dom_pnext
, count
++)
290 /* prevent denial of service */
291 if (count
> 100) return NULL
;
292 if (!strcmp(ypdb
->dom_domain
, arg
)) break;
297 ypdb
= makebinding(arg
);
298 ypdb
->dom_vers
= YPVERS
;
300 ypdb
->dom_lockfd
= -1;
302 ypdb
->dom_xid
= unique_xid(ypdb
);
303 ypdb
->dom_pnext
= ypbindlist
;
306 sys_msg(debug
, LOG_ERR
, "unknown domain %s", arg
);
310 if (ypdb
->dom_alive
== 0)
312 sys_msg(debug
, LOG_ERR
, "dead domain %s", arg
);
318 if (now
< ypdb
->dom_ask_t
+ 5)
321 * Hmm. More than 2 requests in 5 seconds have indicated
322 * that my binding is possibly incorrect.
323 * Ok, do an immediate poll of the server.
325 if (ypdb
->dom_check_t
>= now
)
328 ypdb
->dom_check_t
= 0;
332 ypdb
->dom_ask_t
= now
;
335 res
.ypbind_status
= YPBIND_SUCC_VAL
;
336 bcopy(&ypdb
->dom_server_addr
.sin_addr
.s_addr
,
337 res
.ypbind_resp_u
.ypbind_bindinfo
.ypbind_binding_addr
, 4);
338 bcopy(&ypdb
->dom_server_port
,
339 res
.ypbind_resp_u
.ypbind_bindinfo
.ypbind_binding_port
, 2);
341 sys_msg(debug
, LOG_DEBUG
, "domain %s at %s/%d", ypdb
->dom_domain
,
342 inet_ntoa(ypdb
->dom_server_addr
.sin_addr
),
343 ntohs(ypdb
->dom_server_addr
.sin_port
));
348 svc_ypbindproc_setdom_2(void *argp
, SVCXPRT
*transp
)
350 struct ypbind_setdom
*sd
= argp
;
351 struct sockaddr_in
*fromsin
, bindsin
;
354 memset(&bindsin
, 0, sizeof bindsin
);
355 bindsin
.sin_family
= AF_INET
;
356 bindsin
.sin_len
= sizeof(bindsin
);
357 bcopy(&sd
->ypsetdom_binding
.ypbind_binding_addr
,
358 &bindsin
.sin_addr
.s_addr
, 4);
359 bcopy(&sd
->ypsetdom_binding
.ypbind_binding_port
,
360 &bindsin
.sin_port
, 2);
361 fromsin
= svc_getcaller(transp
);
363 memset(&res
, 0, sizeof(res
));
367 case YPBIND_SETLOCAL
:
368 if (fromsin
->sin_addr
.s_addr
!= htonl(INADDR_LOOPBACK
))
370 sys_msg(debug
, LOG_ERR
, "ypset from %s denied",
371 inet_ntoa(fromsin
->sin_addr
));
382 case YPBIND_BROADCAST
:
384 sys_msg(debug
, LOG_ERR
, "ypset denied");
388 if (ntohs(fromsin
->sin_port
) >= IPPORT_RESERVED
)
390 sys_msg(debug
, LOG_ERR
, "ypset from unpriviledged port denied");
394 if (sd
->ypsetdom_vers
!= YPVERS
)
396 sys_msg(debug
, LOG_ERR
, "ypset with wrong version denied");
397 sys_msg(debug
, LOG_DEBUG
, "ypsetdom_vers = %lu YPVERS = %lu",
398 sd
->ypsetdom_vers
, YPVERS
);
402 rpc_received(sd
->ypsetdom_domain
, &bindsin
, 1);
404 sys_msg(debug
, LOG_DEBUG
, "ypset to %s succeeded",
405 inet_ntoa(bindsin
.sin_addr
));
411 ypbindprog_2(struct svc_req
*rqstp
, register SVCXPRT
*transp
)
415 char ypbindproc_domain_2_arg
[YPMAXDOMAIN
+ 1];
416 struct ypbind_setdom ypbindproc_setdom_2_arg
;
418 struct authunix_parms
*creds
;
420 xdrproc_t xdr_argument
, xdr_result
;
421 void *(*local
) __P((void *, SVCXPRT
*));
423 switch (rqstp
->rq_proc
)
425 case YPBINDPROC_NULL
:
426 xdr_argument
= xdr_void
;
427 xdr_result
= xdr_void
;
428 local
= svc_ypbindproc_null_2
;
431 case YPBINDPROC_DOMAIN
:
432 xdr_argument
= xdr_domainname
;
433 xdr_result
= xdr_ypbind_resp
;
434 local
= svc_ypbindproc_domain_2
;
437 case YPBINDPROC_SETDOM
:
438 switch (rqstp
->rq_cred
.oa_flavor
)
441 creds
= (struct authunix_parms
*)rqstp
->rq_clntcred
;
442 if (creds
->aup_uid
!= 0)
444 svcerr_auth(transp
, AUTH_BADCRED
);
450 svcerr_auth(transp
, AUTH_TOOWEAK
);
454 xdr_argument
= xdr_ypbind_setdom
;
455 xdr_result
= xdr_void
;
456 local
= svc_ypbindproc_setdom_2
;
460 svcerr_noproc(transp
);
464 memset(&argument
, 0, sizeof(argument
));
465 if (!svc_getargs(transp
, xdr_argument
, (caddr_t
)&argument
))
467 svcerr_decode(transp
);
471 result
= (*local
)(&argument
, transp
);
472 if (result
!= NULL
&& !svc_sendreply(transp
, xdr_result
, result
))
474 svcerr_systemerr(transp
);
481 main(int argc
, char *argv
[])
486 int evil
= 0, one
, i
;
487 char pathname
[MAXPATHLEN
];
490 yp_get_default_domain(&dname
);
491 if (dname
[0] == '\0')
493 fprintf(stderr
, "Domainname not set. Aborting.\n");
497 debug
= DEBUG_SYSLOG
;
498 ypbindmode
= YPBIND_DIRECT
;
499 for (i
= 1; i
< argc
; i
++)
501 if (!strcmp(argv
[i
], "-insecure"))
504 else if (!strcmp(argv
[i
], "-ypset"))
505 ypbindmode
= YPBIND_SETALL
;
507 else if (!strcmp(argv
[i
], "-ypsetme"))
508 ypbindmode
= YPBIND_SETLOCAL
;
510 else if (!strcmp(argv
[i
], "-broadcast"))
511 ypbindmode
= YPBIND_BROADCAST
;
513 else if (!strcmp(argv
[i
], "-d"))
514 debug
= DEBUG_STDERR
;
520 sys_openlog(debug
, "ypbind", LOG_NDELAY
| LOG_PID
, LOG_DAEMON
);
523 * Per traditional ypbind(8) semantics, if a ypservers
524 * file does not exist, we default to broadcast mode.
525 * If the file does exist, we default to direct mode.
526 * Note that we can still override direct mode by passing
527 * the -broadcast flag.
529 snprintf(pathname
, sizeof(pathname
), "%s/%s%s",
530 BINDINGDIR
, dname
, YPSERVERSSUFF
);
532 if ((ypbindmode
== YPBIND_DIRECT
) && (stat(pathname
, &st
) < 0))
534 sys_msg(debug
, LOG_DEBUG
, "%s does not exist, defaulting to broadcast.",
536 ypbindmode
= YPBIND_BROADCAST
;
539 /* blow away everything in BINDINGDIR */
541 lockfd
= open(_PATH_YPBIND_LOCK
, O_CREAT
|O_SHLOCK
|O_RDWR
|O_TRUNC
, 0644);
544 sys_msg(debug
, LOG_ERR
, "Cannot create %s", _PATH_YPBIND_LOCK
);
549 flock(lockfd
, LOCK_SH
);
552 pmap_unset(YPBINDPROG
, YPBINDVERS
);
554 udptransp
= svcudp_create(RPC_ANYSOCK
);
555 if (udptransp
== NULL
)
557 sys_msg(debug
, LOG_ERR
, "Cannot create udp service.");
561 if (!svc_register(udptransp
, YPBINDPROG
, YPBINDVERS
, ypbindprog_2
,
564 sys_msg(debug
, LOG_ERR
,
565 "Unable to register (YPBINDPROG, YPBINDVERS, udp).");
569 tcptransp
= svctcp_create(RPC_ANYSOCK
, 0, 0);
570 if (tcptransp
== NULL
)
572 sys_msg(debug
, LOG_ERR
, "Cannot create tcp service.");
576 if (!svc_register(tcptransp
, YPBINDPROG
, YPBINDVERS
, ypbindprog_2
,
579 sys_msg(debug
, LOG_ERR
,
580 "Unable to register (YPBINDPROG, YPBINDVERS, tcp).");
584 /* XXX use SOCK_STREAM for direct queries? */
585 rpcsock
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
588 sys_msg(debug
, LOG_ERR
, "rpc socket() failed.");
592 pingsock
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
595 sys_msg(debug
, LOG_ERR
, "ping socket() failed.");
599 fcntl(rpcsock
, F_SETFL
, fcntl(rpcsock
, F_GETFL
, 0) | FNDELAY
);
600 fcntl(pingsock
, F_SETFL
, fcntl(pingsock
, F_GETFL
, 0) | FNDELAY
);
603 setsockopt(rpcsock
, SOL_SOCKET
, SO_BROADCAST
, &one
, sizeof(one
));
606 rmtca
.proc
= YPPROC_DOMAIN_NONACK
;
607 rmtca
.xdr_args
= NULL
; /* set at call time */
608 rmtca
.args_ptr
= NULL
; /* set at call time */
609 rmtcr
.port_ptr
= &rmtcr_port
;
610 rmtcr
.xdr_results
= xdr_bool
;
611 rmtcr
.results_ptr
= (caddr_t
)&rmtcr_outval
;
613 /* build initial domain binding, make it "unsuccessful" */
614 ypbindlist
= makebinding(dname
);
615 ypbindlist
->dom_vers
= YPVERS
;
616 ypbindlist
->dom_alive
= 0;
617 ypbindlist
->dom_lockfd
= -1;
618 removelock(ypbindlist
);
622 // width = svc_maxfd;
627 if (pingsock
> width
)
634 FD_SET(rpcsock
, &fdsr
);
635 FD_SET(pingsock
, &fdsr
);
639 switch (select(width
, &fdsr
, NULL
, NULL
, &tv
))
646 sys_msg(debug
, LOG_WARNING
, "select: %s", strerror(errno
));
650 if (FD_ISSET(rpcsock
, &fdsr
)) handle_replies();
651 if (FD_ISSET(pingsock
, &fdsr
)) handle_ping();
652 svc_getreqset(&fdsr
);
653 if (check
) checkwork();
657 if ((evil
== 0) && (ypbindlist
->dom_alive
!= 0))
660 if (debug
== DEBUG_SYSLOG
) daemon(0, 0);
666 * State transition is done like this:
668 * STATE EVENT ACTION NEWSTATE TIMEOUT
669 * no binding timeout broadcast no binding 5 sec
670 * no binding answer -- binding 60 sec
671 * binding timeout ping server checking 5 sec
672 * checking timeout ping server + broadcast checking 5 sec
673 * checking answer -- binding 60 sec
678 struct _dom_binding
*ypdb
;
684 for (ypdb
= ypbindlist
; ypdb
; ypdb
= ypdb
->dom_pnext
)
686 if (ypdb
->dom_check_t
< t
)
688 if (ypdb
->dom_alive
== 1) ping(ypdb
);
689 else nag_servers(ypdb
);
691 ypdb
->dom_check_t
= t
+ 5;
697 ping(struct _dom_binding
*ypdb
)
699 char *dom
= ypdb
->dom_domain
;
707 memset(&xdr
, 0, sizeof xdr
);
708 memset(&msg
, 0, sizeof msg
);
710 rpcua
= authunix_create_default();
713 sys_msg(debug
, LOG_ERR
, "ping: cannot get unix auth");
714 return RPC_SYSTEMERROR
;
717 msg
.rm_direction
= CALL
;
718 msg
.rm_call
.cb_rpcvers
= RPC_MSG_VERSION
;
719 msg
.rm_call
.cb_prog
= YPPROG
;
720 msg
.rm_call
.cb_vers
= YPVERS
;
721 msg
.rm_call
.cb_proc
= YPPROC_DOMAIN_NONACK
;
722 msg
.rm_call
.cb_cred
= rpcua
->ah_cred
;
723 msg
.rm_call
.cb_verf
= rpcua
->ah_verf
;
725 msg
.rm_xid
= ypdb
->dom_xid
;
726 xdrmem_create(&xdr
, buf
, sizeof buf
, XDR_ENCODE
);
727 if (!xdr_callmsg(&xdr
, &msg
))
729 st
= RPC_CANTENCODEARGS
;
734 if (!xdr_domainname(&xdr
, (void *)&dom
))
736 st
= RPC_CANTENCODEARGS
;
741 outlen
= (int)xdr_getpos(&xdr
);
745 st
= RPC_CANTENCODEARGS
;
753 if (sendto(pingsock
, buf
, outlen
, 0,
754 (struct sockaddr
*)&ypdb
->dom_server_addr
,
755 sizeof ypdb
->dom_server_addr
) == -1)
756 sys_msg(debug
, LOG_WARNING
, "ping: sendto");
762 nag_servers(struct _dom_binding
*ypdb
)
764 char *dom
= ypdb
->dom_domain
;
772 rmtca
.xdr_args
= xdr_domainname
;
773 rmtca
.args_ptr
= (char *)&dom
;
775 memset(&xdr
, 0, sizeof xdr
);
776 memset(&msg
, 0, sizeof msg
);
778 rpcua
= authunix_create_default();
781 sys_msg(debug
, LOG_ERR
, "ping: cannot get unix auth");
782 return RPC_SYSTEMERROR
;
785 msg
.rm_direction
= CALL
;
786 msg
.rm_call
.cb_rpcvers
= RPC_MSG_VERSION
;
787 msg
.rm_call
.cb_prog
= PMAPPROG
;
788 msg
.rm_call
.cb_vers
= PMAPVERS
;
789 msg
.rm_call
.cb_proc
= PMAPPROC_CALLIT
;
790 msg
.rm_call
.cb_cred
= rpcua
->ah_cred
;
791 msg
.rm_call
.cb_verf
= rpcua
->ah_verf
;
793 msg
.rm_xid
= ypdb
->dom_xid
;
794 xdrmem_create(&xdr
, buf
, sizeof buf
, XDR_ENCODE
);
795 if (!xdr_callmsg(&xdr
, &msg
))
797 st
= RPC_CANTENCODEARGS
;
802 if (!xdr_rmtcall_args(&xdr
, &rmtca
))
804 st
= RPC_CANTENCODEARGS
;
809 outlen
= (int)xdr_getpos(&xdr
);
813 st
= RPC_CANTENCODEARGS
;
820 if (ypdb
->dom_lockfd
!= -1)
822 close(ypdb
->dom_lockfd
);
823 ypdb
->dom_lockfd
= -1;
827 if (ypdb
->dom_alive
== 2)
830 * This resolves the following situation:
831 * ypserver on other subnet was once bound,
832 * but rebooted and is now using a different port
834 struct sockaddr_in bindsin
;
836 memset(&bindsin
, 0, sizeof bindsin
);
837 bindsin
.sin_family
= AF_INET
;
838 bindsin
.sin_len
= sizeof(bindsin
);
839 bindsin
.sin_port
= htons(PMAPPORT
);
840 bindsin
.sin_addr
= ypdb
->dom_server_addr
.sin_addr
;
842 if (sendto(rpcsock
, buf
, outlen
, 0, (struct sockaddr
*)&bindsin
,
843 sizeof bindsin
) == -1)
844 sys_msg(debug
, LOG_WARNING
, "broadcast: sendto");
850 case YPBIND_SETLOCAL
:
851 if (been_ypset
) return direct_set(buf
, outlen
, ypdb
);
854 case YPBIND_BROADCAST
:
855 return broadcast(buf
, outlen
);
858 return direct(buf
, outlen
);
865 broadcast(char *buf
, int outlen
)
873 struct sockaddr_in bindsin
;
875 /* find all networks and send the RPC packet out them all */
876 sock
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
879 sys_msg(debug
, LOG_WARNING
, "broadcast: socket: %s", strerror(errno
));
883 memset(&bindsin
, 0, sizeof bindsin
);
884 bindsin
.sin_family
= AF_INET
;
885 bindsin
.sin_len
= sizeof(bindsin
);
886 bindsin
.sin_port
= htons(PMAPPORT
);
888 ifc
.ifc_len
= sizeof inbuf
;
890 if (ioctl(sock
, SIOCGIFCONF
, &ifc
) < 0)
893 sys_msg(debug
, LOG_WARNING
, "broadcast: ioctl(SIOCGIFCONF): %s",
898 addrlen
= sizeof(struct ifreq
) - IFNAMSIZ
;
901 while (offset
<= ifc
.ifc_len
)
903 ifr
= (struct ifreq
*)(ifc
.ifc_buf
+ offset
);
905 if (ifr
->ifr_addr
.sa_len
> addrlen
) offset
+= ifr
->ifr_addr
.sa_len
;
906 else offset
+= addrlen
;
908 if (ifr
->ifr_addr
.sa_family
!= AF_INET
) continue;
909 if (ioctl(sock
, SIOCGIFFLAGS
, ifr
) < 0) continue;
910 if ((ifr
->ifr_flags
& IFF_UP
) == 0) continue;
912 if (ifr
->ifr_flags
& IFF_BROADCAST
)
914 if (ioctl(sock
, SIOCGIFBRDADDR
, ifr
) < 0)
916 sys_msg(debug
, LOG_WARNING
,
917 "broadcast: ioctl(SIOCGIFBRDADDR): %s", strerror(errno
));
921 else if (ifr
->ifr_flags
& IFF_LOOPBACK
)
923 if (ioctl(sock
, SIOCGIFADDR
, ifr
) < 0)
925 sys_msg(debug
, LOG_WARNING
,
926 "broadcast: ioctl(SIOCGIFADDR): %s", strerror(errno
));
932 in
= ((struct sockaddr_in
*)&(ifr
->ifr_addr
))->sin_addr
;
933 bindsin
.sin_addr
= in
;
934 if (sendto(rpcsock
, buf
, outlen
, 0, (struct sockaddr
*)&bindsin
,
935 sizeof bindsin
) == -1)
936 sys_msg(debug
, LOG_WARNING
, "broadcast: sendto: %s",
945 direct(char *buf
, int outlen
)
948 static char ypservers_path
[MAXPATHLEN
];
949 char line
[_POSIX2_LINE_MAX
];
952 struct sockaddr_in bindsin
;
957 snprintf(ypservers_path
, sizeof(ypservers_path
),
958 "%s/%s%s", BINDINGDIR
, dname
, YPSERVERSSUFF
);
959 df
= fopen(ypservers_path
, "r");
962 sys_msg(debug
, LOG_ALERT
, "Missing file %s, aborting.",
968 memset(&bindsin
, 0, sizeof bindsin
);
969 bindsin
.sin_family
= AF_INET
;
970 bindsin
.sin_len
= sizeof(bindsin
);
971 bindsin
.sin_port
= htons(PMAPPORT
);
973 while(fgets(line
, sizeof(line
), df
) != NULL
)
975 /* skip lines that are too big */
976 p
= strchr(line
, '\n');
981 while ((c
= getc(df
)) != '\n' && c
!= EOF
);
987 while (isspace(*p
)) p
++;
988 if (*p
== '#') continue;
989 hp
= gethostbyname(p
);
992 sys_msg(debug
, LOG_ERR
, "Can't find host: %s", p
);
996 /* step through all addresses in case first is unavailable */
997 for (i
= 0; hp
->h_addr_list
[i
]; i
++)
999 memmove(&bindsin
.sin_addr
, hp
->h_addr_list
[0],
1001 if (sendto(rpcsock
, buf
, outlen
, 0,
1002 (struct sockaddr
*)&bindsin
, sizeof bindsin
) < 0)
1004 sys_msg(debug
, LOG_WARNING
, "direct: sendto: %s",
1014 sys_msg(debug
, LOG_ALERT
,
1015 "Can't contact any servers listed in %s. Aborting", ypservers_path
);
1023 direct_set(char *buf
, int outlen
, struct _dom_binding
*ypdb
)
1025 struct sockaddr_in bindsin
;
1026 char path
[MAXPATHLEN
];
1027 struct iovec iov
[2];
1028 struct ypbind_resp ybr
;
1033 * Gack, we lose if binding file went away. We reset
1034 * "been_set" if this happens, otherwise we'll never
1037 snprintf(path
, sizeof(path
), "%s/%s.%ld", BINDINGDIR
,
1038 ypdb
->dom_domain
, ypdb
->dom_vers
);
1040 if ((fd
= open(path
, O_SHLOCK
|O_RDONLY
, 0644)) == -1)
1042 sys_msg(debug
, LOG_WARNING
, "Can't open file %s", path
);
1051 /* Read the binding file... */
1052 iov
[0].iov_base
= (caddr_t
)&(dummy_svc
.xp_port
);
1053 iov
[0].iov_len
= sizeof(dummy_svc
.xp_port
);
1054 iov
[1].iov_base
= (caddr_t
)&ybr
;
1055 iov
[1].iov_len
= sizeof(ybr
);
1056 bytes
= readv(fd
, iov
, 2);
1059 if (bytes
!= (iov
[0].iov_len
+ iov
[1].iov_len
))
1061 /* Binding file corrupt? */
1062 sys_msg(debug
, LOG_WARNING
, "Can't parse file %s", path
);
1067 bcopy(&ybr
.ypbind_resp_u
.ypbind_bindinfo
.ypbind_binding_addr
,
1068 &bindsin
.sin_addr
, 4);
1070 if (sendto(rpcsock
, buf
, outlen
, 0, (struct sockaddr
*)&bindsin
,
1071 sizeof(bindsin
)) < 0)
1073 sys_msg(debug
, LOG_WARNING
, "direct_set: sendto: %s", strerror(errno
));
1080 static enum clnt_stat
1085 struct _dom_binding
*ypdb
;
1086 struct sockaddr_in raddr
;
1091 memset(&xdr
, 0, sizeof(xdr
));
1092 memset(&msg
, 0, sizeof(msg
));
1093 msg
.acpted_rply
.ar_verf
= _null_auth
;
1094 msg
.acpted_rply
.ar_results
.where
= (caddr_t
)&rmtcr
;
1095 msg
.acpted_rply
.ar_results
.proc
= xdr_rmtcallres
;
1098 fromlen
= sizeof (struct sockaddr
);
1099 inlen
= recvfrom(rpcsock
, buf
, sizeof buf
, 0,
1100 (struct sockaddr
*)&raddr
, &fromlen
);
1103 if (errno
== EINTR
) goto try_again
;
1104 return RPC_CANTRECV
;
1107 if (inlen
< sizeof(u_int32_t
)) goto recv_again
;
1110 * see if reply transaction id matches sent id.
1111 * If so, decode the results.
1113 xdrmem_create(&xdr
, buf
, (u_int
)inlen
, XDR_DECODE
);
1114 if (xdr_replymsg(&xdr
, &msg
))
1116 if ((msg
.rm_reply
.rp_stat
== MSG_ACCEPTED
) &&
1117 (msg
.acpted_rply
.ar_stat
== SUCCESS
)) {
1118 raddr
.sin_port
= htons((u_short
)rmtcr_port
);
1119 ypdb
= xid2ypdb(msg
.rm_xid
);
1120 if (ypdb
!= NULL
) rpc_received(ypdb
->dom_domain
, &raddr
, 0);
1124 xdr
.x_op
= XDR_FREE
;
1125 msg
.acpted_rply
.ar_results
.proc
= xdr_void
;
1131 static enum clnt_stat
1136 struct _dom_binding
*ypdb
;
1137 struct sockaddr_in raddr
;
1143 memset(&xdr
, 0, sizeof(xdr
));
1144 memset(&msg
, 0, sizeof(msg
));
1145 msg
.acpted_rply
.ar_verf
= _null_auth
;
1146 msg
.acpted_rply
.ar_results
.where
= (caddr_t
)&res
;
1147 msg
.acpted_rply
.ar_results
.proc
= xdr_bool
;
1150 fromlen
= sizeof (struct sockaddr
);
1151 inlen
= recvfrom(pingsock
, buf
, sizeof buf
, 0,
1152 (struct sockaddr
*)&raddr
, &fromlen
);
1155 if (errno
== EINTR
) goto try_again
;
1156 return RPC_CANTRECV
;
1159 if (inlen
< sizeof(u_int32_t
)) goto recv_again
;
1162 * see if reply transaction id matches sent id.
1163 * If so, decode the results.
1165 xdrmem_create(&xdr
, buf
, (u_int
)inlen
, XDR_DECODE
);
1166 if (xdr_replymsg(&xdr
, &msg
))
1168 if ((msg
.rm_reply
.rp_stat
== MSG_ACCEPTED
) &&
1169 (msg
.acpted_rply
.ar_stat
== SUCCESS
))
1171 ypdb
= xid2ypdb(msg
.rm_xid
);
1172 if (ypdb
!= NULL
) rpc_received(ypdb
->dom_domain
, &raddr
, 0);
1176 xdr
.x_op
= XDR_FREE
;
1177 msg
.acpted_rply
.ar_results
.proc
= xdr_void
;
1184 * LOOPBACK IS MORE IMPORTANT: PUT IN HACK
1187 rpc_received(char *dom
, struct sockaddr_in
*raddrp
, int force
)
1189 struct _dom_binding
*ypdb
;
1190 struct iovec iov
[2];
1191 struct ypbind_resp ybr
;
1194 sys_msg(debug
, LOG_DEBUG
, "returned from %s about %s",
1195 inet_ntoa(raddrp
->sin_addr
), dom
);
1197 if (dom
== NULL
) return;
1199 /* don't support insecure servers by default */
1200 if (!insecure
&& ntohs(raddrp
->sin_port
) >= IPPORT_RESERVED
) return;
1202 for (ypdb
= ypbindlist
; ypdb
; ypdb
= ypdb
->dom_pnext
)
1204 if (!strcmp(ypdb
->dom_domain
, dom
)) break;
1209 if (force
== 0) return;
1210 ypdb
= makebinding(dom
);
1211 ypdb
->dom_lockfd
= -1;
1212 ypdb
->dom_pnext
= ypbindlist
;
1216 /* soft update, alive */
1217 if (ypdb
->dom_alive
== 1 && force
== 0)
1219 if (!memcmp(&ypdb
->dom_server_addr
, raddrp
,
1220 sizeof ypdb
->dom_server_addr
))
1222 ypdb
->dom_alive
= 1;
1223 /* recheck binding in 60 sec */
1224 ypdb
->dom_check_t
= time(NULL
) + 60;
1229 memcpy(&ypdb
->dom_server_addr
, raddrp
, sizeof ypdb
->dom_server_addr
);
1230 /* recheck binding in 60 seconds */
1231 ypdb
->dom_check_t
= time(NULL
) + 60;
1232 ypdb
->dom_vers
= YPVERS
;
1233 ypdb
->dom_alive
= 1;
1235 if (ypdb
->dom_lockfd
!= -1) close(ypdb
->dom_lockfd
);
1237 if ((fd
= makelock(ypdb
)) == -1) return;
1240 * ok, if BINDINGDIR exists, and we can create the binding file,
1241 * then write to it..
1243 ypdb
->dom_lockfd
= fd
;
1245 iov
[0].iov_base
= (caddr_t
)&(udptransp
->xp_port
);
1246 iov
[0].iov_len
= sizeof udptransp
->xp_port
;
1247 iov
[1].iov_base
= (caddr_t
)&ybr
;
1248 iov
[1].iov_len
= sizeof ybr
;
1250 memset(&ybr
, 0, sizeof ybr
);
1251 ybr
.ypbind_status
= YPBIND_SUCC_VAL
;
1252 bcopy(&raddrp
->sin_addr
.s_addr
,
1253 ybr
.ypbind_resp_u
.ypbind_bindinfo
.ypbind_binding_addr
, 4);
1254 bcopy(&raddrp
->sin_port
,
1255 ybr
.ypbind_resp_u
.ypbind_bindinfo
.ypbind_binding_port
, 2);
1257 if (writev(ypdb
->dom_lockfd
, iov
, 2) !=
1258 iov
[0].iov_len
+ iov
[1].iov_len
)
1260 sys_msg(debug
, LOG_WARNING
, "writev: %s", strerror(errno
));
1261 close(ypdb
->dom_lockfd
);
1263 ypdb
->dom_lockfd
= -1;
1267 static struct _dom_binding
*
1268 xid2ypdb(u_int32_t xid
)
1270 struct _dom_binding
*ypdb
;
1272 for (ypdb
= ypbindlist
; ypdb
; ypdb
= ypdb
->dom_pnext
)
1274 if (ypdb
->dom_xid
== xid
) break;
1281 unique_xid(struct _dom_binding
*ypdb
)
1285 tmp_xid
= (u_int32_t
)(((u_long
)ypdb
) & 0xffffffff);
1286 while (xid2ypdb(tmp_xid
) != NULL
) tmp_xid
++;