From adf2e6e827c6caf55247c5e63b88775393156ae5 Mon Sep 17 00:00:00 2001 From: Simon Wilkinson Date: Fri, 5 Feb 2010 11:12:45 +0000 Subject: [PATCH] Unix CM: Generalise token storage 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 Tested-by: Derrick Brashear --- src/afs/IRIX/osi_idbg.c | 16 +- src/afs/LINUX/osi_proc.c | 8 +- src/afs/LINUX24/osi_proc.c | 8 +- src/afs/afs.h | 20 ++- src/afs/afs_conn.c | 19 ++- src/afs/afs_init.c | 4 +- src/afs/afs_nfsclnt.c | 28 ++-- src/afs/afs_pag_cred.c | 34 ++-- src/afs/afs_pioctl.c | 38 ++--- src/afs/afs_prototypes.h | 9 ++ src/afs/afs_tokens.c | 275 +++++++++++++++++++++++++++++++++ src/afs/afs_user.c | 23 ++- src/libafs/Makefile.common.in | 4 + src/libuafs/Makefile.common.in | 10 ++ 14 files changed, 411 insertions(+), 85 deletions(-) create mode 100644 src/afs/afs_tokens.c diff --git a/src/afs/IRIX/osi_idbg.c b/src/afs/IRIX/osi_idbg.c index ba18a6a31..5d9b683a4 100644 --- a/src/afs/IRIX/osi_idbg.c +++ b/src/afs/IRIX/osi_idbg.c @@ -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]; diff --git a/src/afs/LINUX/osi_proc.c b/src/afs/LINUX/osi_proc.c index b4b5c9e95..ee9accf3b 100644 --- a/src/afs/LINUX/osi_proc.c +++ b/src/afs/LINUX/osi_proc.c @@ -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"); } diff --git a/src/afs/LINUX24/osi_proc.c b/src/afs/LINUX24/osi_proc.c index 02d0d09ce..a77766e3b 100644 --- a/src/afs/LINUX24/osi_proc.c +++ b/src/afs/LINUX24/osi_proc.c @@ -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"); } diff --git a/src/afs/afs.h b/src/afs/afs.h index a54a3173c..064ba2b20 100644 --- a/src/afs/afs.h +++ b/src/afs/afs.h @@ -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) */ }; diff --git a/src/afs/afs_conn.c b/src/afs/afs_conn.c index 0fa9f5ca3..e725bb1fd 100644 --- a/src/afs/afs_conn.c +++ b/src/afs/afs_conn.c @@ -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; diff --git a/src/afs/afs_init.c b/src/afs/afs_init.c index 5e44fa3d9..7721a3fac 100644 --- a/src/afs/afs_init.c +++ b/src/afs/afs_init.c @@ -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)); diff --git a/src/afs/afs_nfsclnt.c b/src/afs/afs_nfsclnt.c index 782ce7f42..bfb4f6b8c 100644 --- a/src/afs/afs_nfsclnt.c +++ b/src/afs/afs_nfsclnt.c @@ -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; diff --git a/src/afs/afs_pag_cred.c b/src/afs/afs_pag_cred.c index e35cc829b..4da747f5f 100644 --- a/src/afs/afs_pag_cred.c +++ b/src/afs/afs_pag_cred.c @@ -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; } diff --git a/src/afs/afs_pioctl.c b/src/afs/afs_pioctl.c index 9546d8198..48b7130d7 100644 --- a/src/afs/afs_pioctl.c +++ b/src/afs/afs_pioctl.c @@ -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 */ } diff --git a/src/afs/afs_prototypes.h b/src/afs/afs_prototypes.h index 0959fdca2..793180342 100644 --- a/src/afs/afs_prototypes.h +++ b/src/afs/afs_prototypes.h @@ -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 index 000000000..38119f1c7 --- /dev/null +++ b/src/afs/afs_tokens.c @@ -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 +#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; +} + diff --git a/src/afs/afs_user.c b/src/afs/afs_user.c index f101ab8bc..7da47d056 100644 --- a/src/afs/afs_user.c +++ b/src/afs/afs_user.c @@ -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) */ diff --git a/src/libafs/Makefile.common.in b/src/libafs/Makefile.common.in index a7b65d306..eb45bac8d 100644 --- a/src/libafs/Makefile.common.in +++ b/src/libafs/Makefile.common.in @@ -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 diff --git a/src/libuafs/Makefile.common.in b/src/libuafs/Makefile.common.in index 108031d8c..bffb76a7c 100644 --- a/src/libuafs/Makefile.common.in +++ b/src/libuafs/Makefile.common.in @@ -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 -- 2.39.5