Subject: bin/1759: forcing specific servers for ypbind(8) to bind to
To: None <gnats-bugs@gnats.netbsd.org>
From: Luke Mewburn <lukem@supp.cpr.itg.telecom.com.au>
List: netbsd-bugs
Date: 11/13/1995 18:11:11
>Number: 1759
>Category: bin
>Synopsis: ypbind needs ability to bind to specific servers
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: bin-bug-people (Utility Bug People)
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Mon Nov 13 02:35:00 1995
>Last-Modified:
>Originator: Luke Mewburn
>Organization:
Werj
>Release: 951112
>Environment:
System: ULTRIX balrog 4.4 0 RISC
Machine: mips
>Description:
NetBSD's ypbind only supports broadcast/ypset/ypsetme modes
of operation. There is no way to explicitly force a binding
to server(s) of your choice. This is a security issue.
(YP has security problems, but if you can force a specific
ypserver, then some of the issues are resolved.)
>How-To-Repeat:
run ypbind and without using ypset (a problem anyway), try and
get ypbind to bind to your preferred server.
>Fix:
apply this patch. it's a bit "quick and dirty", but then again,
the ypbind code leaves a lot to be desired about being ``clean
code'' anyway... This patch fixes the complaints that
"gcc -Wall" has as well.
To take advantage of this code, create a file called
/var/yp/`domainname`/.ypservers
that contains one line per ypserver that you wish to connect to.
diff -cbr /ftp/pub/NetBSD/NetBSD-current/src/usr.sbin/ypbind/Makefile ypbind/Makefile
*** /ftp/pub/NetBSD/NetBSD-current/src/usr.sbin/ypbind/Makefile Sat Oct 14 15:07:00 1995
--- ypbind/Makefile Mon Nov 13 18:04:15 1995
***************
*** 3,8 ****
PROG= ypbind
MAN= ypbind.8
! CFLAGS+=-DDAEMON -DHEURISTIC
.include <bsd.prog.mk>
--- 3,8 ----
PROG= ypbind
MAN= ypbind.8
! CFLAGS+=-DHEURISTIC
.include <bsd.prog.mk>
diff -cbr /ftp/pub/NetBSD/NetBSD-current/src/usr.sbin/ypbind/ypbind.8 ypbind/ypbind.8
*** /ftp/pub/NetBSD/NetBSD-current/src/usr.sbin/ypbind/ypbind.8 Sat Oct 14 15:07:00 1995
--- ypbind/ypbind.8 Mon Nov 13 18:01:06 1995
***************
*** 38,49 ****
.Nm ypbind
.Nd create and maintain a binding to a YP server
.Sh SYNOPSIS
! .Nm ypbind
.Op Fl ypset
! .Nm ypbind
.Op Fl ypsetme
.Sh DESCRIPTION
! .Nm Ypbind
finds the server for a particular YP domain and stores information about it
in a
.Pa binding file.
--- 38,51 ----
.Nm ypbind
.Nd create and maintain a binding to a YP server
.Sh SYNOPSIS
! .Nm
.Op Fl ypset
! .Nm
.Op Fl ypsetme
+ .Nm
+ .Op Fl broadcast
.Sh DESCRIPTION
! .Nm
finds the server for a particular YP domain and stores information about it
in a
.Pa binding file.
***************
*** 55,75 ****
.Pa domainname.version.
(The YP system only supplies information on version 2.)
.Pp
! When
! .Nm ypbind
! starts, it broadcasts looking for a process willing to serve maps for the
! client's domain. Once a binding is established,
! .Nm ypbind
maintains this binding by periodically communicating with the server to which
! it is bound. If the binding is somehow lost, e.g by server reboot,
! .Nm ypbind
marks the domain as unbound and attempts to re-establish the binding.
When the binding is once again successful,
! .Nm ypbind
marks the domain as bound and resumes its periodic check.
.Pp
The options are as follows:
! .Bl -tag -width indent
.It Fl ypset
.Xr ypset 8
may be used to change the server to which a domain is bound.
--- 57,95 ----
.Pa domainname.version.
(The YP system only supplies information on version 2.)
.Pp
! If
! .Nm
! is started with the
! .Fl broadcast
! option, it broadcasts looking for a process willing to serve maps for the
! client's domain.
! .Pp
! If
! .NM
! is started without the
! .Fl broadcast
! option,
! .Nm
! steps through the list of YP servers specified in
! .Pa /var/yp/domainname/.ypservers
! and contacts each in turn attempting to bind to that server.
! It is strongly recommended that these hosts are in the local
! hosts file, and that hosts are looked up in local files before
! the YP hosts map.
! .Pp
! Once a binding is established,
! .Nm
maintains this binding by periodically communicating with the server to which
! it is bound.
! If the binding is somehow lost, e.g by server reboot,
! .Nm
marks the domain as unbound and attempts to re-establish the binding.
When the binding is once again successful,
! .Nm
marks the domain as bound and resumes its periodic check.
.Pp
The options are as follows:
! .Bl -tag -width "-broadcast"
.It Fl ypset
.Xr ypset 8
may be used to change the server to which a domain is bound.
***************
*** 77,89 ****
.Xr ypset 8
may be used only from this machine to change the server
to which a domain is bound.
.El
.Pp
The
.Fl ypset
! and
.Fl ypsetme
! options are dangerous and should be avoided.
.Pp
If the directory
.Pa /var/yp
--- 97,113 ----
.Xr ypset 8
may be used only from this machine to change the server
to which a domain is bound.
+ .It Fl broadcast
+ sends a broadcast requesting for a YP server to bind to.
.El
.Pp
The
.Fl ypset
! ,
.Fl ypsetme
! and
! .Fl broadcast
! options are inherently insecure and should be avoided.
.Pp
If the directory
.Pa /var/yp
***************
*** 92,97 ****
--- 116,123 ----
.Sh FILES
.Pa /var/yp/bindings/domainname.version
- binding file for domainname
+ .Pa /var/yp/domainname/.ypservers
+ - explicit servers to bind to.
.Sh SEE ALSO
.Xr domainname 1 ,
.Xr ypcat 1 ,
diff -cbr /ftp/pub/NetBSD/NetBSD-current/src/usr.sbin/ypbind/ypbind.c ypbind/ypbind.c
*** /ftp/pub/NetBSD/NetBSD-current/src/usr.sbin/ypbind/ypbind.c Sat Oct 14 15:07:00 1995
--- ypbind/ypbind.c Mon Nov 13 18:03:56 1995
***************
*** 31,40 ****
*/
#ifndef LINT
! static char rcsid[] = "$Id: ypbind.c,v 1.19 1995/04/21 04:40:36 cgd Exp $";
#endif
#include <sys/param.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/signal.h>
--- 31,41 ----
*/
#ifndef LINT
! static char rcsid[] = "$NetBSD: ypbind.c,v 1.19 1995/04/21 04:40:36 cgd Exp $";
#endif
#include <sys/param.h>
+ #include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/signal.h>
***************
*** 61,67 ****
#include <rpcsvc/yp_prot.h>
#include <rpcsvc/ypclnt.h>
! #define BINDINGDIR "/var/yp/binding"
#define YPBINDLOCK "/var/run/ypbind.lock"
struct _dom_binding {
--- 62,70 ----
#include <rpcsvc/yp_prot.h>
#include <rpcsvc/ypclnt.h>
! #define VARYPDIR "/var/yp/"
! #define SERVERSFILE ".ypservers"
! #define BINDINGDIR __CONCAT(VARYPDIR, "binding")
#define YPBINDLOCK "/var/run/ypbind.lock"
struct _dom_binding {
***************
*** 87,96 ****
struct _dom_binding *ypbindlist;
int check;
! #define YPSET_NO 0
! #define YPSET_LOCAL 1
! #define YPSET_ALL 2
! int ypsetmode = YPSET_NO;
int rpcsock, pingsock;
struct rmtcallargs rmtca;
--- 90,99 ----
struct _dom_binding *ypbindlist;
int check;
! enum _ypbindmode {
! YPBIND_DIRECT, YPBIND_BROADCAST, YPBIND_SETLOCAL, YPBIND_SETALL
! };
! static enum _ypbindmode ypbindmode;
int rpcsock, pingsock;
struct rmtcallargs rmtca;
***************
*** 99,104 ****
--- 102,117 ----
u_long rmtcr_port;
SVCXPRT *udptransp, *tcptransp;
+ void checkwork __P((void));
+ void rpc_received __P((char *, struct sockaddr_in *, int));
+ int handle_replies __P((void));
+ int handle_ping __P((void));
+ int ping __P((struct _dom_binding *));
+ int nag_servers __P((struct _dom_binding *));
+ int broadcast __P((char *, int));
+ int direct __P((char *, int));
+
+
void *
ypbindproc_null_2(transp, argp, clnt)
SVCXPRT *transp;
***************
*** 136,142 ****
ypdb->dom_vers = YPVERS;
ypdb->dom_alive = 0;
ypdb->dom_lockfd = -1;
! sprintf(path, "%s/%s.%d", BINDINGDIR, ypdb->dom_domain, ypdb->dom_vers);
unlink(path);
ypdb->dom_pnext = ypbindlist;
ypbindlist = ypdb;
--- 149,156 ----
ypdb->dom_vers = YPVERS;
ypdb->dom_alive = 0;
ypdb->dom_lockfd = -1;
! sprintf(path, "%s/%s.%d", BINDINGDIR, ypdb->dom_domain,
! (int)ypdb->dom_vers);
unlink(path);
ypdb->dom_pnext = ypbindlist;
ypbindlist = ypdb;
***************
*** 164,170 ****
ypdb->dom_ask_t = now;
#endif
- answer:
res.ypbind_status = YPBIND_SUCC_VAL;
res.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr.s_addr =
ypdb->dom_server_addr.sin_addr.s_addr;
--- 178,183 ----
***************
*** 188,201 ****
memset(&res, 0, sizeof(res));
fromsin = svc_getcaller(transp);
! switch (ypsetmode) {
! case YPSET_LOCAL:
if (fromsin->sin_addr.s_addr != htonl(INADDR_LOOPBACK))
return (bool_t *)NULL;
break;
! case YPSET_ALL:
break;
! case YPSET_NO:
default:
return (bool_t *)NULL;
}
--- 201,215 ----
memset(&res, 0, sizeof(res));
fromsin = svc_getcaller(transp);
! switch (ypbindmode) {
! case YPBIND_SETLOCAL:
if (fromsin->sin_addr.s_addr != htonl(INADDR_LOOPBACK))
return (bool_t *)NULL;
break;
! case YPBIND_SETALL:
break;
! case YPBIND_DIRECT:
! case YPBIND_BROADCAST:
default:
return (bool_t *)NULL;
}
***************
*** 279,284 ****
--- 293,299 ----
return;
}
+ int
main(argc, argv)
int argc;
char *argv[];
***************
*** 298,306 ****
while (--argc) {
++argv;
if (!strcmp("-ypset", *argv))
! ypsetmode = YPSET_ALL;
else if (!strcmp("-ypsetme", *argv))
! ypsetmode = YPSET_LOCAL;
}
/* blow away everything in BINDINGDIR */
--- 313,323 ----
while (--argc) {
++argv;
if (!strcmp("-ypset", *argv))
! ypbindmode = YPBIND_SETALL;
else if (!strcmp("-ypsetme", *argv))
! ypbindmode = YPBIND_SETLOCAL;
! else if (!strcmp("-broadcast", *argv))
! ypbindmode = YPBIND_BROADCAST;
}
/* blow away everything in BINDINGDIR */
***************
*** 342,347 ****
--- 359,365 ----
exit(1);
}
+ /* XXX: use SOCK_STREAM for direct queries? */
if ((rpcsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
perror("socket");
return -1;
***************
*** 372,390 ****
ypbindlist->dom_alive = 0;
ypbindlist->dom_lockfd = -1;
sprintf(path, "%s/%s.%d", BINDINGDIR, ypbindlist->dom_domain,
! ypbindlist->dom_vers);
(void)unlink(path);
checkwork();
- while (1) {
width = svc_maxfd;
if (rpcsock > width)
width = rpcsock;
if (pingsock > width)
width = pingsock;
width++;
!
fdsr = svc_fdset;
FD_SET(rpcsock, &fdsr);
FD_SET(pingsock, &fdsr);
--- 390,407 ----
ypbindlist->dom_alive = 0;
ypbindlist->dom_lockfd = -1;
sprintf(path, "%s/%s.%d", BINDINGDIR, ypbindlist->dom_domain,
! (int)ypbindlist->dom_vers);
(void)unlink(path);
checkwork();
width = svc_maxfd;
if (rpcsock > width)
width = rpcsock;
if (pingsock > width)
width = pingsock;
width++;
! while (1) {
fdsr = svc_fdset;
FD_SET(rpcsock, &fdsr);
FD_SET(pingsock, &fdsr);
***************
*** 400,408 ****
break;
default:
if (FD_ISSET(rpcsock, &fdsr))
! handle_replies();
if (FD_ISSET(pingsock, &fdsr))
! handle_ping();
svc_getreqset(&fdsr);
if (check)
checkwork();
--- 417,425 ----
break;
default:
if (FD_ISSET(rpcsock, &fdsr))
! (void)handle_replies();
if (FD_ISSET(pingsock, &fdsr))
! (void)handle_ping();
svc_getreqset(&fdsr);
if (check)
checkwork();
***************
*** 426,431 ****
--- 443,449 ----
* checking timeout ping server + broadcast checking 5 sec
* checking answer -- binding 60 sec
*/
+ void
checkwork()
{
struct _dom_binding *ypdb;
***************
*** 439,451 ****
if (ypdb->dom_alive == 1)
ping(ypdb);
else
! broadcast(ypdb);
time(&t);
ypdb->dom_check_t = t + 5;
}
}
}
ping(ypdb)
struct _dom_binding *ypdb;
{
--- 457,470 ----
if (ypdb->dom_alive == 1)
ping(ypdb);
else
! nag_servers(ypdb);
time(&t);
ypdb->dom_check_t = t + 5;
}
}
}
+ int
ping(ypdb)
struct _dom_binding *ypdb;
{
***************
*** 503,521 ****
}
! broadcast(ypdb)
struct _dom_binding *ypdb;
{
char *dom = ypdb->dom_domain;
struct rpc_msg msg;
! char buf[1400], inbuf[8192];
char path[MAXPATHLEN];
enum clnt_stat st;
! int outlen, i, sock, len;
! struct sockaddr_in bindsin;
! struct ifconf ifc;
! struct ifreq ifreq, *ifr;
! struct in_addr in;
AUTH *rpcua;
XDR xdr;
--- 522,537 ----
}
! int
! nag_servers(ypdb)
struct _dom_binding *ypdb;
{
char *dom = ypdb->dom_domain;
struct rpc_msg msg;
! char buf[1400];
char path[MAXPATHLEN];
enum clnt_stat st;
! int outlen;
AUTH *rpcua;
XDR xdr;
***************
*** 563,576 ****
close(ypdb->dom_lockfd);
ypdb->dom_lockfd = -1;
sprintf(path, "%s/%s.%d", BINDINGDIR,
! ypdb->dom_domain, ypdb->dom_vers);
unlink(path);
}
- memset(&bindsin, 0, sizeof bindsin);
- bindsin.sin_family = AF_INET;
- bindsin.sin_len = sizeof(bindsin);
- bindsin.sin_port = htons(PMAPPORT);
if (ypdb->dom_alive == 2) {
/*
--- 579,588 ----
close(ypdb->dom_lockfd);
ypdb->dom_lockfd = -1;
sprintf(path, "%s/%s.%d", BINDINGDIR,
! ypdb->dom_domain, (int)ypdb->dom_vers);
unlink(path);
}
if (ypdb->dom_alive == 2) {
/*
***************
*** 578,594 ****
--- 590,635 ----
* ypserver on other subnet was once bound,
* but rebooted and is now using a different port
*/
+ struct sockaddr_in bindsin;
+
+ memset(&bindsin, 0, sizeof bindsin);
+ bindsin.sin_family = AF_INET;
+ bindsin.sin_len = sizeof(bindsin);
+ bindsin.sin_port = htons(PMAPPORT);
bindsin.sin_addr = ypdb->dom_server_addr.sin_addr;
if (sendto(rpcsock, buf, outlen, 0, (struct sockaddr *)&bindsin,
sizeof bindsin) < 0)
perror("sendto");
}
+ if (ypbindmode == YPBIND_BROADCAST)
+ return broadcast(buf, outlen);
+ else
+ return direct(buf, outlen);
+ }
+
+ int
+ broadcast(buf, outlen)
+ char *buf;
+ int outlen;
+ {
+ struct ifconf ifc;
+ struct ifreq ifreq, *ifr;
+ struct in_addr in;
+ int i, sock, len;
+ char inbuf[8192];
+ struct sockaddr_in bindsin;
+
/* find all networks and send the RPC packet out them all */
if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
perror("socket");
return -1;
}
+ memset(&bindsin, 0, sizeof bindsin);
+ bindsin.sin_family = AF_INET;
+ bindsin.sin_len = sizeof(bindsin);
+ bindsin.sin_port = htons(PMAPPORT);
+
ifc.ifc_len = sizeof inbuf;
ifc.ifc_buf = inbuf;
if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
***************
*** 638,644 ****
return 0;
}
! /*enum clnt_stat*/
handle_replies()
{
char buf[1400];
--- 679,758 ----
return 0;
}
! int
! direct(buf, outlen)
! char *buf;
! int outlen;
! {
! static FILE *df;
! #define MAXLINELEN 1024
! char line[MAXLINELEN];
! char *p;
! struct hostent *hp;
! struct sockaddr_in bindsin;
! int i, count = 0;
!
! if (df)
! rewind(df);
! else {
! char path[MAXPATHLEN];
!
! sprintf(path, "%s%s/%s", VARYPDIR, domainname, SERVERSFILE);
! df = fopen(path, "r");
! if (df == NULL) {
! perror(path);
! exit(1);
! }
! }
! memset(&bindsin, 0, sizeof bindsin);
! bindsin.sin_family = AF_INET;
! bindsin.sin_len = sizeof(bindsin);
! bindsin.sin_port = htons(PMAPPORT);
!
! while(fgets(line, sizeof(line), df) != NULL) {
! /* skip lines that are too big */
! p = strchr(line, '\n');
! if (p == NULL) {
! int c;
!
! while ((c = getc(df)) != '\n' && c != EOF)
! ;
! continue;
! }
! *p = '\0';
! p = line;
! while (isspace(*p))
! p++;
! if (*p == '#')
! continue;
! hp = gethostbyname(p);
! if (!hp) {
! herror(p);
! continue;
! }
! /* step through all addresses in case first is unavailable */
! for (i = 0; hp->h_addr_list[i]; i++) {
! memmove(&bindsin.sin_addr, hp->h_addr_list[0],
! hp->h_length);
! if (sendto(rpcsock, buf, outlen, 0,
! (struct sockaddr *)&bindsin,
! sizeof bindsin) < 0) {
! perror("sendto");
! continue;
! }
! else
! count++;
! }
! }
! if (!count) {
! fprintf(stderr, "no contactable servers found in %s\n",
! SERVERSFILE);
! exit(1);
! }
! return 0;
! }
!
! int
handle_replies()
{
char buf[1400];
***************
*** 675,681 ****
if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
(msg.acpted_rply.ar_stat == SUCCESS)) {
raddr.sin_port = htons((u_short)rmtcr_port);
! rpc_received(msg.rm_xid, &raddr, 0);
}
}
xdr.x_op = XDR_FREE;
--- 789,795 ----
if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
(msg.acpted_rply.ar_stat == SUCCESS)) {
raddr.sin_port = htons((u_short)rmtcr_port);
! rpc_received((char *)msg.rm_xid, &raddr, 0);
}
}
xdr.x_op = XDR_FREE;
***************
*** 685,691 ****
return RPC_SUCCESS;
}
! /*enum clnt_stat*/
handle_ping()
{
char buf[1400];
--- 799,805 ----
return RPC_SUCCESS;
}
! int
handle_ping()
{
char buf[1400];
***************
*** 722,728 ****
if (xdr_replymsg(&xdr, &msg)) {
if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
(msg.acpted_rply.ar_stat == SUCCESS)) {
! rpc_received(msg.rm_xid, &raddr, 0);
}
}
xdr.x_op = XDR_FREE;
--- 836,842 ----
if (xdr_replymsg(&xdr, &msg)) {
if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
(msg.acpted_rply.ar_stat == SUCCESS)) {
! rpc_received((char *)msg.rm_xid, &raddr, 0);
}
}
xdr.x_op = XDR_FREE;
***************
*** 735,744 ****
/*
* LOOPBACK IS MORE IMPORTANT: PUT IN HACK
*/
rpc_received(dom, raddrp, force)
! char *dom;
! struct sockaddr_in *raddrp;
! int force;
{
struct _dom_binding *ypdb;
struct iovec iov[2];
--- 849,859 ----
/*
* LOOPBACK IS MORE IMPORTANT: PUT IN HACK
*/
+ void
rpc_received(dom, raddrp, force)
! char *dom;
! struct sockaddr_in *raddrp;
! int force;
{
struct _dom_binding *ypdb;
struct iovec iov[2];
***************
*** 792,798 ****
close(ypdb->dom_lockfd);
sprintf(path, "%s/%s.%d", BINDINGDIR,
! ypdb->dom_domain, ypdb->dom_vers);
#ifdef O_SHLOCK
if ((fd = open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1) {
(void)mkdir(BINDINGDIR, 0755);
--- 907,913 ----
close(ypdb->dom_lockfd);
sprintf(path, "%s/%s.%d", BINDINGDIR,
! ypdb->dom_domain, (int)ypdb->dom_vers);
#ifdef O_SHLOCK
if ((fd = open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1) {
(void)mkdir(BINDINGDIR, 0755);
>Audit-Trail:
>Unformatted: