afsdb-support-use-afs-not-dce-records-only-20010715
[openafs.git] / src / auth / cellconfig.c
index 4a31cac..49b5643 100644 (file)
@@ -7,7 +7,11 @@
  * directory or online at http://www.openafs.org/dl/license10.html
  */
 
+#include <afsconfig.h>
 #include <afs/param.h>
+
+RCSID("$Header$");
+
 #include <afs/stds.h>
 #include <afs/pthread_glock.h>
 #ifdef UKERNEL
 #include <netdb.h>
 #include <sys/file.h>
 #include <sys/time.h>
-#endif
+#ifdef AFS_AFSDB_ENV
+#include <arpa/nameser.h>
+#include <resolv.h>
+#endif /* AFS_AFSDB_ENV */
+#endif /* AFS_NT40_ENV */
 #include <errno.h>
 #include <ctype.h>
 #include <time.h>
@@ -73,6 +81,7 @@ register char *aname; {
     /* lookup a service name */
     struct servent *ts;
     register struct afsconf_servPair *tsp;
+
 #if     defined(AFS_OSF_ENV) || defined(AFS_DEC_ENV)
     ts = getservbyname(aname, "");
 #else
@@ -82,6 +91,7 @@ register char *aname; {
        /* we found it in /etc/services, so we use this value */
        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 == (char *) 0) return -1;
@@ -218,7 +228,7 @@ register char *adir; {
     tdir->name = (char *) malloc(strlen(adir)+1);
     strcpy(tdir->name, adir);
 
-    code = afsconf_OpenInternal(tdir);
+    code = afsconf_OpenInternal(tdir, 0, 0);
     if (code) {
        char *afsconf_path, *getenv(), afs_confdir[128];
 
@@ -272,7 +282,7 @@ register char *adir; {
        }
        tdir->name = (char *) malloc(strlen(afsconf_path)+1);
        strcpy(tdir->name, afsconf_path);
-       code = afsconf_OpenInternal(tdir);
+       code = afsconf_OpenInternal(tdir, 0, 0);
        if (code) {
            free(tdir->name);
            free(tdir);
@@ -322,8 +332,11 @@ static int GetCellNT(struct afsconf_dir *adir)
 #endif /* AFS_NT40_ENV */
 
 
-static int afsconf_OpenInternal(adir)
-register struct afsconf_dir *adir; {
+static int afsconf_OpenInternal(adir, cell, clones)
+register struct afsconf_dir *adir; 
+char *cell;
+char clones[];
+{
     FILE *tf;
     register char *tp, *bp;
     register struct afsconf_entry *curEntry;
@@ -409,7 +422,10 @@ register struct afsconf_dir *adir; {
                return -1;
            }
            i = curEntry->cellInfo.numServers;
-           code = ParseHostLine(tbuffer, (char *) &curEntry->cellInfo.hostAddr[i], curEntry->cellInfo.hostName[i]);
+           if (cell && !strcmp(cell, curEntry->cellInfo.name)) 
+                code = ParseHostLine(tbuffer, (char *) &curEntry->cellInfo.hostAddr[i], curEntry->cellInfo.hostName[i], &clones[i]);
+           else
+                code = ParseHostLine(tbuffer, (char *) &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 */
@@ -442,17 +458,26 @@ register struct afsconf_dir *adir; {
 }
 
 /* parse a line of the form
- *"128.2.1.3   #hostname"
+ *"128.2.1.3   #hostname" or
+ *"[128.2.1.3]  #hostname" for clones
  * into the appropriate pieces.  
  */
-static ParseHostLine(aline, addr, aname)
-register struct sockaddr_in *addr;
-char *aline, *aname; {
+static ParseHostLine(aline, addr, aname, aclone)
+    char *aclone;
+    register struct sockaddr_in *addr;
+    char *aline, *aname; 
+{
     int c1, c2, c3, c4;
     register afs_int32 code;
     register char *tp;
 
-    code = sscanf(aline, "%d.%d.%d.%d #%s", &c1, &c2, &c3, &c4, aname);
+    if (*aline == '[') {
+        if (aclone) *aclone = 1;
+        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 (code != 5) return AFSCONF_SYNTAX;
     addr->sin_family = AF_INET;
     addr->sin_port = 0;
@@ -501,6 +526,124 @@ char *arock; {
 }
 
 afs_int32 afsconf_SawCell = 0;
+
+afsconf_GetExtendedCellInfo(adir, acellName, aservice, acellInfo, clones)
+    struct afsconf_dir *adir;
+    char *aservice;
+    char *acellName;
+    struct afsconf_cell *acellInfo; 
+    char clones[];
+{
+    afs_int32 code;
+    char *cell;
+
+    code = afsconf_GetCellInfo(adir, acellName, aservice, acellInfo);
+    if (code) 
+       return code;
+
+    if (acellName) 
+       cell = acellName;
+    else
+       cell = (char *) &acellInfo->name;
+
+    code = afsconf_OpenInternal(adir, cell, clones);
+    return code;
+}
+
+#ifdef AFS_AFSDB_ENV
+afsconf_GetAfsdbInfo(acellName, aservice, acellInfo)
+    char *acellName;
+    char *aservice;
+    struct afsconf_cell *acellInfo;
+{
+    afs_int32 code;
+    int tservice, len, i;
+    unsigned char answer[1024];
+    unsigned char *p;
+    char host[256];
+    int server_num = 0;
+    int minttl = 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)
+       return AFSCONF_NOTFOUND;
+
+    p = answer + sizeof(HEADER);       /* Skip header */
+    code = dn_expand(answer, answer + len, p, host, sizeof(host));
+    if (code < 0)
+       return AFSCONF_NOTFOUND;
+    strncpy(acellInfo->name, host, sizeof(acellInfo->name));
+
+    p += code + QFIXEDSZ;      /* Skip name */
+
+    while (p < answer + len) {
+       int type, ttl, size;
+
+       code = dn_expand(answer, answer + len, p, host, sizeof(host));
+       if (code < 0)
+           return AFSCONF_NOTFOUND;
+
+       p += code;      /* Skip the name */
+       type = (p[0] << 8) | p[1];
+       p += 4;         /* Skip type and class */
+       ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
+       p += 4;         /* Skip the TTL */
+       size = (p[0] << 8) | p[1];
+       p += 2;         /* Skip the size */
+
+       if (type == T_AFSDB) {
+           struct hostent *he;
+           short afsdb_type;
+
+           afsdb_type = (p[0] << 8) | p[1];
+           code = dn_expand(answer, answer+len, p+2, host, sizeof(host));
+           if (code < 0)
+               return AFSCONF_NOTFOUND;
+
+           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]));
+               server_num++;
+
+               if (!minttl || ttl < minttl) minttl = ttl;
+           }
+       }
+
+       p += size;
+    }
+
+    if (server_num == 0)               /* No AFSDB records */
+       return AFSCONF_NOTFOUND;
+    acellInfo->numServers = server_num;
+
+    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;
+       }
+    }
+
+    acellInfo->timeout = minttl ? (time(0) + minttl) : 0;
+
+    return 0;
+}
+#endif /* AFS_AFSDB_ENV */
+
 afsconf_GetCellInfo(adir, acellName, aservice, acellInfo)
 struct afsconf_dir *adir;
 char *aservice;
@@ -520,8 +663,8 @@ struct afsconf_cell *acellInfo; {
        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  */
+       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) {
@@ -562,12 +705,17 @@ struct afsconf_cell *acellInfo; {
                acellInfo->hostAddr[i].sin_port = tservice;
            }
        }
+       acellInfo->timeout = 0;
        UNLOCK_GLOBAL_MUTEX
        return 0;
     }
     else {
        UNLOCK_GLOBAL_MUTEX
+#ifdef AFS_AFSDB_ENV
+       return afsconf_GetAfsdbInfo(acellName, aservice, acellInfo);
+#else
        return AFSCONF_NOTFOUND;
+#endif /* AFS_AFSDB_ENV */
     }
 }
 
@@ -643,7 +791,7 @@ register struct afsconf_dir *adir; {
     register afs_int32 code;
     code = afsconf_CloseInternal(adir);
     if (code) return code;
-    code = afsconf_OpenInternal(adir);
+    code = afsconf_OpenInternal(adir, 0, 0);
     return code;
 }
 
@@ -704,8 +852,12 @@ afsconf_GetKeys(adir, astr)
 struct afsconf_dir *adir;
 struct afsconf_keys *astr;
 {
+    register afs_int32 code;
+
     LOCK_GLOBAL_MUTEX
-    afsconf_Check(adir);
+    code = afsconf_Check(adir);
+    if (code)
+       return AFSCONF_FAILURE;
     bcopy(adir->keystr, astr, sizeof(struct afsconf_keys));
     UNLOCK_GLOBAL_MUTEX
     return 0;
@@ -722,9 +874,12 @@ afs_int32 afsconf_GetLatestKey(adir, avno, akey)
     register struct afsconf_key *tk;
     register afs_int32 best;
     struct afsconf_key *bestk;
+    register afs_int32 code;
     
     LOCK_GLOBAL_MUTEX
-    afsconf_Check(adir);
+    code = afsconf_Check(adir);
+    if (code)
+       return AFSCONF_FAILURE;
     maxa = adir->keystr->nkeys;
 
     best = -1;     /* highest kvno we've seen yet */
@@ -754,9 +909,12 @@ char *akey;
 {
     register int i, maxa;
     register struct afsconf_key *tk;
+    register afs_int32 code;
 
     LOCK_GLOBAL_MUTEX
-    afsconf_Check(adir);
+    code = afsconf_Check(adir);
+    if (code)
+       return AFSCONF_FAILURE;
     maxa = adir->keystr->nkeys;
 
     for(tk = adir->keystr->key,i=0;i<maxa;i++,tk++) {