auth-warning-cleanup-20011005
[openafs.git] / src / auth / cellconfig.c
index 4a31cac..ed47eeb 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>
 #include <stdio.h>
+#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
 #endif /* UKERNEL */
 #include <afs/afsutil.h>
 #include "cellconfig.h"
@@ -45,19 +64,19 @@ static afsconf_CloseInternal();
 static afsconf_Reopen();
 
 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",       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 */
 };
 
 /*
@@ -73,6 +92,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 +102,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;
@@ -96,7 +117,7 @@ char *abuffer; {
     register int tc;
 
     tp = abuffer;
-    while (tc = *tp) {
+    while ((tc = *tp)) {
        if (!isspace(tc)) break;
        tp++;
     }
@@ -181,10 +202,15 @@ register struct afsconf_dir *adir; {
 static afsconf_Touch(adir)
 register struct afsconf_dir *adir; {
     char tbuffer[256];
+#ifndef AFS_NT40_ENV
     struct timeval tvp[2];
+#endif
+
+    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);
@@ -192,14 +218,11 @@ register struct afsconf_dir *adir; {
        strcompose(tbuffer, 256,
                   adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
     }
-#else
-    strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
-#endif /* AFS_NT40_ENV */
 
-    adir->timeRead = 0;        /* just in case */
-#ifdef AFS_NT40_ENV
     return _utime(tbuffer, NULL);
+
 #else
+    strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
     gettimeofday(&tvp[0], NULL);
     tvp[1] = tvp[0];
     return utimes(tbuffer, tvp);
@@ -214,11 +237,11 @@ register char *adir; {
     LOCK_GLOBAL_MUTEX
     /* zero structure and fill in name; rest is done by internal routine */
     tdir = (struct afsconf_dir *) malloc(sizeof(struct afsconf_dir));
-    bzero(tdir, sizeof(struct afsconf_dir));
+    memset(tdir, 0, sizeof(struct afsconf_dir));
     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];
 
@@ -228,7 +251,7 @@ register char *adir; {
            /* 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;
-           int len;
+           size_t len;
 
            if (!(home_dir = getenv("HOME"))) {
                /* Our last chance is the "/.AFSCONF" file */
@@ -272,7 +295,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 +345,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;
@@ -388,7 +414,7 @@ register struct afsconf_dir *adir; {
                curEntry = 0;
            }
            curEntry = (struct afsconf_entry *) malloc(sizeof(struct afsconf_entry));
-           bzero(curEntry, sizeof(struct afsconf_entry));
+           memset(curEntry, 0, sizeof(struct afsconf_entry));
            code = ParseCellLine(tbuffer, curEntry->cellInfo.name, linkedcell);
            if (code) {
                afsconf_CloseInternal(adir);
@@ -409,7 +435,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 +471,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 +539,125 @@ 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, i;
+    size_t len;
+    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;
@@ -511,7 +668,8 @@ struct afsconf_cell *acellInfo; {
     register afs_int32 i;
     int tservice;
     char *tcell;
-    int cnLen, ambig;
+    size_t cnLen;
+    int ambig;
     char tbuffer[64];
 
     LOCK_GLOBAL_MUTEX
@@ -520,8 +678,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 +720,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 */
     }
 }
 
@@ -633,7 +796,7 @@ register struct afsconf_dir *adir; {
     if (adir->keystr) free(adir->keystr);
 
     /* reinit */
-    bzero(adir, sizeof(struct afsconf_dir));
+    memset(adir, 0, sizeof(struct afsconf_dir));
     adir->name = tname;            /* restore it */
     return 0;
 }
@@ -643,7 +806,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,9 +867,13 @@ afsconf_GetKeys(adir, astr)
 struct afsconf_dir *adir;
 struct afsconf_keys *astr;
 {
+    register afs_int32 code;
+
     LOCK_GLOBAL_MUTEX
-    afsconf_Check(adir);
-    bcopy(adir->keystr, astr, sizeof(struct afsconf_keys));
+    code = afsconf_Check(adir);
+    if (code)
+       return AFSCONF_FAILURE;
+    memcpy(astr, adir->keystr, sizeof(struct afsconf_keys));
     UNLOCK_GLOBAL_MUTEX
     return 0;
 }
@@ -722,9 +889,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 */
@@ -737,7 +907,7 @@ afs_int32 afsconf_GetLatestKey(adir, avno, akey)
        }
     }
     if (bestk) {    /* found any  */
-       if (akey) bcopy(bestk->key, akey, 8); /* copy out latest key */
+       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;
@@ -754,14 +924,17 @@ 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++) {
        if (tk->kvno == avno) {
-           bcopy(tk->key, akey, 8);
+           memcpy(akey, tk->key, 8);
            UNLOCK_GLOBAL_MUTEX
            return 0;
        }
@@ -780,7 +953,7 @@ struct afsconf_dir *adir;
     register afs_int32 i;
     char tbuffer[256];
 
-    bcopy(adir->keystr, &tkeys, sizeof(struct afsconf_keys));
+    memcpy(&tkeys, adir->keystr, sizeof(struct afsconf_keys));
 
     /* convert it to net byte order */
     for(i = 0; i<tkeys.nkeys; i++ )
@@ -838,7 +1011,7 @@ char akey[8];
        tkey = &tk->key[tk->nkeys++];
     }
     tkey->kvno = akvno;
-    bcopy(akey, tkey->key, 8);
+    memcpy(tkey->key, akey, 8);
     i = SaveKeys(adir);
     afsconf_Touch(adir);
     UNLOCK_GLOBAL_MUTEX
@@ -874,7 +1047,7 @@ afs_int32 akvno;
     /* 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;
-       bcopy((tkey+1)->key, tkey->key, 8);
+       memcpy(tkey->key, (tkey+1)->key, 8);
     }
     tk->nkeys--;
     i = SaveKeys(adir);