/* * Invalidate all ACL entries for particular user on this particular vnode. * * The scp must not be locked. */ void cm_InvalidateACLUser(cm_scache_t *scp, cm_user_t *userp) { cm_aclent_t *aclp; cm_aclent_t **laclpp; int found = 0; int callback = 0; lock_ObtainWrite(&scp->rw); 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; found = 1; break; } } lock_ReleaseWrite(&cm_aclLock); if (found) callback = cm_HaveCallback(scp); lock_ReleaseWrite(&scp->rw); if (found && callback && RDR_Initialized) RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique, scp->fid.hash, scp->fileType, AFS_INVALIDATE_CREDS); }
/* called with scp write-locked, check to see if we have the ACL info we need * and can get it w/o blocking for any locks. * * Never drops the scp lock, but may fail if the access control info comes from * the parent directory, and the parent's scache entry can't be found, or it * can't be locked. Thus, this must always be called in a while loop to stabilize * things, since we can always lose the race condition getting to the parent vnode. */ int cm_HaveAccessRights(struct cm_scache *scp, struct cm_user *userp, afs_uint32 rights, afs_uint32 *outRightsp) { cm_scache_t *aclScp; long code; cm_fid_t tfid; int didLock; long trights; int release = 0; /* Used to avoid a call to cm_HoldSCache in the directory case */ didLock = 0; if (scp->fileType == CM_SCACHETYPE_DIRECTORY || cm_accessPerFileCheck) { aclScp = scp; /* not held, not released */ } else { cm_SetFid(&tfid, scp->fid.cell, scp->fid.volume, scp->parentVnode, scp->parentUnique); aclScp = cm_FindSCache(&tfid); if (!aclScp) return 0; if (aclScp != scp) { if (aclScp->fid.vnode < scp->fid.vnode) lock_ReleaseWrite(&scp->rw); lock_ObtainRead(&aclScp->rw); if (aclScp->fid.vnode < scp->fid.vnode) lock_ObtainWrite(&scp->rw); /* check that we have a callback, too */ if (!cm_HaveCallback(aclScp)) { /* can't use it */ lock_ReleaseRead(&aclScp->rw); cm_ReleaseSCache(aclScp); return 0; } didLock = 1; } release = 1; } lock_AssertAny(&aclScp->rw); /* now if rights is a subset of the public rights, we're done. * Otherwise, if we an explicit acl entry, we're also in good shape, * and can definitively answer. */ #ifdef AFS_FREELANCE_CLIENT if (cm_freelanceEnabled && aclScp->fid.cell==AFS_FAKE_ROOT_CELL_ID && aclScp->fid.volume==AFS_FAKE_ROOT_VOL_ID) { *outRightsp = aclScp->anyAccess; } else #endif if ((~aclScp->anyAccess & rights) == 0) { *outRightsp = rights; } else { /* we have to check the specific rights info */ code = cm_FindACLCache(aclScp, userp, &trights); if (code) { code = 0; goto done; } *outRightsp = trights; } if (scp->fileType > 0 && scp->fileType != CM_SCACHETYPE_DIRECTORY) { /* check mode bits */ if ((scp->unixModeBits & 0400) == 0) { osi_Log2(afsd_logp,"cm_HaveAccessRights UnixMode removing READ scp 0x%p unix 0%o", scp, scp->unixModeBits); *outRightsp &= ~PRSFS_READ; } if ((scp->unixModeBits & 0200) == 0 && (rights != (PRSFS_WRITE | PRSFS_LOCK))) { osi_Log2(afsd_logp,"cm_HaveAccessRights UnixMode removing WRITE scp 0x%p unix 0%o", scp, scp->unixModeBits); *outRightsp &= ~PRSFS_WRITE; } if ((scp->unixModeBits & 0200) == 0 && !cm_deleteReadOnly) { osi_Log2(afsd_logp,"cm_HaveAccessRights UnixMode removing DELETE scp 0x%p unix 0%o", scp, scp->unixModeBits); *outRightsp &= ~PRSFS_DELETE; } } /* if the user can insert, we must assume they can read/write as well * because we do not have the ability to determine if the current user * is the owner of the file. We will have to make the call to the * file server and let the file server tell us if the request should * be denied. */ if ((*outRightsp & PRSFS_INSERT) && (scp->creator == userp)) *outRightsp |= PRSFS_READ | PRSFS_WRITE; /* if the user can obtain a write-lock, read-locks are implied */ if (*outRightsp & PRSFS_WRITE) *outRightsp |= PRSFS_LOCK; code = 1; /* fall through */ done: if (didLock) lock_ReleaseRead(&aclScp->rw); if (release) cm_ReleaseSCache(aclScp); return code; }