2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
13 #include <afsconfig.h>
14 #include "afs/param.h"
18 #include "afs/sysincludes.h" /* Standard vendor system headers */
21 #if !defined(AFS_LINUX20_ENV)
24 #include <netinet/in.h>
27 #include "h/hashing.h"
29 #if !defined(AFS_HPUX110_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV)
30 #include <netinet/in_var.h>
31 #endif /* ! AFS_HPUX110_ENV */
32 #endif /* !defined(UKERNEL) */
34 #include "afsincludes.h" /* Afs-based standard headers */
35 #include "afs/afs_stats.h" /* afs statistics */
37 #if defined(AFS_SUN5_ENV)
39 #include <inet/common.h>
40 #include <netinet/ip6.h>
44 #include "afs/afs_axscache.h"
46 /* Exported variables */
47 afs_rwlock_t afs_xuser;
48 struct unixuser *afs_users[NUSERS];
51 #ifndef AFS_PAG_MANAGER
52 /* Forward declarations */
53 void afs_ResetAccessCache(afs_int32 uid, afs_int32 cell, int alock);
54 #endif /* !AFS_PAG_MANAGER */
57 /* Called from afs_Daemon to garbage collect unixusers no longer using system,
58 * and their conns. The aforce parameter tells the function to flush all
59 * *unauthenticated* conns, no matter what their expiration time; it exists
60 * because after we choose our final rx epoch, we want to stop using calls with
61 * other epochs as soon as possible (old file servers act bizarrely when they
65 afs_GCUserData(int aforce)
67 struct unixuser *tu, **lu, *nu;
69 afs_int32 now, delFlag;
71 AFS_STATCNT(afs_GCUserData);
72 /* Obtain locks in valid order */
73 ObtainWriteLock(&afs_xuser, 95);
74 #ifndef AFS_PAG_MANAGER
75 ObtainReadLock(&afs_xserver);
76 ObtainWriteLock(&afs_xconn, 96);
79 for (i = 0; i < NUSERS; i++) {
80 for (lu = &afs_users[i], tu = *lu; tu; tu = nu) {
81 delFlag = 0; /* should we delete this dude? */
82 /* Don't garbage collect users in use now (refCount) */
83 if (tu->refCount == 0) {
85 /* Need to walk the token stack, and dispose of
86 * all expired tokens */
87 afs_DiscardExpiredTokens(&tu->tokens, now);
88 if (!afs_HasUsableTokens(tu->tokens, now))
91 if (aforce || (tu->tokenTime < now - NOTOKTIMEOUT))
98 #ifndef AFS_PAG_MANAGER
99 afs_ReleaseConnsUser(tu);
101 afs_FreeTokens(&tu->tokens);
104 EXP_RELE(tu->exporter);
105 afs_osi_Free(tu, sizeof(struct unixuser));
111 #ifndef AFS_PAG_MANAGER
112 ReleaseWriteLock(&afs_xconn);
114 #ifndef AFS_PAG_MANAGER
115 ReleaseReadLock(&afs_xserver);
117 ReleaseWriteLock(&afs_xuser);
119 } /*afs_GCUserData */
121 static struct unixuser *
122 afs_FindUserNoLock(afs_int32 auid, afs_int32 acell)
127 AFS_STATCNT(afs_FindUser);
129 for (tu = afs_users[i]; tu; tu = tu->next) {
130 if (tu->uid == auid && ((tu->cell == acell) || (acell == -1))) {
139 #ifndef AFS_PAG_MANAGER
141 * Check for unixusers who encountered bad tokens, and reset the access
142 * cache for these guys. Can't do this when token expiration detected,
143 * since too many locks are set then.
146 afs_CheckTokenCache(void)
152 struct axscache *tofreelist;
155 AFS_STATCNT(afs_CheckCacheResets);
156 ObtainReadLock(&afs_xvcache);
157 ObtainReadLock(&afs_xuser);
159 for (i = 0; i < NUSERS; i++) {
160 for (tu = afs_users[i]; tu; tu = tu->next) {
162 * If tokens are still good and user has Kerberos tickets,
165 if ((tu->states & UHasTokens) && !(tu->states & UTokensBad)) {
166 if (!afs_HasUsableTokens(tu->tokens, now)) {
168 * This token has expired, warn users and reset access
171 tu->states |= (UTokensBad | UNeedsReset);
174 if (tu->states & UNeedsReset)
178 /* Skip the potentially expensive scan if nothing to do */
183 for (i = 0; i < VCSIZE; i++) {
184 for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
185 /* really should do this under cache write lock, but that.
186 * is hard to under locking hierarchy */
188 struct axscache **ac, **nac;
190 for ( ac = &tvc->Access; *ac;) {
192 tu = afs_FindUserNoLock((*ac)->uid, tvc->f.fid.Cell);
193 if (tu == NULL || (tu->states & UNeedsReset)) {
194 struct axscache *tmp;
197 tmp->next = tofreelist;
207 afs_FreeAllAxs(&tofreelist);
208 for (i = 0; i < NUSERS; i++) {
209 for (tu = afs_users[i]; tu; tu = tu->next) {
210 if (tu->states & UNeedsReset)
211 tu->states &= ~UNeedsReset;
216 ReleaseReadLock(&afs_xuser);
217 ReleaseReadLock(&afs_xvcache);
218 } /*afs_CheckTokenCache */
221 /* Remove any access caches associated with this uid+cell
222 * by scanning the entire vcache table. Specify cell=-1
223 * to remove all access caches associated with this uid
224 * regardless of cell.
227 afs_ResetAccessCache(afs_int32 uid, afs_int32 cell, int alock)
233 AFS_STATCNT(afs_ResetAccessCache);
235 ObtainReadLock(&afs_xvcache);
236 for (i = 0; i < VCSIZE; i++) {
237 for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
238 /* really should do this under cache write lock, but that.
239 * is hard to under locking hierarchy */
240 if (tvc->Access && (cell == -1 || tvc->f.fid.Cell == cell)) {
241 ac = afs_FindAxs(tvc->Access, uid);
243 afs_RemoveAxs(&tvc->Access, ac);
249 ReleaseReadLock(&afs_xvcache);
251 } /*afs_ResetAccessCache */
255 * Ensure all connections make use of new tokens. Discard incorrectly-cached
259 afs_ResetUserConns(struct unixuser *auser)
263 struct sa_conn_vector *tcv;
265 AFS_STATCNT(afs_ResetUserConns);
266 ObtainReadLock(&afs_xsrvAddr);
267 ObtainWriteLock(&afs_xconn, 98);
269 for (i = 0; i < NSERVERS; i++) {
270 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
271 for (tcv = sa->conns; tcv; tcv = tcv->next) {
272 if (tcv->user == auser) {
273 for(j = 0; j < CVEC_LEN; ++j) {
274 (tcv->cvec[j]).forceConnectFS = 1;
281 ReleaseWriteLock(&afs_xconn);
282 ReleaseReadLock(&afs_xsrvAddr);
283 afs_ResetAccessCache(auser->uid, auser->cell, 1);
284 auser->states &= ~UNeedsReset;
285 } /*afs_ResetUserConns */
286 #endif /* !AFS_PAG_MANAGER */
290 afs_FindUser(afs_int32 auid, afs_int32 acell, afs_int32 locktype)
294 ObtainWriteLock(&afs_xuser, 99);
295 tu = afs_FindUserNoLock(auid, acell);
296 ReleaseWriteLock(&afs_xuser);
298 afs_LockUser(tu, locktype, 365);
303 /*------------------------------------------------------------------------
304 * EXPORTED afs_ComputePAGStats
307 * Compute a set of stats concerning PAGs used by this machine.
316 * The results are put in the structure responsible for keeping
317 * detailed CM stats. Note: entries corresponding to a single PAG
318 * will appear on the identical hash chain, so sweeping the chain
319 * will find all entries related to a single PAG.
323 *------------------------------------------------------------------------*/
326 afs_ComputePAGStats(void)
328 struct unixuser *currPAGP; /*Ptr to curr PAG */
329 struct unixuser *cmpPAGP; /*Ptr to PAG being compared */
330 struct afs_stats_AuthentInfo *authP; /*Ptr to stats area */
331 int curr_Record; /*Curr record */
332 int currChain; /*Curr hash chain */
333 int currChainLen; /*Length of curr hash chain */
334 int currPAGRecords; /*# records in curr PAG */
337 * Lock out everyone else from scribbling on the PAG entries.
339 ObtainReadLock(&afs_xuser);
342 * Initialize the tallies, then sweep through each hash chain. We
343 * can't bzero the structure, since some fields are cumulative over
347 authP = &(afs_stats_cmfullperf.authent);
348 authP->curr_PAGs = 0;
349 authP->curr_Records = 0;
350 authP->curr_AuthRecords = 0;
351 authP->curr_UnauthRecords = 0;
352 authP->curr_MaxRecordsInPAG = 0;
353 authP->curr_LongestChain = 0;
355 for (currChain = 0; currChain < NUSERS; currChain++) {
357 for (currPAGP = afs_users[currChain]; currPAGP;
358 currPAGP = currPAGP->next) {
360 * Bump the number of records on this current chain, along with
361 * the total number of records in existence.
366 * We've found a previously-uncounted PAG. If it's been deleted
367 * but just not garbage-collected yet, we step over it.
369 if (!(currPAGP->states & UHasTokens))
373 * If this PAG record has already been ``counted', namely
374 * associated with a PAG and tallied, clear its bit and move on.
376 (authP->curr_Records)++;
377 if (currPAGP->states & UPAGCounted) {
378 currPAGP->states &= ~UPAGCounted;
384 /*We've counted this one already */
386 * Jot initial info down, then sweep down the rest of the hash
387 * chain, looking for matching PAG entries. Note: to properly
388 * ``count'' the current record, we first compare it to itself
389 * in the following loop.
391 (authP->curr_PAGs)++;
394 for (cmpPAGP = currPAGP; cmpPAGP; cmpPAGP = cmpPAGP->next) {
395 if (currPAGP->uid == cmpPAGP->uid) {
397 * The records belong to the same PAG. First, mark the
398 * new record as ``counted'' and bump the PAG size.
399 * Then, record the state of its ticket, if any.
401 cmpPAGP->states |= UPAGCounted;
403 if ((cmpPAGP->states & UHasTokens)
404 && !(cmpPAGP->states & UTokensBad))
405 (authP->curr_AuthRecords)++;
407 (authP->curr_UnauthRecords)++;
408 } /*Records belong to same PAG */
409 } /*Compare to rest of PAG records in chain */
412 * In the above comparisons, the current PAG record has been
413 * marked as counted. Erase this mark before moving on.
415 currPAGP->states &= ~UPAGCounted;
418 * We've compared our current PAG record with all remaining
419 * PAG records in the hash chain. Update our tallies, and
420 * perhaps even our lifetime high water marks. After that,
421 * remove our search mark and advance to the next comparison
424 if (currPAGRecords > authP->curr_MaxRecordsInPAG) {
425 authP->curr_MaxRecordsInPAG = currPAGRecords;
426 if (currPAGRecords > authP->HWM_MaxRecordsInPAG)
427 authP->HWM_MaxRecordsInPAG = currPAGRecords;
429 } /*Sweep a hash chain */
432 * If the chain we just finished zipping through is the longest we've
433 * seen yet, remember this fact before advancing to the next chain.
435 if (currChainLen > authP->curr_LongestChain) {
436 authP->curr_LongestChain = currChainLen;
437 if (currChainLen > authP->HWM_LongestChain)
438 authP->HWM_LongestChain = currChainLen;
441 } /*For each hash chain in afs_user */
444 * Now that we've counted everything up, we can consider all-time
447 if (authP->curr_PAGs > authP->HWM_PAGs)
448 authP->HWM_PAGs = authP->curr_PAGs;
449 if (authP->curr_Records > authP->HWM_Records)
450 authP->HWM_Records = authP->curr_Records;
453 * People are free to manipulate the PAG structures now.
455 ReleaseReadLock(&afs_xuser);
457 } /*afs_ComputePAGStats */
460 * Obtain a unixuser for the specified uid and cell;
461 * if no existing match found, allocate a new one.
463 * \param[in] auid uid/PAG value
464 * \param[in] acell cell number; if -1, match on auid only
465 * \param[in] locktype locktype desired on returned unixuser
467 * \post unixuser is chained in afs_users[], returned with <locktype> held
469 * \note Maintain unixusers in sorted order within hash bucket to enable
470 * small lookup optimizations.
474 afs_GetUser(afs_int32 auid, afs_int32 acell, afs_int32 locktype)
476 struct unixuser *tu, *xu = 0, *pu = 0;
478 afs_int32 RmtUser = 0;
480 AFS_STATCNT(afs_GetUser);
482 ObtainWriteLock(&afs_xuser, 104);
483 /* unixusers are sorted by uid in each hash bucket */
484 for (tu = afs_users[i]; tu && (tu->uid <= auid) ; xu = tu, tu = tu->next) {
485 if (tu->uid == auid) {
492 if (tu->cell == -1 && acell != -1) {
493 /* Here we setup the real cell for the client */
497 } else if (tu->cell == acell || acell == -1) {
503 /* no matching unixuser found; repurpose the tu pointer to
504 * allocate a new unixuser.
505 * xu will be insertion point for our new unixuser.
507 tu = afs_osi_Alloc(sizeof(struct unixuser));
508 osi_Assert(tu != NULL);
510 afs_stats_cmfullperf.authent.PAGCreations++;
511 #endif /* AFS_NOSTATS */
512 memset(tu, 0, sizeof(struct unixuser));
513 AFS_RWLOCK_INIT(&tu->lock, "unixuser lock");
514 /* insert new nu in sorted order after xu */
516 tu->next = afs_users[i];
524 * This is for the case where an additional unixuser struct is
525 * created because the remote client is accessing a different cell;
526 * we simply rerecord relevant information from the original
529 if (pu && pu->exporter) {
530 tu->exporter = pu->exporter;
531 (void)EXP_HOLD(tu->exporter);
536 tu->viceId = UNDEFVID;
538 tu->tokenTime = osi_Time();
539 /* fall through to return the new one */
542 ReleaseWriteLock(&afs_xuser);
543 afs_LockUser(tu, locktype, 364);
549 afs_LockUser(struct unixuser *au, afs_int32 locktype,
550 unsigned int src_indicator)
554 ObtainReadLock(&au->lock);
557 ObtainWriteLock(&au->lock, src_indicator);
560 ObtainSharedLock(&au->lock, src_indicator);
569 afs_PutUser(struct unixuser *au, afs_int32 locktype)
571 AFS_STATCNT(afs_PutUser);
575 ReleaseReadLock(&au->lock);
578 ReleaseWriteLock(&au->lock);
581 ReleaseSharedLock(&au->lock);
593 * Set the primary flag on a unixuser structure, ensuring that exactly one
594 * dude has the flag set at any time for a particular unix uid.
597 afs_SetPrimary(struct unixuser *au, int aflag)
603 AFS_STATCNT(afs_SetPrimary);
606 ObtainWriteLock(&afs_xuser, 105);
608 * See if anyone is this uid's primary cell yet; recording in pu the
611 for (tu = afs_users[i]; tu; tu = tu->next) {
612 if (tu->uid == au->uid && (tu->states & UPrimary)) {
616 if (pu && !(pu->states & UHasTokens)) {
618 * Primary user has unlogged, don't treat him as primary any longer;
619 * note that we want to treat him as primary until now, so that
620 * people see a primary identity until now.
622 pu->states &= ~UPrimary;
626 /* setting au to be primary */
628 pu->states &= ~UPrimary;
629 au->states |= UPrimary;
630 } else if (aflag == 0) {
631 /* we don't know if we're supposed to be primary or not */
632 if (!pu || au == pu) {
633 au->states |= UPrimary;
635 au->states &= ~UPrimary;
637 ReleaseWriteLock(&afs_xuser);
639 } /*afs_SetPrimary */
642 afs_NotifyUser(struct unixuser *auser, int event)
644 #ifdef AFS_DARWIN_ENV
645 darwin_notify_perms(auser, event);
650 * Mark all of the unixuser records held for a particular PAG as
654 * PAG to expire records for
657 afs_MarkUserExpired(afs_int32 pag)
663 ObtainWriteLock(&afs_xuser, 9);
664 for (tu = afs_users[i]; tu; tu = tu->next) {
665 if (tu->uid == pag) {
666 tu->states &= ~UHasTokens;
670 ReleaseWriteLock(&afs_xuser);
677 * Called by osi_TraverseProcTable (from afs_GCPAGs) for each
678 * process in the system.
679 * If the specified process uses a PAG, clear that PAG's temporary
684 * This variable keeps track of the number of UID-base
685 * tokens in the afs_users table. When it's zero
686 * the per process loop in GCPAGs doesn't have to
687 * check processes without pags against the afs_users table.
689 static afs_int32 afs_GCPAGs_UIDBaseTokenCount = 0;
692 * These variables keep track of the number of times
693 * afs_GCPAGs_perproc_func() is called. If it is not called at all when
694 * walking the process table, there is something wrong and we should not
695 * prematurely expire any tokens.
697 static size_t afs_GCPAGs_perproc_count = 0;
698 static size_t afs_GCPAGs_cred_count = 0;
701 * LOCKS: afs_GCPAGs_perproc_func requires write lock on afs_xuser
703 #if !defined(LINUX_KEYRING_SUPPORT) && (!defined(STRUCT_TASK_STRUCT_HAS_CRED) || defined(HAVE_LINUX_RCU_READ_LOCK))
705 afs_GCPAGs_perproc_func(afs_proc_t * pproc)
707 afs_int32 pag, hash, uid;
708 const afs_ucred_t *pcred;
710 afs_GCPAGs_perproc_count++;
712 pcred = afs_osi_proc2cred(pproc);
716 afs_GCPAGs_cred_count++;
718 pag = PagInCred(pcred);
719 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV) || defined(AFS_LINUX22_ENV)
720 uid = (pag != NOPAG ? pag : afs_cr_uid(pcred));
721 #elif defined(AFS_SUN510_ENV)
722 uid = (pag != NOPAG ? pag : crgetruid(pcred));
724 uid = (pag != NOPAG ? pag : afs_cr_ruid(pcred));
728 /* if this token is PAG based, or it's UID based and
729 * UID-based tokens exist */
730 if ((pag != NOPAG) || (afs_GCPAGs_UIDBaseTokenCount)) {
731 /* find the entries for this uid in all cells and clear the not
732 * referenced flag. Can't use afs_FindUser, because it just returns
733 * the specific cell asked for, or the first one found.
736 for (pu = afs_users[hash]; pu; pu = pu->next) {
737 if (pu->uid == uid) {
738 if (pu->states & TMP_UPAGNotReferenced) {
739 /* clear the 'deleteme' flag for this entry */
740 pu->states &= ~TMP_UPAGNotReferenced;
742 /* This is a uid based token that hadn't
743 * previously been cleared, so decrement the
744 * outstanding uid based token count */
745 afs_GCPAGs_UIDBaseTokenCount--;
755 * Go through the process table, find all unused PAGs
756 * and cause them to be deleted during the next GC.
758 * returns the number of PAGs marked for deletion
760 * On AIX we free PAGs when the last accessing process exits,
761 * so this routine is not needed.
763 * In AFS WebSecure, we explicitly call unlog when we remove
764 * an entry in the login cache, so this routine is not needed.
768 afs_GCPAGs(afs_int32 * ReleasedCount)
773 if (afs_gcpags != AFS_GCPAGS_OK) {
779 /* first, loop through afs_users, setting the temporary 'deleteme' flag */
780 ObtainWriteLock(&afs_xuser, 419);
781 afs_GCPAGs_UIDBaseTokenCount = 0;
782 for (i = 0; i < NUSERS; i++) {
783 for (pu = afs_users[i]; pu; pu = pu->next) {
784 pu->states |= TMP_UPAGNotReferenced;
785 if (((pu->uid >> 24) & 0xff) != 'A') {
786 /* this is a uid-based token, */
787 /* increment the count */
788 afs_GCPAGs_UIDBaseTokenCount++;
793 /* Now, iterate through the systems process table,
794 * for each process, mark it's PAGs (if any) in use.
795 * i.e. clear the temporary deleteme flag.
797 afs_GCPAGs_perproc_count = 0;
798 afs_GCPAGs_cred_count = 0;
800 afs_osi_TraverseProcTable();
802 /* If there is an internal problem and afs_GCPAGs_perproc_func()
803 * does not get called, disable gcpags so that we do not
804 * accidentally expire all the tokens in the system.
806 if (afs_gcpags == AFS_GCPAGS_OK && !afs_GCPAGs_perproc_count) {
807 afs_gcpags = AFS_GCPAGS_EPROCWALK;
810 if (afs_gcpags == AFS_GCPAGS_OK && !afs_GCPAGs_cred_count) {
811 afs_gcpags = AFS_GCPAGS_ECREDWALK;
814 /* Now, go through afs_users again, any that aren't in use
815 * (temp deleteme flag still set) will be marked for later deletion,
816 * by setting their expire times to 0.
818 for (i = 0; i < NUSERS; i++) {
819 for (pu = afs_users[i]; pu; pu = pu->next) {
820 if (pu->states & TMP_UPAGNotReferenced) {
822 /* clear the temp flag */
823 pu->states &= ~TMP_UPAGNotReferenced;
825 /* Is this entry on behalf of a 'remote' user ?
826 * i.e. nfs translator, etc.
828 if (!pu->exporter && afs_gcpags == AFS_GCPAGS_OK) {
829 /* make afs_GCUserData remove this entry */
830 pu->states &= ~UHasTokens;
833 (*ReleasedCount)++; /* remember how many we marked (info only) */
839 ReleaseWriteLock(&afs_xuser);
844 #endif /* AFS_GCPAGS */