/*
* Copyright 2000, International Business Machines Corporation and others.
* All Rights Reserved.
- *
+ *
* This software has been released under the terms of the IBM Public
* License. For details, see the LICENSE file in the top-level source
* directory or online at http://www.openafs.org/dl/license10.html
#include <afsconfig.h>
#include "afs/param.h"
-RCSID
- ("$Header$");
#include "afs/stds.h"
#include "afs/sysincludes.h" /* Standard vendor system headers */
#ifdef AFS_SGI62_ENV
#include "h/hashing.h"
#endif
-#if !defined(AFS_HPUX110_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN60_ENV)
+#if !defined(AFS_HPUX110_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV)
#include <netinet/in_var.h>
#endif /* ! AFS_HPUX110_ENV */
#endif /* !defined(UKERNEL) */
#include "afsincludes.h" /* Afs-based standard headers */
#include "afs/afs_stats.h" /* afs statistics */
-#if defined(AFS_SUN56_ENV)
+#if defined(AFS_SUN5_ENV)
#include <inet/led.h>
#include <inet/common.h>
-#if defined(AFS_SUN58_ENV)
#include <netinet/ip6.h>
-#endif
#include <inet/ip.h>
#endif
+#include "afs/afs_axscache.h"
/* Exported variables */
afs_rwlock_t afs_xuser;
#ifndef AFS_PAG_MANAGER
/* Forward declarations */
-void afs_ResetAccessCache(afs_int32 uid, int alock);
-
-/*
- * Called with afs_xuser, afs_xserver and afs_xconn locks held, to delete
- * appropriate conn structures for au
- */
-static void
-RemoveUserConns(register struct unixuser *au)
-{
- register int i;
- register struct server *ts;
- register struct srvAddr *sa;
- register struct afs_conn *tc, **lc;
-
- AFS_STATCNT(RemoveUserConns);
- for (i = 0; i < NSERVERS; i++) {
- for (ts = afs_servers[i]; ts; ts = ts->next) {
- for (sa = ts->addr; sa; sa = sa->next_sa) {
- lc = &sa->conns;
- for (tc = *lc; tc; lc = &tc->next, tc = *lc) {
- if (tc->user == au && tc->refCount == 0) {
- *lc = tc->next;
- AFS_GUNLOCK();
- rx_DestroyConnection(tc->id);
- AFS_GLOCK();
- afs_osi_Free(tc, sizeof(struct afs_conn));
- break; /* at most one instance per server */
- } /*Found unreferenced connection for user */
- } /*For each connection on the server */
- }
- } /*For each server on chain */
- } /*For each chain */
-
-} /*RemoveUserConns */
+void afs_ResetAccessCache(afs_int32 uid, afs_int32 cell, int alock);
#endif /* !AFS_PAG_MANAGER */
void
afs_GCUserData(int aforce)
{
- register struct unixuser *tu, **lu, *nu;
- register int i;
+ struct unixuser *tu, **lu, *nu;
+ int i;
afs_int32 now, delFlag;
AFS_STATCNT(afs_GCUserData);
delFlag = 0; /* should we delete this dude? */
/* 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)
+ if (tu->tokens) {
+ /* 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))
if (delFlag) {
*lu = tu->next;
#ifndef AFS_PAG_MANAGER
- RemoveUserConns(tu);
+ afs_ReleaseConnsUser(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));
} /*afs_GCUserData */
+static struct unixuser *
+afs_FindUserNoLock(afs_int32 auid, afs_int32 acell)
+{
+ struct unixuser *tu;
+ afs_int32 i;
+
+ AFS_STATCNT(afs_FindUser);
+ i = UHash(auid);
+ for (tu = afs_users[i]; tu; tu = tu->next) {
+ if (tu->uid == auid && ((tu->cell == acell) || (acell == -1))) {
+ tu->refCount++;
+ return tu;
+ }
+ }
+ return NULL;
+
+}
#ifndef AFS_PAG_MANAGER
/*
void
afs_CheckTokenCache(void)
{
- register int i;
- register struct unixuser *tu;
+ int i;
+ struct unixuser *tu;
afs_int32 now;
+ struct vcache *tvc;
+ struct axscache *tofreelist;
+ int do_scan = 0;
AFS_STATCNT(afs_CheckCacheResets);
ObtainReadLock(&afs_xvcache);
now = osi_Time();
for (i = 0; i < NUSERS; i++) {
for (tu = afs_users[i]; tu; tu = tu->next) {
- register afs_int32 uid;
-
/*
* If tokens are still good and user has Kerberos tickets,
* check expiration
*/
- if (!(tu->states & UTokensBad) && tu->vid != UNDEFVID) {
- if (tu->ct.EndTimestamp < now) {
+ if ((tu->states & UHasTokens) && !(tu->states & UTokensBad)) {
+ if (!afs_HasUsableTokens(tu->tokens, now)) {
/*
* This token has expired, warn users and reset access
* cache.
*/
-#ifdef notdef
- /* I really hate this message - MLK */
- afs_warn
- ("afs: Tokens for user of AFS id %d for cell %s expired now\n",
- tu->vid, afs_GetCell(tu->cell)->cellName);
-#endif
tu->states |= (UTokensBad | UNeedsReset);
}
}
- if (tu->states & UNeedsReset) {
- tu->states &= ~UNeedsReset;
- uid = tu->uid;
- afs_ResetAccessCache(uid, 0);
+ if (tu->states & UNeedsReset)
+ do_scan = 1;
+ }
+ }
+ /* Skip the potentially expensive scan if nothing to do */
+ if (!do_scan)
+ goto done;
+
+ tofreelist = NULL;
+ for (i = 0; i < VCSIZE; i++) {
+ for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
+ /* really should do this under cache write lock, but that.
+ * is hard to under locking hierarchy */
+ if (tvc->Access) {
+ struct axscache **ac, **nac;
+
+ for ( ac = &tvc->Access; *ac;) {
+ nac = &(*ac)->next;
+ tu = afs_FindUserNoLock((*ac)->uid, tvc->f.fid.Cell);
+ if (tu == NULL || (tu->states & UNeedsReset)) {
+ struct axscache *tmp;
+ tmp = *ac;
+ *ac = *nac;
+ tmp->next = tofreelist;
+ tofreelist = tmp;
+ } else
+ ac = nac;
+ if (tu != NULL)
+ tu->refCount--;
+ }
}
}
}
+ afs_FreeAllAxs(&tofreelist);
+ for (i = 0; i < NUSERS; i++) {
+ for (tu = afs_users[i]; tu; tu = tu->next) {
+ if (tu->states & UNeedsReset)
+ tu->states &= ~UNeedsReset;
+ }
+ }
+
+done:
ReleaseReadLock(&afs_xuser);
ReleaseReadLock(&afs_xvcache);
-
} /*afs_CheckTokenCache */
+/* Remove any access caches associated with this uid+cell
+ * by scanning the entire vcache table. Specify cell=-1
+ * to remove all access caches associated with this uid
+ * regardless of cell.
+ */
void
-afs_ResetAccessCache(afs_int32 uid, int alock)
+afs_ResetAccessCache(afs_int32 uid, afs_int32 cell, int alock)
{
- register int i;
- register struct vcache *tvc;
+ int i;
+ struct vcache *tvc;
struct axscache *ac;
AFS_STATCNT(afs_ResetAccessCache);
for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
/* really should do this under cache write lock, but that.
* is hard to under locking hierarchy */
- if (tvc->Access && (ac = afs_FindAxs(tvc->Access, uid))) {
- afs_RemoveAxs(&tvc->Access, ac);
+ if (tvc->Access && (cell == -1 || tvc->f.fid.Cell == cell)) {
+ ac = afs_FindAxs(tvc->Access, uid);
+ if (ac) {
+ afs_RemoveAxs(&tvc->Access, ac);
+ }
}
}
}
* access info.
*/
void
-afs_ResetUserConns(register struct unixuser *auser)
+afs_ResetUserConns(struct unixuser *auser)
{
- int i;
+ int i, j;
struct srvAddr *sa;
- struct afs_conn *tc;
+ struct sa_conn_vector *tcv;
AFS_STATCNT(afs_ResetUserConns);
ObtainReadLock(&afs_xsrvAddr);
for (i = 0; i < NSERVERS; i++) {
for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
- for (tc = sa->conns; tc; tc = tc->next) {
- if (tc->user == auser) {
- tc->forceConnectFS = 1;
+ for (tcv = sa->conns; tcv; tcv = tcv->next) {
+ if (tcv->user == auser) {
+ for(j = 0; j < CVEC_LEN; ++j) {
+ (tcv->cvec[j]).forceConnectFS = 1;
+ }
}
}
}
ReleaseWriteLock(&afs_xconn);
ReleaseReadLock(&afs_xsrvAddr);
- afs_ResetAccessCache(auser->uid, 1);
+ afs_ResetAccessCache(auser->uid, auser->cell, 1);
auser->states &= ~UNeedsReset;
} /*afs_ResetUserConns */
#endif /* !AFS_PAG_MANAGER */
struct unixuser *
afs_FindUser(afs_int32 auid, afs_int32 acell, afs_int32 locktype)
{
- register struct unixuser *tu;
- register afs_int32 i;
+ struct unixuser *tu;
- AFS_STATCNT(afs_FindUser);
- i = UHash(auid);
ObtainWriteLock(&afs_xuser, 99);
- for (tu = afs_users[i]; tu; tu = tu->next) {
- if (tu->uid == auid && ((tu->cell == acell) || (acell == -1))) {
- tu->refCount++;
- ReleaseWriteLock(&afs_xuser);
- return tu;
- }
- }
+ tu = afs_FindUserNoLock(auid, acell);
ReleaseWriteLock(&afs_xuser);
- return NULL;
-
+ if (tu)
+ afs_LockUser(tu, locktype, 365);
+ return tu;
} /*afs_FindUser */
void
afs_ComputePAGStats(void)
{
- register struct unixuser *currPAGP; /*Ptr to curr PAG */
- register struct unixuser *cmpPAGP; /*Ptr to PAG being compared */
- register struct afs_stats_AuthentInfo *authP; /*Ptr to stats area */
+ struct unixuser *currPAGP; /*Ptr to curr PAG */
+ struct unixuser *cmpPAGP; /*Ptr to PAG being compared */
+ struct afs_stats_AuthentInfo *authP; /*Ptr to stats area */
int curr_Record; /*Curr record */
int currChain; /*Curr hash chain */
int currChainLen; /*Length of curr hash chain */
* We've found a previously-uncounted PAG. If it's been deleted
* but just not garbage-collected yet, we step over it.
*/
- if (currPAGP->vid == UNDEFVID)
+ if (!(currPAGP->states & UHasTokens))
continue;
/*
} /*afs_ComputePAGStats */
+/*!
+ * Obtain a unixuser for the specified uid and cell;
+ * if no existing match found, allocate a new one.
+ *
+ * \param[in] auid uid/PAG value
+ * \param[in] acell cell number; if -1, match on auid only
+ * \param[in] locktype locktype desired on returned unixuser
+ *
+ * \post unixuser is chained in afs_users[], returned with <locktype> held
+ *
+ * \note Maintain unixusers in sorted order within hash bucket to enable
+ * small lookup optimizations.
+ */
struct unixuser *
-afs_GetUser(register afs_int32 auid, afs_int32 acell, afs_int32 locktype)
+afs_GetUser(afs_int32 auid, afs_int32 acell, afs_int32 locktype)
{
- register struct unixuser *tu, *pu = 0;
- register afs_int32 i;
- register afs_int32 RmtUser = 0;
+ struct unixuser *tu, *xu = 0, *pu = 0;
+ afs_int32 i;
+ afs_int32 RmtUser = 0;
AFS_STATCNT(afs_GetUser);
i = UHash(auid);
ObtainWriteLock(&afs_xuser, 104);
- for (tu = afs_users[i]; tu; tu = tu->next) {
+ /* unixusers are sorted by uid in each hash bucket */
+ for (tu = afs_users[i]; tu && (tu->uid <= auid) ; xu = tu, tu = tu->next) {
if (tu->uid == auid) {
RmtUser = 0;
pu = NULL;
/* Here we setup the real cell for the client */
tu->cell = acell;
tu->refCount++;
- ReleaseWriteLock(&afs_xuser);
- return tu;
+ goto done;
} else if (tu->cell == acell || acell == -1) {
tu->refCount++;
- ReleaseWriteLock(&afs_xuser);
- return tu;
+ goto done;
}
}
}
- tu = (struct unixuser *)afs_osi_Alloc(sizeof(struct unixuser));
+ /* no matching unixuser found; repurpose the tu pointer to
+ * allocate a new unixuser.
+ * xu will be insertion point for our new unixuser.
+ */
+ tu = afs_osi_Alloc(sizeof(struct unixuser));
+ osi_Assert(tu != NULL);
#ifndef AFS_NOSTATS
afs_stats_cmfullperf.authent.PAGCreations++;
#endif /* AFS_NOSTATS */
- memset((char *)tu, 0, sizeof(struct unixuser));
- tu->next = afs_users[i];
- afs_users[i] = tu;
+ memset(tu, 0, sizeof(struct unixuser));
+ AFS_RWLOCK_INIT(&tu->lock, "unixuser lock");
+ /* insert new nu in sorted order after xu */
+ if (xu == NULL) {
+ tu->next = afs_users[i];
+ afs_users[i] = tu;
+ } else {
+ tu->next = xu->next;
+ xu->next = tu;
+ }
if (RmtUser) {
/*
* This is for the case where an additional unixuser struct is
* structure
*/
if (pu && pu->exporter) {
- (void)EXP_HOLD(tu->exporter = pu->exporter);
+ tu->exporter = pu->exporter;
+ (void)EXP_HOLD(tu->exporter);
}
}
tu->uid = auid;
tu->cell = acell;
- tu->vid = UNDEFVID;
+ tu->viceId = UNDEFVID;
tu->refCount = 1;
tu->tokenTime = osi_Time();
+ /* fall through to return the new one */
+
+ done:
ReleaseWriteLock(&afs_xuser);
+ afs_LockUser(tu, locktype, 364);
return tu;
} /*afs_GetUser */
+void
+afs_LockUser(struct unixuser *au, afs_int32 locktype,
+ unsigned int src_indicator)
+{
+ switch (locktype) {
+ case READ_LOCK:
+ ObtainReadLock(&au->lock);
+ break;
+ case WRITE_LOCK:
+ ObtainWriteLock(&au->lock, src_indicator);
+ break;
+ case SHARED_LOCK:
+ ObtainSharedLock(&au->lock, src_indicator);
+ break;
+ default:
+ /* noop */
+ break;
+ }
+}
void
-afs_PutUser(register struct unixuser *au, afs_int32 locktype)
+afs_PutUser(struct unixuser *au, afs_int32 locktype)
{
AFS_STATCNT(afs_PutUser);
+
+ switch (locktype) {
+ case READ_LOCK:
+ ReleaseReadLock(&au->lock);
+ break;
+ case WRITE_LOCK:
+ ReleaseWriteLock(&au->lock);
+ break;
+ case SHARED_LOCK:
+ ReleaseSharedLock(&au->lock);
+ break;
+ default:
+ /* noop */
+ break;
+ }
+
--au->refCount;
} /*afs_PutUser */
* dude has the flag set at any time for a particular unix uid.
*/
void
-afs_SetPrimary(register struct unixuser *au, register int aflag)
+afs_SetPrimary(struct unixuser *au, int aflag)
{
- register struct unixuser *tu;
- register int i;
+ struct unixuser *tu;
+ int i;
struct unixuser *pu;
AFS_STATCNT(afs_SetPrimary);
} /*afs_SetPrimary */
+void
+afs_NotifyUser(struct unixuser *auser, int event)
+{
+#ifdef AFS_DARWIN_ENV
+ darwin_notify_perms(auser, event);
+#endif
+}
+
+/**
+ * Mark all of the unixuser records held for a particular PAG as
+ * expired
+ *
+ * @param[in] pag
+ * PAG to expire records for
+ */
+void
+afs_MarkUserExpired(afs_int32 pag)
+{
+ afs_int32 i;
+ struct unixuser *tu;
+
+ i = UHash(pag);
+ ObtainWriteLock(&afs_xuser, 9);
+ for (tu = afs_users[i]; tu; tu = tu->next) {
+ if (tu->uid == pag) {
+ tu->states &= ~UHasTokens;
+ tu->tokenTime = 0;
+ }
+ }
+ ReleaseWriteLock(&afs_xuser);
+}
+
#if AFS_GCPAGS
/*
- * Called by osi_TraverseProcTable (from afs_GCPAGs) for each
+ * Called by osi_TraverseProcTable (from afs_GCPAGs) for each
* process in the system.
* If the specified process uses a PAG, clear that PAG's temporary
* 'deleteme' flag.
/*
* LOCKS: afs_GCPAGs_perproc_func requires write lock on afs_xuser
*/
+#if !defined(LINUX_KEYRING_SUPPORT) && (!defined(STRUCT_TASK_STRUCT_HAS_CRED) || defined(HAVE_LINUX_RCU_READ_LOCK))
void
-afs_GCPAGs_perproc_func(AFS_PROC * pproc)
+afs_GCPAGs_perproc_func(afs_proc_t * pproc)
{
afs_int32 pag, hash, uid;
- const struct AFS_UCRED *pcred;
+ const afs_ucred_t *pcred;
afs_GCPAGs_perproc_count++;
afs_GCPAGs_cred_count++;
pag = PagInCred(pcred);
-#if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD40_ENV) || defined(AFS_LINUX22_ENV)
- uid = (pag != NOPAG ? pag : pcred->cr_uid);
+#if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV) || defined(AFS_LINUX22_ENV)
+ uid = (pag != NOPAG ? pag : afs_cr_uid(pcred));
#elif defined(AFS_SUN510_ENV)
uid = (pag != NOPAG ? pag : crgetruid(pcred));
#else
- uid = (pag != NOPAG ? pag : pcred->cr_ruid);
+ uid = (pag != NOPAG ? pag : afs_cr_ruid(pcred));
#endif
hash = UHash(uid);
- /* if this token is PAG based, or it's UID based and
+ /* if this token is PAG based, or it's UID based and
* UID-based tokens exist */
if ((pag != NOPAG) || (afs_GCPAGs_UIDBaseTokenCount)) {
/* find the entries for this uid in all cells and clear the not
* referenced flag. Can't use afs_FindUser, because it just returns
- * the specific cell asked for, or the first one found.
+ * the specific cell asked for, or the first one found.
*/
struct unixuser *pu;
for (pu = afs_users[hash]; pu; pu = pu->next) {
/* clear the 'deleteme' flag for this entry */
pu->states &= ~TMP_UPAGNotReferenced;
if (pag == NOPAG) {
- /* This is a uid based token that hadn't
+ /* This is a uid based token that hadn't
* previously been cleared, so decrement the
* outstanding uid based token count */
afs_GCPAGs_UIDBaseTokenCount--;
}
}
}
+#endif
/*
- * Go through the process table, find all unused PAGs
+ * Go through the process table, find all unused PAGs
* and cause them to be deleted during the next GC.
*
* returns the number of PAGs marked for deletion
}
}
- /* Now, iterate through the systems process table,
+ /* Now, iterate through the systems process table,
* for each process, mark it's PAGs (if any) in use.
* i.e. clear the temporary deleteme flag.
*/
* 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) */