afsconf srv lookup fill cellname
[openafs.git] / src / auth / cellconfig.c
index c8635ce..2009978 100644 (file)
 #include <afsconfig.h>
 #include <afs/param.h>
 
-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>
+#include <ctype.h>
 #else /* UKERNEL */
 #include <sys/types.h>
 #ifdef AFS_NT40_ENV
@@ -31,13 +33,12 @@ RCSID
 #include <netdb.h>
 #include <sys/file.h>
 #include <sys/time.h>
-#ifdef AFS_AFSDB_ENV
+#include <ctype.h>
 #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 */
 #include <afs/afsint.h>
 #include <errno.h>
@@ -47,47 +48,52 @@ RCSID
 #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"
 #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>
+
+struct afsconf_servPair {
+    const char *name;
+    const char *ianaName;
+    int port;
+};
+
 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 */
+    {"afs", "afs3-fileserver", 7000,},
+    {"afscb", "afs3-callback", 7001,},
+    {"afsprot", "afs3-prserver", 7002,},
+    {"afsvldb", "afs3-vlserver", 7003,},
+    {"afskauth", "afs3-kaserver", 7004,},
+    {"afsvol", "afs3-volserver", 7005,},
+    {"afserror", "afs3-errors", 7006,},
+    {"afsnanny", "afs3-bos", 7007,},
+    {"afsupdate", "afs3-update", 7008,},
+    {"afsrmtsys", "afs3-rmtsys", 7009,},
+    {"afsres", NULL, 7010,},/* residency database for MR-AFS */
+    {"afsremio", NULL, 7011,}, /* remote I/O interface for MR-AFS */
+    {0, 0, 0}                  /* insert new services before this spot */
 };
 
 /* Prototypes */
-static afs_int32 afsconf_FindService(register const char *aname);
 static int TrimLine(char *abuffer, int abufsize);
-#ifdef AFS_NT40_ENV
 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);
@@ -106,6 +112,9 @@ static int SaveKeys(struct afsconf_dir *adir);
 #ifndef T_AFSDB
 #define T_AFSDB 18             /* per RFC1183 section 1 */
 #endif
+#ifndef T_SRV
+#define T_SRV 33               /* RFC2782 */
+#endif
 
 /*
  * Basic Rule: we touch "<AFSCONF_DIR>/CellServDB" every time we change anything, so
@@ -222,17 +231,20 @@ afsconf_fgets(char *s, int n, afsconf_FILE *iop)
 #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)
+afs_int32
+afsconf_FindService(const char *aname)
 {
     /* lookup a service name */
     struct servent *ts;
-    register struct afsconf_servPair *tsp;
+    struct afsconf_servPair *tsp;
+
+    if (aname == NULL || aname[0] == '\0')
+       return -1;
 
 #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 */
@@ -240,12 +252,30 @@ afsconf_FindService(register const char *aname)
     }
 
     /* 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))
+    for (tsp = serviceTable; tsp->port; tsp++) {
+       if ((tsp->name && (!strcmp(tsp->name, aname)))
+           || (tsp->ianaName && (!strcmp(tsp->ianaName, aname))))
            return htons(tsp->port);
     }
+    return -1;
+}
+
+const char *
+afsconf_FindIANAName(const char *aname)
+{
+    /* lookup a service name */
+    struct afsconf_servPair *tsp;
+
+    if (aname == NULL || aname[0] == '\0')
+        return NULL;
+
+    /* see if it is one of ours */
+    for (tsp = serviceTable; tsp->port; tsp++) {
+       if ((tsp->name && (!strcmp(tsp->name, aname)))
+           || (tsp->ianaName && (!strcmp(tsp->ianaName, aname))))
+           return tsp->ianaName;
+    }
+    return NULL;
 }
 
 static int
@@ -266,20 +296,25 @@ TrimLine(char *abuffer, int abufsize)
     return 0;
 }
 
-#ifdef AFS_NT40_ENV
 /*
  * IsClientConfigDirectory() -- determine if path matches well-known
  *     client configuration directory.
  */
+#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 = '/';
@@ -287,31 +322,37 @@ 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)
 {
-    char tbuffer[256], *p;
+    char tbuffer[256];
+#ifdef AFS_NT40_ENV
+    char *p;
+#endif
     struct stat tstat;
     register afs_int32 code;
 
@@ -357,9 +398,11 @@ afsconf_Check(register struct afsconf_dir *adir)
 static int
 afsconf_Touch(register struct afsconf_dir *adir)
 {
-    char tbuffer[256], *p;
+    char tbuffer[256];
 #ifndef AFS_NT40_ENV
     struct timeval tvp[2];
+#else
+    char *p;
 #endif
 
     adir->timeRead = 0;                /* just in case */
@@ -516,6 +559,69 @@ 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 */
 
 
@@ -531,10 +637,14 @@ afsconf_OpenInternal(register struct afsconf_dir *adir, char *cell,
     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
@@ -555,6 +665,9 @@ afsconf_OpenInternal(register struct afsconf_dir *adir, char *cell,
     if (IsClientConfigDirectory(adir->name)) {
        /* NT client config dir */
        char *p;
+
+        enumCellRegistry.client = 1;
+
        if (!afssw_GetClientCellServDBDir(&p)) {
            strcompose(tbuffer, sizeof(tbuffer), p, "/",
                       AFSDIR_CELLSERVDB_FILE_NTCLIENT, NULL);
@@ -590,6 +703,19 @@ afsconf_OpenInternal(register struct afsconf_dir *adir, char *cell,
     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)
@@ -627,31 +753,41 @@ afsconf_OpenInternal(register struct afsconf_dir *adir, char *cell,
                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 */
@@ -662,6 +798,18 @@ afsconf_OpenInternal(register struct afsconf_dir *adir, char *cell,
        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);
 
@@ -776,8 +924,8 @@ 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) (struct afsconf_cell * cell, char *arock,
-                               struct afsconf_dir * dir), char *arock)
+                 int (*aproc) (struct afsconf_cell * cell, void *arock,
+                               struct afsconf_dir * dir), void *arock)
 {
     register struct afsconf_entry *tde;
     register afs_int32 code;
@@ -799,8 +947,8 @@ afsconf_CellApply(struct afsconf_dir *adir,
 int
 afsconf_CellAliasApply(struct afsconf_dir *adir,
                       int (*aproc) (struct afsconf_cellalias * alias,
-                                    char *arock, struct afsconf_dir * dir),
-                      char *arock)
+                                    void *arock, struct afsconf_dir * dir),
+                      void *arock)
 {
     register struct afsconf_aliasentry *tde;
     register afs_int32 code;
@@ -839,61 +987,108 @@ afsconf_GetExtendedCellInfo(struct afsconf_dir *adir, char *acellName,
     return code;
 }
 
-#ifdef AFS_AFSDB_ENV
 #if !defined(AFS_NT40_ENV)
 int
-afsconf_GetAfsdbInfo(char *acellName, char *aservice,
-                    struct afsconf_cell *acellInfo)
+afsconf_LookupServer(const char *service, const char *protocol,
+                    const char *cellName, unsigned short afsdbPort,
+                    int *cellHostAddrs, char cellHostNames[][MAXHOSTCHARS],
+                    unsigned short ports[], unsigned short ipRanks[],
+                    int *numServers, int *ttl, char **arealCellName)
 {
-    afs_int32 code;
-    int tservice, i, len;
+    int code = 0;
+    int len;
     unsigned char answer[1024];
     unsigned char *p;
     char *dotcellname;
-    int cellnamelength;
-    char realCellName[256];
+    char *realCellName;
+    int cellnamelength, fullnamelength;
     char host[256];
     int server_num = 0;
     int minttl = 0;
     int try_init = 0;
+    int dnstype = 0;
+    int pass = 0;
+    char *IANAname = (char *) afsconf_FindIANAName(service);
+    int tservice = afsconf_FindService(service);
+
+    realCellName = NULL;
+
+    *numServers = 0;
+    *ttl = 0;
+    if (tservice <= 0 || !IANAname)
+       return AFSCONF_NOTFOUND;        /* service not found */
+
+    if (strchr(cellName,'.'))
+       pass += 2;
+
+    cellnamelength=strlen(cellName); /* _ ._ . . \0 */
+    fullnamelength=cellnamelength+strlen(protocol)+strlen(IANAname)+6;
+    dotcellname=malloc(fullnamelength);
+    if (!dotcellname)
+       return AFSCONF_NOTFOUND;        /* service not found */
+
+#ifdef HAVE_RES_RETRANSRETRY
+    if ((_res.options & RES_INIT) == 0 && res_init() == -1)
+      return (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.
+    /*
+     * Rx timeout is typically 56 seconds; limit user experience to
+     * similar timeout
      */
+    _res.retrans = 18;
+    _res.retry = 3;
+#endif
 
  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;
+    switch (pass) {
+    case 0:
+       dnstype = T_SRV;
+       code = snprintf(dotcellname, fullnamelength, "_%s._%s.%s.",
+                IANAname, protocol, cellName);
+       break;
+    case 1:
+       dnstype = T_AFSDB;
+       code = snprintf(dotcellname, fullnamelength, "%s.",
+                cellName);
+       break;
+    case 2:
+       dnstype = T_SRV;
+       code = snprintf(dotcellname, fullnamelength, "_%s._%s.%s",
+                IANAname, protocol, cellName);
+       break;
+    case 3:
+       dnstype = T_AFSDB;
+       code = snprintf(dotcellname, fullnamelength, "%s",
+                cellName);
+       break;
     }
+    if ((code < 0) || (code >= fullnamelength))
+       goto findservererror;
+    LOCK_GLOBAL_MUTEX;
+    len = res_search(dotcellname, C_IN, dnstype, answer, sizeof(answer));
+    UNLOCK_GLOBAL_MUTEX;
+
     if (len < 0) {
        if (try_init < 1) {
            try_init++;
            res_init();
            goto retryafsdb;
        }
-       return AFSCONF_NOTFOUND;
+       if (pass < 3) {
+           pass++;
+           goto retryafsdb;
+       } else {
+           code = AFSCONF_NOTFOUND;
+           goto findservererror;
+       }
     }
 
     p = answer + sizeof(HEADER);       /* Skip header */
     code = dn_expand(answer, answer + len, p, host, sizeof(host));
-    if (code < 0)
-       return AFSCONF_NOTFOUND;
+    if (code < 0) {
+       code = AFSCONF_NOTFOUND;
+       goto findservererror;
+    }
 
     p += code + QFIXEDSZ;      /* Skip name */
 
@@ -901,8 +1096,10 @@ afsconf_GetAfsdbInfo(char *acellName, char *aservice,
        int type, ttl, size;
 
        code = dn_expand(answer, answer + len, p, host, sizeof(host));
-       if (code < 0)
-           return AFSCONF_NOTFOUND;
+       if (code < 0) {
+           code = AFSCONF_NOTFOUND;
+           goto findservererror;
+       }
 
        p += code;              /* Skip the name */
        type = (p[0] << 8) | p[1];
@@ -923,21 +1120,58 @@ afsconf_GetAfsdbInfo(char *acellName, char *aservice,
                 * right AFSDB type.  Write down the true cell name that
                 * the resolver gave us above.
                 */
-               strlcpy(realCellName, host, sizeof realCellName);
+               realCellName = strdup(host);
            }
 
            code = dn_expand(answer, answer + len, p + 2, host, sizeof(host));
-           if (code < 0)
-               return AFSCONF_NOTFOUND;
+           if (code < 0) {
+               code = AFSCONF_NOTFOUND;
+               goto findservererror;
+           }
 
            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;
                memcpy(&ipaddr, he->h_addr, he->h_length);
-               acellInfo->hostAddr[server_num].sin_addr.s_addr = ipaddr;
-               strncpy(acellInfo->hostName[server_num], host,
-                       sizeof(acellInfo->hostName[server_num]));
+               cellHostAddrs[server_num] = ipaddr;
+               ports[server_num] = afsdbPort;
+               ipRanks[server_num] = 0;
+               strncpy(cellHostNames[server_num], host,
+                       sizeof(cellHostNames[server_num]));
+               server_num++;
+
+               if (!minttl || ttl < minttl)
+                   minttl = ttl;
+           }
+       }
+       if (type == T_SRV) {
+           struct hostent *he;
+           /* math here: _ is 1, _ ._ is 3, _ ._ . is 4. then the domain. */
+           if ((strncmp(host + 1, IANAname, strlen(IANAname)) == 0) &&
+               (strncmp(host + strlen(IANAname) + 3, protocol,
+                        strlen(protocol)) == 0)) {
+               realCellName = strdup(host + strlen(IANAname) +
+                                     strlen(protocol) + 4);
+           }
+
+           code = dn_expand(answer, answer + len, p + 6, host, sizeof(host));
+           if (code < 0) {
+               code = AFSCONF_NOTFOUND;
+               goto findservererror;
+           }
+
+           if ((server_num < MAXHOSTSPERCELL) &&
+               /* Do we want to get TTL data for the A record as well? */
+               (he = gethostbyname(host))) {
+               afs_int32 ipaddr;
+               memcpy(&ipaddr, he->h_addr, he->h_length);
+               cellHostAddrs[server_num] = ipaddr;
+               ipRanks[server_num] = (p[0] << 8) | p[1];
+               ports[server_num] = (p[4] << 8) | p[5];
+               /* weight = (p[2] << 8) | p[3]; */
+               strncpy(cellHostNames[server_num], host,
+                       sizeof(cellHostNames[server_num]));
                server_num++;
 
                if (!minttl || ttl < minttl)
@@ -948,52 +1182,128 @@ afsconf_GetAfsdbInfo(char *acellName, char *aservice,
        p += size;
     }
 
-    if (server_num == 0)       /* No AFSDB records */
-       return AFSCONF_NOTFOUND;
+    if (server_num == 0) {     /* No AFSDB or SRV records */
+       code = AFSCONF_NOTFOUND;
+       goto findservererror;
+    }
 
-    /* Convert the real cell name to lowercase */
-    for (p = (unsigned char *)realCellName; *p; p++)
-       *p = tolower(*p);
+    if (realCellName) {
+       /* Convert the real cell name to lowercase */
+       for (p = (unsigned char *)realCellName; *p; p++)
+           *p = tolower(*p);
+    }
 
-    strncpy(acellInfo->name, realCellName, sizeof(acellInfo->name));
-    acellInfo->numServers = server_num;
+    *arealCellName = realCellName;
 
-    if (aservice) {
-       tservice = afsconf_FindService(aservice);
-       if (tservice < 0)
-           return AFSCONF_NOTFOUND;    /* service not found */
-       for (i = 0; i < acellInfo->numServers; i++) {
-           acellInfo->hostAddr[i].sin_port = tservice;
-       }
-    }
+    *numServers = server_num;
+    *ttl = minttl ? (time(0) + minttl) : 0;
+
+    if ( *numServers > 0 )
+        code =  0;
+    else
+        code = AFSCONF_NOTFOUND;
 
-    acellInfo->timeout = minttl ? (time(0) + minttl) : 0;
+findservererror:
+    free(dotcellname);
+    return code;
+}
 
-    return 0;
+int
+afsconf_GetAfsdbInfo(char *acellName, char *aservice,
+                    struct afsconf_cell *acellInfo)
+{
+    afs_int32 cellHostAddrs[AFSMAXCELLHOSTS];
+    char cellHostNames[AFSMAXCELLHOSTS][MAXHOSTCHARS];
+    unsigned short ipRanks[AFSMAXCELLHOSTS];
+    unsigned short ports[AFSMAXCELLHOSTS];
+    char *realCellName = NULL;
+    int ttl, numServers, i;
+    char *service = aservice;
+    int code;
+    unsigned short afsdbport;
+    if (!service) {
+       service = "afs3-vlserver";
+       afsdbport = htons(7003);
+    } else {
+       service = aservice;
+       afsdbport = afsconf_FindService(service);
+    }
+    code = afsconf_LookupServer((const char *)service, "udp",
+                               (const char *)acellName, afsdbport,
+                               cellHostAddrs, cellHostNames,
+                               ports, ipRanks, &numServers, &ttl,
+                               &realCellName);
+
+    if (code == 0) {
+       acellInfo->timeout = ttl;
+       acellInfo->numServers = numServers;
+       for (i = 0; i < numServers; i++) {
+           memcpy(&acellInfo->hostAddr[i].sin_addr.s_addr, &cellHostAddrs[i],
+                  sizeof(afs_int32));
+           memcpy(acellInfo->hostName[i], cellHostNames[i], MAXHOSTCHARS);
+           acellInfo->hostAddr[i].sin_family = AF_INET;
+           acellInfo->hostAddr[i].sin_port = ports[i];
+
+           if (realCellName)
+               strlcpy(acellInfo->name, realCellName,
+                       sizeof(acellInfo->name));
+       }
+       acellInfo->linkedCell = NULL;       /* no linked cell */
+       acellInfo->flags = 0;
+    }
+    return code;
 }
 #else /* windows */
 int
 afsconf_GetAfsdbInfo(char *acellName, char *aservice,
                     struct afsconf_cell *acellInfo)
 {
-    register afs_int32 i;
-    int tservice;
+    afs_int32 i;
+    int tservice = afsconf_FindService(aservice);   /* network byte order */
+    const char *ianaName = afsconf_FindIANAName(aservice);
     struct afsconf_entry DNSce;
     afs_int32 cellHostAddrs[AFSMAXCELLHOSTS];
     char cellHostNames[AFSMAXCELLHOSTS][MAXHOSTCHARS];
+    unsigned short ipRanks[AFSMAXCELLHOSTS];
+    unsigned short ports[AFSMAXCELLHOSTS];          /* network byte order */
     int numServers;
     int rc;
     int ttl;
 
+    if (tservice < 0) {
+        if (aservice)
+            return AFSCONF_NOTFOUND;
+        else
+            tservice = 0;       /* port will be assigned by caller */
+    }
+
+    if (ianaName == NULL)
+        ianaName = "afs3-vlserver";
+
     DNSce.cellInfo.numServers = 0;
     DNSce.next = NULL;
-    rc = getAFSServer(acellName, cellHostAddrs, cellHostNames, &numServers,
+
+    rc = getAFSServer(ianaName, "udp", acellName, tservice,
+                      cellHostAddrs, cellHostNames, ports, ipRanks, &numServers,
                      &ttl);
     /* ignore the ttl here since this code is only called by transitory programs
      * like klog, etc. */
-    if (rc < 0)
-       return -1;
-    if (numServers == 0)
+
+    /* If we couldn't find an entry for the requested service
+     * and that service happens to be the prservice or kaservice
+     * then fallback to searching for afs3-vlserver and assigning
+     * the port number here. */
+    if (rc < 0 && tservice == htons(7002) || tservice == htons(7004)) {
+        rc = getAFSServer("afs3-vlserver", "udp", acellName, tservice,
+                           cellHostAddrs, cellHostNames, ports, ipRanks, &numServers,
+                           &ttl);
+        if (rc >= 0) {
+            for (i = 0; i < numServers; i++)
+                ports[i] = tservice;
+        }
+    }
+
+    if (rc < 0 || numServers == 0)
        return -1;
 
     for (i = 0; i < numServers; i++) {
@@ -1001,29 +1311,19 @@ afsconf_GetAfsdbInfo(char *acellName, char *aservice,
               sizeof(long));
        memcpy(acellInfo->hostName[i], cellHostNames[i], MAXHOSTCHARS);
        acellInfo->hostAddr[i].sin_family = AF_INET;
-
-       /* sin_port supplied by connection code */
+        if (aservice)
+            acellInfo->hostAddr[i].sin_port = ports[i];
+        else
+            acellInfo->hostAddr[i].sin_port = 0;
     }
 
     acellInfo->numServers = numServers;
     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;
-       }
-    }
     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,
@@ -1100,15 +1400,69 @@ afsconf_GetCellInfo(struct afsconf_dir *adir, char *acellName, char *aservice,
            }
        }
        acellInfo->timeout = 0;
+
+        /* 
+         * 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;
-#ifdef AFS_AFSDB_ENV
        return afsconf_GetAfsdbInfo(tcell, aservice, acellInfo);
-#else
-       return AFSCONF_NOTFOUND;
-#endif /* AFS_AFSDB_ENV */
     }
 }
 
@@ -1277,7 +1631,8 @@ afsconf_GetKeys(struct afsconf_dir *adir, struct afsconf_keys *astr)
 
 /* get latest key */
 afs_int32
-afsconf_GetLatestKey(struct afsconf_dir * adir, afs_int32 * avno, char *akey)
+afsconf_GetLatestKey(struct afsconf_dir * adir, afs_int32 * avno, 
+                    struct ktc_encryptionKey *akey)
 {
     register int i;
     int maxa;
@@ -1318,8 +1673,9 @@ afsconf_GetLatestKey(struct afsconf_dir * adir, afs_int32 * avno, char *akey)
 
 /* get a particular key */
 int
-afsconf_GetKey(struct afsconf_dir *adir, afs_int32 avno, char *akey)
+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;