}
/*!
+ * 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
DECL_PIOCTL(PFlush);
DECL_PIOCTL(PNewStatMount);
DECL_PIOCTL(PGetTokens);
+DECL_PIOCTL(PGetTokens2);
DECL_PIOCTL(PUnlog);
DECL_PIOCTL(PMariner);
DECL_PIOCTL(PCheckServers);
PBogus, /* 4 */
PDiscon, /* 5 -- get/set discon mode */
PBogus, /* 6 */
- PBogus, /* 7 */
+ PGetTokens2, /* 7 */
PSetTokens2, /* 8 */
PNewUuid, /* 9 */
PBogus, /* 10 */
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);
}
/*!
+ * 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
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);
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;
}
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;
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 *),
/* 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
}
/*!
+ * 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
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
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;
+}
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.
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 */
}
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
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 *);
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.
*/
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;
* 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;
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;
}
/*!
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; i<tokenSetA->tokens.tokens_len; i++) {
+ found = 0;
+
+ decodedOK = decodeToken(&tokenSetA->tokens.tokens_val[i], &tokenA);
+
+ for (j=0; j<tokenSetB->tokens.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)
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;
+}