]> git.saurik.com Git - apple/libinfo.git/blobdiff - netinfo.subproj/ni_glue.c
Libinfo-129.4.tar.gz
[apple/libinfo.git] / netinfo.subproj / ni_glue.c
index 0a22e74740e32839eac98b91dcf06668f6b63c65..7ec53c910170a24c8119387ded1e522ac5574c7c 100644 (file)
@@ -26,6 +26,7 @@
  * Copyright (C) 1989 by NeXT, Inc.
  */
 #include <libc.h>
  * Copyright (C) 1989 by NeXT, Inc.
  */
 #include <libc.h>
+#include <string.h>
 #include <syslog.h>
 #include <netinfo/ni.h>
 #include <rpc/pmap_clnt.h>
 #include <syslog.h>
 #include <netinfo/ni.h>
 #include <rpc/pmap_clnt.h>
@@ -34,6 +35,9 @@
 #include <net/if.h>
 #include <ctype.h>
 #include "clib.h"
 #include <net/if.h>
 #include <ctype.h>
 #include "clib.h"
+#include "sys_interfaces.h"
+
+#define LOCAL_PORT 1033
 
 #define NI_TIMEOUT_SHORT 5     /* 5 second timeout for transactions */
 #define NI_TIMEOUT_LONG 60     /* 60 second timeout for writes */
 
 #define NI_TIMEOUT_SHORT 5     /* 5 second timeout for transactions */
 #define NI_TIMEOUT_LONG 60     /* 60 second timeout for writes */
@@ -44,7 +48,7 @@
 
 /* Hack for determining if an IP address is a broadcast address. -GRS */
 /* Note that addr is network byte order (big endian) - BKM */
 
 /* Hack for determining if an IP address is a broadcast address. -GRS */
 /* Note that addr is network byte order (big endian) - BKM */
-
 #define IS_BROADCASTADDR(addr) (((unsigned char *) &addr)[0] == 0xFF)
 
 #ifndef INADDR_LOOPBACK
 #define IS_BROADCASTADDR(addr) (((unsigned char *) &addr)[0] == 0xFF)
 
 #ifndef INADDR_LOOPBACK
@@ -82,6 +86,8 @@ static const ni_name NAME_MASTER = "master";
 static const ni_name NAME_USERS = "users";
 static const ni_name NAME_UID = "uid";
 
 static const ni_name NAME_USERS = "users";
 static const ni_name NAME_UID = "uid";
 
+static const ni_name NAME_DOMAIN_SERVERS = "domain_servers";
+
 typedef struct getreg_stuff {
        nibind_getregister_res res;
        ni_private *ni;
 typedef struct getreg_stuff {
        nibind_getregister_res res;
        ni_private *ni;
@@ -117,46 +123,6 @@ getmyport(
 }
 
 
 }
 
 
-/*
- * Is the NetInfo binder running?
- */
-static int
-nibind_up(
-       ni_private *ni
-       )
-{
-       int sock;
-       struct sockaddr_in sin;
-       int res;
-
-       sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
-       if (sock < 0) {
-               return (0);
-       }
-       sin.sin_family = AF_INET;
-       sin.sin_port = htons(PMAPPORT);
-       sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-       bzero(sin.sin_zero, sizeof(sin.sin_zero));
-       res = connect(sock, (struct sockaddr *)&sin, sizeof(sin));
-       close(sock);
-       if (res != 0) {
-               return (0);
-       }
-       sin.sin_port = htons(pmap_getport(&sin, NIBIND_PROG, NIBIND_VERS, 
-                                         IPPROTO_TCP));
-       if (sin.sin_port == 0) {
-               return (0);
-       }
-       sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
-       if (sock < 0) {
-               return (0);
-       }
-       res = connect(sock, (struct sockaddr *)&sin, sizeof(sin));
-       close(sock);
-       return (res == 0);
-}
-       
-
 static void
 createauth(
           ni_private *ni
 static void
 createauth(
           ni_private *ni
@@ -203,9 +169,7 @@ ni_settimeout(
  * Connect to a given address/tag
  */
 static int
  * Connect to a given address/tag
  */
 static int
-connectit(
-         ni_private *ni
-         )
+connectit(ni_private *ni)
 {
        struct sockaddr_in sin;
        int sock;
 {
        struct sockaddr_in sin;
        int sock;
@@ -213,54 +177,82 @@ connectit(
        struct timeval tv;
        enum clnt_stat stat;
        nibind_getregister_res res;
        struct timeval tv;
        enum clnt_stat stat;
        nibind_getregister_res res;
-       
+
+       sock = -1;
        bzero(&sin, sizeof(sin));
        sin.sin_port = 0;
        sin.sin_family = AF_INET;
        bzero(&sin, sizeof(sin));
        sin.sin_port = 0;
        sin.sin_family = AF_INET;
-       sin.sin_addr = ni->addrs[0];
-       ni_settimeout(ni, ni->rtv_sec == 0 ? NI_TIMEOUT_SHORT : ni->rtv_sec);
-       fixtimeout(&tv, ni->tv_sec, NI_TRIES);
-       sock = socket_open(&sin, NIBIND_PROG, NIBIND_VERS, ni->tv_sec, 
-                          NI_TRIES, IPPROTO_UDP);
-       if (sock < 0) {
-               return (0);
-       }
-       cl = clntudp_create(&sin, NIBIND_PROG, NIBIND_VERS, tv,
-                           &sock);
-       if (cl == NULL) {
-               close(sock);
-               return (0);
-       }
+       
        tv.tv_sec = ni->rtv_sec == 0 ? NI_TIMEOUT_SHORT : ni->rtv_sec;
        tv.tv_usec = 0;
        tv.tv_sec = ni->rtv_sec == 0 ? NI_TIMEOUT_SHORT : ni->rtv_sec;
        tv.tv_usec = 0;
-       stat = clnt_call(cl, NIBIND_GETREGISTER, xdr_ni_name, &ni->tags[0],
-                        xdr_nibind_getregister_res, &res, tv);
-       clnt_destroy(cl);
-       close(sock);
-       if (stat != RPC_SUCCESS || res.status != NI_OK) {
-               return (0);
-       }
        
        
+       ni_settimeout(ni, tv.tv_sec);
+       fixtimeout(&tv, ni->tv_sec, NI_TRIES);
+
        /*
        /*
-        * Found the address, now connect to it. 
+        * If connecting to local domain, try using the "well-known" port first.
         */
         */
-       sin.sin_port = htons(res.nibind_getregister_res_u.addrs.tcp_port);
-       sock = socket_open(&sin, NI_PROG, NI_VERS, ni->tv_sec, NI_TRIES,
-                          IPPROTO_TCP);
-       if (sock < 0) {
-               return (0);
+       if (!strcmp(ni->tags[0], "local"))
+       {
+               interface_list_t *ilist;
+
+               ilist = sys_interfaces();
+               if (sys_is_my_address(ilist, &ni->addrs[0]))
+               {
+                       sin.sin_port = htons(LOCAL_PORT);
+                       sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+                       sock = socket_open(&sin, NI_PROG, NI_VERS, ni->tv_sec, NI_TRIES, IPPROTO_TCP);
+               }
+               sys_interfaces_release(ilist);
+       }
+
+       /*
+        * If connecting to a domain other than the local domain,
+        * or if connection to local didn't work with local's well-known port,
+        * then go through portmap & nibindd to find the port and connect.
+        */
+       if (sock < 0)
+       {
+               sin.sin_port = 0;
+               sin.sin_addr = ni->addrs[0];
+
+               sock = socket_open(&sin, NIBIND_PROG, NIBIND_VERS, ni->tv_sec, NI_TRIES, IPPROTO_UDP);
+               if (sock < 0) return (0);
+
+               cl = clntudp_create(&sin, NIBIND_PROG, NIBIND_VERS, tv, &sock);
+               if (cl == NULL)
+               {
+                       close(sock);
+                       return (0);
+               }
+
+               tv.tv_sec = ni->rtv_sec == 0 ? NI_TIMEOUT_SHORT : ni->rtv_sec;
+               tv.tv_usec = 0;
+
+               stat = clnt_call(cl, NIBIND_GETREGISTER, xdr_ni_name, &ni->tags[0], xdr_nibind_getregister_res, &res, tv);
+               clnt_destroy(cl);
+               close(sock);
+               if (stat != RPC_SUCCESS || res.status != NI_OK) return (0);
+       
+               sin.sin_port = htons(res.nibind_getregister_res_u.addrs.tcp_port);
+               sock = socket_open(&sin, NI_PROG, NI_VERS, ni->tv_sec, NI_TRIES, IPPROTO_TCP);
        }
        }
+
+       if (sock < 0) return (0);
+
        cl = clnttcp_create(&sin, NI_PROG, NI_VERS, &sock, 0, 0);
        cl = clnttcp_create(&sin, NI_PROG, NI_VERS, &sock, 0, 0);
-       if (cl == NULL) {
+       if (cl == NULL)
+       {
                close(sock);
                return (0);
        }
                close(sock);
                return (0);
        }
+
        clnt_control(cl, CLSET_TIMEOUT, &tv);
        ni->tc = cl;
        ni->tsock = sock;
        ni->tport = getmyport(sock);
        createauth(ni);
        clnt_control(cl, CLSET_TIMEOUT, &tv);
        ni->tc = cl;
        ni->tsock = sock;
        ni->tport = getmyport(sock);
        createauth(ni);
-       (void) fcntl(ni->tsock, F_SETFD, 1);
+       fcntl(ni->tsock, F_SETFD, 1);
        return (1);
 }
 
        return (1);
 }
 
@@ -305,118 +297,6 @@ ni_needwrite(
 }
 
 
 }
 
 
-static unsigned long
-sys_netmask(void)
-{
-       struct ifconf ifc;
-       struct ifreq *ifr;
-       char buf[1024]; /* XXX */
-       int i, len, ifreq_size, offset, sockaddr_size, size;
-       int sock;
-       struct sockaddr_in *sin;
-       unsigned long n_addr;
-
-       sock = socket(AF_INET, SOCK_DGRAM, 0);
-
-       if (sock < 0) return (htonl(IN_CLASSA_NET));
-
-       ifc.ifc_len = sizeof(buf);
-       ifc.ifc_buf = buf;
-
-       if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0)
-       {
-               close(sock);
-               return (htonl(IN_CLASSA_NET));
-       }
-
-       ifreq_size = sizeof(struct ifreq);
-       sockaddr_size = sizeof(struct sockaddr);
-
-       offset = 0;
-       len = ifc.ifc_len / ifreq_size;
-       for (i = 0; i < len; i++)
-       {
-               ifr = (struct ifreq *)(ifc.ifc_buf + offset);
-               offset += IFNAMSIZ;
-               offset += sockaddr_size;
-
-               size = ifr->ifr_addr.sa_len;
-               if (size > sockaddr_size) offset += (size - sockaddr_size);
-
-               if (ifr->ifr_addr.sa_family != AF_INET) continue;
-               if (ioctl(sock, SIOCGIFFLAGS, (char *)ifr) < 0) continue;
-
-               sin = (struct sockaddr_in *)&ifr->ifr_addr;
-               if ((ifr->ifr_flags & IFF_UP) &&
-                       !(ifr->ifr_flags & IFF_LOOPBACK) &&
-                       (sin->sin_addr.s_addr != 0))
-               {
-                       ioctl(sock, SIOCGIFNETMASK, (char *)ifr);
-                       n_addr = ((struct sockaddr_in *)&(ifr->ifr_addr))->sin_addr.s_addr;
-                       close(sock);
-                       return (n_addr);
-               }
-       }
-
-       close(sock);
-       return (htonl(IN_CLASSA_NET));
-}
-
-
-static unsigned long
-sys_address(void)
-{
-       struct ifconf ifc;
-       struct ifreq *ifr;
-       char buf[1024]; /* XXX */
-       int i, len, ifreq_size, offset, sockaddr_size, size;
-       int sock;
-
-       sock = socket(AF_INET, SOCK_DGRAM, 0);
-
-       if (sock < 0) 
-       {
-               return (htonl(INADDR_LOOPBACK));
-       }
-
-       ifc.ifc_len = sizeof(buf);
-       ifc.ifc_buf = buf;
-
-       if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0)
-       {
-               close(sock);
-               return (htonl(INADDR_LOOPBACK));
-       }
-
-       ifreq_size = sizeof(struct ifreq);
-       sockaddr_size = sizeof(struct sockaddr);
-
-       offset = 0;
-       len = ifc.ifc_len / ifreq_size;
-       for (i = 0; i < len; i++)
-       {
-               ifr = (struct ifreq *)(ifc.ifc_buf + offset);
-               offset += IFNAMSIZ;
-               offset += sockaddr_size;
-
-               size = ifr->ifr_addr.sa_len;
-               if (size > sockaddr_size) offset += (size - sockaddr_size);
-
-               if (ifr->ifr_addr.sa_family != AF_INET) continue;
-               if (ioctl(sock, SIOCGIFFLAGS, ifr) < 0) continue;
-
-               if ((ifr->ifr_flags & IFF_UP) && (!(ifr->ifr_flags & IFF_LOOPBACK)))
-               {
-                       close(sock);
-                       return (((struct sockaddr_in *)&(ifr->ifr_addr))->sin_addr.s_addr);
-               }
-       }
-
-       close(sock);
-       return (htonl(INADDR_LOOPBACK));
-}
-
-
 /*
  * Returns a client handle to the NetInfo server, if it's running
  */
 /*
  * Returns a client handle to the NetInfo server, if it's running
  */
@@ -425,26 +305,30 @@ connectlocal(ni_private *ni)
 {
        int printed = 0;
 
 {
        int printed = 0;
 
-       if (!nibind_up(ni)) {
-               return (0);
-       }
        ni->naddrs = 1;
        ni->addrs = (struct in_addr *)malloc(sizeof(struct in_addr));
        ni->addrs[0].s_addr = htonl(INADDR_LOOPBACK);
        ni->tags = (ni_name *)malloc(sizeof(ni_name));
        ni->tags[0] = ni_name_dup("local");
        ni->whichwrite = 0;
        ni->naddrs = 1;
        ni->addrs = (struct in_addr *)malloc(sizeof(struct in_addr));
        ni->addrs[0].s_addr = htonl(INADDR_LOOPBACK);
        ni->tags = (ni_name *)malloc(sizeof(ni_name));
        ni->tags[0] = ni_name_dup("local");
        ni->whichwrite = 0;
-       while (!connectit(ni)) {
-               if (!printed) {
+
+       while (!connectit(ni))
+       {
+               if (!printed)
+               {
                        syslog(LOG_ERR, "NetInfo timeout connecting to local domain, sleeping");
                        printed++;
                }
                        syslog(LOG_ERR, "NetInfo timeout connecting to local domain, sleeping");
                        printed++;
                }
+
                sleep(NI_SLEEPTIME);
                /* wait forever */
        }
                sleep(NI_SLEEPTIME);
                /* wait forever */
        }
-       if (printed) {
+
+       if (printed)
+       {
                syslog(LOG_ERR, "NetInfo connection to local domain waking");
        }
                syslog(LOG_ERR, "NetInfo connection to local domain waking");
        }
+
        return (1);
 }
 
        return (1);
 }
 
@@ -546,6 +430,8 @@ ni_swap(
        struct in_addr tmp_addr;
        ni_name tmp_tag;
 
        struct in_addr tmp_addr;
        ni_name tmp_tag;
 
+       if (a == b) return;
+
        tmp_addr = ni->addrs[a];
        tmp_tag = ni->tags[a];
 
        tmp_addr = ni->addrs[a];
        tmp_tag = ni->tags[a];
 
@@ -585,6 +471,51 @@ eachresult(
 }
 
 
 }
 
 
+/*
+ * shuffle addresses
+ */
+static void
+shuffle(ni_private *ni)
+{
+       int *shuffle;
+       int i, j;
+       int rfd;
+
+       if (ni->naddrs <= 1) return;
+
+       rfd = open("/dev/random", O_RDONLY, 0);
+       shuffle = (int *)malloc(ni->naddrs * sizeof(int));
+       for (i = 0; i < ni->naddrs; i++) shuffle[i] = i;
+       for (i = 0, j = ni->naddrs; j > 0; i++, j--) {
+               unsigned int rEnt;
+               long rVal;
+               int tEnt;
+
+               /* get a random number */
+               if ((rfd < 0) ||
+                   (read(rfd, &rVal, sizeof(rVal)) != sizeof(rVal))) {
+                       /* if we could not read from /dev/random */
+                       static int initialized = 0;
+                       if (!initialized)
+                       {
+                               srandom(gethostid() ^ time(NULL));
+                               initialized++;
+                       }
+                       rVal = random();
+               }
+
+               rEnt = (unsigned int)rVal % j;  /* pick one of the remaining entries */
+               tEnt = shuffle[rEnt];           /* grab the random entry */
+               shuffle[rEnt] = shuffle[j-1];   /* the last entry moves to the random slot */ 
+               shuffle[j-1]  = tEnt;           /* the last slot gets the random entry */
+               ni_swap(ni, rEnt, j-1);         /* and swap the actual NI addresses */
+       }
+       free(shuffle);
+       if (rfd > 0) (void)close(rfd);
+       return;
+}
+
+
 static int
 rebind(
        ni_private *ni
 static int
 rebind(
        ni_private *ni
@@ -596,9 +527,7 @@ rebind(
        int printed = 0;
        int nlocal;
        int nnetwork;
        int printed = 0;
        int nlocal;
        int nnetwork;
-       unsigned long myaddr;
-       unsigned long mynetmask;
-       unsigned long mynetwork;
+       interface_list_t *ilist;
        int i;
 
        if (ni->naddrs == 1) {
        int i;
 
        if (ni->naddrs == 1) {
@@ -614,17 +543,19 @@ rebind(
         * all other servers are next
         */
 
         * all other servers are next
         */
 
-       myaddr = sys_address();
-       mynetmask = sys_netmask();
-       mynetwork = myaddr & mynetmask;
+       ilist = sys_interfaces();
+
+       /*
+        * shuffle addresses
+        */
+       shuffle(ni);
 
        /*
         * move local servers to the head of the list
         */
        nlocal = 0;
        for (i = nlocal; i < ni->naddrs; i++) {
 
        /*
         * move local servers to the head of the list
         */
        nlocal = 0;
        for (i = nlocal; i < ni->naddrs; i++) {
-               if ((ni->addrs[i].s_addr == myaddr) ||
-                       (ni->addrs[i].s_addr == htonl(INADDR_LOOPBACK)))
+               if (sys_is_my_address(ilist, &ni->addrs[i]))
                {
                        ni_swap(ni, nlocal, i);
                        nlocal++;
                {
                        ni_swap(ni, nlocal, i);
                        nlocal++;
@@ -636,7 +567,7 @@ rebind(
         */
        nnetwork = nlocal;
        for (i = nnetwork; i < ni->naddrs; i++) {
         */
        nnetwork = nlocal;
        for (i = nnetwork; i < ni->naddrs; i++) {
-               if (((ni->addrs[i].s_addr & mynetmask) == mynetwork) ||
+               if (sys_is_my_network(ilist, &ni->addrs[i]) ||
                        IS_BROADCASTADDR(ni->addrs[i].s_addr))
                {
                        ni_swap(ni, nnetwork, i);
                        IS_BROADCASTADDR(ni->addrs[i].s_addr))
                {
                        ni_swap(ni, nnetwork, i);
@@ -644,6 +575,8 @@ rebind(
                }
        }
 
                }
        }
 
+       sys_interfaces_release(ilist);
+
        stuff.ni = ni;
        for (;;) {
                /*
        stuff.ni = ni;
        for (;;) {
                /*
@@ -752,9 +685,12 @@ confirm_tcp(
                 * Somebody closed our socket. Do not close it, it could
                 * be owned by somebody else now.
                 */
                 * Somebody closed our socket. Do not close it, it could
                 * be owned by somebody else now.
                 */
-               auth_destroy(ni->tc->cl_auth);
-               clnt_destroy(ni->tc);
-               ni->tc = NULL;
+               if (ni->tc != NULL)
+               {
+                       if (ni->tc->cl_auth != NULL) auth_destroy(ni->tc->cl_auth);
+                       clnt_destroy(ni->tc);
+                       ni->tc = NULL;
+               }
        }
        if (!needwrite && !rebind(ni) && ni->abort) {
                return (0);
        }
        if (!needwrite && !rebind(ni) && ni->abort) {
                return (0);
@@ -792,6 +728,7 @@ setmaster(
                ni->needwrite = needwrite;
                return (0);
        }
                ni->needwrite = needwrite;
                return (0);
        }
+       NI_INIT(&nl);
        if (ni_lookupprop(ni, &root, NAME_MASTER, &nl) != NI_OK) {
                ni->needwrite = needwrite;
                return (0);
        if (ni_lookupprop(ni, &root, NAME_MASTER, &nl) != NI_OK) {
                ni->needwrite = needwrite;
                return (0);
@@ -807,6 +744,7 @@ setmaster(
        }
        *sep++ = 0;
        master = nl.ninl_val[0];
        }
        *sep++ = 0;
        master = nl.ninl_val[0];
+       NI_INIT(&idl);
        if (ni_lookup(ni, &root, NAME_NAME, NAME_MACHINES, &idl) != NI_OK) {
                ni->needwrite = needwrite;
                ni_namelist_free(&nl);
        if (ni_lookup(ni, &root, NAME_NAME, NAME_MACHINES, &idl) != NI_OK) {
                ni->needwrite = needwrite;
                ni_namelist_free(&nl);
@@ -818,6 +756,7 @@ setmaster(
        }
        id.nii_object = idl.niil_val[0];
        ni_idlist_free(&idl);
        }
        id.nii_object = idl.niil_val[0];
        ni_idlist_free(&idl);
+       NI_INIT(&idl);
        if (ni_lookup(ni, &id, NAME_NAME, master, &idl) != NI_OK) {
                ni_namelist_free(&nl);
                ni->needwrite = needwrite;
        if (ni_lookup(ni, &id, NAME_NAME, master, &idl) != NI_OK) {
                ni_namelist_free(&nl);
                ni->needwrite = needwrite;
@@ -830,6 +769,7 @@ setmaster(
        }
        id.nii_object = idl.niil_val[0];
        ni_idlist_free(&idl);
        }
        id.nii_object = idl.niil_val[0];
        ni_idlist_free(&idl);
+       NI_INIT(&nl);
        if (ni_lookupprop(ni, &id, NAME_IP_ADDRESS, &nl) != NI_OK) {
                return (0);
        }
        if (ni_lookupprop(ni, &id, NAME_IP_ADDRESS, &nl) != NI_OK) {
                return (0);
        }
@@ -903,9 +843,10 @@ callit(
                                }
                                return (resp);
                        }
                                }
                                return (resp);
                        }
-                       clnt_geterr(ni->tc, &err);
-                       if (err.re_status != RPC_CANTRECV) {
-                               break;
+                       if (ni->tc != NULL)
+                       {
+                               clnt_geterr(ni->tc, &err);
+                               if (err.re_status != RPC_CANTRECV) break;
                        }
                        if (i + 1 < NI_MAXCONNTRIES) {
                                /*
                        }
                        if (i + 1 < NI_MAXCONNTRIES) {
                                /*
@@ -1082,13 +1023,47 @@ match(
 }
 
 
 }
 
 
+static void
+add_addr_tag(ni_private *ni, ni_name addrtag)
+{
+       struct in_addr addr;
+       ni_name tag;
+       char *slash;
+
+       slash = strchr(addrtag, '/');
+       if (slash == NULL) return;
+
+       tag = slash + 1;
+       if (tag[0] == '\0') return;
+
+       *slash = '\0';
+
+       if (inet_aton(addrtag, &addr) == 0) return;
+
+       if (ni->naddrs == 0)
+       {
+               ni->addrs = (struct in_addr *)calloc(1, sizeof(struct in_addr));
+               if (ni->addrs == NULL) return;
+
+               ni->tags = (ni_name *)calloc(1, sizeof(ni_name));
+               if (ni->tags == NULL) return;
+       }
+       else
+       {
+               ni->addrs = (struct in_addr *)realloc(ni->addrs, ((ni->naddrs + 1) * sizeof(struct in_addr)));
+               if (ni->addrs == NULL) return;
+
+               ni->tags = (ni_name *)realloc(ni->tags, ((ni->naddrs + 1) * sizeof(ni_name)));
+               if (ni->tags == NULL) return;
+       }
+
+       ni->addrs[ni->naddrs] = addr;
+       ni->tags[ni->naddrs] = ni_name_dup(tag);
+       ni->naddrs++;
+}
+
 static int
 static int
-addaddr(
-       void *ni,
-       ni_index ido,
-       ni_name tag,
-       ni_private *target_ni
-       )
+addaddr(void *ni, ni_index ido, ni_name tag, ni_private *target_ni)
 {
        ni_id id;
        ni_namelist nl;
 {
        ni_id id;
        ni_namelist nl;
@@ -1096,168 +1071,142 @@ addaddr(
        int i;
 
        id.nii_object = ido;
        int i;
 
        id.nii_object = ido;
-       if (ni_lookupprop(ni, &id, NAME_IP_ADDRESS, &nl) != NI_OK) {
-               return (0);
-       }
-       if (nl.ninl_len == 0) {
-               return(0);
-       }
+       NI_INIT(&nl);
+       if (ni_lookupprop(ni, &id, NAME_IP_ADDRESS, &nl) != NI_OK) return 0;
 
 
-       if (target_ni->naddrs == 0) {
-               target_ni->addrs =
-                       (struct in_addr *)malloc(nl.ninl_len * sizeof(struct in_addr));
-               target_ni->tags =
-                       (ni_name *)malloc(nl.ninl_len * sizeof(ni_name));
-       } else {
-               target_ni->addrs =
-                       (struct in_addr *)realloc(target_ni->addrs,
-                                               ((target_ni->naddrs + nl.ninl_len) * sizeof(struct in_addr)));
-               target_ni->tags =
-                       (ni_name *)realloc(target_ni->tags,
-                                               ((target_ni->naddrs + nl.ninl_len) * sizeof(ni_name)));
+       if (nl.ni_namelist_len == 0) return 0;
+
+       if (target_ni->naddrs == 0) 
+       {
+               target_ni->addrs = (struct in_addr *)malloc(nl.ni_namelist_len * sizeof(struct in_addr));
+               target_ni->tags = (ni_name *)malloc(nl.ni_namelist_len * sizeof(ni_name));
+       }
+       else
+       {
+               target_ni->addrs = (struct in_addr *)realloc(target_ni->addrs, ((target_ni->naddrs + nl.ni_namelist_len) * sizeof(struct in_addr)));
+               target_ni->tags = (ni_name *)realloc(target_ni->tags, ((target_ni->naddrs + nl.ni_namelist_len) * sizeof(ni_name)));
        }
 
        }
 
-       for (i=0; i<nl.ninl_len; i++) {
-               addr.s_addr = inet_addr(nl.ninl_val[i]);
+       for (i = 0; i < nl.ni_namelist_len; i++)
+       {
+               addr.s_addr = inet_addr(nl.ni_namelist_val[i]);
                target_ni->addrs[target_ni->naddrs] = addr;
                target_ni->tags[target_ni->naddrs] = ni_name_dup(tag);
                target_ni->naddrs++;
        }
 
        ni_namelist_free(&nl);
                target_ni->addrs[target_ni->naddrs] = addr;
                target_ni->tags[target_ni->naddrs] = ni_name_dup(tag);
                target_ni->naddrs++;
        }
 
        ni_namelist_free(&nl);
-       return (1);
+       return 1;
 }
 
 }
 
-
 static int
 static int
-get_daddr(
-         ni_private *ni,
-         ni_name dom,
-         ni_private *target_ni
-       )
+get_daddr(ni_private *ni, ni_name dom, ni_private *target_ni)
 {
 {
-       ni_id id;
+       ni_id nid;
        ni_idlist ids;
        ni_idlist ids;
-       ni_namelist nl;
        ni_entrylist entries;
        ni_entrylist entries;
+       ni_proplist pl;
        ni_index i;
        ni_index j;
        ni_name tag;
 
        ni_index i;
        ni_index j;
        ni_name tag;
 
-       if (ni_root(ni, &id) != NI_OK) {
-               return(0);
-       }
-
-       if (ni_lookup(ni, &id, NAME_NAME, NAME_MACHINES, &ids) != NI_OK) {
-               return (0);
-       }
-
-       id.nii_object = ids.niil_val[0];
-       ni_idlist_free(&ids);
-
-       if (ni_list(ni, &id, NAME_SERVES, &entries) != NI_OK) {
-               return (0);
-       }
+       if (dom == NULL) return 0;
 
 
-       for (i = 0; i < entries.niel_len; i++) {
-               if (entries.niel_val[i].names != NULL) {
-                       nl = *entries.niel_val[i].names;
-                       for (j = 0; j < nl.ninl_len; j++) {
-                               if (match(dom, nl.ninl_val[j], &tag)) {
-                                       if (addaddr(ni,
-                                                   entries.niel_val[i].id,
-                                                   tag,
-                                                   target_ni)) {
-                                               ni_name_free(&tag);
-                                               break;
+       if (!strcmp(dom, "."))
+       {
+               /* check for server list */
+               NI_INIT(&pl);
+               if (ni_statistics(ni, &pl) == NI_OK)
+               {
+                       i = ni_proplist_match(pl, NAME_DOMAIN_SERVERS, NULL);
+                       if (i != NI_INDEX_NULL)
+                       {
+                               if (pl.ni_proplist_val[i].nip_val.ni_namelist_len > 0)
+                               {
+                                       for (j = 0; j < pl.ni_proplist_val[i].nip_val.ni_namelist_len; j++)
+                                       {
+                                               add_addr_tag(target_ni, pl.ni_proplist_val[i].nip_val.ni_namelist_val[j]);
                                        }
                                        }
-                                       ni_name_free(&tag);
+                                       ni_proplist_free(&pl);
+                                       return 1;
                                }
                        }
                                }
                        }
+                       ni_proplist_free(&pl);
                }
                }
-
        }
        }
-       ni_entrylist_free(&entries);
-       return (target_ni->naddrs > 0);
-}
 
 
+       if (ni_root(ni, &nid) != NI_OK) return 0;
+       NI_INIT(&ids);
+       if (ni_lookup(ni, &nid, NAME_NAME, NAME_MACHINES, &ids) != NI_OK) return 0;
 
 
-#ifdef notdef
-static int
-get_haddr(
-         ni_private *ni,
-         ni_name hname,
-         ni_name tag,
-         ni_private *target_ni
-       )
-{
-       ni_id id;
-       ni_idlist ids;
-
-       if (ni_root(ni, &id) != NI_OK) {
-               return(0);
-       }
-       if (ni_lookup(ni, &id, NAME_NAME, NAME_MACHINES, &ids) != NI_OK) {
-               return (0);
-       }
-       id.nii_object = ids.niil_val[0];
+       nid.nii_object = ids.niil_val[0];
        ni_idlist_free(&ids);
 
        ni_idlist_free(&ids);
 
-       if (ni_lookup(ni, &id, NAME_NAME, hname, &ids) != NI_OK) {
-               return (0);
-       }
-       id.nii_object = ids.niil_val[0];
-       ni_idlist_free(&ids);
-       if (!addaddr(ni, id.nii_object, tag, target_ni)) {
-               return (0);
+       NI_INIT(&entries);
+       if (ni_list(ni, &nid, NAME_SERVES, &entries) != NI_OK) return 0;
+
+       for (i = 0; i < entries.niel_len; i++)
+       {
+               if (entries.niel_val[i].names == NULL) continue;
+
+               for (j = 0; j < entries.niel_val[i].names->ni_namelist_len; j++)
+               {
+                       if (match(dom, entries.niel_val[i].names->ni_namelist_val[j], &tag))
+                       {
+                               addaddr(ni, entries.niel_val[i].id, tag, target_ni);
+                               ni_name_free(&tag);
+                       }
+               }
        }
        }
-       return (1);
-}
-#endif
 
 
+       ni_entrylist_free(&entries);
+       return (target_ni->naddrs > 0);
+}
 
 static ni_status
 getparent(ni_private *oldni, ni_private **newni)
 {
        ni_rparent_res *resp;
 
 static ni_status
 getparent(ni_private *oldni, ni_private **newni)
 {
        ni_rparent_res *resp;
-       ni_private *ni;
+       ni_private *ni = NULL;
        ni_private *dupni;
        ni_private *dupni;
-       int found;
+       int found = 0;
        ni_index i;
        struct in_addr raddr;
        int printed = 0;
        int inlist = 0;
 
        ni_index i;
        struct in_addr raddr;
        int printed = 0;
        int inlist = 0;
 
-       found = 0;
-       while (!found) {
+       while (found == 0)
+       {
                /*
                 * First, find our parent, any parent
                 */
                /*
                 * First, find our parent, any parent
                 */
-               for (;;) {
+               for (;;)
+               {
                        resp = RCALLIT(oldni, _ni_rparent_2, NULL);
                        resp = RCALLIT(oldni, _ni_rparent_2, NULL);
-                       if (resp == NULL) {
-                               return (NI_FAILED);
-                       }
-                       if (resp->status != NI_NORESPONSE) {
-                               break;
-                       }
-                       if (!printed) {
+                       if (resp == NULL) return NI_FAILED;
+                       if (resp->status != NI_NORESPONSE) break;
+
+                       if (!printed)
+                       {
                                syslog(LOG_ERR, "NetInfo timeout finding server for parent of %s/%s, sleeping",
                                        inet_ntoa(oldni->addrs[0]), oldni->tags[0]);
                                printed++;
                        }
                                syslog(LOG_ERR, "NetInfo timeout finding server for parent of %s/%s, sleeping",
                                        inet_ntoa(oldni->addrs[0]), oldni->tags[0]);
                                printed++;
                        }
+
                        sleep(NI_SLEEPTIME);
                }
                        sleep(NI_SLEEPTIME);
                }
-               if (printed) {
+
+               if (printed)
+               {
                        raddr.s_addr = htonl(resp->ni_rparent_res_u.binding.addr);
                        
                        syslog(LOG_ERR, "NetInfo %s/%s found parent %s/%s",
                                        inet_ntoa(oldni->addrs[0]), oldni->tags[0],
                                        inet_ntoa(raddr), resp->ni_rparent_res_u.binding.tag);
                }
                        raddr.s_addr = htonl(resp->ni_rparent_res_u.binding.addr);
                        
                        syslog(LOG_ERR, "NetInfo %s/%s found parent %s/%s",
                                        inet_ntoa(oldni->addrs[0]), oldni->tags[0],
                                        inet_ntoa(raddr), resp->ni_rparent_res_u.binding.tag);
                }
-               if (resp->status != NI_OK) {
-                       return (resp->status);
-               }
+
+               if (resp->status != NI_OK) return (resp->status);
+
                ni = ni_alloc();
                *ni = *oldni;
                ni_clear(ni);
                ni = ni_alloc();
                *ni = *oldni;
                ni_clear(ni);
@@ -1273,15 +1222,19 @@ getparent(ni_private *oldni, ni_private **newni)
                ni = ni_alloc();
                *ni = *dupni;
                ni_clear(ni);
                ni = ni_alloc();
                *ni = *dupni;
                ni_clear(ni);
-               if (get_daddr(dupni, ".", ni)) {
-
+               if (get_daddr(dupni, ".", ni) == 0) 
+               {
+                       if (oldni->abort == 1) break;
+               }
+               else
+               {
                        /*
                        /*
-                        * Now make sure returned parent is head of
-                        * list
+                        * Make sure returned parent is head of list
                         */
                         */
-                       for (i = 0; i < ni->naddrs; i++) {
-                               if (ni->addrs[i].s_addr ==
-                                   dupni->addrs[0].s_addr) {
+                       for (i = 0; i < ni->naddrs; i++)
+                       {
+                               if (ni->addrs[i].s_addr == dupni->addrs[0].s_addr)
+                               {
                                        ni_switch(ni, i);
                                        inlist++;
                                        break;
                                        ni_switch(ni, i);
                                        inlist++;
                                        break;
@@ -1297,13 +1250,14 @@ getparent(ni_private *oldni, ni_private **newni)
                        dupni->tsock = -1;
                        dupni->tport = -1;
                        dupni->tc = NULL;
                        dupni->tsock = -1;
                        dupni->tport = -1;
                        dupni->tc = NULL;
-                       found++;
+                       found = 1;
 
                        /*
                         * If returned parent wasn't in list, it's a rogue.
                         * Log an error and drop the connection.
                         */
 
                        /*
                         * If returned parent wasn't in list, it's a rogue.
                         * Log an error and drop the connection.
                         */
-                       if (inlist == 0) {
+                       if (inlist == 0)
+                       {
                                syslog(LOG_ERR, "Rogue NetInfo server detected: %s/%s",
                                        inet_ntoa(dupni->addrs[0]), dupni->tags[0]);
                                reinit(ni);
                                syslog(LOG_ERR, "Rogue NetInfo server detected: %s/%s",
                                        inet_ntoa(dupni->addrs[0]), dupni->tags[0]);
                                reinit(ni);
@@ -1312,13 +1266,15 @@ getparent(ni_private *oldni, ni_private **newni)
                }
                ni_free(dupni);
        }
                }
                ni_free(dupni);
        }
-       if (found) {
+
+       if (found)
+       {
                *newni = ni;
                *newni = ni;
-               return (NI_OK);
-       } else {
-               ni_free(ni);
-               return (NI_FAILED);
+               return NI_OK;
        }
        }
+
+       if (ni != NULL) ni_free(ni);
+       return NI_FAILED;
 }
 
 
 }
 
 
@@ -2051,17 +2007,20 @@ ni_setuser(
        if (ni_root(ni, &id) != NI_OK) {
                return(NI_NOUSER);
        }
        if (ni_root(ni, &id) != NI_OK) {
                return(NI_NOUSER);
        }
+       NI_INIT(&ids);
        if (ni_lookup(ni, &id, NAME_NAME, NAME_USERS, &ids) != NI_OK) {
                return (NI_NOUSER);
        }
        id.nii_object = ids.niil_val[0];
        ni_idlist_free(&ids);
 
        if (ni_lookup(ni, &id, NAME_NAME, NAME_USERS, &ids) != NI_OK) {
                return (NI_NOUSER);
        }
        id.nii_object = ids.niil_val[0];
        ni_idlist_free(&ids);
 
+       NI_INIT(&ids);
        if (ni_lookup(ni, &id, NAME_NAME, user, &ids) != NI_OK) {
                return (NI_NOUSER);
        }
        id.nii_object = ids.niil_val[0];
        ni_idlist_free(&ids);
        if (ni_lookup(ni, &id, NAME_NAME, user, &ids) != NI_OK) {
                return (NI_NOUSER);
        }
        id.nii_object = ids.niil_val[0];
        ni_idlist_free(&ids);
+       NI_INIT(&nl);
        if (ni_lookupprop(ni, &id, NAME_UID, &nl) != NI_OK) {
                return (NI_NOUSER);
        }
        if (ni_lookupprop(ni, &id, NAME_UID, &nl) != NI_OK) {
                return (NI_NOUSER);
        }
@@ -2220,7 +2179,8 @@ socket_open(
            )
 {
        int sock;
            )
 {
        int sock;
-       
+       int reuse = 1;
+
        /*
         * If no port number given ask the pmap for one
         */
        /*
         * If no port number given ask the pmap for one
         */
@@ -2240,6 +2200,7 @@ socket_open(
                return (-1);
        }
        (void)bindresvport(sock, (struct sockaddr_in *)0);
                return (-1);
        }
        (void)bindresvport(sock, (struct sockaddr_in *)0);
+       setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(int));
        if (proto == IPPROTO_TCP) {
                if (connect(sock, (struct sockaddr *)raddr,
                            sizeof(*raddr)) < 0) {
        if (proto == IPPROTO_TCP) {
                if (connect(sock, (struct sockaddr *)raddr,
                            sizeof(*raddr)) < 0) {