if at first-request-for-a-domain we discover a file /etc/yp/$domainneme
authorderaadt <deraadt@openbsd.org>
Thu, 30 Jan 1997 07:47:28 +0000 (07:47 +0000)
committerderaadt <deraadt@openbsd.org>
Thu, 30 Jan 1997 07:47:28 +0000 (07:47 +0000)
to exist, use it as a list of valid servers instead of doing broadcasts.
However, do not change the semantics of -ypset or -ypsetme. Based on the
reasoning provided in netbsd pr#1759, lukem@supp.cpr.itg.telecom.com.au

usr.sbin/ypbind/ypbind.8
usr.sbin/ypbind/ypbind.c

index de5c356..7fad0c1 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: ypbind.8,v 1.5 1996/04/29 08:05:39 deraadt Exp $
+.\"    $OpenBSD: ypbind.8,v 1.6 1997/01/30 07:47:28 deraadt Exp $
 .\"    $NetBSD: ypbind.8,v 1.2 1996/02/28 01:21:00 thorpej Exp $
 .\"
 .\" Copyright (c) 1996 The NetBSD Foundation, Inc.
 .Nm ypbind
 .Nd create and maintain a binding to a YP server
 .Sh SYNOPSIS
-.Nm ypbind
+.Nm
 .Op Fl ypset
-.Nm ypbind
+.Nm
 .Op Fl ypsetme
 .Sh DESCRIPTION
-.Nm Ypbind
+.Nm
 finds the server for a particular YP domain and stores information about it
 in a
 .Pa binding file.
@@ -56,20 +56,32 @@ that particular domain and which port the server is using.  This information
 is stored in the directory
 .Pa /var/yp/binding
 in a file named with the convention
-.Pa domainname.version.
+.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
+.Nm
+starts the primary domain (or gets the first request for a new domain),
+it checks if a file for the domain in question exists in the directory
+.Pa /etc/yp/
+(ie. /etc/yp/DOMAINNAME).
+If such a file exists, it will list the hosts which
+.Nm
+should restrict it's server search to.
+Otherwise,
+.Nm
+assumes it will need to use broadcasts to find a valid server.
+Using either of these techniques,
+.Nm
+will search for a server willing to serve maps for the
 client's domain.  Once a binding is established,
-.Nm ypbind
+.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 ypbind
+.Nm
 marks the domain as unbound and attempts to re-establish the binding.
 When the binding is once again successful,
-.Nm ypbind
+.Nm
 marks the domain as bound and resumes its periodic check.
 .Pp
 The options are as follows:
@@ -88,14 +100,19 @@ The
 and
 .Fl ypsetme
 options are dangerous and should be avoided.
+For greatest security, the use of a server list in
+.Pa /var/yp/DOMAINNAME
+is recommended.
 .Pp
 If the directory
 .Pa /var/yp/binding
 exists, YP is started automatically at boot time by
 .Pa /etc/rc .
 .Sh FILES
-.Pa /var/yp/binding/domainname.version
+.Pa /var/yp/binding/DOMAINNAME.version
 - binding file for domainname
+.Pa /etc/yp/DOMAINNNAME
+- server list for this particular domain
 .Sh SEE ALSO
 .Xr domainname 1 ,
 .Xr ypcat 1 ,
@@ -103,7 +120,7 @@ exists, YP is started automatically at boot time by
 .Xr yppoll 8 ,
 .Xr ypset 8 ,
 .Xr ypwhich 1 ,
-.Xr ypserv 8
+.Xr ypserv 8 ,
 .Xr yp 8
 .Sh AUTHOR
 Theo de Raadt
index 4ceaa90..ce154b3 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ypbind.c,v 1.17 1997/01/30 06:03:08 deraadt Exp $ */
+/*     $OpenBSD: ypbind.c,v 1.18 1997/01/30 07:47:29 deraadt Exp $ */
 
 /*
  * Copyright (c) 1996 Theo de Raadt <deraadt@theos.com>
@@ -34,7 +34,7 @@
  */
 
 #ifndef LINT
-static char rcsid[] = "$OpenBSD: ypbind.c,v 1.17 1997/01/30 06:03:08 deraadt Exp $";
+static char rcsid[] = "$OpenBSD: ypbind.c,v 1.18 1997/01/30 07:47:29 deraadt Exp $";
 #endif
 
 #include <sys/param.h>
@@ -63,9 +63,11 @@ static char rcsid[] = "$OpenBSD: ypbind.c,v 1.17 1997/01/30 06:03:08 deraadt Exp
 #include <rpc/pmap_prot.h>
 #include <rpc/pmap_rmt.h>
 #include <unistd.h>
+#include <err.h>
 #include <rpcsvc/yp.h>
 #include <rpcsvc/ypclnt.h>
 
+#define SERVERSDIR     "/etc/yp"
 #define BINDINGDIR     "/var/yp/binding"
 #define YPBINDLOCK     "/var/run/ypbind.lock"
 
@@ -82,6 +84,8 @@ struct _dom_binding {
        int dom_lockfd;
        int dom_alive;
        int dom_xid;
+       char dom_servlist[MAXPATHLEN];
+       FILE *dom_servlistfp;
 };
 
 extern bool_t xdr_domainname(), xdr_ypbind_resp();
@@ -92,8 +96,10 @@ void rpc_received __P((char *dom, struct sockaddr_in *raddrp, int force));
 void checkwork __P((void));
 enum clnt_stat handle_replies __P((void));
 enum clnt_stat handle_ping __P((void));
-int broadcast __P((struct _dom_binding *ypdb));
+int broadcast __P((struct _dom_binding *ypdb, char *, int));
+int direct __P((struct _dom_binding *ypdb, char *, int));
 int ping __P((struct _dom_binding *ypdb));
+int pings __P((struct _dom_binding *ypdb));
 
 char *domain;
 
@@ -150,6 +156,9 @@ ypbindproc_domain_2x(transp, argp, clnt)
        char path[MAXPATHLEN];
        time_t now;
 
+       if (strchr((char *)argp, '/') || strchr((char *)argp, '.'))
+               return NULL;
+
        memset(&res, 0, sizeof res);
        res.ypbind_status = YPBIND_FAIL_VAL;
 
@@ -164,9 +173,12 @@ ypbindproc_domain_2x(transp, argp, clnt)
                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);
+               sprintf(path, "%s/%s.%d", BINDINGDIR,
+                   ypdb->dom_domain, (int)ypdb->dom_vers);
                unlink(path);
+               sprintf(ypdb->dom_servlist, "%s/%s",
+                   SERVERSDIR, ypdb->dom_domain);
+               ypdb->dom_servlistfp = fopen(ypdb->dom_servlist, "r");
                ypdb->dom_xid = unique_xid(ypdb);
                ypdb->dom_pnext = ypbindlist;
                ypbindlist = ypdb;
@@ -483,6 +495,9 @@ main(argc, argv)
        rmtcr.xdr_results = xdr_bool;
        rmtcr.results_ptr = (caddr_t)&rmtcr_outval;
 
+       if (strchr(domain, '/') || strchr(domain, '.'))
+               errx(1, "bad domainname %s", domain);
+
        /* build initial domain binding, make it "unsuccessful" */
        ypbindlist = (struct _dom_binding *)malloc(sizeof *ypbindlist);
        memset(ypbindlist, 0, sizeof *ypbindlist);
@@ -490,8 +505,8 @@ main(argc, argv)
        ypbindlist->dom_vers = YPVERS;
        ypbindlist->dom_alive = 0;
        ypbindlist->dom_lockfd = -1;
-       sprintf(path, "%s/%s.%d", BINDINGDIR, ypbindlist->dom_domain,
-           (int)ypbindlist->dom_vers);
+       sprintf(path, "%s/%s.%d", BINDINGDIR,
+           ypbindlist->dom_domain, (int)ypbindlist->dom_vers);
        (void)unlink(path);
 
        checkwork();
@@ -559,7 +574,7 @@ checkwork()
                        if (ypdb->dom_alive == 1)
                                ping(ypdb);
                        else
-                               broadcast(ypdb);
+                               pings(ypdb);
                        time(&t);
                        ypdb->dom_check_t = t + 5;
                }
@@ -626,19 +641,16 @@ ping(ypdb)
 }
 
 int
-broadcast(ypdb)
+pings(ypdb)
        struct _dom_binding *ypdb;
 {
        domainname dom = ypdb->dom_domain;
        struct rpc_msg msg;
-       char buf[1400], *inbuf = NULL;
+       struct sockaddr_in bindsin;
+       char buf[1400];
        char path[MAXPATHLEN];
        enum clnt_stat st;
-       int outlen, i, sock, len, inlen = 8192;
-       struct sockaddr_in bindsin;
-       struct ifconf ifc;
-       struct ifreq ifreq, *ifr;
-       struct in_addr in;
+       int outlen;
        AUTH *rpcua;
        XDR xdr;
 
@@ -685,27 +697,49 @@ broadcast(ypdb)
        if (ypdb->dom_lockfd != -1) {
                close(ypdb->dom_lockfd);
                ypdb->dom_lockfd = -1;
-               sprintf(path, "%s/%s.%d", BINDINGDIR, ypdb->dom_domain,
-                   (int)ypdb->dom_vers);
+               sprintf(path, "%s/%s.%d", BINDINGDIR,
+                   ypdb->dom_domain, (int)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) {
                /*
                 * This resolves the following situation:
                 * ypserver on other subnet was once bound,
                 * but rebooted and is now using a different port
                 */
+               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 (ypdb->dom_servlistfp)
+               return direct(ypdb, buf, outlen);
+       return broadcast(ypdb, buf, outlen);
+}
+
+int
+broadcast(ypdb, buf, outlen)
+       struct _dom_binding *ypdb;
+       char *buf;
+       int outlen;
+{
+       char *inbuf = NULL;
+       int i, sock, len, inlen = 8192;
+       struct sockaddr_in bindsin;
+       struct ifconf ifc;
+       struct ifreq ifreq, *ifr;
+       struct in_addr in;
+
+       memset(&bindsin, 0, sizeof bindsin);
+       bindsin.sin_family = AF_INET;
+       bindsin.sin_len = sizeof(bindsin);
+       bindsin.sin_port = htons(PMAPPORT);
+
        /* find all networks and send the RPC packet out them all */
        if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
                perror("socket");
@@ -774,6 +808,67 @@ broadcast(ypdb)
        return 0;
 }
 
+int
+direct(ypdb, buf, outlen)
+       struct _dom_binding *ypdb;
+       char *buf;
+       int outlen;
+{
+       char line[1024], *p;
+       struct hostent *hp;
+       struct sockaddr_in bindsin;
+       int i, c;
+       struct stat fst, st;
+
+       if (fstat(fileno(ypdb->dom_servlistfp), &fst) != -1 &&
+           stat(ypdb->dom_servlist, &st) != -1 &&
+           (st.st_dev != fst.st_dev || st.st_ino != fst.st_ino)) {
+               FILE *fp;
+
+               fp = fopen(ypdb->dom_servlist, "r");
+               if (fp) {
+                       fclose(ypdb->dom_servlistfp);
+                       ypdb->dom_servlistfp = fp;
+               }
+       }
+       (void) rewind(ypdb->dom_servlistfp);
+
+       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), ypdb->dom_servlistfp) != NULL) {
+               /* skip lines that are too big */
+               p = strchr(line, '\n');
+               if (p == NULL) {
+                       while ((c = getc(ypdb->dom_servlistfp)) != '\n' && c != EOF)
+                               ;
+                       continue;
+               }
+               *p = '\0';
+               p = line;
+               while (isspace(*p))
+                       p++;
+               if (*p == '#')
+                       continue;
+               hp = gethostbyname(p);
+               if (!hp)
+                       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;
+                       }
+               }
+       }
+       return 0;
+}
+
 enum clnt_stat
 handle_replies()
 {