Unix CM: Generalise token storage
authorSimon Wilkinson <sxw@your-file-system.com>
Fri, 5 Feb 2010 11:12:45 +0000 (11:12 +0000)
committerDerrick Brashear <shadow@dementia.org>
Thu, 26 Aug 2010 16:16:33 +0000 (09:16 -0700)
This generalises token storage in the Unix CM, so that it isn't
rxkad specific. We add a new, dynamically allocated, list of tokens
hanging off each unixuser structure. Each token is expressed as
a discrimated union keyed on the security class of that token,
with the token's details contained within that Union.

All token handling is performed through a set of functions in
afs_token.c - token access is modified to use this interface
throughout the rest of the code.

Change-Id: I939f3a611bb6e991e1e0d075ced0a59fc6f57693
Reviewed-on: http://gerrit.openafs.org/2580
Reviewed-by: Derrick Brashear <shadow@dementia.org>
Tested-by: Derrick Brashear <shadow@dementia.org>

14 files changed:
src/afs/IRIX/osi_idbg.c
src/afs/LINUX/osi_proc.c
src/afs/LINUX24/osi_proc.c
src/afs/afs.h
src/afs/afs_conn.c
src/afs/afs_init.c
src/afs/afs_nfsclnt.c
src/afs/afs_pag_cred.c
src/afs/afs_pioctl.c
src/afs/afs_prototypes.h
src/afs/afs_tokens.c [new file with mode: 0644]
src/afs/afs_user.c
src/libafs/Makefile.common.in
src/libuafs/Makefile.common.in

index ba18a6a..5d9b683 100644 (file)
@@ -136,15 +136,23 @@ static char *tab_userstates[] = {
 static void
 idbg_pruser(struct unixuser *tu)
 {
+    union tokenUnion *token;
+
+    token = afs_FindToken(tu->tokens, RX_SECIDX_KAD);
+
     qprintf("@0x%x nxt 0x%x uid %d (0x%x) cell 0x%x vid 0x%x ref %d\n", tu,
            tu->next, tu->uid, tu->uid, tu->cell, tu->vid, tu->refCount);
-    qprintf("time %d stLen %d stp 0x%x exp 0x%x ", tu->tokenTime, tu->stLen,
-           tu->stp, tu->exporter);
+    qprintf("time %dRX_SECIDX_KADstLen %d stp 0x%x exp 0x%x ", tu->tokenTime,
+           (token != NULL)?token->rxkad.ticketLen:0,
+           (token != NULL)?token->rxkad.ticket:NULL,
+           tu->exporter);
     printflags(tu->states, tab_userstates);
     qprintf("\n");
     qprintf("ClearToken: handle 0x%x ViceID 0x%x Btime %d Etime %d\n",
-           tu->ct.AuthHandle, tu->ct.ViceId, tu->ct.BeginTimestamp,
-           tu->ct.EndTimestamp);
+           (token != NULL)?token->rxkad.clearToken.AuthHandle:0,
+           tu->vid,
+           (token != NULL)?token->rxkad.clearToken.BeginTimestamp:0,
+           (token != NULL)?token->rxkad.clearToken.EndTimestamp:0);
 }
 
 extern struct unixuser *afs_users[NUSERS];
index b4b5c9e..ee9accf 100644 (file)
@@ -173,6 +173,7 @@ static int uu_show(struct seq_file *m, void *p)
 {
     struct cell *tc = 0;
     struct unixuser *tu = p;
+    union tokenUnion *token;
     char *cellname;
 
     if (p == (void *)1) {
@@ -200,9 +201,12 @@ static int uu_show(struct seq_file *m, void *p)
     if (tc) afs_PutCell(tc, READ_LOCK);
 
     if (tu->states & UHasTokens) {
+       token = afs_FindToken(tu->tokens, RX_SECIDX_KAD);
        seq_printf(m, "  %10d %10d %10d %3d",
-                  tu->tokenTime, tu->ct.BeginTimestamp, tu->ct.EndTimestamp,
-                  tu->ct.AuthHandle);
+                  tu->tokenTime,
+                  (token!=NULL)?token->rxkad.clearToken.BeginTimestamp:0,
+                  (token!=NULL)?token->rxkad.clearToken.EndTimestamp:0,
+                  (token!=NULL)?token->rxkad.clearToken.AuthHandle:0);
     } else {
        seq_printf(m, "  %-36s", "Tokens Not Set");
     }
index 02d0d09..a77766e 100644 (file)
@@ -169,6 +169,7 @@ static int uu_show(struct seq_file *m, void *p)
 {
     struct cell *tc = 0;
     struct unixuser *tu = p;
+    union tokenUnion *token;
     char *cellname;
 
     if (p == (void *)1) {
@@ -196,9 +197,12 @@ static int uu_show(struct seq_file *m, void *p)
     if (tc) afs_PutCell(tc, READ_LOCK);
 
     if (tu->states & UHasTokens) {
+       token = afs_FindToken(tu->tokens, RX_SECIDX_KAD);
        seq_printf(m, "  %10d %10d %10d %3d",
-                  tu->tokenTime, tu->ct.BeginTimestamp, tu->ct.EndTimestamp,
-                  tu->ct.AuthHandle);
+                  tu->tokenTime,
+                  (token != NULL)?token->rxkad.clearToken.BeginTimestamp:0,
+                  (token != NULL)?token->rxkad.clearToken.EndTimestamp:0,
+                  (token != NULL)?token->rxkad.clearToken.AuthHandle:0);
     } else {
        seq_printf(m, "  %-36s", "Tokens Not Set");
     }
index a54a317..064ba2b 100644 (file)
@@ -337,6 +337,22 @@ extern char afs_cachebasedir[1024];
 extern afs_int32 afs_numcachefiles;
 extern afs_int32 afs_numfilesperdir;
 
+struct rxkadToken {
+    afs_int32 ticketLen;
+    char * ticket;
+    struct ClearToken clearToken;
+};
+
+union tokenUnion {
+    struct rxkadToken rxkad;
+};
+
+struct tokenJar {
+    struct tokenJar *next;
+    int type;
+    union tokenUnion u;
+};
+
 struct unixuser {
     struct unixuser *next;     /* next hash pointer */
     afs_int32 uid;             /* search based on uid and cell */
@@ -345,9 +361,7 @@ struct unixuser {
     short refCount;            /* reference count for allocation */
     char states;               /* flag info */
     afs_int32 tokenTime;       /* last time tokens were set, used for timing out conn data */
-    afs_int32 stLen;           /* ticket length (if kerberos, includes kvno at head) */
-    char *stp;                 /* pointer to ticket itself */
-    struct ClearToken ct;
+    struct tokenJar *tokens;
     struct afs_exporter *exporter;     /* more info about the exporter for the remote user */
     void *cellinfo;             /* pointer to cell info (PAG manager only) */
 };
index 0fa9f5c..e725bb1 100644 (file)
@@ -69,16 +69,21 @@ static struct rx_securityClass *
 afs_pickSecurityObject(struct afs_conn *conn, int *secLevel)
 {
     struct rx_securityClass *secObj = NULL;
+    union tokenUnion *token;
 
     /* Do we have tokens ? */
     if (conn->user->vid != UNDEFVID) {
-       *secLevel = 2;
-       /* kerberos tickets on channel 2 */
-       secObj = rxkad_NewClientSecurityObject(
-                   cryptall ? rxkad_crypt : rxkad_clear,
-                    (struct ktc_encryptionKey *)conn->user->ct.HandShakeKey,
-                   conn->user->ct.AuthHandle,
-                   conn->user->stLen, conn->user->stp);
+       token = afs_FindToken(conn->user->tokens, RX_SECIDX_KAD);
+       if (token) {
+           *secLevel = RX_SECIDX_KAD;
+           /* kerberos tickets on channel 2 */
+           secObj = rxkad_NewClientSecurityObject(
+                        cryptall ? rxkad_crypt : rxkad_clear,
+                         (struct ktc_encryptionKey *)
+                              token->rxkad.clearToken.HandShakeKey,
+                        token->rxkad.clearToken.AuthHandle,
+                        token->rxkad.ticketLen, token->rxkad.ticket);
+       }
      }
      if (secObj == NULL) {
        *secLevel = 0;
index 5e44fa3..7721a3f 100644 (file)
@@ -851,8 +851,8 @@ shutdown_AFS(void)
            for (i = 0; i < NUSERS; i++) {
                for (tu = afs_users[i]; tu; tu = ntu) {
                    ntu = tu->next;
-                   if (tu->stp)
-                       afs_osi_Free(tu->stp, tu->stLen);
+                   if (tu->tokens)
+                       afs_FreeTokens(&tu->tokens);
                    if (tu->exporter)
                        EXP_RELE(tu->exporter);
                    afs_osi_Free(tu, sizeof(struct unixuser));
index 782ce7f..bfb4f6b 100644 (file)
@@ -306,6 +306,8 @@ afs_nfsclient_getcreds(struct unixuser *au)
     struct nfsclientpag *np = (struct nfsclientpag *)(au->exporter);
     struct rx_securityClass *csec;
     struct rx_connection *tconn;
+    struct tokenUnion *tokenPtr;
+    struct rkxadToken *token;
     SysNameList tsysnames;
     CredInfos tcreds;
     CredInfo *tcred;
@@ -378,21 +380,23 @@ afs_nfsclient_getcreds(struct unixuser *au)
            tu->exporter = (struct afs_exporter *)np;
        }
 
-       /* free any old secret token, and keep the new one */
-       if (tu->stp != NULL) {
-           afs_osi_Free(tu->stp, tu->stLen);
-       }
-       tu->stp = tcred->st.st_val;
-       tu->stLen = tcred->st.st_len;
+       afs_FreeTokens(&tu->tokens);
+
+       /* Add a new rxkad token. Using the afs_AddRxkadToken interface
+        * would require another copy, so we do this the hard way */
+       tokenptr = afs_AddToken(&tu->tokens, 2);
+       token = &tokenptr->rxkad;
+       token->ticket = tcred->st.st_val;
+       token->ticketLen = tcred->st.st_len;
 
        /* copy the clear token */
-       memset(&tu->ct, 0, sizeof(tu->ct));
-       memcpy(tu->ct.HandShakeKey, tcred->ct.HandShakeKey, 8);
+       memset(&token->clearToken, 0, sizeof(token->clearToken));
+       memcpy(token->clearToken.HandShakeKey, tcred->ct.HandShakeKey, 8);
        memset(tcred->ct.HandShakeKey, 0, 8);
-       tu->ct.AuthHandle     = tcred->ct.AuthHandle;
-       tu->ct.ViceId         = tcred->ct.ViceId;
-       tu->ct.BeginTimestamp = tcred->ct.BeginTimestamp;
-       tu->ct.EndTimestamp   = tcred->ct.EndTimestamp;
+       token->clearToken.AuthHandle     = tcred->ct.AuthHandle;
+       token->clearToken.ViceId         = tcred->ct.ViceId;
+       token->clearToken.BeginTimestamp = tcred->ct.BeginTimestamp;
+       token->clearToken.EndTimestamp   = tcred->ct.EndTimestamp;
 
        /* Set everything else, reset connections, and move on. */
        tu->vid = tcred->vid;
index e35cc82..4da747f 100644 (file)
@@ -110,13 +110,11 @@ afspag_PUnlog(char *ain, afs_int32 ainSize, afs_ucred_t **acred)
        if (tu->uid == uid) {
            tu->vid = UNDEFVID;
            tu->states &= ~UHasTokens;
-           /* security is not having to say you're sorry */
-           memset(&tu->ct, 0, sizeof(struct ClearToken));
+           afs_FreeTokens(&tu->tokens);
 #ifdef UKERNEL
            /* set the expire times to 0, causes
             * afs_GCUserData to remove this entry
             */
-           tu->ct.EndTimestamp = 0;
            tu->tokenTime = 0;
 #endif /* UKERNEL */
        }
@@ -194,13 +192,8 @@ afspag_PSetTokens(char *ain, afs_int32 ainSize, afs_ucred_t **acred)
     if (!tu->cellinfo)
        tu->cellinfo = (void *)tcell;
     tu->vid = clear.ViceId;
-    if (tu->stp != NULL) {
-       afs_osi_Free(tu->stp, tu->stLen);
-    }
-    tu->stp = (char *)afs_osi_Alloc(stLen);
-    tu->stLen = stLen;
-    memcpy(tu->stp, stp, stLen);
-    tu->ct = clear;
+    afs_FreeTokens(&tu->tokens);
+    afs_AddRxkadToken(&tu->tokens, stp, stLen, &clear);
 #ifndef AFS_NOSTATS
     afs_stats_cmfullperf.authent.TicketUpdates++;
     afs_ComputePAGStats();
@@ -220,6 +213,7 @@ SPAGCB_GetCreds(struct rx_call *a_call, afs_int32 a_uid,
                 CredInfos *a_creds)
 {
     struct unixuser *tu;
+    union tokenUnion *token;
     CredInfo *tci;
     int bucket, count, i = 0, clen;
     char *cellname;
@@ -262,13 +256,16 @@ SPAGCB_GetCreds(struct rx_call *a_call, afs_int32 a_uid,
        if (tu->uid == a_uid && tu->cellinfo &&
            (tu->states & UHasTokens) && !(tu->states & UTokensBad)) {
 
+           token = afs_FindToken(tu->tokens, RX_SECIDX_KAD);
+
            tci = &a_creds->CredInfos_val[i];
            tci->vid               = tu->vid;
-           tci->ct.AuthHandle     = tu->ct.AuthHandle;
-           memcpy(tci->ct.HandShakeKey, tu->ct.HandShakeKey, 8);
-           tci->ct.ViceId         = tu->ct.ViceId;
-           tci->ct.BeginTimestamp = tu->ct.BeginTimestamp;
-           tci->ct.EndTimestamp   = tu->ct.EndTimestamp;
+           tci->ct.AuthHandle     = token->rxkad.clearToken.AuthHandle;
+           memcpy(tci->ct.HandShakeKey,
+                  token->rxkad.clearToken.HandShakeKey, 8);
+           tci->ct.ViceId         = token->rxkad.clearToken.ViceId;
+           tci->ct.BeginTimestamp = token->rxkad.clearToken.BeginTimestamp;
+           tci->ct.EndTimestamp   = token->rxkad.clearToken.EndTimestamp;
 
            cellname = ((struct afspag_cell *)(tu->cellinfo))->cellname;
            clen = strlen(cellname) + 1;
@@ -277,13 +274,14 @@ SPAGCB_GetCreds(struct rx_call *a_call, afs_int32 a_uid,
                goto out;
            memcpy(tci->cellname, cellname, clen);
 
-           tci->st.st_len = tu->stLen;
-           tci->st.st_val = afs_osi_Alloc(tu->stLen);
+           tci->st.st_len = token->rxkad.ticketLen;
+           tci->st.st_val = afs_osi_Alloc(token->rxkad.ticketLen);
            if (!tci->st.st_val) {
                afs_osi_Free(tci->cellname, clen);
                goto out;
            }
-           memcpy(tci->st.st_val, tu->stp, tu->stLen);
+           memcpy(tci->st.st_val,
+                  token->rxkad.ticket, token->rxkad.ticketLen);
            if (tu->states & UPrimary)
                tci->states |= UPrimary;
        }
index 9546d81..48b7130 100644 (file)
@@ -1874,16 +1874,9 @@ DECL_PIOCTL(PSetTokens)
     /* now we just set the tokens */
     tu = afs_GetUser(areq->uid, i, WRITE_LOCK);        /* i has the cell # */
     tu->vid = clear.ViceId;
-    if (tu->stp != NULL) {
-       afs_osi_Free(tu->stp, tu->stLen);
-    }
-    tu->stp = (char *)afs_osi_Alloc(stLen);
-    if (tu->stp == NULL) {
-       return ENOMEM;
-    }
-    tu->stLen = stLen;
-    memcpy(tu->stp, stp, stLen);
-    tu->ct = clear;
+    /* Set tokens destroys any that are already there */
+    afs_FreeTokens(&tu->tokens);
+    afs_AddRxkadToken(&tu->tokens, stp, stLen, &clear);
 #ifndef AFS_NOSTATS
     afs_stats_cmfullperf.authent.TicketUpdates++;
     afs_ComputePAGStats();
@@ -2238,6 +2231,7 @@ DECL_PIOCTL(PGetTokens)
     struct cell *tcell;
     afs_int32 i;
     struct unixuser *tu;
+    union tokenUnion *token;
     afs_int32 iterator = 0;
     int newStyle;
     int code = E2BIG;
@@ -2285,30 +2279,34 @@ DECL_PIOCTL(PGetTokens)
        return EDOM;
     }
     if (((tu->states & UHasTokens) == 0)
-       || (tu->ct.EndTimestamp < osi_Time())) {
+       || !afs_HasUsableTokens(tu->tokens, osi_Time())) {
        tu->states |= (UTokensBad | UNeedsReset);
        afs_NotifyUser(tu, UTokensDropped);
        afs_PutUser(tu, READ_LOCK);
        return ENOTCONN;
     }
-    iterator = tu->stLen;      /* for compat, we try to return 56 byte tix if they fit */
+    token = afs_FindToken(tu->tokens, RX_SECIDX_KAD);
+
+    /* for compat, we try to return 56 byte tix if they fit */
+    iterator = token->rxkad.ticketLen;
     if (iterator < 56)
        iterator = 56;          /* # of bytes we're returning */
 
     if (afs_pd_putInt(aout, iterator) != 0)
        goto out;
-    if (afs_pd_putBytes(aout, tu->stp, tu->stLen) != 0)
+    if (afs_pd_putBytes(aout, token->rxkad.ticket, token->rxkad.ticketLen) != 0)
        goto out;
-    if (tu->stLen < 56) {
+    if (token->rxkad.ticketLen < 56) {
        /* Tokens are always 56 bytes or larger */
-       if (afs_pd_skip(aout, iterator - tu->stLen) != 0) {
+       if (afs_pd_skip(aout, iterator - token->rxkad.ticketLen) != 0) {
            goto out;
        }
     }
 
     if (afs_pd_putInt(aout, sizeof(struct ClearToken)) != 0)
        goto out;
-    if (afs_pd_putBytes(aout, &tu->ct, sizeof(struct ClearToken)) != 0)
+    if (afs_pd_putBytes(aout, &token->rxkad.clearToken,
+                       sizeof(struct ClearToken)) != 0)
        goto out;
 
     if (newStyle) {
@@ -2362,8 +2360,7 @@ DECL_PIOCTL(PUnlog)
        if (tu->uid == areq->uid) {
            tu->vid = UNDEFVID;
            tu->states &= ~UHasTokens;
-           /* security is not having to say you're sorry */
-           memset(&tu->ct, 0, sizeof(struct ClearToken));
+           afs_FreeTokens(&tu->tokens);
            tu->refCount++;
            ReleaseWriteLock(&afs_xuser);
            afs_NotifyUser(tu, UTokensDropped);
@@ -2382,7 +2379,6 @@ DECL_PIOCTL(PUnlog)
            /* set the expire times to 0, causes
             * afs_GCUserData to remove this entry
             */
-           tu->ct.EndTimestamp = 0;
            tu->tokenTime = 0;
 #endif /* UKERNEL */
        }
@@ -5240,8 +5236,7 @@ DECL_PIOCTL(PNFSNukeCreds)
            if (tu->exporter && EXP_CHECKHOST(tu->exporter, addr)) {
                tu->vid = UNDEFVID;
                tu->states &= ~UHasTokens;
-               /* security is not having to say you're sorry */
-               memset(&tu->ct, 0, sizeof(struct ClearToken));
+               afs_FreeTokens(&tu->tokens);
                tu->refCount++;
                ReleaseWriteLock(&afs_xuser);
                afs_ResetUserConns(tu);
@@ -5251,7 +5246,6 @@ DECL_PIOCTL(PNFSNukeCreds)
                /* set the expire times to 0, causes
                 * afs_GCUserData to remove this entry
                 */
-               tu->ct.EndTimestamp = 0;
                tu->tokenTime = 0;
 #endif /* UKERNEL */
            }
index 0959fdc..7931803 100644 (file)
@@ -915,6 +915,15 @@ extern int afs3_syscall(afs_proc_t *p, void *args, long *retval);
 extern int Afs_syscall(void);
 #endif
 
+/* afs_tokens.c */
+extern union tokenUnion *afs_FindToken(struct tokenJar *, rx_securityIndex);
+extern void afs_FreeTokens(struct tokenJar **);
+extern union tokenUnion *afs_AddToken(struct tokenJar **, rx_securityIndex);
+extern void afs_DiscardExpiredTokens(struct tokenJar **, afs_int32);
+extern int afs_HasUsableTokens(struct tokenJar *, afs_int32);
+extern void afs_AddRxkadToken(struct tokenJar **, char *, int,
+                             struct ClearToken *);
+
 /* UKERNEL/afs_usrops.c */
 #ifdef UKERNEL
 extern void uafs_Shutdown(void);
diff --git a/src/afs/afs_tokens.c b/src/afs/afs_tokens.c
new file mode 100644 (file)
index 0000000..38119f1
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2010 Your Filesystem Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <afsconfig.h>
+#include "afs/param.h"
+#include "afs/sysincludes.h"
+#include "afsincludes.h"
+
+/* A jar for storing tokens in */
+
+/*!
+ * Return a token of the specified type from the selected tokenjar.
+ *
+ * @param[in] tokens
+ *     The tokenjar in which to search
+ * @param[in] type
+ *     The type of token to return
+ *
+ * @return
+ *     A tokenUnion structure, from which the desired token can be
+ *     accessed using the appropriate element of the union.
+ */
+union tokenUnion *
+afs_FindToken(struct tokenJar *tokens, rx_securityIndex type) {
+    while (tokens != NULL) {
+       if (tokens->type == type) {
+           return &tokens->u;
+       }
+       tokens = tokens->next;
+    }
+    return NULL;
+}
+
+/*!
+ * Free a single token
+ *
+ * This will free the given token. No attempt is made to unlink
+ * the token from its container, and it is an error to attempt to
+ * free a token which is still linked.
+ *
+ * This performs a secure free, setting all token information to 0
+ * before returning allocated data blocks to the kernel.
+ *
+ * Intended primarily for internal use.
+ *
+ * @param[in] token
+ *     The token to free
+ */
+
+void
+afs_FreeOneToken(struct tokenJar *token) {
+    if (token->next != NULL)
+       osi_Panic("Freeing linked token");
+
+    switch (token->type) {
+      case RX_SECIDX_KAD:
+       if (token->u.rxkad.ticket != NULL) {
+               memset(token->u.rxkad.ticket, 0, token->u.rxkad.ticketLen);
+               afs_osi_Free(token->u.rxkad.ticket,
+                            token->u.rxkad.ticketLen);
+       }
+       break;
+      default:
+       break;
+    }
+    memset(token, 0, sizeof(struct tokenJar));
+    afs_osi_Free(token, sizeof(struct tokenJar));
+}
+
+/*!
+ * Free a token jar
+ *
+ * Free all of the tokens in a given token jar. This will also set the
+ * pointer to the jar to NULL, to indicate that it has been freed.
+ *
+ * @param[in] tokenPtr
+ *     A pointer to the address of the tokenjar to free.
+ */
+void
+afs_FreeTokens(struct tokenJar **tokenPtr) {
+    struct tokenJar *next, *tokens;
+
+    tokens = *tokenPtr;
+    *tokenPtr = NULL;
+    while(tokens != NULL) {
+       next = tokens->next;
+       tokens->next = NULL; /* Unlink from chain */
+       afs_FreeOneToken(tokens);
+       tokens = next;
+    }
+}
+
+/*!
+ * Add a token to a token jar
+ *
+ * Add a new token to a token jar. If the jar already exists,
+ * then this token becomes the first in the jar. If it doesn't
+ * exist, then a new jar is created. The contents of the new
+ * token are initialised to 0 upon creation.
+ *
+ * @param[in] tokens
+ *     A pointer to the address of the token jar to populate
+ * @param[in] type
+ *     The type of token to create
+ *
+ * @return
+ *     A pointer to the tokenUnion of the newly created token,
+ *     which may then be used to populate the token.
+ */
+union tokenUnion *
+afs_AddToken(struct tokenJar **tokens, rx_securityIndex type) {
+    struct tokenJar *newToken;
+
+    newToken = afs_osi_Alloc(sizeof(struct tokenJar));
+    memset(newToken, 0, sizeof(*newToken));
+
+    newToken->type = type;
+    newToken->next = *tokens;
+    *tokens = newToken;
+
+    return &newToken->u;
+}
+
+/*!
+ * Indicate if a single token is expired
+ *
+ * @param[in] token
+ *     The token to check
+ * @param[in] now
+ *     The time to check against for expiry (typically the results of
+ *     calling osi_Time())
+ *
+ * @returns
+ *     True if the token has expired, false otherwise
+ */
+int
+afs_IsTokenExpired(struct tokenJar *token, afs_int32 now) {
+    switch (token->type) {
+      case RX_SECIDX_KAD:
+       if (token->u.rxkad.clearToken.EndTimestamp < now - NOTOKTIMEOUT)
+           return 1;
+       break;
+      default:
+       return 0;
+    }
+    return 0; /* not reached, but keep gcc happy */
+}
+
+/*!
+ * Indicate if a token is usable by the kernel module
+ *
+ * This determines whether a token is usable. A usable token is one that
+ * has not expired, and which is otherwise suitable for use.
+ *
+ * @param[in] token
+ *     The token to check
+ * @param[in] now
+ *     The time to use for the expiry check
+ *
+ * @returns
+ *     True if the token is usable, false otherwise
+ */
+int
+afs_IsTokenUsable(struct tokenJar *token, afs_int32 now) {
+
+    if (afs_IsTokenExpired(token, now))
+       return 0;
+
+    switch (token->type) {
+      case RX_SECIDX_KAD:
+       /* We assume that all non-expired rxkad tokens are usable by us */
+       return 1;
+      default :
+       return 0;
+    }
+}
+
+/*!
+ * Discard all expired tokens from a token jar
+ *
+ * This permanently removes all tokens which have expired from the token
+ * jar. Note that tokens which are not usable, but which have not expired,
+ * will not be deleted.
+ *
+ * @param[in] tokenPtr
+ *     A pointer to the address of the token jar to check
+ * @param[in] now
+ *     The time to use for the expiry check
+ */
+
+void
+afs_DiscardExpiredTokens(struct tokenJar **tokenPtr, afs_int32 now) {
+    struct tokenJar *next;
+
+    while (*tokenPtr != NULL) {
+       if (afs_IsTokenExpired(*tokenPtr, now)) {
+           next = (*tokenPtr)->next;
+           (*tokenPtr)->next = NULL;
+           afs_FreeOneToken(*tokenPtr);
+           *tokenPtr = next;
+       } else {
+           tokenPtr = &(*tokenPtr)->next;
+        }
+    }
+}
+
+/*!
+ * Indicate whether a token jar contains one, or more usable tokens
+ *
+ * @param[in] token
+ *     The token jar to check
+ * @param[in] now
+ *     The cime to use for the expiry check
+ *
+ * @returns
+ *     True if the jar contains usable tokens, otherwise false
+ */
+int
+afs_HasUsableTokens(struct tokenJar *token, afs_int32 now) {
+    while (token != NULL) {
+        if (afs_IsTokenUsable(token, now))
+           return 1;
+       token = token->next;
+    }
+    return 0;
+}
+
+/*!
+ * Add an rxkad token to the token jar
+ *
+ * @param[in] tokens
+ *     A pointer to the address of the jar to add the token to
+ * @param[in] ticket
+ *     A data block containing the token's opaque ticket
+ * @param[in] ticketLen
+ *     The length of the ticket data block
+ * @param[in] clearToken
+ *     The cleartext token information
+ */
+void
+afs_AddRxkadToken(struct tokenJar **tokens, char *ticket, int ticketLen,
+                 struct ClearToken *clearToken) {
+    union tokenUnion *tokenU;
+    struct rxkadToken *rxkad;
+
+    tokenU = afs_AddToken(tokens, RX_SECIDX_KAD);
+    rxkad = &tokenU->rxkad;
+
+    rxkad->ticket = afs_osi_Alloc(ticketLen);
+    rxkad->ticketLen = ticketLen;
+    memcpy(rxkad->ticket, ticket, ticketLen);
+    rxkad->clearToken = *clearToken;
+}
+
index f101ab8..7da47d0 100644 (file)
@@ -116,11 +116,10 @@ afs_GCUserData(int aforce)
            /* Don't garbage collect users in use now (refCount) */
            if (tu->refCount == 0) {
                if (tu->states & UHasTokens) {
-                   /*
-                    * Give ourselves a little extra slack, in case we
-                    * reauthenticate
-                    */
-                   if (tu->ct.EndTimestamp < now - NOTOKTIMEOUT)
+                   /* Need to walk the token stack, and dispose of
+                    * all expired tokens */
+                   afs_DiscardExpiredTokens(&tu->tokens, now);
+                   if (!afs_HasUsableTokens(tu->tokens, now))
                        delFlag = 1;
                } else {
                    if (aforce || (tu->tokenTime < now - NOTOKTIMEOUT))
@@ -133,8 +132,8 @@ afs_GCUserData(int aforce)
 #ifndef AFS_PAG_MANAGER
                RemoveUserConns(tu);
 #endif
-               if (tu->stp)
-                   afs_osi_Free(tu->stp, tu->stLen);
+               afs_FreeTokens(&tu->tokens);
+
                if (tu->exporter)
                    EXP_RELE(tu->exporter);
                afs_osi_Free(tu, sizeof(struct unixuser));
@@ -180,7 +179,7 @@ afs_CheckTokenCache(void)
             * check expiration
             */
            if (!(tu->states & UTokensBad) && tu->vid != UNDEFVID) {
-               if (tu->ct.EndTimestamp < now) {
+               if (!afs_HasUsableTokens(tu->tokens, now)) {
                    /*
                     * This token has expired, warn users and reset access
                     * cache.
@@ -587,7 +586,7 @@ afs_MarkUserExpired(afs_int32 pag)
     ObtainWriteLock(&afs_xuser, 9);
     for (tu = afs_users[i]; tu; tu = tu->next) {
        if (tu->uid == pag) {
-           tu->ct.EndTimestamp = 0;
+           tu->states &= ~UHasTokens;
            tu->tokenTime = 0;
        }
     }
@@ -750,10 +749,8 @@ afs_GCPAGs(afs_int32 * ReleasedCount)
                 * i.e. nfs translator, etc.
                 */
                if (!pu->exporter && afs_gcpags == AFS_GCPAGS_OK) {
-                   /* set the expire times to 0, causes
-                    * afs_GCUserData to remove this entry
-                    */
-                   pu->ct.EndTimestamp = 0;
+                   /* make afs_GCUserData remove this entry  */
+                   pu->states &= ~UHasTokens;
                    pu->tokenTime = 0;
 
                    (*ReleasedCount)++; /* remember how many we marked (info only) */
index a7b65d3..eb45bac 100644 (file)
@@ -106,6 +106,7 @@ AFSAOBJS = \
        afs_server.o \
        afs_stat.o \
        afs_syscall.o \
+       afs_tokens.o \
        afs_user.o \
        afs_util.o \
        afs_vcache.o \
@@ -196,6 +197,7 @@ AFSPAGOBJS = \
        afs_pag_user.o \
        afs_stat.o \
        afs_syscall.o \
+       afs_tokens.o \
        afs_warn.o \
        afsaux.o                \
        xdr_arrayn.o    \
@@ -283,6 +285,8 @@ afs_segments.o: $(TOP_SRC_AFS)/afs_segments.c
        $(CRULE_OPT)
 afs_server.o: $(TOP_SRC_AFS)/afs_server.c
        $(CRULE_OPT)
+afs_tokens.o: $(TOP_SRC_AFS)/afs_tokens.c
+       $(CRULE_OPT)
 afs_user.o: $(TOP_SRC_AFS)/afs_user.c
        $(CRULE_OPT)
 afs_util.o: $(TOP_SRC_AFS)/afs_util.c
index 108031d..bffb76a 100644 (file)
@@ -110,6 +110,7 @@ UAFSOBJ = \
        $(UOBJ)/afs_server.o \
        $(UOBJ)/afs_stat.o \
        $(UOBJ)/afs_syscall.o \
+       $(UOBJ)/afs_tokens.o \
        $(UOBJ)/afs_user.o \
        $(UOBJ)/afs_util.o \
        $(UOBJ)/afs_vcache.o \
@@ -246,6 +247,7 @@ AFSWEBOBJ = \
        $(WEBOBJ)/afs_server.o \
        $(WEBOBJ)/afs_stat.o \
        $(WEBOBJ)/afs_syscall.o \
+       $(WEBOBJ)/afs_tokens.o \
        $(WEBOBJ)/afs_user.o \
        $(WEBOBJ)/afs_util.o \
        $(WEBOBJ)/afs_vcache.o \
@@ -382,6 +384,7 @@ AFSWEBOBJKRB = \
        $(WEBOBJ)/afs_server.o \
        $(WEBOBJ)/afs_stat.o \
        $(WEBOBJ)/afs_syscall.o \
+       $(WEBOBJ)/afs_tokens.o \
        $(WEBOBJ)/afs_user.o \
        $(WEBOBJ)/afs_util.o \
        $(WEBOBJ)/afs_vcache.o \
@@ -513,6 +516,7 @@ JUAFSOBJ = \
        $(JUAFS)/afs_server.o \
        $(JUAFS)/afs_stat.o \
        $(JUAFS)/afs_syscall.o \
+       $(JUAFS)/afs_tokens.o \
        $(JUAFS)/afs_user.o \
        $(JUAFS)/afs_util.o \
        $(JUAFS)/afs_vcache.o \
@@ -658,6 +662,8 @@ $(UOBJ)/afs_segments.o: $(TOP_SRC_AFS)/afs_segments.c
        $(CRULE1)
 $(UOBJ)/afs_server.o: $(TOP_SRC_AFS)/afs_server.c
        $(CRULE1)
+$(UOBJ)/afs_tokens.o: $(TOP_SRC_AFS)/afs_tokens.c
+       $(CRULE1)
 $(UOBJ)/afs_user.o: $(TOP_SRC_AFS)/afs_user.c
        $(CRULE1)
 $(UOBJ)/afs_util.o: $(TOP_SRC_AFS)/afs_util.c
@@ -937,6 +943,8 @@ $(WEBOBJ)/afs_segments.o: $(TOP_SRC_AFS)/afs_segments.c
        $(CRULE2)
 $(WEBOBJ)/afs_server.o: $(TOP_SRC_AFS)/afs_server.c
        $(CRULE2)
+$(WEBOBJ)/afs_tokens.o: $(TOP_SRC_AFS)/afs_tokens.c
+       $(CRULE2)
 $(WEBOBJ)/afs_user.o: $(TOP_SRC_AFS)/afs_user.c
        $(CRULE2)
 $(WEBOBJ)/afs_util.o: $(TOP_SRC_AFS)/afs_util.c
@@ -1220,6 +1228,8 @@ $(JUAFS)/afs_segments.o: $(TOP_SRC_AFS)/afs_segments.c
        $(CRULE1)
 $(JUAFS)/afs_server.o: $(TOP_SRC_AFS)/afs_server.c
        $(CRULE1)
+$(JUAFS)/afs_tokens.o: $(TOP_SRC_AFS)/afs_tokens.c
+       $(CRULE1)
 $(JUAFS)/afs_user.o: $(TOP_SRC_AFS)/afs_user.c
        $(CRULE1)
 $(JUAFS)/afs_util.o: $(TOP_SRC_AFS)/afs_util.c