From ff3436446e1c8447d0f9703b088c6d65c6845aa0 Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Tue, 25 Jan 2005 23:24:43 +0000 Subject: [PATCH] windows-misc-20050125 The list of ACL entries was being corrupted because the function which obtains a free ACL entry was doing so without the appropriate lock being held. Returning Not A Directory is not the right thing to do when we are attempting to resolve a path if the error is found on one of the intermediary path components. Instead return No Such Path or No Such File as appropriate. --- src/WINNT/afsd/cm_aclent.c | 366 ++++++++++++++++++++++++++----------------- src/WINNT/afsd/cm_vnodeops.c | 13 +- 2 files changed, 230 insertions(+), 149 deletions(-) diff --git a/src/WINNT/afsd/cm_aclent.c b/src/WINNT/afsd/cm_aclent.c index 6dc9dff..bbaf4ff 100644 --- a/src/WINNT/afsd/cm_aclent.c +++ b/src/WINNT/afsd/cm_aclent.c @@ -28,8 +28,6 @@ * An aclent structure is free if it has no back vnode pointer. */ osi_rwlock_t cm_aclLock; /* lock for system's aclents */ -cm_aclent_t *cm_aclLRUp; /* LRUQ for dudes in vnodes' lists */ -cm_aclent_t *cm_aclLRUEndp; /* ditto */ /* * Get an acl cache entry for a particular user and file, or return that it doesn't exist. @@ -37,39 +35,39 @@ cm_aclent_t *cm_aclLRUEndp; /* ditto */ */ long cm_FindACLCache(cm_scache_t *scp, cm_user_t *userp, long *rightsp) { - cm_aclent_t *aclp; - - lock_ObtainWrite(&cm_aclLock); - for (aclp = scp->randomACLp; aclp; aclp = aclp->nextp) { - if (aclp->userp == userp) { - if (aclp->tgtLifetime && aclp->tgtLifetime <= (long) osi_Time()) { - /* ticket expired */ - aclp->tgtLifetime = 0; - *rightsp = 0; - break; /* get a new acl from server */ - } - else { - *rightsp = aclp->randomAccess; - if (cm_aclLRUEndp == aclp) - cm_aclLRUEndp = (cm_aclent_t *) osi_QPrev(&aclp->q); - - /* move to the head of the LRU queue */ - osi_QRemove((osi_queue_t **) &cm_aclLRUp, &aclp->q); - osi_QAddH((osi_queue_t **) &cm_aclLRUp, - (osi_queue_t **) &cm_aclLRUEndp, - &aclp->q); - } - lock_ReleaseWrite(&cm_aclLock); - return 0; - } - } - - /* - * If we make it here, this entry isn't present, so we're going to fail. - */ - lock_ReleaseWrite(&cm_aclLock); - return -1; -} + cm_aclent_t *aclp; + long retval = -1; + + lock_ObtainWrite(&cm_aclLock); + for (aclp = scp->randomACLp; aclp; aclp = aclp->nextp) { + if (aclp->userp == userp) { + if (aclp->tgtLifetime && aclp->tgtLifetime <= (long) osi_Time()) { + /* ticket expired */ + aclp->tgtLifetime = 0; + *rightsp = 0; /* get a new acl from server */ + + /* Shouldn't we remove this entry from the scp? + * 2005-01-25 - jaltman@secure-endpoints.com + */ + } else { + *rightsp = aclp->randomAccess; + if (cm_data.aclLRUEndp == aclp) + cm_data.aclLRUEndp = (cm_aclent_t *) osi_QPrev(&aclp->q); + + /* move to the head of the LRU queue */ + osi_QRemove((osi_queue_t **) &cm_data.aclLRUp, &aclp->q); + osi_QAddH((osi_queue_t **) &cm_data.aclLRUp, + (osi_queue_t **) &cm_data.aclLRUEndp, + &aclp->q); + retval = 0; /* success */ + } + break; + } + } + + lock_ReleaseWrite(&cm_aclLock); + return retval; +} /* @@ -78,38 +76,40 @@ long cm_FindACLCache(cm_scache_t *scp, cm_user_t *userp, long *rightsp) */ static cm_aclent_t *GetFreeACLEnt(void) { - cm_aclent_t *aclp; - cm_aclent_t *taclp; - cm_aclent_t **laclpp; - - if (cm_aclLRUp == NULL) - osi_panic("empty aclent LRU", __FILE__, __LINE__); - - aclp = cm_aclLRUEndp; - if (aclp == cm_aclLRUEndp) - cm_aclLRUEndp = (cm_aclent_t *) osi_QPrev(&aclp->q); - osi_QRemove((osi_queue_t **) &cm_aclLRUp, &aclp->q); - if (aclp->backp) { - /* - * Remove the entry from the vnode's list - */ - laclpp = &aclp->backp->randomACLp; - for (taclp = *laclpp; taclp; laclpp = &taclp->nextp, taclp = *laclpp) { - if (taclp == aclp) - break; - } - if (!taclp) - osi_panic("GetFreeACLEnt race", __FILE__, __LINE__); - *laclpp = aclp->nextp; /* remove from vnode list */ - aclp->backp = NULL; - } - + cm_aclent_t *aclp; + cm_aclent_t *taclp; + cm_aclent_t **laclpp; + + if (cm_data.aclLRUp == NULL) + osi_panic("empty aclent LRU", __FILE__, __LINE__); + + lock_ObtainWrite(&cm_aclLock); + aclp = cm_data.aclLRUEndp; + if (aclp == cm_data.aclLRUEndp) + cm_data.aclLRUEndp = (cm_aclent_t *) osi_QPrev(&aclp->q); + osi_QRemove((osi_queue_t **) &cm_data.aclLRUp, &aclp->q); + if (aclp->backp) { + /* + * Remove the entry from the vnode's list + */ + laclpp = &aclp->backp->randomACLp; + for (taclp = *laclpp; taclp; laclpp = &taclp->nextp, taclp = *laclpp) { + if (taclp == aclp) + break; + } + if (!taclp) + osi_panic("GetFreeACLEnt race", __FILE__, __LINE__); + *laclpp = aclp->nextp; /* remove from vnode list */ + aclp->backp = NULL; + } + /* release the old user */ if (aclp->userp) { - cm_ReleaseUser(aclp->userp); + cm_ReleaseUser(aclp->userp); aclp->userp = NULL; - } - return aclp; + } + lock_ReleaseWrite(&cm_aclLock); + return aclp; } @@ -121,69 +121,139 @@ static cm_aclent_t *GetFreeACLEnt(void) */ long cm_AddACLCache(cm_scache_t *scp, cm_user_t *userp, long rights) { - register struct cm_aclent *aclp; - - lock_ObtainWrite(&cm_aclLock); - for (aclp = scp->randomACLp; aclp; aclp = aclp->nextp) { - if (aclp->userp == userp) { - aclp->randomAccess = rights; - if (aclp->tgtLifetime == 0) - aclp->tgtLifetime = cm_TGTLifeTime(pag); - lock_ReleaseWrite(&cm_aclLock); - return 0; - } - } - - /* - * Didn't find the dude we're looking for, so take someone from the LRUQ - * and reuse. But first try the free list and see if there's already - * someone there. - */ - aclp = GetFreeACLEnt(); /* can't fail, panics instead */ - osi_QAddH((osi_queue_t **) &cm_aclLRUp, (osi_queue_t **) &cm_aclLRUEndp, &aclp->q); - aclp->backp = scp; - aclp->nextp = scp->randomACLp; - scp->randomACLp = aclp; + register struct cm_aclent *aclp; + + lock_ObtainWrite(&cm_aclLock); + for (aclp = scp->randomACLp; aclp; aclp = aclp->nextp) { + if (aclp->userp == userp) { + aclp->randomAccess = rights; + if (aclp->tgtLifetime == 0) + aclp->tgtLifetime = cm_TGTLifeTime(pag); + lock_ReleaseWrite(&cm_aclLock); + return 0; + } + } + + /* + * Didn't find the dude we're looking for, so take someone from the LRUQ + * and reuse. But first try the free list and see if there's already + * someone there. + */ + aclp = GetFreeACLEnt(); /* can't fail, panics instead */ + osi_QAddH((osi_queue_t **) &cm_data.aclLRUp, (osi_queue_t **) &cm_data.aclLRUEndp, &aclp->q); + aclp->backp = scp; + aclp->nextp = scp->randomACLp; + scp->randomACLp = aclp; cm_HoldUser(userp); - aclp->userp = userp; - aclp->randomAccess = rights; - aclp->tgtLifetime = cm_TGTLifeTime(userp); - lock_ReleaseWrite(&cm_aclLock); + aclp->userp = userp; + aclp->randomAccess = rights; + aclp->tgtLifetime = cm_TGTLifeTime(userp); + lock_ReleaseWrite(&cm_aclLock); - return 0; + return 0; +} + +long cm_ShutdownACLCache(void) +{ + return 0; +} + +long cm_ValidateACLCache(void) +{ + long size = cm_data.stats * 2; + long count; + cm_aclent_t * aclp; + + for ( aclp = cm_data.aclLRUp, count = 0; aclp; + aclp = (cm_aclent_t *) osi_QNext(&aclp->q), count++ ) { + if (aclp->magic != CM_ACLENT_MAGIC) { + afsi_log("cm_ValidateACLCache failure: acpl->magic != CM_ACLENT_MAGIC"); + fprintf(stderr, "cm_ValidateACLCache failure: acpl->magic != CM_ACLENT_MAGIC\n"); + return -1; + } + if (aclp->nextp && aclp->nextp->magic != CM_ACLENT_MAGIC) { + afsi_log("cm_ValidateACLCache failure: acpl->nextp->magic != CM_ACLENT_MAGIC"); + fprintf(stderr,"cm_ValidateACLCache failure: acpl->nextp->magic != CM_ACLENT_MAGIC\n"); + return -2; + } + if (aclp->backp && aclp->backp->magic != CM_SCACHE_MAGIC) { + afsi_log("cm_ValidateACLCache failure: acpl->backp->magic != CM_SCACHE_MAGIC"); + fprintf(stderr,"cm_ValidateACLCache failure: acpl->backp->magic != CM_SCACHE_MAGIC\n"); + return -3; + } + if (count != 0 && aclp == cm_data.aclLRUp || count > size) { + afsi_log("cm_ValidateACLCache failure: loop in cm_data.aclLRUp list"); + fprintf(stderr, "cm_ValidateACLCache failure: loop in cm_data.aclLRUp list\n"); + return -4; + } + } + + for ( aclp = cm_data.aclLRUEndp, count = 0; aclp; + aclp = (cm_aclent_t *) osi_QPrev(&aclp->q), count++ ) { + if (aclp->magic != CM_ACLENT_MAGIC) { + afsi_log("cm_ValidateACLCache failure: aclp->magic != CM_ACLENT_MAGIC"); + fprintf(stderr, "cm_ValidateACLCache failure: aclp->magic != CM_ACLENT_MAGIC\n"); + return -5; + } + if (aclp->nextp && aclp->nextp->magic != CM_ACLENT_MAGIC) { + afsi_log("cm_ValidateACLCache failure: aclp->nextp->magic != CM_ACLENT_MAGIC"); + fprintf(stderr, "cm_ValidateACLCache failure: aclp->nextp->magic != CM_ACLENT_MAGIC\n"); + return -6; + } + if (aclp->backp && aclp->backp->magic != CM_SCACHE_MAGIC) { + afsi_log("cm_ValidateACLCache failure: aclp->backp->magic != CM_SCACHE_MAGIC"); + fprintf(stderr, "cm_ValidateACLCache failure: aclp->backp->magic != CM_SCACHE_MAGIC\n"); + return -7; + } + + if (count != 0 && aclp == cm_data.aclLRUEndp || count > size) { + afsi_log("cm_ValidateACLCache failure: loop in cm_data.aclLRUEndp list"); + fprintf(stderr, "cm_ValidateACLCache failure: loop in cm_data.aclLRUEndp list\n"); + return -8; + } + } + + return 0; } /* * Initialize the cache to have an entries. Called during system startup. */ -long cm_InitACLCache(long size) +long cm_InitACLCache(int newFile, long size) { - cm_aclent_t *aclp; - long i; - static osi_once_t once; - - - if (osi_Once(&once)) { - lock_InitializeRWLock(&cm_aclLock, "cm_aclLock"); - osi_EndOnce(&once); - } - - lock_ObtainWrite(&cm_aclLock); - cm_aclLRUp = cm_aclLRUEndp = NULL; - aclp = (cm_aclent_t *) malloc(size * sizeof(cm_aclent_t)); - memset(aclp, 0, size * sizeof(cm_aclent_t)); - - /* - * Put all of these guys on the LRU queue - */ - for (i = 0; i < size; i++) { - osi_QAddH((osi_queue_t **) &cm_aclLRUp, (osi_queue_t **) &cm_aclLRUEndp, - &aclp->q); - aclp++; - } - - lock_ReleaseWrite(&cm_aclLock); - return 0; + cm_aclent_t *aclp; + long i; + static osi_once_t once; + + if (osi_Once(&once)) { + lock_InitializeRWLock(&cm_aclLock, "cm_aclLock"); + osi_EndOnce(&once); + } + + lock_ObtainWrite(&cm_aclLock); + if ( newFile ) { + cm_data.aclLRUp = cm_data.aclLRUEndp = NULL; + aclp = (cm_aclent_t *) cm_data.aclBaseAddress; + memset(aclp, 0, size * sizeof(cm_aclent_t)); + + /* + * Put all of these guys on the LRU queue + */ + for (i = 0; i < size; i++) { + aclp->magic = CM_ACLENT_MAGIC; + osi_QAddH((osi_queue_t **) &cm_data.aclLRUp, (osi_queue_t **) &cm_data.aclLRUEndp, &aclp->q); + aclp++; + } + } else { + aclp = (cm_aclent_t *) cm_data.aclBaseAddress; + for (i = 0; i < size; i++) { + aclp->userp = NULL; + aclp->tgtLifetime = 0; + aclp++; + } + } + lock_ReleaseWrite(&cm_aclLock); + return 0; } @@ -194,22 +264,22 @@ long cm_InitACLCache(long size) */ void cm_FreeAllACLEnts(cm_scache_t *scp) { - cm_aclent_t *aclp; - cm_aclent_t *taclp; - - lock_ObtainWrite(&cm_aclLock); - for (aclp = scp->randomACLp; aclp; aclp = taclp) { - taclp = aclp->nextp; - if (aclp->userp) { - cm_ReleaseUser(aclp->userp); - aclp->userp = NULL; - } - aclp->backp = (struct cm_scache *) 0; - } - - scp->randomACLp = (struct cm_aclent *) 0; - scp->anyAccess = 0; /* reset this, too */ - lock_ReleaseWrite(&cm_aclLock); + cm_aclent_t *aclp; + cm_aclent_t *taclp; + + lock_ObtainWrite(&cm_aclLock); + for (aclp = scp->randomACLp; aclp; aclp = taclp) { + taclp = aclp->nextp; + if (aclp->userp) { + cm_ReleaseUser(aclp->userp); + aclp->userp = NULL; + } + aclp->backp = (struct cm_scache *) 0; + } + + scp->randomACLp = (struct cm_aclent *) 0; + scp->anyAccess = 0; /* reset this, too */ + lock_ReleaseWrite(&cm_aclLock); } @@ -220,19 +290,19 @@ void cm_FreeAllACLEnts(cm_scache_t *scp) */ void cm_InvalidateACLUser(cm_scache_t *scp, cm_user_t *userp) { - cm_aclent_t *aclp; - cm_aclent_t **laclpp; - - lock_ObtainWrite(&cm_aclLock); - laclpp = &scp->randomACLp; - for (aclp = *laclpp; aclp; laclpp = &aclp->nextp, aclp = *laclpp) { - if (userp == aclp->userp) { /* One for a given user/scache */ - *laclpp = aclp->nextp; + cm_aclent_t *aclp; + cm_aclent_t **laclpp; + + lock_ObtainWrite(&cm_aclLock); + laclpp = &scp->randomACLp; + for (aclp = *laclpp; aclp; laclpp = &aclp->nextp, aclp = *laclpp) { + if (userp == aclp->userp) { /* One for a given user/scache */ + *laclpp = aclp->nextp; cm_ReleaseUser(aclp->userp); aclp->userp = NULL; - aclp->backp = (struct cm_scache *) 0; - break; - } - } - lock_ReleaseWrite(&cm_aclLock); + aclp->backp = (struct cm_scache *) 0; + break; + } + } + lock_ReleaseWrite(&cm_aclLock); } diff --git a/src/WINNT/afsd/cm_vnodeops.c b/src/WINNT/afsd/cm_vnodeops.c index b936b44..27ba3f8 100644 --- a/src/WINNT/afsd/cm_vnodeops.c +++ b/src/WINNT/afsd/cm_vnodeops.c @@ -995,8 +995,19 @@ long cm_LookupInternal(cm_scache_t *dscp, char *namep, long flags, cm_user_t *us * that we stopped early, probably because we found the entry we're * looking for. Any other non-zero code is an error. */ - if (code && code != CM_ERROR_STOPNOW) + if (code && code != CM_ERROR_STOPNOW) { + /* if the cm_scache_t we are searching in is not a directory + * we must return path not found because the error + * is to describe the final component not an intermediary + */ + if (code == CM_ERROR_NOTDIR) { + if (flags & CM_FLAG_CHECKPATH) + return CM_ERROR_NOSUCHPATH; + else + return CM_ERROR_NOSUCHFILE; + } return code; + } getroot = (dscp==cm_rootSCachep) ; if (!rock.found) { -- 1.9.4