2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 * Copyright (c) 1992, 1993 Theo de Raadt <deraadt@fsa.ca>
27 * All rights reserved.
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * 3. All advertising materials mentioning features or use of this software
38 * must display the following acknowledgement:
39 * This product includes software developed by Theo de Raadt.
40 * 4. The name of the author may not be used to endorse or promote
41 * products derived from this software without specific prior written
44 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
45 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
46 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
48 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 static char rcsid
[] = "$Id: ypbind.c,v 1.1.1.1 1999/05/02 03:59:00 wsanchez Exp $";
60 #include <sys/cdefs.h>
62 #include <sys/param.h>
63 #include <sys/types.h>
64 #include <sys/ioctl.h>
65 #include <sys/signal.h>
66 #include <sys/socket.h>
68 #include <sys/fcntl.h>
85 #include <arpa/inet.h>
86 #include <rpc/pmap_clnt.h>
87 #include <rpc/pmap_prot.h>
88 #include <rpc/pmap_rmt.h>
90 #include <rpcsvc/yp.h>
91 // #include <rpcsvc/yp_prot.h>
92 // #include <rpcsvc/ypclnt.h>
94 #define _PATH_YPBIND_LOCK "/var/run/ypbind.lock"
95 #define YPSERVERSSUFF ".ypservers"
96 #define BINDINGDIR "/var/yp/binding"
106 struct _dom_binding
*dom_pnext
;
107 char dom_domain
[YPMAXDOMAIN
+ 1];
108 struct sockaddr_in dom_server_addr
;
109 unsigned short int dom_server_port
;
122 static struct _dom_binding
*ypbindlist
;
133 ypbind_mode_t ypbindmode
;
136 * If ypbindmode is YPBIND_SETLOCAL or YPBIND_SETALL, this indicates
137 * whether or not we've been "ypset". If we haven't, we behave like
138 * YPBIND_BROADCAST. If we have, we behave like YPBIND_DIRECT.
143 static int rpcsock
, pingsock
;
144 static struct rmtcallargs rmtca
;
145 static struct rmtcallres rmtcr
;
146 static bool_t rmtcr_outval
;
147 static u_long rmtcr_port
;
148 static SVCXPRT
*udptransp
, *tcptransp
;
150 int main
__P((int, char *[]));
152 static void usage
__P((void));
153 static struct _dom_binding
*makebinding
__P((const char *));
154 static int makelock
__P((struct _dom_binding
*));
155 static void removelock
__P((struct _dom_binding
*));
156 static void checkwork
__P((void));
157 static int ping
__P((struct _dom_binding
*));
158 static int nag_servers
__P((struct _dom_binding
*));
159 static enum clnt_stat handle_replies
__P((void));
160 static enum clnt_stat handle_ping
__P((void));
161 static void rpc_received
__P((char *, struct sockaddr_in
*, int));
162 static struct _dom_binding
*xid2ypdb
__P((u_int32_t
));
163 static u_int32_t unique_xid
__P((struct _dom_binding
*));
164 static int broadcast
__P((char *, int));
165 static int direct
__P((char *, int));
166 static int direct_set
__P((char *, int, struct _dom_binding
*));
169 #define DEBUG_STDERR 1
170 #define DEBUG_SYSLOG 2
173 static char *msg_str
= NULL
;
176 sys_openlog(int debug
, char *str
, int flags
, int facility
)
178 if (msg_str
!= NULL
) free(msg_str
);
182 msg_str
= malloc(strlen(str
) + 1);
183 strcpy(msg_str
, str
);
186 if (debug
& DEBUG_SYSLOG
) openlog(msg_str
, flags
, facility
);
190 sys_msg(int debug
, int priority
, char *message
, ...)
194 va_start(ap
, message
);
196 if (debug
& DEBUG_SYSLOG
) vsyslog(priority
, message
, ap
);
198 if (debug
& DEBUG_STDERR
)
200 if (msg_str
!= NULL
) fprintf(stderr
, "%s: ", msg_str
);
201 vfprintf(stderr
, message
, ap
);
202 fprintf(stderr
, "\n");
213 "Usage: ypbind [-broadcast] [-insecure] [-ypset] [-ypsetme] [-d]\n");
217 static struct _dom_binding
*
218 makebinding(const char *dm
)
220 struct _dom_binding
*ypdb
;
222 ypdb
= (struct _dom_binding
*)malloc(sizeof *ypdb
);
223 memset(ypdb
, 0, sizeof *ypdb
);
224 strncpy(ypdb
->dom_domain
, dm
, sizeof ypdb
->dom_domain
);
225 ypdb
->dom_domain
[sizeof(ypdb
->dom_domain
) - 1] = '\0';
231 makelock(struct _dom_binding
*ypdb
)
234 char path
[MAXPATHLEN
];
236 snprintf(path
, sizeof(path
), "%s/%s.%ld", BINDINGDIR
,
237 ypdb
->dom_domain
, ypdb
->dom_vers
);
239 fd
= open(path
, O_CREAT
|O_SHLOCK
|O_RDWR
|O_TRUNC
, 0644);
242 mkdir(BINDINGDIR
, 0755);
243 fd
= open(path
, O_CREAT
|O_SHLOCK
|O_RDWR
|O_TRUNC
, 0644);
244 if (fd
== -1) return -1;
254 removelock(struct _dom_binding
*ypdb
)
256 char path
[MAXPATHLEN
];
258 snprintf(path
, sizeof(path
), "%s/%s.%ld",
259 BINDINGDIR
, ypdb
->dom_domain
, ypdb
->dom_vers
);
264 svc_ypbindproc_null_2(void *argp
, SVCXPRT
*transp
)
268 sys_msg(debug
, LOG_DEBUG
, "ypbindproc_null_2");
270 memset(&res
, 0, sizeof(res
));
275 svc_ypbindproc_domain_2(void *argp
, SVCXPRT
*transp
)
277 static struct ypbind_resp res
;
278 struct _dom_binding
*ypdb
;
279 char *arg
= *(char **) argp
;
282 sys_msg(debug
, LOG_DEBUG
, "ypbindproc_domain_2 %s", arg
);
284 memset(&res
, 0, sizeof res
);
285 res
.ypbind_status
= YPBIND_FAIL_VAL
;
287 for (count
= 0, ypdb
= ypbindlist
;
289 ypdb
= ypdb
->dom_pnext
, count
++)
291 /* prevent denial of service */
292 if (count
> 100) return NULL
;
293 if (!strcmp(ypdb
->dom_domain
, arg
)) break;
298 ypdb
= makebinding(arg
);
299 ypdb
->dom_vers
= YPVERS
;
301 ypdb
->dom_lockfd
= -1;
303 ypdb
->dom_xid
= unique_xid(ypdb
);
304 ypdb
->dom_pnext
= ypbindlist
;
307 sys_msg(debug
, LOG_ERR
, "unknown domain %s", arg
);
311 if (ypdb
->dom_alive
== 0)
313 sys_msg(debug
, LOG_ERR
, "dead domain %s", arg
);
319 if (now
< ypdb
->dom_ask_t
+ 5)
322 * Hmm. More than 2 requests in 5 seconds have indicated
323 * that my binding is possibly incorrect.
324 * Ok, do an immediate poll of the server.
326 if (ypdb
->dom_check_t
>= now
)
329 ypdb
->dom_check_t
= 0;
333 ypdb
->dom_ask_t
= now
;
336 res
.ypbind_status
= YPBIND_SUCC_VAL
;
337 bcopy(&ypdb
->dom_server_addr
.sin_addr
.s_addr
,
338 res
.ypbind_resp_u
.ypbind_bindinfo
.ypbind_binding_addr
, 4);
339 bcopy(&ypdb
->dom_server_port
,
340 res
.ypbind_resp_u
.ypbind_bindinfo
.ypbind_binding_port
, 2);
342 sys_msg(debug
, LOG_DEBUG
, "domain %s at %s/%d", ypdb
->dom_domain
,
343 inet_ntoa(ypdb
->dom_server_addr
.sin_addr
),
344 ntohs(ypdb
->dom_server_addr
.sin_port
));
349 svc_ypbindproc_setdom_2(void *argp
, SVCXPRT
*transp
)
351 struct ypbind_setdom
*sd
= argp
;
352 struct sockaddr_in
*fromsin
, bindsin
;
355 memset(&bindsin
, 0, sizeof bindsin
);
356 bindsin
.sin_family
= AF_INET
;
357 bindsin
.sin_len
= sizeof(bindsin
);
358 bcopy(&sd
->ypsetdom_binding
.ypbind_binding_addr
,
359 &bindsin
.sin_addr
.s_addr
, 4);
360 bcopy(&sd
->ypsetdom_binding
.ypbind_binding_port
,
361 &bindsin
.sin_port
, 2);
362 fromsin
= svc_getcaller(transp
);
364 memset(&res
, 0, sizeof(res
));
368 case YPBIND_SETLOCAL
:
369 if (fromsin
->sin_addr
.s_addr
!= htonl(INADDR_LOOPBACK
))
371 sys_msg(debug
, LOG_ERR
, "ypset from %s denied",
372 inet_ntoa(fromsin
->sin_addr
));
383 case YPBIND_BROADCAST
:
385 sys_msg(debug
, LOG_ERR
, "ypset denied");
389 if (ntohs(fromsin
->sin_port
) >= IPPORT_RESERVED
)
391 sys_msg(debug
, LOG_ERR
, "ypset from unpriviledged port denied");
395 if (sd
->ypsetdom_vers
!= YPVERS
)
397 sys_msg(debug
, LOG_ERR
, "ypset with wrong version denied");
398 sys_msg(debug
, LOG_DEBUG
, "ypsetdom_vers = %lu YPVERS = %lu",
399 sd
->ypsetdom_vers
, YPVERS
);
403 rpc_received(sd
->ypsetdom_domain
, &bindsin
, 1);
405 sys_msg(debug
, LOG_DEBUG
, "ypset to %s succeeded",
406 inet_ntoa(bindsin
.sin_addr
));
412 ypbindprog_2(struct svc_req
*rqstp
, register SVCXPRT
*transp
)
416 char ypbindproc_domain_2_arg
[YPMAXDOMAIN
+ 1];
417 struct ypbind_setdom ypbindproc_setdom_2_arg
;
419 struct authunix_parms
*creds
;
421 xdrproc_t xdr_argument
, xdr_result
;
422 void *(*local
) __P((void *, SVCXPRT
*));
424 switch (rqstp
->rq_proc
)
426 case YPBINDPROC_NULL
:
427 xdr_argument
= xdr_void
;
428 xdr_result
= xdr_void
;
429 local
= svc_ypbindproc_null_2
;
432 case YPBINDPROC_DOMAIN
:
433 xdr_argument
= xdr_domainname
;
434 xdr_result
= xdr_ypbind_resp
;
435 local
= svc_ypbindproc_domain_2
;
438 case YPBINDPROC_SETDOM
:
439 switch (rqstp
->rq_cred
.oa_flavor
)
442 creds
= (struct authunix_parms
*)rqstp
->rq_clntcred
;
443 if (creds
->aup_uid
!= 0)
445 svcerr_auth(transp
, AUTH_BADCRED
);
451 svcerr_auth(transp
, AUTH_TOOWEAK
);
455 xdr_argument
= xdr_ypbind_setdom
;
456 xdr_result
= xdr_void
;
457 local
= svc_ypbindproc_setdom_2
;
461 svcerr_noproc(transp
);
465 memset(&argument
, 0, sizeof(argument
));
466 if (!svc_getargs(transp
, xdr_argument
, (caddr_t
)&argument
))
468 svcerr_decode(transp
);
472 result
= (*local
)(&argument
, transp
);
473 if (result
!= NULL
&& !svc_sendreply(transp
, xdr_result
, result
))
475 svcerr_systemerr(transp
);
482 main(int argc
, char *argv
[])
487 int evil
= 0, one
, i
;
488 char pathname
[MAXPATHLEN
];
491 yp_get_default_domain(&dname
);
492 if (dname
[0] == '\0')
494 fprintf(stderr
, "Domainname not set. Aborting.\n");
498 debug
= DEBUG_SYSLOG
;
499 ypbindmode
= YPBIND_DIRECT
;
500 for (i
= 1; i
< argc
; i
++)
502 if (!strcmp(argv
[i
], "-insecure"))
505 else if (!strcmp(argv
[i
], "-ypset"))
506 ypbindmode
= YPBIND_SETALL
;
508 else if (!strcmp(argv
[i
], "-ypsetme"))
509 ypbindmode
= YPBIND_SETLOCAL
;
511 else if (!strcmp(argv
[i
], "-broadcast"))
512 ypbindmode
= YPBIND_BROADCAST
;
514 else if (!strcmp(argv
[i
], "-d"))
515 debug
= DEBUG_STDERR
;
521 sys_openlog(debug
, "ypbind", LOG_NDELAY
| LOG_PID
, LOG_DAEMON
);
524 * Per traditional ypbind(8) semantics, if a ypservers
525 * file does not exist, we default to broadcast mode.
526 * If the file does exist, we default to direct mode.
527 * Note that we can still override direct mode by passing
528 * the -broadcast flag.
530 snprintf(pathname
, sizeof(pathname
), "%s/%s%s",
531 BINDINGDIR
, dname
, YPSERVERSSUFF
);
533 if ((ypbindmode
== YPBIND_DIRECT
) && (stat(pathname
, &st
) < 0))
535 sys_msg(debug
, LOG_DEBUG
, "%s does not exist, defaulting to broadcast.",
537 ypbindmode
= YPBIND_BROADCAST
;
540 /* blow away everything in BINDINGDIR */
542 lockfd
= open(_PATH_YPBIND_LOCK
, O_CREAT
|O_SHLOCK
|O_RDWR
|O_TRUNC
, 0644);
545 sys_msg(debug
, LOG_ERR
, "Cannot create %s", _PATH_YPBIND_LOCK
);
550 flock(lockfd
, LOCK_SH
);
553 pmap_unset(YPBINDPROG
, YPBINDVERS
);
555 udptransp
= svcudp_create(RPC_ANYSOCK
);
556 if (udptransp
== NULL
)
558 sys_msg(debug
, LOG_ERR
, "Cannot create udp service.");
562 if (!svc_register(udptransp
, YPBINDPROG
, YPBINDVERS
, ypbindprog_2
,
565 sys_msg(debug
, LOG_ERR
,
566 "Unable to register (YPBINDPROG, YPBINDVERS, udp).");
570 tcptransp
= svctcp_create(RPC_ANYSOCK
, 0, 0);
571 if (tcptransp
== NULL
)
573 sys_msg(debug
, LOG_ERR
, "Cannot create tcp service.");
577 if (!svc_register(tcptransp
, YPBINDPROG
, YPBINDVERS
, ypbindprog_2
,
580 sys_msg(debug
, LOG_ERR
,
581 "Unable to register (YPBINDPROG, YPBINDVERS, tcp).");
585 /* XXX use SOCK_STREAM for direct queries? */
586 rpcsock
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
589 sys_msg(debug
, LOG_ERR
, "rpc socket() failed.");
593 pingsock
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
596 sys_msg(debug
, LOG_ERR
, "ping socket() failed.");
600 fcntl(rpcsock
, F_SETFL
, fcntl(rpcsock
, F_GETFL
, 0) | FNDELAY
);
601 fcntl(pingsock
, F_SETFL
, fcntl(pingsock
, F_GETFL
, 0) | FNDELAY
);
604 setsockopt(rpcsock
, SOL_SOCKET
, SO_BROADCAST
, &one
, sizeof(one
));
607 rmtca
.proc
= YPPROC_DOMAIN_NONACK
;
608 rmtca
.xdr_args
= NULL
; /* set at call time */
609 rmtca
.args_ptr
= NULL
; /* set at call time */
610 rmtcr
.port_ptr
= &rmtcr_port
;
611 rmtcr
.xdr_results
= xdr_bool
;
612 rmtcr
.results_ptr
= (caddr_t
)&rmtcr_outval
;
614 /* build initial domain binding, make it "unsuccessful" */
615 ypbindlist
= makebinding(dname
);
616 ypbindlist
->dom_vers
= YPVERS
;
617 ypbindlist
->dom_alive
= 0;
618 ypbindlist
->dom_lockfd
= -1;
619 removelock(ypbindlist
);
623 // width = svc_maxfd;
628 if (pingsock
> width
)
635 FD_SET(rpcsock
, &fdsr
);
636 FD_SET(pingsock
, &fdsr
);
640 switch (select(width
, &fdsr
, NULL
, NULL
, &tv
))
647 sys_msg(debug
, LOG_WARNING
, "select: %s", strerror(errno
));
651 if (FD_ISSET(rpcsock
, &fdsr
)) handle_replies();
652 if (FD_ISSET(pingsock
, &fdsr
)) handle_ping();
653 svc_getreqset(&fdsr
);
654 if (check
) checkwork();
658 if ((evil
== 0) && (ypbindlist
->dom_alive
!= 0))
661 if (debug
== DEBUG_SYSLOG
) daemon(0, 0);
667 * State transition is done like this:
669 * STATE EVENT ACTION NEWSTATE TIMEOUT
670 * no binding timeout broadcast no binding 5 sec
671 * no binding answer -- binding 60 sec
672 * binding timeout ping server checking 5 sec
673 * checking timeout ping server + broadcast checking 5 sec
674 * checking answer -- binding 60 sec
679 struct _dom_binding
*ypdb
;
685 for (ypdb
= ypbindlist
; ypdb
; ypdb
= ypdb
->dom_pnext
)
687 if (ypdb
->dom_check_t
< t
)
689 if (ypdb
->dom_alive
== 1) ping(ypdb
);
690 else nag_servers(ypdb
);
692 ypdb
->dom_check_t
= t
+ 5;
698 ping(struct _dom_binding
*ypdb
)
700 char *dom
= ypdb
->dom_domain
;
708 memset(&xdr
, 0, sizeof xdr
);
709 memset(&msg
, 0, sizeof msg
);
711 rpcua
= authunix_create_default();
714 sys_msg(debug
, LOG_ERR
, "ping: cannot get unix auth");
715 return RPC_SYSTEMERROR
;
718 msg
.rm_direction
= CALL
;
719 msg
.rm_call
.cb_rpcvers
= RPC_MSG_VERSION
;
720 msg
.rm_call
.cb_prog
= YPPROG
;
721 msg
.rm_call
.cb_vers
= YPVERS
;
722 msg
.rm_call
.cb_proc
= YPPROC_DOMAIN_NONACK
;
723 msg
.rm_call
.cb_cred
= rpcua
->ah_cred
;
724 msg
.rm_call
.cb_verf
= rpcua
->ah_verf
;
726 msg
.rm_xid
= ypdb
->dom_xid
;
727 xdrmem_create(&xdr
, buf
, sizeof buf
, XDR_ENCODE
);
728 if (!xdr_callmsg(&xdr
, &msg
))
730 st
= RPC_CANTENCODEARGS
;
735 if (!xdr_domainname(&xdr
, (void *)&dom
))
737 st
= RPC_CANTENCODEARGS
;
742 outlen
= (int)xdr_getpos(&xdr
);
746 st
= RPC_CANTENCODEARGS
;
754 if (sendto(pingsock
, buf
, outlen
, 0,
755 (struct sockaddr
*)&ypdb
->dom_server_addr
,
756 sizeof ypdb
->dom_server_addr
) == -1)
757 sys_msg(debug
, LOG_WARNING
, "ping: sendto");
763 nag_servers(struct _dom_binding
*ypdb
)
765 char *dom
= ypdb
->dom_domain
;
773 rmtca
.xdr_args
= xdr_domainname
;
774 rmtca
.args_ptr
= (char *)&dom
;
776 memset(&xdr
, 0, sizeof xdr
);
777 memset(&msg
, 0, sizeof msg
);
779 rpcua
= authunix_create_default();
782 sys_msg(debug
, LOG_ERR
, "ping: cannot get unix auth");
783 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
, sizeof buf
, XDR_ENCODE
);
796 if (!xdr_callmsg(&xdr
, &msg
))
798 st
= RPC_CANTENCODEARGS
;
803 if (!xdr_rmtcall_args(&xdr
, &rmtca
))
805 st
= RPC_CANTENCODEARGS
;
810 outlen
= (int)xdr_getpos(&xdr
);
814 st
= RPC_CANTENCODEARGS
;
821 if (ypdb
->dom_lockfd
!= -1)
823 close(ypdb
->dom_lockfd
);
824 ypdb
->dom_lockfd
= -1;
828 if (ypdb
->dom_alive
== 2)
831 * This resolves the following situation:
832 * ypserver on other subnet was once bound,
833 * but rebooted and is now using a different port
835 struct sockaddr_in bindsin
;
837 memset(&bindsin
, 0, sizeof bindsin
);
838 bindsin
.sin_family
= AF_INET
;
839 bindsin
.sin_len
= sizeof(bindsin
);
840 bindsin
.sin_port
= htons(PMAPPORT
);
841 bindsin
.sin_addr
= ypdb
->dom_server_addr
.sin_addr
;
843 if (sendto(rpcsock
, buf
, outlen
, 0, (struct sockaddr
*)&bindsin
,
844 sizeof bindsin
) == -1)
845 sys_msg(debug
, LOG_WARNING
, "broadcast: sendto");
851 case YPBIND_SETLOCAL
:
852 if (been_ypset
) return direct_set(buf
, outlen
, ypdb
);
855 case YPBIND_BROADCAST
:
856 return broadcast(buf
, outlen
);
859 return direct(buf
, outlen
);
866 broadcast(char *buf
, int outlen
)
874 struct sockaddr_in bindsin
;
876 /* find all networks and send the RPC packet out them all */
877 sock
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
880 sys_msg(debug
, LOG_WARNING
, "broadcast: socket: %s", strerror(errno
));
884 memset(&bindsin
, 0, sizeof bindsin
);
885 bindsin
.sin_family
= AF_INET
;
886 bindsin
.sin_len
= sizeof(bindsin
);
887 bindsin
.sin_port
= htons(PMAPPORT
);
889 ifc
.ifc_len
= sizeof inbuf
;
891 if (ioctl(sock
, SIOCGIFCONF
, &ifc
) < 0)
894 sys_msg(debug
, LOG_WARNING
, "broadcast: ioctl(SIOCGIFCONF): %s",
899 addrlen
= sizeof(struct ifreq
) - IFNAMSIZ
;
902 while (offset
<= ifc
.ifc_len
)
904 ifr
= (struct ifreq
*)(ifc
.ifc_buf
+ offset
);
906 if (ifr
->ifr_addr
.sa_len
> addrlen
) offset
+= ifr
->ifr_addr
.sa_len
;
907 else offset
+= addrlen
;
909 if (ifr
->ifr_addr
.sa_family
!= AF_INET
) continue;
910 if (ioctl(sock
, SIOCGIFFLAGS
, ifr
) < 0) continue;
911 if ((ifr
->ifr_flags
& IFF_UP
) == 0) continue;
913 if (ifr
->ifr_flags
& IFF_BROADCAST
)
915 if (ioctl(sock
, SIOCGIFBRDADDR
, ifr
) < 0)
917 sys_msg(debug
, LOG_WARNING
,
918 "broadcast: ioctl(SIOCGIFBRDADDR): %s", strerror(errno
));
922 else if (ifr
->ifr_flags
& IFF_LOOPBACK
)
924 if (ioctl(sock
, SIOCGIFADDR
, ifr
) < 0)
926 sys_msg(debug
, LOG_WARNING
,
927 "broadcast: ioctl(SIOCGIFADDR): %s", strerror(errno
));
933 in
= ((struct sockaddr_in
*)&(ifr
->ifr_addr
))->sin_addr
;
934 bindsin
.sin_addr
= in
;
935 if (sendto(rpcsock
, buf
, outlen
, 0, (struct sockaddr
*)&bindsin
,
936 sizeof bindsin
) == -1)
937 sys_msg(debug
, LOG_WARNING
, "broadcast: sendto: %s",
946 direct(char *buf
, int outlen
)
949 static char ypservers_path
[MAXPATHLEN
];
950 char line
[_POSIX2_LINE_MAX
];
953 struct sockaddr_in bindsin
;
958 snprintf(ypservers_path
, sizeof(ypservers_path
),
959 "%s/%s%s", BINDINGDIR
, dname
, YPSERVERSSUFF
);
960 df
= fopen(ypservers_path
, "r");
963 sys_msg(debug
, LOG_ALERT
, "Missing file %s, aborting.",
969 memset(&bindsin
, 0, sizeof bindsin
);
970 bindsin
.sin_family
= AF_INET
;
971 bindsin
.sin_len
= sizeof(bindsin
);
972 bindsin
.sin_port
= htons(PMAPPORT
);
974 while(fgets(line
, sizeof(line
), df
) != NULL
)
976 /* skip lines that are too big */
977 p
= strchr(line
, '\n');
982 while ((c
= getc(df
)) != '\n' && c
!= EOF
);
988 while (isspace(*p
)) p
++;
989 if (*p
== '#') continue;
990 hp
= gethostbyname(p
);
993 sys_msg(debug
, LOG_ERR
, "Can't find host: %s", p
);
997 /* step through all addresses in case first is unavailable */
998 for (i
= 0; hp
->h_addr_list
[i
]; i
++)
1000 memmove(&bindsin
.sin_addr
, hp
->h_addr_list
[0],
1002 if (sendto(rpcsock
, buf
, outlen
, 0,
1003 (struct sockaddr
*)&bindsin
, sizeof bindsin
) < 0)
1005 sys_msg(debug
, LOG_WARNING
, "direct: sendto: %s",
1015 sys_msg(debug
, LOG_ALERT
,
1016 "Can't contact any servers listed in %s. Aborting", ypservers_path
);
1024 direct_set(char *buf
, int outlen
, struct _dom_binding
*ypdb
)
1026 struct sockaddr_in bindsin
;
1027 char path
[MAXPATHLEN
];
1028 struct iovec iov
[2];
1029 struct ypbind_resp ybr
;
1034 * Gack, we lose if binding file went away. We reset
1035 * "been_set" if this happens, otherwise we'll never
1038 snprintf(path
, sizeof(path
), "%s/%s.%ld", BINDINGDIR
,
1039 ypdb
->dom_domain
, ypdb
->dom_vers
);
1041 if ((fd
= open(path
, O_SHLOCK
|O_RDONLY
, 0644)) == -1)
1043 sys_msg(debug
, LOG_WARNING
, "Can't open file %s", path
);
1052 /* Read the binding file... */
1053 iov
[0].iov_base
= (caddr_t
)&(dummy_svc
.xp_port
);
1054 iov
[0].iov_len
= sizeof(dummy_svc
.xp_port
);
1055 iov
[1].iov_base
= (caddr_t
)&ybr
;
1056 iov
[1].iov_len
= sizeof(ybr
);
1057 bytes
= readv(fd
, iov
, 2);
1060 if (bytes
!= (iov
[0].iov_len
+ iov
[1].iov_len
))
1062 /* Binding file corrupt? */
1063 sys_msg(debug
, LOG_WARNING
, "Can't parse file %s", path
);
1068 bcopy(&ybr
.ypbind_resp_u
.ypbind_bindinfo
.ypbind_binding_addr
,
1069 &bindsin
.sin_addr
, 4);
1071 if (sendto(rpcsock
, buf
, outlen
, 0, (struct sockaddr
*)&bindsin
,
1072 sizeof(bindsin
)) < 0)
1074 sys_msg(debug
, LOG_WARNING
, "direct_set: sendto: %s", strerror(errno
));
1081 static enum clnt_stat
1086 struct _dom_binding
*ypdb
;
1087 struct sockaddr_in raddr
;
1092 memset(&xdr
, 0, sizeof(xdr
));
1093 memset(&msg
, 0, sizeof(msg
));
1094 msg
.acpted_rply
.ar_verf
= _null_auth
;
1095 msg
.acpted_rply
.ar_results
.where
= (caddr_t
)&rmtcr
;
1096 msg
.acpted_rply
.ar_results
.proc
= xdr_rmtcallres
;
1099 fromlen
= sizeof (struct sockaddr
);
1100 inlen
= recvfrom(rpcsock
, buf
, sizeof buf
, 0,
1101 (struct sockaddr
*)&raddr
, &fromlen
);
1104 if (errno
== EINTR
) goto try_again
;
1105 return RPC_CANTRECV
;
1108 if (inlen
< sizeof(u_int32_t
)) goto recv_again
;
1111 * see if reply transaction id matches sent id.
1112 * If so, decode the results.
1114 xdrmem_create(&xdr
, buf
, (u_int
)inlen
, XDR_DECODE
);
1115 if (xdr_replymsg(&xdr
, &msg
))
1117 if ((msg
.rm_reply
.rp_stat
== MSG_ACCEPTED
) &&
1118 (msg
.acpted_rply
.ar_stat
== SUCCESS
)) {
1119 raddr
.sin_port
= htons((u_short
)rmtcr_port
);
1120 ypdb
= xid2ypdb(msg
.rm_xid
);
1121 if (ypdb
!= NULL
) rpc_received(ypdb
->dom_domain
, &raddr
, 0);
1125 xdr
.x_op
= XDR_FREE
;
1126 msg
.acpted_rply
.ar_results
.proc
= xdr_void
;
1132 static enum clnt_stat
1137 struct _dom_binding
*ypdb
;
1138 struct sockaddr_in raddr
;
1144 memset(&xdr
, 0, sizeof(xdr
));
1145 memset(&msg
, 0, sizeof(msg
));
1146 msg
.acpted_rply
.ar_verf
= _null_auth
;
1147 msg
.acpted_rply
.ar_results
.where
= (caddr_t
)&res
;
1148 msg
.acpted_rply
.ar_results
.proc
= xdr_bool
;
1151 fromlen
= sizeof (struct sockaddr
);
1152 inlen
= recvfrom(pingsock
, buf
, sizeof buf
, 0,
1153 (struct sockaddr
*)&raddr
, &fromlen
);
1156 if (errno
== EINTR
) goto try_again
;
1157 return RPC_CANTRECV
;
1160 if (inlen
< sizeof(u_int32_t
)) goto recv_again
;
1163 * see if reply transaction id matches sent id.
1164 * If so, decode the results.
1166 xdrmem_create(&xdr
, buf
, (u_int
)inlen
, XDR_DECODE
);
1167 if (xdr_replymsg(&xdr
, &msg
))
1169 if ((msg
.rm_reply
.rp_stat
== MSG_ACCEPTED
) &&
1170 (msg
.acpted_rply
.ar_stat
== SUCCESS
))
1172 ypdb
= xid2ypdb(msg
.rm_xid
);
1173 if (ypdb
!= NULL
) rpc_received(ypdb
->dom_domain
, &raddr
, 0);
1177 xdr
.x_op
= XDR_FREE
;
1178 msg
.acpted_rply
.ar_results
.proc
= xdr_void
;
1185 * LOOPBACK IS MORE IMPORTANT: PUT IN HACK
1188 rpc_received(char *dom
, struct sockaddr_in
*raddrp
, int force
)
1190 struct _dom_binding
*ypdb
;
1191 struct iovec iov
[2];
1192 struct ypbind_resp ybr
;
1195 sys_msg(debug
, LOG_DEBUG
, "returned from %s about %s",
1196 inet_ntoa(raddrp
->sin_addr
), dom
);
1198 if (dom
== NULL
) return;
1200 /* don't support insecure servers by default */
1201 if (!insecure
&& ntohs(raddrp
->sin_port
) >= IPPORT_RESERVED
) return;
1203 for (ypdb
= ypbindlist
; ypdb
; ypdb
= ypdb
->dom_pnext
)
1205 if (!strcmp(ypdb
->dom_domain
, dom
)) break;
1210 if (force
== 0) return;
1211 ypdb
= makebinding(dom
);
1212 ypdb
->dom_lockfd
= -1;
1213 ypdb
->dom_pnext
= ypbindlist
;
1217 /* soft update, alive */
1218 if (ypdb
->dom_alive
== 1 && force
== 0)
1220 if (!memcmp(&ypdb
->dom_server_addr
, raddrp
,
1221 sizeof ypdb
->dom_server_addr
))
1223 ypdb
->dom_alive
= 1;
1224 /* recheck binding in 60 sec */
1225 ypdb
->dom_check_t
= time(NULL
) + 60;
1230 memcpy(&ypdb
->dom_server_addr
, raddrp
, sizeof ypdb
->dom_server_addr
);
1231 /* recheck binding in 60 seconds */
1232 ypdb
->dom_check_t
= time(NULL
) + 60;
1233 ypdb
->dom_vers
= YPVERS
;
1234 ypdb
->dom_alive
= 1;
1236 if (ypdb
->dom_lockfd
!= -1) close(ypdb
->dom_lockfd
);
1238 if ((fd
= makelock(ypdb
)) == -1) return;
1241 * ok, if BINDINGDIR exists, and we can create the binding file,
1242 * then write to it..
1244 ypdb
->dom_lockfd
= fd
;
1246 iov
[0].iov_base
= (caddr_t
)&(udptransp
->xp_port
);
1247 iov
[0].iov_len
= sizeof udptransp
->xp_port
;
1248 iov
[1].iov_base
= (caddr_t
)&ybr
;
1249 iov
[1].iov_len
= sizeof ybr
;
1251 memset(&ybr
, 0, sizeof ybr
);
1252 ybr
.ypbind_status
= YPBIND_SUCC_VAL
;
1253 bcopy(&raddrp
->sin_addr
.s_addr
,
1254 ybr
.ypbind_resp_u
.ypbind_bindinfo
.ypbind_binding_addr
, 4);
1255 bcopy(&raddrp
->sin_port
,
1256 ybr
.ypbind_resp_u
.ypbind_bindinfo
.ypbind_binding_port
, 2);
1258 if (writev(ypdb
->dom_lockfd
, iov
, 2) !=
1259 iov
[0].iov_len
+ iov
[1].iov_len
)
1261 sys_msg(debug
, LOG_WARNING
, "writev: %s", strerror(errno
));
1262 close(ypdb
->dom_lockfd
);
1264 ypdb
->dom_lockfd
= -1;
1268 static struct _dom_binding
*
1269 xid2ypdb(u_int32_t xid
)
1271 struct _dom_binding
*ypdb
;
1273 for (ypdb
= ypbindlist
; ypdb
; ypdb
= ypdb
->dom_pnext
)
1275 if (ypdb
->dom_xid
== xid
) break;
1282 unique_xid(struct _dom_binding
*ypdb
)
1286 tmp_xid
= (u_int32_t
)(((u_long
)ypdb
) & 0xffffffff);
1287 while (xid2ypdb(tmp_xid
) != NULL
) tmp_xid
++;