From: Simon Wilkinson Date: Wed, 7 Apr 2010 22:03:21 +0000 (+0100) Subject: New GetToken pioctl X-Git-Tag: openafs-devel-1_7_1~1628 X-Git-Url: https://git.openafs.org/?p=openafs.git;a=commitdiff_plain;h=5ec5ad5dcca84e99e5f55987cc4f787cd482fdde;hp=53837416cbed3ba4d11f63015e1f13800519f2ed New GetToken pioctl Implement a new, XDR based, GetToken pioctl which mirrors the new SetToken pioctl. Change-Id: I213e74edb3496baa40b5c8048e97df6888f742b4 Reviewed-on: http://gerrit.openafs.org/2584 Reviewed-by: Derrick Brashear Tested-by: Derrick Brashear --- diff --git a/src/afs/afs_cell.c b/src/afs/afs_cell.c index 9b3fd9a..a819767 100644 --- a/src/afs/afs_cell.c +++ b/src/afs/afs_cell.c @@ -830,6 +830,24 @@ afs_GetPrimaryCell(afs_int32 locktype) } /*! + * Return number of the primary cell. + * \return + * Cell number, or 0 if primary cell not found + */ +afs_int32 +afs_GetPrimaryCellNum(void) +{ + struct cell *cell; + afs_int32 cellNum = 0; + cell = afs_GetPrimaryCell(READ_LOCK); + if (cell) { + cellNum = cell->cellNum; + afs_PutCell(cell, READ_LOCK); + } + return cellNum; +} + +/*! * Returns true if the given cell is the primary cell. * \param cell * \return diff --git a/src/afs/afs_pioctl.c b/src/afs/afs_pioctl.c index 61a7cae..6b1a57c 100644 --- a/src/afs/afs_pioctl.c +++ b/src/afs/afs_pioctl.c @@ -269,6 +269,7 @@ DECL_PIOCTL(PSetVolumeStatus); DECL_PIOCTL(PFlush); DECL_PIOCTL(PNewStatMount); DECL_PIOCTL(PGetTokens); +DECL_PIOCTL(PGetTokens2); DECL_PIOCTL(PUnlog); DECL_PIOCTL(PMariner); DECL_PIOCTL(PCheckServers); @@ -423,7 +424,7 @@ static pioctlFunction CpioctlSw[] = { PBogus, /* 4 */ PDiscon, /* 5 -- get/set discon mode */ PBogus, /* 6 */ - PBogus, /* 7 */ + PGetTokens2, /* 7 */ PSetTokens2, /* 8 */ PNewUuid, /* 9 */ PBogus, /* 10 */ @@ -1353,7 +1354,8 @@ afs_HandlePioctl(struct vnode *avp, afs_int32 acom, if (code) goto out; - if (function == 8 && device == 'V') { /* PGetTokens */ + if ((function == 8 && device == 'V') || + (function == 7 && device == 'C')) { /* PGetTokens */ code = afs_pd_alloc(&output, MAXPIOCTLTOKENLEN); } else { code = afs_pd_alloc(&output, AFS_LRALLOCSIZ); @@ -2242,6 +2244,34 @@ DECL_PIOCTL(PNewStatMount) } /*! + * A helper function to get the n'th cell which a particular user has tokens + * for. This is racy. If new tokens are added whilst we're iterating, then + * we may return some cells twice. If tokens expire mid run, then we'll + * miss some cells from our output. So, could be better, but that would + * require an interface change. + */ + +static struct unixuser * +getNthCell(afs_int32 uid, afs_int32 iterator) { + int i; + struct unixuser *tu = NULL; + + i = UHash(uid); + ObtainReadLock(&afs_xuser); + for (tu = afs_users[i]; tu; tu = tu->next) { + if (tu->uid == uid && (tu->states & UHasTokens)) { + if (iterator-- == 0) + break; /* are we done yet? */ + } + } + if (tu) { + tu->refCount++; + } + ReleaseReadLock(&afs_xuser); + + return tu; +} +/*! * VIOCGETTOK (8) - Get authentication tokens * * \ingroup pioctl @@ -2268,11 +2298,11 @@ DECL_PIOCTL(PNewStatMount) DECL_PIOCTL(PGetTokens) { struct cell *tcell; - afs_int32 i; - struct unixuser *tu; + struct unixuser *tu = NULL; union tokenUnion *token; afs_int32 iterator = 0; int newStyle; + int cellNum; int code = E2BIG; AFS_STATCNT(PGetTokens); @@ -2293,27 +2323,13 @@ DECL_PIOCTL(PGetTokens) if (afs_pd_getInt(ain, &iterator) != 0) return EINVAL; } - i = UHash(areq->uid); - ObtainReadLock(&afs_xuser); - for (tu = afs_users[i]; tu; tu = tu->next) { - if (newStyle) { - if (tu->uid == areq->uid && (tu->states & UHasTokens)) { - if (iterator-- == 0) - break; /* are we done yet? */ - } - } else { - if (tu->uid == areq->uid && afs_IsPrimaryCellNum(tu->cell)) - break; - } - } - if (tu) { - /* - * No need to hold a read lock on each user entry - */ - tu->refCount++; + if (newStyle) { + tu = getNthCell(areq->uid, iterator); + } else { + cellNum = afs_GetPrimaryCellNum(); + if (cellNum) + tu = afs_FindUser(areq->uid, cellNum, READ_LOCK); } - ReleaseReadLock(&afs_xuser); - if (!tu) { return EDOM; } @@ -5348,6 +5364,82 @@ out: return code; } +DECL_PIOCTL(PGetTokens2) +{ + struct cell *cell; + struct unixuser *tu = NULL; + afs_int32 iterator; + char *cellName = NULL; + afs_int32 cellNum; + int code = 0; + time_t now; + XDR xdrs; + struct ktc_setTokenData tokenSet; + + AFS_STATCNT(PGetTokens); + if (!afs_resourceinit_flag) + return EIO; + + memset(&tokenSet, 0, sizeof(tokenSet)); + + /* No input data - return tokens for primary cell */ + /* 4 octets of data is an iterator count */ + /* Otherwise, treat as string & return tokens for that cell name */ + + if (afs_pd_remaining(ain) == sizeof(afs_int32)) { + /* Integer iterator - return tokens for the n'th cell found for user */ + if (afs_pd_getInt(ain, &iterator) != 0) + return EINVAL; + tu = getNthCell(areq->uid, iterator); + } else { + if (afs_pd_remaining(ain) > 0) { + if (afs_pd_getStringPtr(ain, &cellName) != 0) + return EINVAL; + } else { + cellName = NULL; + } + code = _settok_tokenCell(cellName, &cellNum, NULL); + if (code) + return code; + tu = afs_FindUser(areq->uid, cellNum, READ_LOCK); + } + if (tu == NULL) + return EDOM; + + now = osi_Time(); + + if (!(tu->states & UHasTokens) + || !afs_HasValidTokens(tu->tokens, now)) { + tu->states |= (UTokensBad | UNeedsReset); + afs_PutUser(tu, READ_LOCK); + return ENOTCONN; + } + + code = afs_ExtractTokensForPioctl(tu->tokens, now, &tokenSet); + if (code) + goto out; + + cell = afs_GetCell(tu->cell, READ_LOCK); + tokenSet.cell = cell->cellName; + afs_pd_xdrStart(aout, &xdrs, XDR_ENCODE); + if (!xdr_ktc_setTokenData(&xdrs, &tokenSet)) { + code = E2BIG; + goto out; + } + afs_pd_xdrEnd(aout, &xdrs); + +out: + tokenSet.cell = NULL; + + if (tu) + afs_PutUser(tu, READ_LOCK); + if (cell) + afs_PutCell(cell, READ_LOCK); + xdr_free((xdrproc_t)xdr_ktc_setTokenData, &tokenSet); + + return code; +}; + DECL_PIOCTL(PNFSNukeCreds) { afs_uint32 addr; diff --git a/src/afs/afs_prototypes.h b/src/afs/afs_prototypes.h index 8cc6a62..979d78d 100644 --- a/src/afs/afs_prototypes.h +++ b/src/afs/afs_prototypes.h @@ -144,6 +144,7 @@ extern struct cell *afs_GetCellByHandle(void *handle, afs_int32 locktype); extern struct cell *afs_GetCellByIndex(afs_int32 cellidx, afs_int32 locktype); extern struct cell *afs_GetCellByName(char *acellName, afs_int32 locktype); extern struct cell *afs_GetPrimaryCell(afs_int32 locktype); +extern afs_int32 afs_GetPrimaryCellNum(void); extern int afs_IsPrimaryCellNum(afs_int32 cellnum); extern int afs_IsPrimaryCell(struct cell *cell); extern void *afs_TraverseCells(void *(*cb) (struct cell *, void *), @@ -917,14 +918,19 @@ extern int Afs_syscall(void); /* afs_tokens.c */ struct ktc_tokenUnion; +struct ktc_setTokenData; + 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_HasValidTokens(struct tokenJar *, afs_int32); extern int afs_HasUsableTokens(struct tokenJar *, afs_int32); extern void afs_AddRxkadToken(struct tokenJar **, char *, int, struct ClearToken *); extern int afs_AddTokenFromPioctl(struct tokenJar **, struct ktc_tokenUnion *); +extern int afs_ExtractTokensForPioctl(struct tokenJar *, time_t, + struct ktc_setTokenData *); /* UKERNEL/afs_usrops.c */ #ifdef UKERNEL diff --git a/src/afs/afs_tokens.c b/src/afs/afs_tokens.c index ac0a080..64b4085 100644 --- a/src/afs/afs_tokens.c +++ b/src/afs/afs_tokens.c @@ -248,6 +248,53 @@ afs_HasUsableTokens(struct tokenJar *token, afs_int32 now) { } /*! + * Indicate whether a token jar contains a valid (non-expired) token + * + * @param[in] token + * The token jar to check + * @param[in] now + * The time to use for the expiry check + * + * @returns + * True if the jar contains valid tokens, otherwise false + * + */ +int +afs_HasValidTokens(struct tokenJar *token, afs_int32 now) { + while (token != NULL) { + if (!afs_IsTokenExpired(token, now)) + return 1; + token = token->next; + } + return 0; +} + +/*! + * Count the number of valid tokens in a jar. A valid token is + * one which is not expired - note that valid tokens may not be + * usable by the kernel. + * + * @param[in] token + * The token jar to check + * @param[in] now + * The time to use for the expiry check + * + * @returns + * The number of valid tokens in the jar + */ +static int +countValidTokens(struct tokenJar *token, time_t now) { + int count = 0; + + while (token != NULL) { + if (!afs_IsTokenExpired(token, now)) + count ++; + token = token->next; + } + return count; +} + +/*! * Add an rxkad token to the token jar * * @param[in] tokens @@ -295,6 +342,31 @@ afs_AddRxkadTokenFromPioctl(struct tokenJar **tokens, return 0; } +static int +rxkad_extractTokenForPioctl(struct tokenJar *token, + struct ktc_tokenUnion *pioctlToken) { + + struct token_rxkad *rxkadPioctl; + struct rxkadToken *rxkadInternal; + + rxkadPioctl = &pioctlToken->ktc_tokenUnion_u.at_kad; + rxkadInternal = &token->u.rxkad; + + rxkadPioctl->rk_kvno = rxkadInternal->clearToken.AuthHandle; + rxkadPioctl->rk_viceid = rxkadInternal->clearToken.ViceId; + rxkadPioctl->rk_begintime = rxkadInternal->clearToken.BeginTimestamp; + rxkadPioctl->rk_endtime = rxkadInternal->clearToken.EndTimestamp; + memcpy(rxkadPioctl->rk_key, rxkadInternal->clearToken.HandShakeKey, 8); + + rxkadPioctl->rk_ticket.rk_ticket_val = xdr_alloc(rxkadInternal->ticketLen); + if (rxkadPioctl->rk_ticket.rk_ticket_val == NULL) + return ENOMEM; + rxkadPioctl->rk_ticket.rk_ticket_len = rxkadInternal->ticketLen; + memcpy(rxkadPioctl->rk_ticket.rk_ticket_val, + rxkadInternal->ticket, rxkadInternal->ticketLen); + + return 0; +} /*! * Add a token to a token jar based on the input from a new-style @@ -320,3 +392,101 @@ afs_AddTokenFromPioctl(struct tokenJar **tokens, return EINVAL; } + +static int +extractPioctlToken(struct tokenJar *token, + struct token_opaque *opaque) { + XDR xdrs; + struct ktc_tokenUnion *pioctlToken; + int code; + + memset(opaque, 0, sizeof(token_opaque)); + + pioctlToken = osi_Alloc(sizeof(struct ktc_tokenUnion)); + if (pioctlToken == NULL) + return ENOMEM; + + pioctlToken->at_type = token->type; + + switch (token->type) { + case RX_SECIDX_KAD: + code = rxkad_extractTokenForPioctl(token, pioctlToken); + break; + default: + code = EINVAL;; + } + + if (code) + goto out; + + xdrlen_create(&xdrs); + if (!xdr_ktc_tokenUnion(&xdrs, pioctlToken)) { + code = EINVAL; + xdr_destroy(&xdrs); + goto out; + } + + opaque->token_opaque_len = xdr_getpos(&xdrs); + xdr_destroy(&xdrs); + + opaque->token_opaque_val = osi_Alloc(opaque->token_opaque_len); + if (opaque->token_opaque_val == NULL) { + code = ENOMEM; + goto out; + } + + xdrmem_create(&xdrs, + opaque->token_opaque_val, + opaque->token_opaque_len, + XDR_ENCODE); + if (!xdr_ktc_tokenUnion(&xdrs, pioctlToken)) { + code = EINVAL; + xdr_destroy(&xdrs); + goto out; + } + xdr_destroy(&xdrs); + +out: + xdr_free((xdrproc_t) xdr_ktc_tokenUnion, &pioctlToken); + osi_Free(pioctlToken, sizeof(struct ktc_tokenUnion)); + + if (code != 0) { + osi_Free(opaque->token_opaque_val, opaque->token_opaque_len); + opaque->token_opaque_val = NULL; + opaque->token_opaque_len = 0; + } + return code; +} + +int +afs_ExtractTokensForPioctl(struct tokenJar *token, + time_t now, + struct ktc_setTokenData *tokenSet) +{ + int numTokens, pos; + int code = 0; + + numTokens = countValidTokens(token, now); + + tokenSet->tokens.tokens_len = numTokens; + tokenSet->tokens.tokens_val + = xdr_alloc(sizeof(struct token_opaque) * numTokens); + + if (tokenSet->tokens.tokens_val == NULL) + return ENOMEM; + + pos = 0; + while (token != NULL && pos < numTokens) { + code = extractPioctlToken(token, &tokenSet->tokens.tokens_val[pos]); + if (code) + goto out; + token = token->next; + pos++; + } + +out: + if (code) + xdr_free((xdrproc_t) xdr_ktc_setTokenData, tokenSet); + + return code; +} diff --git a/src/aklog/aklog.c b/src/aklog/aklog.c index a38b66e..df81a75 100644 --- a/src/aklog/aklog.c +++ b/src/aklog/aklog.c @@ -919,63 +919,7 @@ out: return status; } -/*! - * Get the set of tokens for a given cell out of the cache manager - * - * @param[in] cell - * The cellconf structure for the cell to retrieve tokens for - * @param[out] tokenPtr - * The tokens held for that cell - * - * @returns - * 0 on success, otherwise an error code - */ - -static int -get_kernel_token(struct afsconf_cell *cell, struct ktc_token **tokenPtr) { - struct ktc_principal client, server; - struct ktc_token *token; - int ret; - - *tokenPtr = NULL; - - strncpy(server.name, AFSKEY, MAXKTCNAMELEN - 1); - strncpy(server.instance, AFSINST, MAXKTCNAMELEN - 1); - strncpy(server.cell, cell->name, MAXKTCREALMLEN - 1); - - token = malloc(sizeof(struct ktc_token)); - if (token == NULL) - return ENOMEM; - - memset(token, 0, sizeof(struct ktc_token)); - - ret = ktc_GetToken(&server, token, sizeof(struct ktc_token), &client); - if (ret) { - free(token); - return ret; - } - - *tokenPtr = token; - return 0; -} - -/** - * Return true if a pair of tokens are directly equivalent - */ -static int -tokens_equal(struct ktc_setTokenData *tokenA, struct ktc_token *tokenB) { - return 0; -/* Bodge bodge bodge - return (tokenA != NULL && tokenB != NULL && - tokenA->kvno == tokenB->kvno && - tokenA->ticketLen == tokenB->ticketLen && - !memcmp(&tokenA->sessionKey, &tokenB->sessionKey, - sizeof(tokenA->sessionKey)) && - !memcmp(tokenA->ticket, tokenB->ticket, tokenA->ticketLen)); -*/ -} - -/* +/* * Log to a cell. If the cell has already been logged to, return without * doing anything. Otherwise, log to it and mark that it has been logged * to. @@ -991,7 +935,7 @@ auth_to_cell(krb5_context context, char *cell, char *realm, char **linkedcell) char *local_cell = NULL; struct ktc_tokenUnion *rxkadToken = NULL; struct ktc_setTokenData *token; - struct ktc_token *btoken; + struct ktc_setTokenData *btoken = NULL; struct afsconf_cell cellconf; /* NULL or empty cell returns information on local cell */ @@ -1067,13 +1011,18 @@ auth_to_cell(krb5_context context, char *cell, char *realm, char **linkedcell) } if (!force && - !get_kernel_token(&cellconf, &btoken) && - tokens_equal(token, btoken)) { + ktc_GetTokenEx(cellconf.name, &btoken) == 0 && + token_SetsEquivalent(token, btoken)) { + + token_FreeSet(&btoken); afs_dprintf("Identical tokens already exist; skipping.\n"); status = AKLOG_SUCCESS; goto out; } + if (btoken) + token_FreeSet(&btoken); + #ifdef FORCE_NOPRDB noprdb = 1; #endif diff --git a/src/auth/auth.p.h b/src/auth/auth.p.h index 5d473f3..84f8c0c 100644 --- a/src/auth/auth.p.h +++ b/src/auth/auth.p.h @@ -31,6 +31,7 @@ int ktc_GetToken(struct ktc_principal *, struct ktc_token *, struct ktc_setTokenData; int ktc_SetTokenEx(struct ktc_setTokenData *); +int ktc_GetTokenEx(char *, struct ktc_setTokenData **); int ktc_ListTokens(int, int *, struct ktc_principal *); int ktc_ForgetToken(struct ktc_principal *); diff --git a/src/auth/ktc.c b/src/auth/ktc.c index e52f1c8..a29613c 100644 --- a/src/auth/ktc.c +++ b/src/auth/ktc.c @@ -451,6 +451,94 @@ ktc_SetToken(struct ktc_principal *aserver, return 0; } +/*! + * Get a token, given the cell that we need to get information for + * + * @param cellName + * The name of the cell we're getting the token for - if NULL, we'll + * get information for the primary cell + */ +int +ktc_GetTokenEx(char *cellName, struct ktc_setTokenData **tokenSet) { + struct ViceIoctl iob; + char tbuffer[MAXPIOCTLTOKENLEN]; + char *tp; + afs_int32 code; + XDR xdrs; + + tp = tbuffer; + + /* If we have a cellName, write it out here */ + if (cellName) { + memcpy(tp, cellName, strlen(cellName) +1); + tp += strlen(cellName)+1; + } + + iob.in = tbuffer; + iob.in_size = tp - tbuffer; + iob.out = tbuffer; + iob.out_size = sizeof(tbuffer); + + code = PIOCTL(0, VIOC_GETTOK2, &iob, 0); + + /* If we can't use the new pioctl, the fall back to the old one. We then + * need to convert the rxkad token we get back into the new format + */ + if (code == -1 && errno == EINVAL) { + struct ktc_principal server; + struct ktc_principal client; + struct ktc_tokenUnion token; + struct ktc_token *ktcToken; /* too huge for the stack */ + + memset(&server, 0, sizeof(server)); + ktcToken = malloc(sizeof(struct ktc_token)); + if (ktcToken == NULL) + return ENOMEM; + memset(ktcToken, 0, sizeof(struct ktc_token)); + + strcpy(server.name, "afs"); + strcpy(server.cell, cellName); + code = ktc_GetToken(&server, ktcToken, sizeof(struct ktc_token), + &client); + if (code == 0) { + *tokenSet = token_buildTokenJar(cellName); + token.at_type = AFSTOKEN_UNION_KAD; + token.ktc_tokenUnion_u.at_kad.rk_kvno = ktcToken->kvno; + memcpy(token.ktc_tokenUnion_u.at_kad.rk_key, + ktcToken->sessionKey.data, 8); + + token.ktc_tokenUnion_u.at_kad.rk_begintime = ktcToken->startTime; + token.ktc_tokenUnion_u.at_kad.rk_endtime = ktcToken->endTime; + token.ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_len + = ktcToken->ticketLen; + token.ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_val + = ktcToken->ticket; + + token_addToken(*tokenSet, &token); + + memset(ktcToken, 0, sizeof(struct ktc_token)); + } + free(ktcToken); + } + if (code) + return KTC_PIOCTLFAIL; + + *tokenSet = malloc(sizeof(struct ktc_setTokenData)); + if (*tokenSet == NULL) + return ENOMEM; + memset(*tokenSet, 0, sizeof(struct ktc_setTokenData)); + + xdrmem_create(&xdrs, iob.out, iob.out_size, XDR_DECODE); + if (!xdr_ktc_setTokenData(&xdrs, *tokenSet)) { + free(*tokenSet); + *tokenSet = NULL; + xdr_destroy(&xdrs); + return EINVAL; + } + xdr_destroy(&xdrs); + return 0; +} + /* get token, given server we need and token buffer. aclient will eventually * be set to our identity to the server. */ diff --git a/src/auth/ktc.h b/src/auth/ktc.h index 441e5c3..3507639 100644 --- a/src/auth/ktc.h +++ b/src/auth/ktc.h @@ -23,7 +23,10 @@ extern struct ktc_setTokenData *token_buildTokenJar(char *); extern int token_addToken(struct ktc_setTokenData *, struct ktc_tokenUnion *); extern int token_replaceToken(struct ktc_setTokenData *, struct ktc_tokenUnion *); +extern int token_SetsEquivalent(struct ktc_setTokenData *, + struct ktc_setTokenData *); extern void token_setPag(struct ktc_setTokenData *, int); +extern void token_FreeSet(struct ktc_setTokenData **); struct ktc_token; struct ktc_principal; diff --git a/src/auth/token.c b/src/auth/token.c index 36281b4..4070bb8 100644 --- a/src/auth/token.c +++ b/src/auth/token.c @@ -40,27 +40,84 @@ * otherwise noted, the implementation is new */ +/* Take a peak at the enumerator in a given encoded token, in order to + * return its type + */ +static int +tokenType(struct token_opaque *opaque) { + XDR xdrs; + int type; + + xdrmem_create(&xdrs, opaque->token_opaque_val, opaque->token_opaque_len, + XDR_DECODE); + + if (!xdr_enum(&xdrs, &type)) + type = -1; + + xdr_destroy(&xdrs); + + return type; +} + +static int +decodeToken(struct token_opaque *opaque, struct ktc_tokenUnion *token) { + XDR xdrs; + int code; + + memset(token, 0, sizeof(struct ktc_tokenUnion)); + xdrmem_create(&xdrs, opaque->token_opaque_val, opaque->token_opaque_len, + XDR_DECODE); + code = xdr_ktc_tokenUnion(&xdrs, token); + xdr_destroy(&xdrs); + + return code; +} + +static void +freeToken(struct ktc_tokenUnion *token) { + xdr_free((xdrproc_t)xdr_ktc_tokenUnion, token); +} + +static int +rxkadTokenEqual(struct ktc_tokenUnion *tokenA, struct ktc_tokenUnion *tokenB) { + return (tokenA->ktc_tokenUnion_u.at_kad.rk_kvno == + tokenB->ktc_tokenUnion_u.at_kad.rk_kvno + && tokenA->ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_len == + tokenB->ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_len + && !memcmp(tokenA->ktc_tokenUnion_u.at_kad.rk_key, + tokenB->ktc_tokenUnion_u.at_kad.rk_key, 8) + && !memcmp(tokenA->ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_val, + tokenB->ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_val, + tokenA->ktc_tokenUnion_u.at_kad.rk_ticket.rk_ticket_len)); +} + +static int +tokenEqual(struct ktc_tokenUnion *tokenA, + struct ktc_tokenUnion *tokenB) { + switch (tokenA->at_type) { + case AFSTOKEN_UNION_KAD: + return rxkadTokenEqual(tokenA, tokenB); + } + return 0; +} + +static int +rawTokenEqual(struct token_opaque *tokenA, struct token_opaque *tokenB) { + return (tokenA->token_opaque_len == tokenB->token_opaque_len && + !memcmp(tokenA->token_opaque_val, tokenB->token_opaque_val, + tokenA->token_opaque_len)); +} + /* Given a token type, return the entry number of the first token of that * type */ static int findTokenEntry(struct ktc_setTokenData *token, int targetType) { - XDR xdrs; - int i, type; + int i; for (i = 0; i < token->tokens.tokens_len; i++) { - xdrmem_create(&xdrs, - token->tokens.tokens_val[i].token_opaque_val, - token->tokens.tokens_val[i].token_opaque_len, - XDR_DECODE); - /* Take a peak at the discriminator. */ - if (!xdr_enum(&xdrs, &type)) { - type = -1; - } - xdr_destroy(&xdrs); - - if (type == targetType) + if (tokenType(&token->tokens.tokens_val[i]) == targetType) return i; } return -1; @@ -147,35 +204,22 @@ token_findByType(struct ktc_setTokenData *token, int targetType, struct ktc_tokenUnion *output) { - XDR xdrs; int entry; - int code = EINVAL; memset(output, 0, sizeof *output); entry = findTokenEntry(token, targetType); if (entry == -1) - goto out; + return EINVAL; - xdrmem_create(&xdrs, - token->tokens.tokens_val[entry].token_opaque_val, - token->tokens.tokens_val[entry].token_opaque_len, - XDR_DECODE); - - if (!xdr_ktc_tokenUnion(&xdrs, output)) { - xdr_destroy(&xdrs); - goto out; - } + if (!decodeToken(&token->tokens.tokens_val[entry], output)) + return EINVAL; - xdr_destroy(&xdrs); if (output->at_type != targetType) { xdr_free((xdrproc_t)xdr_ktc_tokenUnion, output); - goto out; + return EINVAL; } - code = 0; - -out: - return code; + return 0; } /*! @@ -317,6 +361,64 @@ out: return code; } +/*! + * Work out if a pair of token sets are equivalent. Equivalence + * is defined as both sets containing the same number of tokens, + * and every token in the first set having an equivalent token + * in the second set. Cell name and flags value are not compared. + * + * @param[in] tokensA + * First set of tokens + * @param[in] tokensB + * Second set of tokens + * + * @returns + * True if token sets are equivalent, false otherwise + */ +int +token_SetsEquivalent(struct ktc_setTokenData *tokenSetA, + struct ktc_setTokenData *tokenSetB) { + int i, j; + int decodedOK, found; + struct ktc_tokenUnion tokenA, tokenB; + + if (tokenSetA->tokens.tokens_len != tokenSetB->tokens.tokens_len) + return 0; + + for (i=0; itokens.tokens_len; i++) { + found = 0; + + decodedOK = decodeToken(&tokenSetA->tokens.tokens_val[i], &tokenA); + + for (j=0; jtokens.tokens_len && !found; j++) { + if (rawTokenEqual(&tokenSetA->tokens.tokens_val[i], + &tokenSetB->tokens.tokens_val[j])) { + found = 1; + break; + } + + if (decodedOK && + tokenType(&tokenSetB->tokens.tokens_val[j]) == tokenA.at_type + && decodeToken(&tokenSetB->tokens.tokens_val[j], &tokenB)) { + + if (tokenEqual(&tokenA, &tokenB)) { + found = 1; + break; + } + freeToken(&tokenB); + } + } + if (decodedOK) + freeToken(&tokenA); + + if (!found) + return 0; + } + /* If we made it this far without exiting, we must have found equivalents + * for all of our tokens */ + return 1; +} + void token_setPag(struct ktc_setTokenData *jar, int setpag) { if (setpag) @@ -324,3 +426,10 @@ token_setPag(struct ktc_setTokenData *jar, int setpag) { else jar->flags &= ~AFSTOKEN_EX_SETPAG; } + +void +token_FreeSet(struct ktc_setTokenData **jar) { + xdr_free((xdrproc_t)xdr_ktc_setTokenData, *jar); + memset(*jar, 0, sizeof(struct ktc_setTokenData)); + *jar = NULL; +}