cellconfig-gethostbyname-20090618
[openafs.git] / src / auth / cellconfig.c
index ba15482..8bd39f7 100644 (file)
 #include <afsconfig.h>
 #include <afs/param.h>
 
-RCSID("$Header$");
+RCSID
+    ("$Header$");
 
 #include <afs/stds.h>
 #include <afs/pthread_glock.h>
 #ifdef UKERNEL
 #include "afs/sysincludes.h"
 #include "afsincludes.h"
+#include "des/des.h"
+#include "rx/rxkad.h"
+#include <netdb.h>
 #else /* UKERNEL */
 #include <sys/types.h>
 #ifdef AFS_NT40_ENV
@@ -24,9 +28,6 @@ RCSID("$Header$");
 #include <sys/utime.h>
 #include <io.h>
 #include <WINNT/afssw.h>
-#ifdef AFS_AFSDB_ENV
-#include <cm_dns.h>
-#endif /* AFS_AFSDB_ENV */
 #else
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -35,6 +36,9 @@ RCSID("$Header$");
 #include <sys/time.h>
 #ifdef AFS_AFSDB_ENV
 #include <arpa/nameser.h>
+#ifdef HAVE_ARPA_NAMESER_COMPAT_H
+#include <arpa/nameser_compat.h>
+#endif
 #include <resolv.h>
 #endif /* AFS_AFSDB_ENV */
 #endif /* AFS_NT40_ENV */
@@ -46,59 +50,66 @@ RCSID("$Header$");
 #include <stdlib.h>
 #include <sys/stat.h>
 #include <fcntl.h>
-#ifdef HAVE_STRING_H
 #include <string.h>
-#else
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
-#endif
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
+#include <rx/rxkad.h>
+#include <rx/rx.h>
 #endif /* UKERNEL */
 #include <afs/afsutil.h>
 #include "cellconfig.h"
 #include "keys.h"
-
-static struct afsconf_servPair serviceTable [] = {
-    { "afs",       7000, },
-    { "afscb",     7001, },
-    { "afsprot",   7002, },
-    { "afsvldb",   7003, },
-    { "afskauth",  7004, },
-    { "afsvol",    7005, },
-    { "afserror",  7006, },
-    { "afsnanny",  7007, },
-    { "afsupdate", 7008, },
-    { "afsrmtsys", 7009, },
-    { "afsres",    7010, },  /* residency database for MR-AFS */
-    { "afsremio",  7011, },  /* remote I/O interface for MR-AFS */
-    { 0, 0 }                /* insert new services before this spot */
+#ifdef AFS_NT40_ENV
+#ifdef AFS_AFSDB_ENV
+#include <cm.h>
+#include <cm_config.h>
+/* cm_dns.h depends on cellconfig.h */
+#include <cm_nls.h>
+#include <cm_dns.h>
+#endif /* AFS_AFSDB_ENV */
+#endif
+#include <rx/rx.h>
+#include <rx/rxkad.h>
+
+static struct afsconf_servPair serviceTable[] = {
+    {"afs", 7000,},
+    {"afscb", 7001,},
+    {"afsprot", 7002,},
+    {"afsvldb", 7003,},
+    {"afskauth", 7004,},
+    {"afsvol", 7005,},
+    {"afserror", 7006,},
+    {"afsnanny", 7007,},
+    {"afsupdate", 7008,},
+    {"afsrmtsys", 7009,},
+    {"afsres", 7010,},         /* residency database for MR-AFS */
+    {"afsremio", 7011,},       /* remote I/O interface for MR-AFS */
+    {0, 0}                     /* insert new services before this spot */
 };
 
 /* Prototypes */
 static afs_int32 afsconf_FindService(register const char *aname);
-static int TrimLine(char *abuffer);
-#ifdef AFS_NT40_ENV
+static int TrimLine(char *abuffer, int abufsize);
 static int IsClientConfigDirectory(const char *path);
+#ifdef AFS_NT40_ENV
 static int GetCellNT(struct afsconf_dir *adir);
 #endif
 static int afsconf_Check(register struct afsconf_dir *adir);
 static int afsconf_Touch(register struct afsconf_dir *adir);
 static int GetCellUnix(struct afsconf_dir *adir);
-static int afsconf_OpenInternal(register struct afsconf_dir *adir,
-        char *cell, char clones[]);
+static int afsconf_OpenInternal(register struct afsconf_dir *adir, char *cell,
+                               char clones[]);
 static int ParseHostLine(char *aline, register struct sockaddr_in *addr,
-        char *aname, char *aclone);
+                        char *aname, char *aclone);
 static int ParseCellLine(register char *aline, register char *aname,
-        register char *alname);
+                        register char *alname);
 static int afsconf_CloseInternal(register struct afsconf_dir *adir);
 static int afsconf_Reopen(register struct afsconf_dir *adir);
 static int SaveKeys(struct afsconf_dir *adir);
 
 #ifndef T_AFSDB
-#define T_AFSDB 18  /* per RFC1183 section 1 */
+#define T_AFSDB 18             /* per RFC1183 section 1 */
 #endif
 
 /*
@@ -108,31 +119,142 @@ static int SaveKeys(struct afsconf_dir *adir);
  * CellServDB changes.
  */
 
+#if defined(AFS_SUN5_ENV) && !defined(__sparcv9)
+/* Solaris through 10 in 32 bit mode will return EMFILE if fopen can't
+   get an fd <= 255. We allow the fileserver to claim more fds than that.
+   This has always been a problem since pr_Initialize would have the same
+   issue, but hpr_Initialize makes it more likely that we would see this. 
+   Work around it. This is not generic. It's coded with the needs of
+   afsconf_* in mind only.
+
+   http://www.opensolaris.org/os/community/onnv/flag-days/pages/2006042001/
+*/
+
+#define BUFFER 4096
+
+struct afsconf_iobuffer {
+    int _file;
+    char *buffer;
+    char *ptr;
+    char *endptr;
+};
+
+typedef struct afsconf_iobuffer afsconf_FILE;
+
+static afsconf_FILE *
+afsconf_fopen(const char *fname, const char *fmode)
+{
+    int fd;
+    afsconf_FILE *iop;
+    
+    if ((fd = open(fname, O_RDONLY)) == -1) {
+       return NULL;
+    }
+    
+    iop = malloc(sizeof(struct afsconf_iobuffer));
+    if (iop == NULL) {
+       (void) close(fd);
+       errno = ENOMEM;
+       return NULL;
+    }
+    iop->_file = fd;
+    iop->buffer = malloc(BUFFER);
+    if (iop->buffer == NULL) {
+       (void) close(fd);
+       free((void *) iop);
+       errno = ENOMEM;
+       return NULL;
+    }
+    iop->ptr = iop->buffer;
+    iop->endptr = iop->buffer;
+    return iop;
+}
+
+static int
+afsconf_fclose(afsconf_FILE *iop)
+{
+    if (iop == NULL) {
+       return 0;
+    }
+    close(iop->_file);
+    free((void *)iop->buffer);
+    free((void *)iop);
+    return 0;
+}
+
+static char *
+afsconf_fgets(char *s, int n, afsconf_FILE *iop)
+{
+    char *p;
+    
+    p = s;
+    for (;;) {
+       char c;
+       
+       if (iop->ptr == iop->endptr) {
+           ssize_t len;
+           
+           if ((len = read(iop->_file, (void *)iop->buffer, BUFFER)) == -1) {
+               return NULL;
+           }
+           if (len == 0) {
+               *p = 0;
+               if (s == p) {
+                   return NULL;
+               }
+               return s;
+           }
+           iop->ptr = iop->buffer;
+           iop->endptr = iop->buffer + len;
+       }
+       c = *iop->ptr++;
+       *p++ = c;
+       if ((p - s) == (n - 1)) {
+           *p = 0;
+           return s;
+       }
+       if (c == '\n') {
+           *p = 0;
+           return s;
+       }
+    }
+}
+#define fopen afsconf_fopen
+#define fclose afsconf_fclose
+#define fgets afsconf_fgets
+#else
+#define afsconf_FILE FILE
+#endif /* AFS_SUN5_ENV && ! __sparcv9 */
+
 /* return port number in network byte order in the low 16 bits of a long; return -1 if not found */
-static afs_int32 afsconf_FindService(register const char *aname)
+static afs_int32
+afsconf_FindService(register const char *aname)
 {
     /* lookup a service name */
     struct servent *ts;
     register struct afsconf_servPair *tsp;
 
-#if     defined(AFS_OSF_ENV) || defined(AFS_DEC_ENV)
+#if     defined(AFS_OSF_ENV) 
     ts = getservbyname(aname, "");
 #else
-    ts = getservbyname(aname, NULL);
+    ts = (struct servent *) getservbyname(aname, NULL);
 #endif
     if (ts) {
        /* we found it in /etc/services, so we use this value */
-       return ts->s_port;  /* already in network byte order */
+       return ts->s_port;      /* already in network byte order */
     }
 
     /* not found in /etc/services, see if it is one of ours */
-    for(tsp = serviceTable;; tsp++) {
-       if (tsp->name == NULL) return -1;
-       if (!strcmp(tsp->name, aname)) return htons(tsp->port);
+    for (tsp = serviceTable;; tsp++) {
+       if (tsp->name == NULL)
+           return -1;
+       if (!strcmp(tsp->name, aname))
+           return htons(tsp->port);
     }
 }
 
-static int TrimLine(char *abuffer)
+static int
+TrimLine(char *abuffer, int abufsize)
 {
     char tbuffer[256];
     register char *tp;
@@ -140,27 +262,34 @@ static int TrimLine(char *abuffer)
 
     tp = abuffer;
     while ((tc = *tp)) {
-       if (!isspace(tc)) break;
+       if (!isspace(tc))
+           break;
        tp++;
     }
-    strcpy(tbuffer, tp);
-    strcpy(abuffer, tbuffer);
+    strlcpy(tbuffer, tp, sizeof tbuffer);
+    strlcpy(abuffer, tbuffer, abufsize);
     return 0;
 }
 
-#ifdef AFS_NT40_ENV
 /*
  * IsClientConfigDirectory() -- determine if path matches well-known
  *     client configuration directory.
  */
-static int IsClientConfigDirectory(const char *path)
+#ifdef AFS_NT40_ENV
+#define IS_SEP(x) ((x) == '\\' || (x) == '/')
+#else /* AFS_NT40_ENV */
+#define IS_SEP(x) ((x) == '/')
+#endif /* AFS_NT40_ENV */
+static int
+IsClientConfigDirectory(const char *path)
 {
     const char *cdir = AFSDIR_CLIENT_ETC_DIRPATH;
-    int i;
+    int i, cc, pc;
 
     for (i = 0; cdir[i] != '\0' && path[i] != '\0'; i++) {
-       int cc = tolower(cdir[i]);
-       int pc = tolower(path[i]);
+#ifdef AFS_NT40_ENV
+       cc = tolower(cdir[i]);
+       pc = tolower(path[i]);
 
        if (cc == '\\') {
            cc = '/';
@@ -168,41 +297,61 @@ static int IsClientConfigDirectory(const char *path)
        if (pc == '\\') {
            pc = '/';
        }
-       if (cc != pc) {
+#else /* AFS_NT40_ENV */
+       cc = cdir[i];
+       pc = path[i];
+#endif /* AFS_NT40_ENV */
+        if (cc != pc) {
            return 0;
        }
     }
 
     /* hit end of one or both; allow mismatch in existence of trailing slash */
     if (cdir[i] != '\0') {
-       if ((cdir[i] != '\\' && cdir[i] != '/') || (cdir[i + 1] != '\0')) {
+       if (!IS_SEP(cdir[i]) || (cdir[i + 1] != '\0')) {
            return 0;
        }
     }
     if (path[i] != '\0') {
-       if ((path[i] != '\\' && path[i] != '/') || (path[i + 1] != '\0')) {
+       if (!IS_SEP(path[i]) || (path[i + 1] != '\0')) {
            return 0;
        }
     }
     return 1;
 }
-#endif /* AFS_NT40_ENV */
 
 
-static int afsconf_Check(register struct afsconf_dir *adir)
+static int
+afsconf_Check(register struct afsconf_dir *adir)
 {
     char tbuffer[256];
+#ifdef AFS_NT40_ENV
+    char *p;
+#endif
     struct stat tstat;
     register afs_int32 code;
 
 #ifdef AFS_NT40_ENV
     /* NT client CellServDB has different file name than NT server or Unix */
     if (IsClientConfigDirectory(adir->name)) {
-       strcompose(tbuffer, 256,
-                  adir->name, "/", AFSDIR_CELLSERVDB_FILE_NTCLIENT, NULL);
+       if (!afssw_GetClientCellServDBDir(&p)) {
+           strcompose(tbuffer, sizeof(tbuffer), p, "/",
+                      AFSDIR_CELLSERVDB_FILE_NTCLIENT, NULL);
+           free(p);
+       } else {
+           int len;
+           strncpy(tbuffer, adir->name, sizeof(tbuffer));
+           len = (int)strlen(tbuffer);
+           if (tbuffer[len - 1] != '\\' && tbuffer[len - 1] != '/') {
+               strncat(tbuffer, "\\", sizeof(tbuffer));
+           }
+           strncat(tbuffer, AFSDIR_CELLSERVDB_FILE_NTCLIENT,
+                   sizeof(tbuffer));
+           tbuffer[sizeof(tbuffer) - 1] = '\0';
+       }
     } else {
-       strcompose(tbuffer, 256,
-                  adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
+       strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLSERVDB_FILE,
+                  NULL);
     }
 #else
     strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
@@ -221,24 +370,38 @@ static int afsconf_Check(register struct afsconf_dir *adir)
 }
 
 /* set modtime on file */
-static int afsconf_Touch(register struct afsconf_dir *adir)
+static int
+afsconf_Touch(register struct afsconf_dir *adir)
 {
     char tbuffer[256];
 #ifndef AFS_NT40_ENV
     struct timeval tvp[2];
+#else
+    char *p;
 #endif
 
-    adir->timeRead = 0;        /* just in case */
+    adir->timeRead = 0;                /* just in case */
 
 #ifdef AFS_NT40_ENV
     /* NT client CellServDB has different file name than NT server or Unix */
 
     if (IsClientConfigDirectory(adir->name)) {
-       strcompose(tbuffer, 256,
-                  adir->name, "/", AFSDIR_CELLSERVDB_FILE_NTCLIENT, NULL);
+       if (!afssw_GetClientCellServDBDir(&p)) {
+           strcompose(tbuffer, sizeof(tbuffer), p, "/",
+                      AFSDIR_CELLSERVDB_FILE_NTCLIENT, NULL);
+           free(p);
+       } else {
+           int len = (int)strlen(tbuffer);
+           if (tbuffer[len - 1] != '\\' && tbuffer[len - 1] != '/') {
+               strncat(tbuffer, "\\", sizeof(tbuffer));
+           }
+           strncat(tbuffer, AFSDIR_CELLSERVDB_FILE_NTCLIENT,
+                   sizeof(tbuffer));
+           tbuffer[sizeof(tbuffer) - 1] = '\0';
+       }
     } else {
-       strcompose(tbuffer, 256,
-                  adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
+       strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLSERVDB_FILE,
+                  NULL);
     }
 
     return _utime(tbuffer, NULL);
@@ -248,20 +411,20 @@ static int afsconf_Touch(register struct afsconf_dir *adir)
     gettimeofday(&tvp[0], NULL);
     tvp[1] = tvp[0];
     return utimes(tbuffer, tvp);
-#endif  /* AFS_NT40_ENV */
+#endif /* AFS_NT40_ENV */
 }
 
-struct afsconf_dir *afsconf_Open(register const char *adir)
+struct afsconf_dir *
+afsconf_Open(register const char *adir)
 {
     register struct afsconf_dir *tdir;
     register afs_int32 code;
 
-    LOCK_GLOBAL_MUTEX
+    LOCK_GLOBAL_MUTEX;
     /* zero structure and fill in name; rest is done by internal routine */
-    tdir = (struct afsconf_dir *) malloc(sizeof(struct afsconf_dir));
+    tdir = (struct afsconf_dir *)malloc(sizeof(struct afsconf_dir));
     memset(tdir, 0, sizeof(struct afsconf_dir));
-    tdir->name = (char *) malloc(strlen(adir)+1);
-    strcpy(tdir->name, adir);
+    tdir->name = strdup(adir);
 
     code = afsconf_OpenInternal(tdir, 0, 0);
     if (code) {
@@ -272,7 +435,7 @@ struct afsconf_dir *afsconf_Open(register const char *adir)
        if (!(afsconf_path = getenv("AFSCONF"))) {
            /* The "AFSCONF" environment (or contents of "/.AFSCONF") will be typically set to something like "/afs/<cell>/common/etc" where, by convention, the default files for "ThisCell" and "CellServDB" will reside; note that a major drawback is that a given afs client on that cell may NOT contain the same contents... */
            char *home_dir;
-           FILE *fp;
+           afsconf_FILE *fp;
            size_t len;
 
            if (!(home_dir = getenv("HOME"))) {
@@ -280,8 +443,8 @@ struct afsconf_dir *afsconf_Open(register const char *adir)
                fp = fopen("/.AFSCONF", "r");
                if (fp == 0) {
                    free(tdir);
-                   UNLOCK_GLOBAL_MUTEX
-                   return (struct afsconf_dir *) 0;
+                   UNLOCK_GLOBAL_MUTEX;
+                   return (struct afsconf_dir *)0;
                }
                fgets(afs_confdir, 128, fp);
                fclose(fp);
@@ -295,66 +458,73 @@ struct afsconf_dir *afsconf_Open(register const char *adir)
                    fp = fopen("/.AFSCONF", "r");
                    if (fp == 0) {
                        free(tdir);
-                       UNLOCK_GLOBAL_MUTEX
-                       return (struct afsconf_dir *) 0;
+                       UNLOCK_GLOBAL_MUTEX;
+                       return (struct afsconf_dir *)0;
                    }
-                   fgets(afs_confdir, 128, fp);
-                   fclose(fp);
                }
                fgets(afs_confdir, 128, fp);
-               fclose(fp);             
+               fclose(fp);
            }
            len = strlen(afs_confdir);
            if (len == 0) {
                free(tdir);
-               UNLOCK_GLOBAL_MUTEX
-               return (struct afsconf_dir *) 0;
+               UNLOCK_GLOBAL_MUTEX;
+               return (struct afsconf_dir *)0;
            }
-           if (afs_confdir[len-1] == '\n') {
-               afs_confdir[len-1] = 0;
+           if (afs_confdir[len - 1] == '\n') {
+               afs_confdir[len - 1] = 0;
            }
            afsconf_path = afs_confdir;
        }
-       tdir->name = (char *) malloc(strlen(afsconf_path)+1);
-       strcpy(tdir->name, afsconf_path);
+       tdir->name = strdup(afsconf_path);
        code = afsconf_OpenInternal(tdir, 0, 0);
        if (code) {
            free(tdir->name);
            free(tdir);
-           UNLOCK_GLOBAL_MUTEX
-           return (struct afsconf_dir *) 0;
+           UNLOCK_GLOBAL_MUTEX;
+           return (struct afsconf_dir *)0;
        }
     }
-    UNLOCK_GLOBAL_MUTEX
+    UNLOCK_GLOBAL_MUTEX;
     return tdir;
 }
 
-
-static int GetCellUnix(struct afsconf_dir *adir)
+static int
+GetCellUnix(struct afsconf_dir *adir)
 {
-    int rc;
+    char *rc;
     char tbuffer[256];
-    FILE *tf;
-
+    char *start, *p;
+    afsconf_FILE *fp;
+    
     strcompose(tbuffer, 256, adir->name, "/", AFSDIR_THISCELL_FILE, NULL);
-    tf = fopen(tbuffer, "r");
-    if (tf) {
-       rc = fscanf(tf, "%s", tbuffer);
-       if (rc == 1) {
-           adir->cellName = (char *) malloc(strlen(tbuffer)+1);
-           strcpy(adir->cellName, tbuffer);
-       }
-       fclose(tf);
-    }
-    else {
+    fp = fopen(tbuffer, "r");
+    if (fp == 0) {
        return -1;
     }
+    rc = fgets(tbuffer, 256, fp);
+    fclose(fp);
+    if (rc == NULL)
+        return -1;
+
+    start = tbuffer;
+    while (*start != '\0' && isspace(*start))
+        start++;
+    p = start;
+    while (*p != '\0' && !isspace(*p))
+        p++;
+    *p = '\0';
+    if (*start == '\0')
+        return -1;
+
+    adir->cellName = strdup(start);
     return 0;
 }
 
 
 #ifdef AFS_NT40_ENV
-static int GetCellNT(struct afsconf_dir *adir)
+static int
+GetCellNT(struct afsconf_dir *adir)
 {
     if (IsClientConfigDirectory(adir->name)) {
        /* NT client config dir; ThisCell is in registry (no file). */
@@ -364,13 +534,77 @@ static int GetCellNT(struct afsconf_dir *adir)
        return GetCellUnix(adir);
     }
 }
+
+/* The following procedures and structs are used on Windows only
+ * to enumerate the Cell information distributed within the 
+ * Windows registry.  (See src/WINNT/afsd/cm_config.c)
+ */
+typedef struct _cm_enumCellRegistry {
+    afs_uint32 client;  /* non-zero if client query */
+    struct afsconf_dir *adir;
+} cm_enumCellRegistry_t;
+
+static long
+cm_serverConfigProc(void *rockp, struct sockaddr_in *addrp, 
+                    char *hostNamep, unsigned short rank)
+{
+    struct afsconf_cell *cellInfop = (struct afsconf_cell *)rockp;
+
+    if (cellInfop->numServers == MAXHOSTSPERCELL)
+        return 0;
+
+    cellInfop->hostAddr[cellInfop->numServers] = *addrp;
+    strncpy(cellInfop->hostName[cellInfop->numServers], hostNamep, MAXHOSTCHARS);
+    cellInfop->hostName[cellInfop->numServers][MAXHOSTCHARS-1] = '\0';
+    cellInfop->numServers++;
+
+    return 0;
+}
+
+static long
+cm_enumCellRegistryProc(void *rockp, char * cellNamep)
+{
+    long code;
+    cm_enumCellRegistry_t *enump = (cm_enumCellRegistry_t *)rockp;
+    char linkedName[256] = "";
+    int timeout = 0;
+    struct afsconf_entry *newEntry;
+
+
+    newEntry = malloc(sizeof(struct afsconf_entry));
+    if (newEntry == NULL)
+        return ENOMEM;
+    newEntry->cellInfo.numServers = 0;
+
+    code = cm_SearchCellRegistry(enump->client, cellNamep, NULL, linkedName, cm_serverConfigProc, &newEntry->cellInfo);
+    if (code == CM_ERROR_FORCE_DNS_LOOKUP)
+        code = cm_SearchCellByDNS(cellNamep, NULL, &timeout, cm_serverConfigProc, &newEntry->cellInfo);
+
+    if (code == 0) {
+        strncpy(newEntry->cellInfo.name, cellNamep, MAXCELLCHARS);
+        newEntry->cellInfo.name[MAXCELLCHARS-1];
+        if (linkedName[0])
+            newEntry->cellInfo.linkedCell = strdup(linkedName);
+        else
+            newEntry->cellInfo.linkedCell = NULL;
+        newEntry->cellInfo.timeout = timeout;
+        newEntry->cellInfo.flags = 0;
+
+        newEntry->next = enump->adir->entries;
+       enump->adir->entries = newEntry;
+    } else {
+        free(newEntry);
+    }
+    return code;
+}       
 #endif /* AFS_NT40_ENV */
 
 
-static int afsconf_OpenInternal(register struct afsconf_dir *adir, 
-       char *cell, char clones[])
+static int
+afsconf_OpenInternal(register struct afsconf_dir *adir, char *cell,
+                    char clones[])
 {
-    FILE *tf;
+    afsconf_FILE *tf;
     register char *tp, *bp;
     register struct afsconf_entry *curEntry;
     struct afsconf_aliasentry *curAlias;
@@ -378,15 +612,19 @@ static int afsconf_OpenInternal(register struct afsconf_dir *adir,
     afs_int32 i;
     char tbuffer[256], tbuf1[256];
     struct stat tstat;
+#ifdef AFS_NT40_ENV
+    cm_enumCellRegistry_t enumCellRegistry = {0, 0};
+#endif /* AFS_NT40_ENV */
 
-    /* figure out the cell name */
+    /* figure out the local cell name */
 #ifdef AFS_NT40_ENV
     i = GetCellNT(adir);
+    enumCellRegistry.adir = adir;
 #else
     i = GetCellUnix(adir);
 #endif
 
-#ifndef AFS_FREELANCE_CLIENT  /* no local cell not fatal in freelance */
+#ifndef AFS_FREELANCE_CLIENT   /* no local cell not fatal in freelance */
     if (i) {
        return i;
     }
@@ -401,16 +639,33 @@ static int afsconf_OpenInternal(register struct afsconf_dir *adir,
      */
     if (IsClientConfigDirectory(adir->name)) {
        /* NT client config dir */
-       strcompose(tbuffer, 256,
-                  adir->name, "/", AFSDIR_CELLSERVDB_FILE_NTCLIENT, NULL);
+       char *p;
+
+        enumCellRegistry.client = 1;
+
+       if (!afssw_GetClientCellServDBDir(&p)) {
+           strcompose(tbuffer, sizeof(tbuffer), p, "/",
+                      AFSDIR_CELLSERVDB_FILE_NTCLIENT, NULL);
+           free(p);
+       } else {
+           int len;
+           strncpy(tbuffer, adir->name, sizeof(tbuffer));
+           len = (int)strlen(tbuffer);
+           if (tbuffer[len - 1] != '\\' && tbuffer[len - 1] != '/') {
+               strncat(tbuffer, "\\", sizeof(tbuffer));
+           }
+           strncat(tbuffer, AFSDIR_CELLSERVDB_FILE_NTCLIENT,
+                   sizeof(tbuffer));
+           tbuffer[sizeof(tbuffer) - 1] = '\0';
+       }
     } else {
        /* NT server config dir */
-       strcompose(tbuffer, 256,
-                  adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
+       strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLSERVDB_FILE,
+                  NULL);
     }
 #else
     strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
-#endif  /* AFS_NT40_ENV */
+#endif /* AFS_NT40_ENV */
 
     if (!stat(tbuffer, &tstat)) {
        adir->timeRead = tstat.st_mtime;
@@ -418,16 +673,31 @@ static int afsconf_OpenInternal(register struct afsconf_dir *adir,
        adir->timeRead = 0;
     }
 
-    strcpy(tbuf1, tbuffer);
+    strlcpy(tbuf1, tbuffer, sizeof tbuf1);
     tf = fopen(tbuffer, "r");
     if (!tf) {
        return -1;
     }
+
+    /* The CellServDB file is now open.  
+     * The following code parses the contents of the 
+     * file and creates a list with the first cell entry
+     * in the CellServDB file at the end of the list.
+     * 
+     * No checking is performed for duplicates.
+     * The side effects of this process are that duplicate
+     * entries appended to the end of the CellServDB file
+     * take precedence and are found in a shorter period 
+     * of time.
+     */
+
     while (1) {
        tp = fgets(tbuffer, sizeof(tbuffer), tf);
-       if (!tp) break;
-       TrimLine(tbuffer);  /* remove white space */
-       if (tbuffer[0] == 0 || tbuffer[0] == '\n') continue;   /* empty line */
+       if (!tp)
+           break;
+       TrimLine(tbuffer, sizeof tbuffer);      /* remove white space */
+       if (tbuffer[0] == 0 || tbuffer[0] == '\n')
+           continue;           /* empty line */
        if (tbuffer[0] == '>') {
            char linkedcell[MAXCELLCHARS];
            /* start new cell item */
@@ -437,21 +707,20 @@ static int afsconf_OpenInternal(register struct afsconf_dir *adir,
                adir->entries = curEntry;
                curEntry = 0;
            }
-           curEntry = (struct afsconf_entry *) malloc(sizeof(struct afsconf_entry));
+           curEntry =
+               (struct afsconf_entry *)malloc(sizeof(struct afsconf_entry));
            memset(curEntry, 0, sizeof(struct afsconf_entry));
-           code = ParseCellLine(tbuffer, curEntry->cellInfo.name, linkedcell);
+           code =
+               ParseCellLine(tbuffer, curEntry->cellInfo.name, linkedcell);
            if (code) {
                afsconf_CloseInternal(adir);
                fclose(tf);
+               free(curEntry);
                return -1;
            }
-           if (linkedcell[0] != '\0') {
-               curEntry->cellInfo.linkedCell =
-                   (char *) malloc(strlen(linkedcell) + 1);
-               strcpy(curEntry->cellInfo.linkedCell, linkedcell);
-           }
-       }
-       else {
+           if (linkedcell[0] != '\0')
+               curEntry->cellInfo.linkedCell = strdup(linkedcell);
+       } else {
            /* new host in the current cell */
            if (!curEntry) {
                afsconf_CloseInternal(adir);
@@ -459,27 +728,44 @@ static int afsconf_OpenInternal(register struct afsconf_dir *adir,
                return -1;
            }
            i = curEntry->cellInfo.numServers;
-           if (cell && !strcmp(cell, curEntry->cellInfo.name)) 
-                code = ParseHostLine(tbuffer, &curEntry->cellInfo.hostAddr[i], curEntry->cellInfo.hostName[i], &clones[i]);
-           else
-                code = ParseHostLine(tbuffer, &curEntry->cellInfo.hostAddr[i], curEntry->cellInfo.hostName[i], 0);
-           if (code) {
-               if (code == AFSCONF_SYNTAX) {
-                   for (bp=tbuffer; *bp != '\n'; bp++) {       /* Take out the <cr> from the buffer */
-                       if (!*bp) break;
+           if (i < MAXHOSTSPERCELL) {
+               if (cell && !strcmp(cell, curEntry->cellInfo.name))
+                   code =
+                       ParseHostLine(tbuffer, 
+                                     &curEntry->cellInfo.hostAddr[i],
+                                     curEntry->cellInfo.hostName[i], 
+                                     &clones[i]);
+               else
+                   code =
+                       ParseHostLine(tbuffer, 
+                                     &curEntry->cellInfo.hostAddr[i],
+                                     curEntry->cellInfo.hostName[i], 0);
+
+               if (code) {
+                   if (code == AFSCONF_SYNTAX) {
+                       for (bp = tbuffer; *bp != '\n'; bp++) { /* Take out the <cr> from the buffer */
+                           if (!*bp)
+                               break;
+                       }
+                       *bp = '\0';
+                       fprintf(stderr,
+                               "Can't properly parse host line \"%s\" in configuration file %s\n",
+                               tbuffer, tbuf1);
                    }
-                   *bp= '\0';
-                   fprintf(stderr, "Can't properly parse host line \"%s\" in configuration file %s\n", tbuffer, tbuf1);
+                   free(curEntry);
+                   fclose(tf);
+                   afsconf_CloseInternal(adir);
+                   return -1;
                }
-               free(curEntry);
-               fclose(tf);
-               afsconf_CloseInternal(adir);
-               return -1;
+               curEntry->cellInfo.numServers = ++i;
+           } else {
+               fprintf(stderr,
+                       "Too many hosts for cell %s in configuration file %s\n", 
+                       curEntry->cellInfo.name, tbuf1);
            }
-           curEntry->cellInfo.numServers = ++i;
        }
     }
-    fclose(tf);        /* close the file now */
+    fclose(tf);                        /* close the file now */
 
     /* end the last partially-completed cell */
     if (curEntry) {
@@ -487,6 +773,18 @@ static int afsconf_OpenInternal(register struct afsconf_dir *adir,
        adir->entries = curEntry;
     }
 
+#ifdef AFS_NT40_ENV
+     /* 
+      * Windows maintains a CellServDB list in the Registry
+      * that supercedes the contents of the CellServDB file.
+      * Prepending these entries to the head of the list 
+      * is sufficient to enforce the precedence.
+      */
+     cm_EnumerateCellRegistry( enumCellRegistry.client,
+                               cm_enumCellRegistryProc,
+                               &enumCellRegistry);
+#endif /* AFS_NT40_ENV */
+
     /* Read in the alias list */
     strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLALIAS_FILE, NULL);
 
@@ -495,37 +793,44 @@ static int afsconf_OpenInternal(register struct afsconf_dir *adir,
        char *aliasPtr;
 
        tp = fgets(tbuffer, sizeof(tbuffer), tf);
-       if (!tp) break;
-       TrimLine(tbuffer);  /* remove white space */
+       if (!tp)
+           break;
+       TrimLine(tbuffer, sizeof tbuffer);      /* remove white space */
 
-       if (tbuffer[0] == '\0' ||
-           tbuffer[0] == '\n' ||
-           tbuffer[0] == '#') continue;        /* empty line */
+       if (tbuffer[0] == '\0' || tbuffer[0] == '\n' || tbuffer[0] == '#')
+           continue;           /* empty line */
 
        tp = tbuffer;
-       while (tp[0] != '\0' && tp[0] != ' ' && tp[0] != '\t') tp++;
-       if (tp[0] == '\0') continue;            /* invalid line */
+       while (tp[0] != '\0' && tp[0] != ' ' && tp[0] != '\t')
+           tp++;
+       if (tp[0] == '\0')
+           continue;           /* invalid line */
 
-       while (tp[0] != '\0' && (tp[0] == ' ' || tp[0] == '\t')) 0[tp++] = '\0';
-       if (tp[0] == '\0') continue;            /* invalid line */
+       while (tp[0] != '\0' && (tp[0] == ' ' || tp[0] == '\t'))
+           0[tp++] = '\0';
+       if (tp[0] == '\0')
+           continue;           /* invalid line */
 
        aliasPtr = tp;
-       while (tp[0] != '\0' && tp[0] != ' ' && tp[0] != '\t' &&
-              tp[0] != '\r' && tp[0] != '\n') tp++;
+       while (tp[0] != '\0' && tp[0] != ' ' && tp[0] != '\t' && tp[0] != '\r'
+              && tp[0] != '\n')
+           tp++;
        tp[0] = '\0';
 
        curAlias = malloc(sizeof(*curAlias));
        memset(curAlias, 0, sizeof(*curAlias));
 
-       strcpy(curAlias->aliasInfo.aliasName, aliasPtr);
-       strcpy(curAlias->aliasInfo.realName, tbuffer);
+       strlcpy(curAlias->aliasInfo.aliasName, aliasPtr, sizeof curAlias->aliasInfo.aliasName);
+       strlcpy(curAlias->aliasInfo.realName, tbuffer, sizeof curAlias->aliasInfo.realName);
 
        curAlias->next = adir->alias_entries;
        adir->alias_entries = curAlias;
     }
 
+    if (tf != NULL)
+       fclose(tf);
     /* now read the fs keys, if possible */
-    adir->keystr = (struct afsconf_keys *) 0;
+    adir->keystr = (struct afsconf_keys *)0;
     afsconf_IntGetKeys(adir);
 
     return 0;
@@ -536,27 +841,33 @@ static int afsconf_OpenInternal(register struct afsconf_dir *adir,
  *"[128.2.1.3]  #hostname" for clones
  * into the appropriate pieces.  
  */
-static int ParseHostLine(char *aline, register struct sockaddr_in *addr, 
-       char *aname, char *aclone)
+static int
+ParseHostLine(char *aline, register struct sockaddr_in *addr, char *aname,
+             char *aclone)
 {
     int c1, c2, c3, c4;
     register afs_int32 code;
     register char *tp;
 
     if (*aline == '[') {
-        if (aclone) *aclone = 1;
-        code = sscanf(aline, "[%d.%d.%d.%d] #%s", &c1, &c2, &c3, &c4, aname);
+       if (aclone)
+           *aclone = 1;
+       /* FIXME: length of aname unknown here */
+       code = sscanf(aline, "[%d.%d.%d.%d] #%s", &c1, &c2, &c3, &c4, aname);
     } else {
-        if (aclone) *aclone = 0;
-        code = sscanf(aline, "%d.%d.%d.%d #%s", &c1, &c2, &c3, &c4, aname);
+       if (aclone)
+           *aclone = 0;
+       /* FIXME: length of aname unknown here */
+       code = sscanf(aline, "%d.%d.%d.%d #%s", &c1, &c2, &c3, &c4, aname);
     }
-    if (code != 5) return AFSCONF_SYNTAX;
+    if (code != 5)
+       return AFSCONF_SYNTAX;
     addr->sin_family = AF_INET;
     addr->sin_port = 0;
 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
     addr->sin_len = sizeof(struct sockaddr_in);
 #endif
-    tp = (char *) &addr->sin_addr;
+    tp = (char *)&addr->sin_addr;
     *tp++ = c1;
     *tp++ = c2;
     *tp++ = c3;
@@ -568,12 +879,15 @@ static int ParseHostLine(char *aline, register struct sockaddr_in *addr,
  * ">cellname [linkedcellname] [#comments]"
  * into the appropriate pieces.
  */
-static int ParseCellLine(register char *aline, register char *aname, 
-       register char *alname)
+static int
+ParseCellLine(register char *aline, register char *aname,
+             register char *alname)
 {
     register int code;
+    /* FIXME: length of aname, alname unknown here */
     code = sscanf(aline, ">%s %s", aname, alname);
-    if (code == 1) *alname = '\0';
+    if (code == 1)
+       *alname = '\0';
     if (code == 2) {
        if (*alname == '#') {
            *alname = '\0';
@@ -583,58 +897,66 @@ static int ParseCellLine(register char *aline, register char *aname,
 }
 
 /* call aproc(entry, arock, adir) for all cells.  Proc must return 0, or we'll stop early and return the code it returns */
-int afsconf_CellApply(struct afsconf_dir *adir, int (*aproc)(), char *arock)
+int
+afsconf_CellApply(struct afsconf_dir *adir,
+                 int (*aproc) (struct afsconf_cell * cell, void *arock,
+                               struct afsconf_dir * dir), void *arock)
 {
     register struct afsconf_entry *tde;
     register afs_int32 code;
-    LOCK_GLOBAL_MUTEX
-    for(tde=adir->entries; tde; tde=tde->next) {
-       code = (*aproc)(&tde->cellInfo, arock, adir);
+    LOCK_GLOBAL_MUTEX;
+    for (tde = adir->entries; tde; tde = tde->next) {
+       code = (*aproc) (&tde->cellInfo, arock, adir);
        if (code) {
-           UNLOCK_GLOBAL_MUTEX
+           UNLOCK_GLOBAL_MUTEX;
            return code;
        }
     }
-    UNLOCK_GLOBAL_MUTEX
+    UNLOCK_GLOBAL_MUTEX;
     return 0;
 }
 
 /* call aproc(entry, arock, adir) for all cell aliases.
  * Proc must return 0, or we'll stop early and return the code it returns
  */
-int afsconf_CellAliasApply(struct afsconf_dir *adir, int (*aproc)(), char *arock)
+int
+afsconf_CellAliasApply(struct afsconf_dir *adir,
+                      int (*aproc) (struct afsconf_cellalias * alias,
+                                    void *arock, struct afsconf_dir * dir),
+                      void *arock)
 {
     register struct afsconf_aliasentry *tde;
     register afs_int32 code;
-    LOCK_GLOBAL_MUTEX
-    for(tde=adir->alias_entries; tde; tde=tde->next) {
-       code = (*aproc)(&tde->aliasInfo, arock, adir);
+    LOCK_GLOBAL_MUTEX;
+    for (tde = adir->alias_entries; tde; tde = tde->next) {
+       code = (*aproc) (&tde->aliasInfo, arock, adir);
        if (code) {
-           UNLOCK_GLOBAL_MUTEX
+           UNLOCK_GLOBAL_MUTEX;
            return code;
        }
     }
-    UNLOCK_GLOBAL_MUTEX
+    UNLOCK_GLOBAL_MUTEX;
     return 0;
 }
 
 afs_int32 afsconf_SawCell = 0;
 
-int afsconf_GetExtendedCellInfo(struct afsconf_dir *adir, 
-       char *acellName, char *aservice, struct afsconf_cell *acellInfo, 
-       char clones[])
+int
+afsconf_GetExtendedCellInfo(struct afsconf_dir *adir, char *acellName,
+                           char *aservice, struct afsconf_cell *acellInfo,
+                           char clones[])
 {
     afs_int32 code;
     char *cell;
 
     code = afsconf_GetCellInfo(adir, acellName, aservice, acellInfo);
-    if (code) 
-       return code;
+    if (code)
+       return code;
 
-    if (acellName) 
-       cell = acellName;
+    if (acellName)
+       cell = acellName;
     else
-       cell = (char *) &acellInfo->name;
+       cell = (char *)&acellInfo->name;
 
     code = afsconf_OpenInternal(adir, cell, clones);
     return code;
@@ -642,29 +964,54 @@ int afsconf_GetExtendedCellInfo(struct afsconf_dir *adir,
 
 #ifdef AFS_AFSDB_ENV
 #if !defined(AFS_NT40_ENV)
-int afsconf_GetAfsdbInfo(char *acellName, char *aservice, 
-       struct afsconf_cell *acellInfo)
+int
+afsconf_GetAfsdbInfo(char *acellName, char *aservice,
+                    struct afsconf_cell *acellInfo)
 {
     afs_int32 code;
-    int tservice, i;
-    size_t len;
+    int tservice, i, len;
     unsigned char answer[1024];
     unsigned char *p;
+    char *dotcellname;
+    int cellnamelength;
     char realCellName[256];
     char host[256];
     int server_num = 0;
     int minttl = 0;
+    int try_init = 0;
 
     /* The resolver isn't always MT-safe.. Perhaps this ought to be
      * replaced with a more fine-grained lock just for the resolver
      * operations.
      */
-    LOCK_GLOBAL_MUTEX
-    len = res_search(acellName, C_IN, T_AFSDB, answer, sizeof(answer));
-    UNLOCK_GLOBAL_MUTEX
 
-    if (len < 0)
+ retryafsdb:
+    if ( ! strchr(acellName,'.') ) {
+       cellnamelength=strlen(acellName);
+       dotcellname=malloc(cellnamelength+2);
+       memcpy(dotcellname,acellName,cellnamelength);
+       dotcellname[cellnamelength]='.';
+       dotcellname[cellnamelength+1]=0;
+       LOCK_GLOBAL_MUTEX;
+       len = res_search(dotcellname, C_IN, T_AFSDB, answer, sizeof(answer));
+       if ( len < 0 ) {
+          len = res_search(acellName, C_IN, T_AFSDB, answer, sizeof(answer));
+       }
+       UNLOCK_GLOBAL_MUTEX;
+       free(dotcellname);
+    } else {
+       LOCK_GLOBAL_MUTEX;
+       len = res_search(acellName, C_IN, T_AFSDB, answer, sizeof(answer));
+       UNLOCK_GLOBAL_MUTEX;
+    }
+    if (len < 0) {
+       if (try_init < 1) {
+           try_init++;
+           res_init();
+           goto retryafsdb;
+       }
        return AFSCONF_NOTFOUND;
+    }
 
     p = answer + sizeof(HEADER);       /* Skip header */
     code = dn_expand(answer, answer + len, p, host, sizeof(host));
@@ -680,13 +1027,13 @@ int afsconf_GetAfsdbInfo(char *acellName, char *aservice,
        if (code < 0)
            return AFSCONF_NOTFOUND;
 
-       p += code;      /* Skip the name */
+       p += code;              /* Skip the name */
        type = (p[0] << 8) | p[1];
-       p += 4;         /* Skip type and class */
+       p += 4;                 /* Skip type and class */
        ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
-       p += 4;         /* Skip the TTL */
+       p += 4;                 /* Skip the TTL */
        size = (p[0] << 8) | p[1];
-       p += 2;         /* Skip the size */
+       p += 2;                 /* Skip the size */
 
        if (type == T_AFSDB) {
            struct hostent *he;
@@ -699,15 +1046,14 @@ int afsconf_GetAfsdbInfo(char *acellName, char *aservice,
                 * right AFSDB type.  Write down the true cell name that
                 * the resolver gave us above.
                 */
-               strcpy(realCellName, host);
+               strlcpy(realCellName, host, sizeof realCellName);
            }
 
-           code = dn_expand(answer, answer+len, p+2, host, sizeof(host));
+           code = dn_expand(answer, answer + len, p + 2, host, sizeof(host));
            if (code < 0)
                return AFSCONF_NOTFOUND;
 
-           if ((afsdb_type == 1) &&
-               (server_num < MAXHOSTSPERCELL) &&
+           if ((afsdb_type == 1) && (server_num < MAXHOSTSPERCELL) &&
                /* Do we want to get TTL data for the A record as well? */
                (he = gethostbyname(host))) {
                afs_int32 ipaddr;
@@ -717,18 +1063,19 @@ int afsconf_GetAfsdbInfo(char *acellName, char *aservice,
                        sizeof(acellInfo->hostName[server_num]));
                server_num++;
 
-               if (!minttl || ttl < minttl) minttl = ttl;
+               if (!minttl || ttl < minttl)
+                   minttl = ttl;
            }
        }
 
        p += size;
     }
 
-    if (server_num == 0)               /* No AFSDB records */
+    if (server_num == 0)       /* No AFSDB records */
        return AFSCONF_NOTFOUND;
 
     /* Convert the real cell name to lowercase */
-    for (p = (unsigned char *) realCellName; *p; p++)
+    for (p = (unsigned char *)realCellName; *p; p++)
        *p = tolower(*p);
 
     strncpy(acellInfo->name, realCellName, sizeof(acellInfo->name));
@@ -737,8 +1084,8 @@ int afsconf_GetAfsdbInfo(char *acellName, char *aservice,
     if (aservice) {
        tservice = afsconf_FindService(aservice);
        if (tservice < 0)
-           return AFSCONF_NOTFOUND;  /* service not found */
-       for (i=0; i<acellInfo->numServers; i++) {
+           return AFSCONF_NOTFOUND;    /* service not found */
+       for (i = 0; i < acellInfo->numServers; i++) {
            acellInfo->hostAddr[i].sin_port = tservice;
        }
     }
@@ -747,60 +1094,64 @@ int afsconf_GetAfsdbInfo(char *acellName, char *aservice,
 
     return 0;
 }
-#else  /* windows */
-int afsconf_GetAfsdbInfo(char *acellName, char *aservice, 
-        struct afsconf_cell *acellInfo)
+#else /* windows */
+int
+afsconf_GetAfsdbInfo(char *acellName, char *aservice,
+                    struct afsconf_cell *acellInfo)
 {
     register afs_int32 i;
     int tservice;
     struct afsconf_entry DNSce;
-    char *DNStmpStrp; /* a temp string pointer */
-    struct hostent *thp;
-    afs_int32 cellHosts[AFSMAXCELLHOSTS];
+    afs_int32 cellHostAddrs[AFSMAXCELLHOSTS];
+    char cellHostNames[AFSMAXCELLHOSTS][MAXHOSTCHARS];
+    unsigned short ipRanks[AFSMAXCELLHOSTS];
     int numServers;
     int rc;
-    int *ttl;
+    int ttl;
 
-    DNSce.cellInfo.numServers=0;
+    DNSce.cellInfo.numServers = 0;
     DNSce.next = NULL;
-    rc = getAFSServer(acellName, cellHosts, &numServers, &ttl);
+    rc = getAFSServer(acellName, cellHostAddrs, cellHostNames, ipRanks, &numServers,
+                     &ttl);
     /* ignore the ttl here since this code is only called by transitory programs
-       like klog, etc. */
+     * like klog, etc. */
     if (rc < 0)
-      return -1;
+       return -1;
     if (numServers == 0)
-      return -1;
+       return -1;
 
-    for (i = 0; i < numServers; i++)
-    {
-        memcpy(&acellInfo->hostAddr[i].sin_addr.s_addr, &cellHosts[i], sizeof(long));
-        acellInfo->hostAddr[i].sin_family = AF_INET;
+    for (i = 0; i < numServers; i++) {
+       memcpy(&acellInfo->hostAddr[i].sin_addr.s_addr, &cellHostAddrs[i],
+              sizeof(long));
+       memcpy(acellInfo->hostName[i], cellHostNames[i], MAXHOSTCHARS);
+       acellInfo->hostAddr[i].sin_family = AF_INET;
 
-        /* sin_port supplied by connection code */
+       /* sin_port supplied by connection code */
     }
 
     acellInfo->numServers = numServers;
-    strcpy(acellInfo->name, acellName);
+    strlcpy(acellInfo->name, acellName, sizeof acellInfo->name);
     if (aservice) {
-        LOCK_GLOBAL_MUTEX
-        tservice = afsconf_FindService(aservice);
-     UNLOCK_GLOBAL_MUTEX
-        if (tservice < 0) {
-            return AFSCONF_NOTFOUND;  /* service not found */
-     }
-     for(i=0; i< acellInfo->numServers; i++) {
-            acellInfo->hostAddr[i].sin_port = tservice;
-     }
+       LOCK_GLOBAL_MUTEX;
+       tservice = afsconf_FindService(aservice);
+       UNLOCK_GLOBAL_MUTEX;
+       if (tservice < 0) {
+           return AFSCONF_NOTFOUND;    /* service not found */
+       }
+       for (i = 0; i < acellInfo->numServers; i++) {
+           acellInfo->hostAddr[i].sin_port = tservice;
+       }
     }
-    acellInfo->linkedCell = NULL;    /* no linked cell */
+    acellInfo->linkedCell = NULL;      /* no linked cell */
     acellInfo->flags = 0;
     return 0;
 }
 #endif /* windows */
 #endif /* AFS_AFSDB_ENV */
 
-int afsconf_GetCellInfo(struct afsconf_dir *adir, char *acellName, 
-       char *aservice, struct afsconf_cell *acellInfo)
+int
+afsconf_GetCellInfo(struct afsconf_dir *adir, char *acellName, char *aservice,
+                   struct afsconf_cell *acellInfo)
 {
     register struct afsconf_entry *tce;
     struct afsconf_aliasentry *tcae;
@@ -808,31 +1159,32 @@ int afsconf_GetCellInfo(struct afsconf_dir *adir, char *acellName,
     register afs_int32 i;
     int tservice;
     char *tcell;
-    size_t cnLen;
+    int cnLen;
     int ambig;
     char tbuffer[64];
 
-    LOCK_GLOBAL_MUTEX
-    if (adir) afsconf_Check(adir);
+    LOCK_GLOBAL_MUTEX;
+    if (adir)
+       afsconf_Check(adir);
     if (acellName) {
        tcell = acellName;
-       cnLen = strlen(tcell)+1;
-       lcstring (tcell, tcell, cnLen);
-       afsconf_SawCell = 1;    /* will ignore the AFSCELL switch on future */
-                               /* call to afsconf_GetLocalCell: like klog  */
+       cnLen = (int)(strlen(tcell) + 1);
+       lcstring(tcell, tcell, cnLen);
+       afsconf_SawCell = 1;    /* will ignore the AFSCELL switch on future */
+       /* call to afsconf_GetLocalCell: like klog  */
     } else {
        i = afsconf_GetLocalCell(adir, tbuffer, sizeof(tbuffer));
        if (i) {
-           UNLOCK_GLOBAL_MUTEX
+           UNLOCK_GLOBAL_MUTEX;
            return i;
        }
        tcell = tbuffer;
     }
     cnLen = strlen(tcell);
-    bestce = (struct afsconf_entry *) 0;
+    bestce = (struct afsconf_entry *)0;
     ambig = 0;
     if (!adir) {
-       UNLOCK_GLOBAL_MUTEX
+       UNLOCK_GLOBAL_MUTEX;
        return 0;
     }
 
@@ -844,16 +1196,18 @@ int afsconf_GetCellInfo(struct afsconf_dir *adir, char *acellName,
        }
     }
 
-    for(tce=adir->entries;tce;tce=tce->next) {
+    for (tce = adir->entries; tce; tce = tce->next) {
        if (strcasecmp(tce->cellInfo.name, tcell) == 0) {
            /* found our cell */
            bestce = tce;
            ambig = 0;
            break;
        }
-       if (strlen(tce->cellInfo.name) < cnLen) continue;   /* clearly wrong */
+       if (strlen(tce->cellInfo.name) < cnLen)
+           continue;           /* clearly wrong */
        if (strncasecmp(tce->cellInfo.name, tcell, cnLen) == 0) {
-           if (bestce) ambig = 1;  /* ambiguous unless we get exact match */
+           if (bestce)
+               ambig = 1;      /* ambiguous unless we get exact match */
            bestce = tce;
        }
     }
@@ -862,19 +1216,76 @@ int afsconf_GetCellInfo(struct afsconf_dir *adir, char *acellName,
        if (aservice) {
            tservice = afsconf_FindService(aservice);
            if (tservice < 0) {
-               UNLOCK_GLOBAL_MUTEX
-               return AFSCONF_NOTFOUND;  /* service not found */
+               UNLOCK_GLOBAL_MUTEX;
+               return AFSCONF_NOTFOUND;        /* service not found */
            }
-           for(i=0;i<acellInfo->numServers;i++) {
+           for (i = 0; i < acellInfo->numServers; i++) {
                acellInfo->hostAddr[i].sin_port = tservice;
            }
        }
        acellInfo->timeout = 0;
-       UNLOCK_GLOBAL_MUTEX
+
+        /* 
+         * Until we figure out how to separate out ubik server
+         * queries from other server queries, only perform gethostbyname()
+         * lookup on the specified hostnames for the client CellServDB files.
+         */
+        if (IsClientConfigDirectory(adir->name) && 
+            !(acellInfo->flags & AFSCONF_CELL_FLAG_DNS_QUERIED)) {
+            int j;
+            short numServers=0;                                        /*Num active servers for the cell */
+            struct sockaddr_in hostAddr[MAXHOSTSPERCELL];      /*IP addresses for cell's servers */
+            char hostName[MAXHOSTSPERCELL][MAXHOSTCHARS];      /*Names for cell's servers */
+
+            memset(&hostAddr, 0, sizeof(hostAddr));
+            memset(&hostName, 0, sizeof(hostName));
+
+            for ( j=0; j<acellInfo->numServers && numServers < MAXHOSTSPERCELL; j++ ) {
+                struct hostent *he = gethostbyname(acellInfo->hostName[j]);
+                int foundAddr = 0;
+
+                if (he && he->h_addrtype == AF_INET) {
+                    int i;
+                    /* obtain all the valid address from the list */
+                    for (i=0 ; he->h_addr_list[i] && numServers < MAXHOSTSPERCELL; i++) {
+                        /* check to see if this is a new address; if so insert it into the list */
+                        int k, dup;
+                        for (k=0, dup=0; !dup && k < numServers; k++) {
+                            if (hostAddr[k].sin_addr.s_addr == *(u_long *)he->h_addr_list[i])
+                                dup = 1;
+                        }
+                        if (dup)
+                            continue;
+
+                        hostAddr[numServers].sin_family = AF_INET;
+                        hostAddr[numServers].sin_port = acellInfo->hostAddr[0].sin_port;
+#ifdef STRUCT_SOCKADDR_HAS_SA_LEN
+                        hostAddr[numServers].sin_len = sizeof(struct sockaddr_in);
+#endif
+                        memcpy(&hostAddr[numServers].sin_addr.s_addr, he->h_addr_list[i], sizeof(long));
+                        strcpy(hostName[numServers], acellInfo->hostName[j]);
+                        foundAddr = 1;
+                        numServers++;
+                    }
+                }
+                if (!foundAddr) {
+                    hostAddr[numServers] = acellInfo->hostAddr[j];
+                    strcpy(hostName[numServers], acellInfo->hostName[j]);
+                    numServers++;
+                }
+            }
+
+            for (i=0; i<numServers; i++) {
+                acellInfo->hostAddr[i] = hostAddr[i];
+                strcpy(acellInfo->hostName[i], hostName[i]);
+            }
+            acellInfo->numServers = numServers;
+            acellInfo->flags |= AFSCONF_CELL_FLAG_DNS_QUERIED;
+        }
+       UNLOCK_GLOBAL_MUTEX;
        return 0;
-    }
-    else {
-       UNLOCK_GLOBAL_MUTEX
+    } else {
+       UNLOCK_GLOBAL_MUTEX;
 #ifdef AFS_AFSDB_ENV
        return afsconf_GetAfsdbInfo(tcell, aservice, acellInfo);
 #else
@@ -883,59 +1294,65 @@ int afsconf_GetCellInfo(struct afsconf_dir *adir, char *acellName,
     }
 }
 
-int afsconf_GetLocalCell(register struct afsconf_dir *adir, 
-       char *aname, afs_int32 alen)
+int
+afsconf_GetLocalCell(register struct afsconf_dir *adir, char *aname,
+                    afs_int32 alen)
 {
-    static int  afsconf_showcell = 0;
-    char        *afscell_path;
-    afs_int32        code = 0;
-
-   LOCK_GLOBAL_MUTEX
-   /*
-    * If a cell switch was specified in a command, then it should override the 
-    * AFSCELL variable.  If a cell was specified, then the afsconf_SawCell flag
-    * is set and the cell name in the adir structure is used.
-    * Read the AFSCELL var each time: in case it changes (unsetenv AFSCELL).
-    */
-   if ( !afsconf_SawCell && (afscell_path= getenv("AFSCELL")) ) {     
-       if ( !afsconf_showcell ) {
-           fprintf(stderr, "Note: Operation is performed on cell %s\n", afscell_path);
+    static int afsconf_showcell = 0;
+    char *afscell_path;
+    afs_int32 code = 0;
+
+    LOCK_GLOBAL_MUTEX;
+    /*
+     * If a cell switch was specified in a command, then it should override the 
+     * AFSCELL variable.  If a cell was specified, then the afsconf_SawCell flag
+     * is set and the cell name in the adir structure is used.
+     * Read the AFSCELL var each time: in case it changes (unsetenv AFSCELL).
+     */
+    if (!afsconf_SawCell && (afscell_path = getenv("AFSCELL"))) {
+       if (!afsconf_showcell) {
+           fprintf(stderr, "Note: Operation is performed on cell %s\n",
+                   afscell_path);
            afsconf_showcell = 1;
        }
        strncpy(aname, afscell_path, alen);
-    } else {                                    
+    } else {
        afsconf_Check(adir);
        if (adir->cellName) {
            strncpy(aname, adir->cellName, alen);
-       }
-       else code = AFSCONF_UNKNOWN;
+       } else
+           code = AFSCONF_UNKNOWN;
     }
 
-    UNLOCK_GLOBAL_MUTEX
-    return(code);
+    UNLOCK_GLOBAL_MUTEX;
+    return (code);
 }
 
-int afsconf_Close(struct afsconf_dir *adir)
+int
+afsconf_Close(struct afsconf_dir *adir)
 {
-    LOCK_GLOBAL_MUTEX
+    LOCK_GLOBAL_MUTEX;
     afsconf_CloseInternal(adir);
-    if (adir->name) free(adir->name);
+    if (adir->name)
+       free(adir->name);
     free(adir);
-    UNLOCK_GLOBAL_MUTEX
+    UNLOCK_GLOBAL_MUTEX;
     return 0;
 }
 
-static int afsconf_CloseInternal(register struct afsconf_dir *adir)
+static int
+afsconf_CloseInternal(register struct afsconf_dir *adir)
 {
     register struct afsconf_entry *td, *nd;
     struct afsconf_aliasentry *ta, *na;
     register char *tname;
 
-    tname = adir->name;        /* remember name, since that's all we preserve */
+    tname = adir->name;                /* remember name, since that's all we preserve */
 
     /* free everything we can find */
-    if (adir->cellName) free(adir->cellName);
-    for(td=adir->entries;td;td=nd) {
+    if (adir->cellName)
+       free(adir->cellName);
+    for (td = adir->entries; td; td = nd) {
        nd = td->next;
        if (td->cellInfo.linkedCell)
            free(td->cellInfo.linkedCell);
@@ -943,27 +1360,31 @@ static int afsconf_CloseInternal(register struct afsconf_dir *adir)
     }
     for (ta = adir->alias_entries; ta; ta = na) {
        na = ta->next;
-       free (ta);
+       free(ta);
     }
-    if (adir->keystr) free(adir->keystr);
+    if (adir->keystr)
+       free(adir->keystr);
 
     /* reinit */
     memset(adir, 0, sizeof(struct afsconf_dir));
-    adir->name = tname;            /* restore it */
+    adir->name = tname;                /* restore it */
     return 0;
 }
 
-static int afsconf_Reopen(register struct afsconf_dir *adir)
+static int
+afsconf_Reopen(register struct afsconf_dir *adir)
 {
     register afs_int32 code;
     code = afsconf_CloseInternal(adir);
-    if (code) return code;
+    if (code)
+       return code;
     code = afsconf_OpenInternal(adir, 0, 0);
     return code;
 }
 
 /* called during opening of config file */
-int afsconf_IntGetKeys(struct afsconf_dir *adir)
+int
+afsconf_IntGetKeys(struct afsconf_dir *adir)
 {
     char tbuffer[256];
     register int fd;
@@ -982,54 +1403,64 @@ int afsconf_IntGetKeys(struct afsconf_dir *adir)
     }
 #endif /* AFS_NT40_ENV */
 
-    LOCK_GLOBAL_MUTEX
+    LOCK_GLOBAL_MUTEX;
     /* compute the key name and other setup */
-
     strcompose(tbuffer, 256, adir->name, "/", AFSDIR_KEY_FILE, NULL);
-    tstr = (struct afsconf_keys *) malloc(sizeof (struct afsconf_keys));
+    tstr = (struct afsconf_keys *)malloc(sizeof(struct afsconf_keys));
     adir->keystr = tstr;
 
     /* read key file */
     fd = open(tbuffer, O_RDONLY);
     if (fd < 0) {
        tstr->nkeys = 0;
-       UNLOCK_GLOBAL_MUTEX
+       UNLOCK_GLOBAL_MUTEX;
        return 0;
     }
     code = read(fd, tstr, sizeof(struct afsconf_keys));
     close(fd);
     if (code < sizeof(afs_int32)) {
        tstr->nkeys = 0;
-       UNLOCK_GLOBAL_MUTEX
+       UNLOCK_GLOBAL_MUTEX;
        return 0;
     }
 
     /* convert key structure to host order */
     tstr->nkeys = ntohl(tstr->nkeys);
-    for(fd=0;fd<tstr->nkeys;fd++)
+
+    if (code < sizeof(afs_int32) + (tstr->nkeys*sizeof(struct afsconf_key))) {
+       tstr->nkeys = 0;
+       UNLOCK_GLOBAL_MUTEX;
+       return 0;
+    }
+
+    for (fd = 0; fd < tstr->nkeys; fd++)
        tstr->key[fd].kvno = ntohl(tstr->key[fd].kvno);
 
-    UNLOCK_GLOBAL_MUTEX
+    UNLOCK_GLOBAL_MUTEX;
     return 0;
 }
 
 /* get keys structure */
-int afsconf_GetKeys(struct afsconf_dir *adir, struct afsconf_keys *astr)
+int
+afsconf_GetKeys(struct afsconf_dir *adir, struct afsconf_keys *astr)
 {
     register afs_int32 code;
 
-    LOCK_GLOBAL_MUTEX
+    LOCK_GLOBAL_MUTEX;
     code = afsconf_Check(adir);
-    if (code)
+    if (code) {
+       UNLOCK_GLOBAL_MUTEX;
        return AFSCONF_FAILURE;
+    }
     memcpy(astr, adir->keystr, sizeof(struct afsconf_keys));
-    UNLOCK_GLOBAL_MUTEX
+    UNLOCK_GLOBAL_MUTEX;
     return 0;
 }
 
 /* get latest key */
-afs_int32 afsconf_GetLatestKey(struct afsconf_dir *adir, 
-       afs_int32 *avno, char *akey)
+afs_int32
+afsconf_GetLatestKey(struct afsconf_dir * adir, afs_int32 * avno, 
+                    struct ktc_encryptionKey *akey)
 {
     register int i;
     int maxa;
@@ -1037,60 +1468,69 @@ afs_int32 afsconf_GetLatestKey(struct afsconf_dir *adir,
     register afs_int32 best;
     struct afsconf_key *bestk;
     register afs_int32 code;
-    
-    LOCK_GLOBAL_MUTEX
+
+    LOCK_GLOBAL_MUTEX;
     code = afsconf_Check(adir);
-    if (code)
+    if (code) {
+       UNLOCK_GLOBAL_MUTEX;
        return AFSCONF_FAILURE;
+    }
     maxa = adir->keystr->nkeys;
 
-    best = -1;     /* highest kvno we've seen yet */
-    bestk = (struct afsconf_key        *) 0;   /* ptr to structure providing best */
-    for(tk = adir->keystr->key,i=0;i<maxa;i++,tk++) {
-       if (tk->kvno == 999) continue;  /* skip bcrypt keys */
+    best = -1;                 /* highest kvno we've seen yet */
+    bestk = (struct afsconf_key *)0;   /* ptr to structure providing best */
+    for (tk = adir->keystr->key, i = 0; i < maxa; i++, tk++) {
+       if (tk->kvno == 999)
+           continue;           /* skip bcrypt keys */
        if (tk->kvno > best) {
            best = tk->kvno;
            bestk = tk;
        }
     }
-    if (bestk) {    /* found any  */
-       if (akey) memcpy(akey, bestk->key, 8); /* copy out latest key */
-       if (avno) *avno = bestk->kvno;  /* and kvno to caller */
-       UNLOCK_GLOBAL_MUTEX
+    if (bestk) {               /* found any  */
+       if (akey)
+           memcpy(akey, bestk->key, 8);        /* copy out latest key */
+       if (avno)
+           *avno = bestk->kvno;        /* and kvno to caller */
+       UNLOCK_GLOBAL_MUTEX;
        return 0;
     }
-    UNLOCK_GLOBAL_MUTEX
+    UNLOCK_GLOBAL_MUTEX;
     return AFSCONF_NOTFOUND;   /* didn't find any keys */
 }
 
 /* get a particular key */
-int afsconf_GetKey(struct afsconf_dir *adir, afs_int32 avno, 
-       char *akey)
+int
+afsconf_GetKey(void *rock, int avno, struct ktc_encryptionKey *akey)
 {
+    struct afsconf_dir *adir = (struct afsconf_dir *) rock;
     register int i, maxa;
     register struct afsconf_key *tk;
     register afs_int32 code;
 
-    LOCK_GLOBAL_MUTEX
+    LOCK_GLOBAL_MUTEX;
     code = afsconf_Check(adir);
-    if (code)
+    if (code) {
+       UNLOCK_GLOBAL_MUTEX;
        return AFSCONF_FAILURE;
+    }
     maxa = adir->keystr->nkeys;
 
-    for(tk = adir->keystr->key,i=0;i<maxa;i++,tk++) {
+    for (tk = adir->keystr->key, i = 0; i < maxa; i++, tk++) {
        if (tk->kvno == avno) {
            memcpy(akey, tk->key, 8);
-           UNLOCK_GLOBAL_MUTEX
+           UNLOCK_GLOBAL_MUTEX;
            return 0;
        }
     }
 
-    UNLOCK_GLOBAL_MUTEX
+    UNLOCK_GLOBAL_MUTEX;
     return AFSCONF_NOTFOUND;
 }
 
 /* save the key structure in the appropriate file */
-static int SaveKeys(struct afsconf_dir *adir)
+static int
+SaveKeys(struct afsconf_dir *adir)
 {
     struct afsconf_keys tkeys;
     register int fd;
@@ -1100,45 +1540,48 @@ static int SaveKeys(struct afsconf_dir *adir)
     memcpy(&tkeys, adir->keystr, sizeof(struct afsconf_keys));
 
     /* convert it to net byte order */
-    for(i = 0; i<tkeys.nkeys; i++ )
+    for (i = 0; i < tkeys.nkeys; i++)
        tkeys.key[i].kvno = htonl(tkeys.key[i].kvno);
     tkeys.nkeys = htonl(tkeys.nkeys);
-    
+
     /* rewrite keys file */
     strcompose(tbuffer, 256, adir->name, "/", AFSDIR_KEY_FILE, NULL);
     fd = open(tbuffer, O_RDWR | O_CREAT | O_TRUNC, 0600);
-    if (fd < 0) return AFSCONF_FAILURE;
+    if (fd < 0)
+       return AFSCONF_FAILURE;
     i = write(fd, &tkeys, sizeof(tkeys));
     if (i != sizeof(tkeys)) {
        close(fd);
        return AFSCONF_FAILURE;
     }
-    if (close(fd) < 0) return AFSCONF_FAILURE;
+    if (close(fd) < 0)
+       return AFSCONF_FAILURE;
     return 0;
 }
 
-int afsconf_AddKey(struct afsconf_dir *adir, afs_int32 akvno, 
-       char akey[8], afs_int32 overwrite)
+int
+afsconf_AddKey(struct afsconf_dir *adir, afs_int32 akvno, char akey[8],
+              afs_int32 overwrite)
 {
     register struct afsconf_keys *tk;
     register struct afsconf_key *tkey;
     register afs_int32 i;
     int foundSlot;
 
-    LOCK_GLOBAL_MUTEX
+    LOCK_GLOBAL_MUTEX;
     tk = adir->keystr;
-    
+
     if (akvno != 999) {
        if (akvno < 0 || akvno > 255) {
-           UNLOCK_GLOBAL_MUTEX
+           UNLOCK_GLOBAL_MUTEX;
            return ERANGE;
        }
     }
     foundSlot = 0;
-    for(i=0, tkey = tk->key; i<tk->nkeys; i++, tkey++) {
+    for (i = 0, tkey = tk->key; i < tk->nkeys; i++, tkey++) {
        if (tkey->kvno == akvno) {
            if (!overwrite) {
-               UNLOCK_GLOBAL_MUTEX
+               UNLOCK_GLOBAL_MUTEX;
                return AFSCONF_KEYINUSE;
            }
            foundSlot = 1;
@@ -1147,7 +1590,7 @@ int afsconf_AddKey(struct afsconf_dir *adir, afs_int32 akvno,
     }
     if (!foundSlot) {
        if (tk->nkeys >= AFSCONF_MAXKEYS) {
-           UNLOCK_GLOBAL_MUTEX
+           UNLOCK_GLOBAL_MUTEX;
            return AFSCONF_FULL;
        }
        tkey = &tk->key[tk->nkeys++];
@@ -1156,42 +1599,43 @@ int afsconf_AddKey(struct afsconf_dir *adir, afs_int32 akvno,
     memcpy(tkey->key, akey, 8);
     i = SaveKeys(adir);
     afsconf_Touch(adir);
-    UNLOCK_GLOBAL_MUTEX
+    UNLOCK_GLOBAL_MUTEX;
     return i;
 }
 
 /* this proc works by sliding the other guys down, rather than using a funny
     kvno value, so that callers can count on getting a good key in key[0].
 */
-int afsconf_DeleteKey(struct afsconf_dir *adir, afs_int32 akvno)
+int
+afsconf_DeleteKey(struct afsconf_dir *adir, afs_int32 akvno)
 {
     register struct afsconf_keys *tk;
     register struct afsconf_key *tkey;
     register int i;
     int foundFlag = 0;
 
-    LOCK_GLOBAL_MUTEX
+    LOCK_GLOBAL_MUTEX;
     tk = adir->keystr;
 
-    for(i=0, tkey = tk->key; i<tk->nkeys; i++, tkey++) {
+    for (i = 0, tkey = tk->key; i < tk->nkeys; i++, tkey++) {
        if (tkey->kvno == akvno) {
            foundFlag = 1;
            break;
        }
     }
     if (!foundFlag) {
-       UNLOCK_GLOBAL_MUTEX
+       UNLOCK_GLOBAL_MUTEX;
        return AFSCONF_NOTFOUND;
     }
 
     /* otherwise slide the others down.  i and tkey point at the guy to delete */
-    for(;i<tk->nkeys-1; i++,tkey++) {
-       tkey->kvno = (tkey+1)->kvno;
-       memcpy(tkey->key, (tkey+1)->key, 8);
+    for (; i < tk->nkeys - 1; i++, tkey++) {
+       tkey->kvno = (tkey + 1)->kvno;
+       memcpy(tkey->key, (tkey + 1)->key, 8);
     }
     tk->nkeys--;
     i = SaveKeys(adir);
     afsconf_Touch(adir);
-    UNLOCK_GLOBAL_MUTEX
+    UNLOCK_GLOBAL_MUTEX;
     return i;
 }