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"
20 #include "afs/sysincludes.h" /* Standard vendor system headers */
23 #if !defined(AFS_LINUX20_ENV)
26 #include <netinet/in.h>
29 #include "h/hashing.h"
31 #if !defined(AFS_HPUX110_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN60_ENV)
32 #include <netinet/in_var.h>
33 #endif /* ! AFS_HPUX110_ENV */
34 #endif /* !defined(UKERNEL) */
36 #include "afsincludes.h" /* Afs-based standard headers */
37 #include "afs/afs_stats.h" /* afs statistics */
39 #if defined(AFS_SUN56_ENV)
41 #include <inet/common.h>
42 #if defined(AFS_SUN58_ENV)
43 #include <netinet/ip6.h>
49 /* Exported variables */
50 afs_rwlock_t afs_xuser;
51 struct unixuser *afs_users[NUSERS];
54 #ifndef AFS_PAG_MANAGER
55 /* Forward declarations */
56 void afs_ResetAccessCache(afs_int32 uid, int alock);
59 * Called with afs_xuser, afs_xserver and afs_xconn locks held, to delete
60 * appropriate conn structures for au
63 RemoveUserConns(register struct unixuser *au)
66 register struct server *ts;
67 register struct srvAddr *sa;
68 register struct afs_conn *tc, **lc;
70 AFS_STATCNT(RemoveUserConns);
71 for (i = 0; i < NSERVERS; i++) {
72 for (ts = afs_servers[i]; ts; ts = ts->next) {
73 for (sa = ts->addr; sa; sa = sa->next_sa) {
75 for (tc = *lc; tc; lc = &tc->next, tc = *lc) {
76 if (tc->user == au && tc->refCount == 0) {
79 rx_DestroyConnection(tc->id);
81 afs_osi_Free(tc, sizeof(struct afs_conn));
82 break; /* at most one instance per server */
83 } /*Found unreferenced connection for user */
84 } /*For each connection on the server */
86 } /*For each server on chain */
89 } /*RemoveUserConns */
90 #endif /* !AFS_PAG_MANAGER */
93 /* Called from afs_Daemon to garbage collect unixusers no longer using system,
94 * and their conns. The aforce parameter tells the function to flush all
95 * *unauthenticated* conns, no matter what their expiration time; it exists
96 * because after we choose our final rx epoch, we want to stop using calls with
97 * other epochs as soon as possible (old file servers act bizarrely when they
101 afs_GCUserData(int aforce)
103 register struct unixuser *tu, **lu, *nu;
105 afs_int32 now, delFlag;
107 AFS_STATCNT(afs_GCUserData);
108 /* Obtain locks in valid order */
109 ObtainWriteLock(&afs_xuser, 95);
110 #ifndef AFS_PAG_MANAGER
111 ObtainReadLock(&afs_xserver);
112 ObtainWriteLock(&afs_xconn, 96);
115 for (i = 0; i < NUSERS; i++) {
116 for (lu = &afs_users[i], tu = *lu; tu; tu = nu) {
117 delFlag = 0; /* should we delete this dude? */
118 /* Don't garbage collect users in use now (refCount) */
119 if (tu->refCount == 0) {
120 if (tu->states & UHasTokens) {
122 * Give ourselves a little extra slack, in case we
125 if (tu->ct.EndTimestamp < now - NOTOKTIMEOUT)
128 if (aforce || (tu->tokenTime < now - NOTOKTIMEOUT))
135 #ifndef AFS_PAG_MANAGER
139 afs_osi_Free(tu->stp, tu->stLen);
141 EXP_RELE(tu->exporter);
142 afs_osi_Free(tu, sizeof(struct unixuser));
148 #ifndef AFS_PAG_MANAGER
149 ReleaseWriteLock(&afs_xconn);
151 #ifndef AFS_PAG_MANAGER
152 ReleaseReadLock(&afs_xserver);
154 ReleaseWriteLock(&afs_xuser);
156 } /*afs_GCUserData */
159 #ifndef AFS_PAG_MANAGER
161 * Check for unixusers who encountered bad tokens, and reset the access
162 * cache for these guys. Can't do this when token expiration detected,
163 * since too many locks are set then.
166 afs_CheckTokenCache(void)
169 register struct unixuser *tu;
172 AFS_STATCNT(afs_CheckCacheResets);
173 ObtainReadLock(&afs_xvcache);
174 ObtainReadLock(&afs_xuser);
176 for (i = 0; i < NUSERS; i++) {
177 for (tu = afs_users[i]; tu; tu = tu->next) {
178 register afs_int32 uid;
181 * If tokens are still good and user has Kerberos tickets,
184 if (!(tu->states & UTokensBad) && tu->vid != UNDEFVID) {
185 if (tu->ct.EndTimestamp < now) {
187 * This token has expired, warn users and reset access
191 /* I really hate this message - MLK */
193 ("afs: Tokens for user of AFS id %d for cell %s expired now\n",
194 tu->vid, afs_GetCell(tu->cell)->cellName);
196 tu->states |= (UTokensBad | UNeedsReset);
199 if (tu->states & UNeedsReset) {
200 tu->states &= ~UNeedsReset;
202 afs_ResetAccessCache(uid, 0);
206 ReleaseReadLock(&afs_xuser);
207 ReleaseReadLock(&afs_xvcache);
209 } /*afs_CheckTokenCache */
213 afs_ResetAccessCache(afs_int32 uid, int alock)
216 register struct vcache *tvc;
219 AFS_STATCNT(afs_ResetAccessCache);
221 ObtainReadLock(&afs_xvcache);
222 for (i = 0; i < VCSIZE; i++) {
223 for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
224 /* really should do this under cache write lock, but that.
225 * is hard to under locking hierarchy */
226 if (tvc->Access && (ac = afs_FindAxs(tvc->Access, uid))) {
227 afs_RemoveAxs(&tvc->Access, ac);
232 ReleaseReadLock(&afs_xvcache);
234 } /*afs_ResetAccessCache */
238 * Ensure all connections make use of new tokens. Discard incorrectly-cached
242 afs_ResetUserConns(register struct unixuser *auser)
248 AFS_STATCNT(afs_ResetUserConns);
249 ObtainReadLock(&afs_xsrvAddr);
250 ObtainWriteLock(&afs_xconn, 98);
252 for (i = 0; i < NSERVERS; i++) {
253 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
254 for (tc = sa->conns; tc; tc = tc->next) {
255 if (tc->user == auser) {
256 tc->forceConnectFS = 1;
262 ReleaseWriteLock(&afs_xconn);
263 ReleaseReadLock(&afs_xsrvAddr);
264 afs_ResetAccessCache(auser->uid, 1);
265 auser->states &= ~UNeedsReset;
266 } /*afs_ResetUserConns */
267 #endif /* !AFS_PAG_MANAGER */
271 afs_FindUser(afs_int32 auid, afs_int32 acell, afs_int32 locktype)
273 register struct unixuser *tu;
274 register afs_int32 i;
276 AFS_STATCNT(afs_FindUser);
278 ObtainWriteLock(&afs_xuser, 99);
279 for (tu = afs_users[i]; tu; tu = tu->next) {
280 if (tu->uid == auid && ((tu->cell == acell) || (acell == -1))) {
282 ReleaseWriteLock(&afs_xuser);
286 ReleaseWriteLock(&afs_xuser);
292 /*------------------------------------------------------------------------
293 * EXPORTED afs_ComputePAGStats
296 * Compute a set of stats concerning PAGs used by this machine.
305 * The results are put in the structure responsible for keeping
306 * detailed CM stats. Note: entries corresponding to a single PAG
307 * will appear on the identical hash chain, so sweeping the chain
308 * will find all entries related to a single PAG.
312 *------------------------------------------------------------------------*/
315 afs_ComputePAGStats(void)
317 register struct unixuser *currPAGP; /*Ptr to curr PAG */
318 register struct unixuser *cmpPAGP; /*Ptr to PAG being compared */
319 register struct afs_stats_AuthentInfo *authP; /*Ptr to stats area */
320 int curr_Record; /*Curr record */
321 int currChain; /*Curr hash chain */
322 int currChainLen; /*Length of curr hash chain */
323 int currPAGRecords; /*# records in curr PAG */
326 * Lock out everyone else from scribbling on the PAG entries.
328 ObtainReadLock(&afs_xuser);
331 * Initialize the tallies, then sweep through each hash chain. We
332 * can't bzero the structure, since some fields are cumulative over
336 authP = &(afs_stats_cmfullperf.authent);
337 authP->curr_PAGs = 0;
338 authP->curr_Records = 0;
339 authP->curr_AuthRecords = 0;
340 authP->curr_UnauthRecords = 0;
341 authP->curr_MaxRecordsInPAG = 0;
342 authP->curr_LongestChain = 0;
344 for (currChain = 0; currChain < NUSERS; currChain++) {
346 for (currPAGP = afs_users[currChain]; currPAGP;
347 currPAGP = currPAGP->next) {
349 * Bump the number of records on this current chain, along with
350 * the total number of records in existence.
355 * We've found a previously-uncounted PAG. If it's been deleted
356 * but just not garbage-collected yet, we step over it.
358 if (currPAGP->vid == UNDEFVID)
362 * If this PAG record has already been ``counted', namely
363 * associated with a PAG and tallied, clear its bit and move on.
365 (authP->curr_Records)++;
366 if (currPAGP->states & UPAGCounted) {
367 currPAGP->states &= ~UPAGCounted;
373 /*We've counted this one already */
375 * Jot initial info down, then sweep down the rest of the hash
376 * chain, looking for matching PAG entries. Note: to properly
377 * ``count'' the current record, we first compare it to itself
378 * in the following loop.
380 (authP->curr_PAGs)++;
383 for (cmpPAGP = currPAGP; cmpPAGP; cmpPAGP = cmpPAGP->next) {
384 if (currPAGP->uid == cmpPAGP->uid) {
386 * The records belong to the same PAG. First, mark the
387 * new record as ``counted'' and bump the PAG size.
388 * Then, record the state of its ticket, if any.
390 cmpPAGP->states |= UPAGCounted;
392 if ((cmpPAGP->states & UHasTokens)
393 && !(cmpPAGP->states & UTokensBad))
394 (authP->curr_AuthRecords)++;
396 (authP->curr_UnauthRecords)++;
397 } /*Records belong to same PAG */
398 } /*Compare to rest of PAG records in chain */
401 * In the above comparisons, the current PAG record has been
402 * marked as counted. Erase this mark before moving on.
404 currPAGP->states &= ~UPAGCounted;
407 * We've compared our current PAG record with all remaining
408 * PAG records in the hash chain. Update our tallies, and
409 * perhaps even our lifetime high water marks. After that,
410 * remove our search mark and advance to the next comparison
413 if (currPAGRecords > authP->curr_MaxRecordsInPAG) {
414 authP->curr_MaxRecordsInPAG = currPAGRecords;
415 if (currPAGRecords > authP->HWM_MaxRecordsInPAG)
416 authP->HWM_MaxRecordsInPAG = currPAGRecords;
418 } /*Sweep a hash chain */
421 * If the chain we just finished zipping through is the longest we've
422 * seen yet, remember this fact before advancing to the next chain.
424 if (currChainLen > authP->curr_LongestChain) {
425 authP->curr_LongestChain = currChainLen;
426 if (currChainLen > authP->HWM_LongestChain)
427 authP->HWM_LongestChain = currChainLen;
430 } /*For each hash chain in afs_user */
433 * Now that we've counted everything up, we can consider all-time
436 if (authP->curr_PAGs > authP->HWM_PAGs)
437 authP->HWM_PAGs = authP->curr_PAGs;
438 if (authP->curr_Records > authP->HWM_Records)
439 authP->HWM_Records = authP->curr_Records;
442 * People are free to manipulate the PAG structures now.
444 ReleaseReadLock(&afs_xuser);
446 } /*afs_ComputePAGStats */
450 afs_GetUser(register afs_int32 auid, afs_int32 acell, afs_int32 locktype)
452 register struct unixuser *tu, *pu = 0;
453 register afs_int32 i;
454 register afs_int32 RmtUser = 0;
456 AFS_STATCNT(afs_GetUser);
458 ObtainWriteLock(&afs_xuser, 104);
459 for (tu = afs_users[i]; tu; tu = tu->next) {
460 if (tu->uid == auid) {
467 if (tu->cell == -1 && acell != -1) {
468 /* Here we setup the real cell for the client */
471 ReleaseWriteLock(&afs_xuser);
473 } else if (tu->cell == acell || acell == -1) {
475 ReleaseWriteLock(&afs_xuser);
480 tu = (struct unixuser *)afs_osi_Alloc(sizeof(struct unixuser));
482 afs_stats_cmfullperf.authent.PAGCreations++;
483 #endif /* AFS_NOSTATS */
484 memset((char *)tu, 0, sizeof(struct unixuser));
485 tu->next = afs_users[i];
489 * This is for the case where an additional unixuser struct is
490 * created because the remote client is accessing a different cell;
491 * we simply rerecord relevant information from the original
494 if (pu && pu->exporter) {
495 (void)EXP_HOLD(tu->exporter = pu->exporter);
502 tu->tokenTime = osi_Time();
503 ReleaseWriteLock(&afs_xuser);
510 afs_PutUser(register struct unixuser *au, afs_int32 locktype)
512 AFS_STATCNT(afs_PutUser);
518 * Set the primary flag on a unixuser structure, ensuring that exactly one
519 * dude has the flag set at any time for a particular unix uid.
522 afs_SetPrimary(register struct unixuser *au, register int aflag)
524 register struct unixuser *tu;
528 AFS_STATCNT(afs_SetPrimary);
531 ObtainWriteLock(&afs_xuser, 105);
533 * See if anyone is this uid's primary cell yet; recording in pu the
536 for (tu = afs_users[i]; tu; tu = tu->next) {
537 if (tu->uid == au->uid && (tu->states & UPrimary)) {
541 if (pu && !(pu->states & UHasTokens)) {
543 * Primary user has unlogged, don't treat him as primary any longer;
544 * note that we want to treat him as primary until now, so that
545 * people see a primary identity until now.
547 pu->states &= ~UPrimary;
551 /* setting au to be primary */
553 pu->states &= ~UPrimary;
554 au->states |= UPrimary;
555 } else if (aflag == 0) {
556 /* we don't know if we're supposed to be primary or not */
557 if (!pu || au == pu) {
558 au->states |= UPrimary;
560 au->states &= ~UPrimary;
562 ReleaseWriteLock(&afs_xuser);
564 } /*afs_SetPrimary */
570 * Called by osi_TraverseProcTable (from afs_GCPAGs) for each
571 * process in the system.
572 * If the specified process uses a PAG, clear that PAG's temporary
577 * This variable keeps track of the number of UID-base
578 * tokens in the afs_users table. When it's zero
579 * the per process loop in GCPAGs doesn't have to
580 * check processes without pags against the afs_users table.
582 static afs_int32 afs_GCPAGs_UIDBaseTokenCount = 0;
585 * These variables keep track of the number of times
586 * afs_GCPAGs_perproc_func() is called. If it is not called at all when
587 * walking the process table, there is something wrong and we should not
588 * prematurely expire any tokens.
590 static size_t afs_GCPAGs_perproc_count = 0;
591 static size_t afs_GCPAGs_cred_count = 0;
594 * LOCKS: afs_GCPAGs_perproc_func requires write lock on afs_xuser
596 #if !defined(LINUX_KEYRING_SUPPORT) && (!defined(STRUCT_TASK_HAS_CRED) || defined(EXPORTED_RCU_READ_LOCK))
598 afs_GCPAGs_perproc_func(AFS_PROC * pproc)
600 afs_int32 pag, hash, uid;
601 const struct AFS_UCRED *pcred;
603 afs_GCPAGs_perproc_count++;
605 pcred = afs_osi_proc2cred(pproc);
609 afs_GCPAGs_cred_count++;
611 pag = PagInCred(pcred);
612 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD40_ENV) || defined(AFS_LINUX22_ENV)
613 uid = (pag != NOPAG ? pag : pcred->cr_uid);
614 #elif defined(AFS_SUN510_ENV)
615 uid = (pag != NOPAG ? pag : crgetruid(pcred));
617 uid = (pag != NOPAG ? pag : pcred->cr_ruid);
621 /* if this token is PAG based, or it's UID based and
622 * UID-based tokens exist */
623 if ((pag != NOPAG) || (afs_GCPAGs_UIDBaseTokenCount)) {
624 /* find the entries for this uid in all cells and clear the not
625 * referenced flag. Can't use afs_FindUser, because it just returns
626 * the specific cell asked for, or the first one found.
629 for (pu = afs_users[hash]; pu; pu = pu->next) {
630 if (pu->uid == uid) {
631 if (pu->states & TMP_UPAGNotReferenced) {
632 /* clear the 'deleteme' flag for this entry */
633 pu->states &= ~TMP_UPAGNotReferenced;
635 /* This is a uid based token that hadn't
636 * previously been cleared, so decrement the
637 * outstanding uid based token count */
638 afs_GCPAGs_UIDBaseTokenCount--;
648 * Go through the process table, find all unused PAGs
649 * and cause them to be deleted during the next GC.
651 * returns the number of PAGs marked for deletion
653 * On AIX we free PAGs when the last accessing process exits,
654 * so this routine is not needed.
656 * In AFS WebSecure, we explicitly call unlog when we remove
657 * an entry in the login cache, so this routine is not needed.
661 afs_GCPAGs(afs_int32 * ReleasedCount)
666 if (afs_gcpags != AFS_GCPAGS_OK) {
672 /* first, loop through afs_users, setting the temporary 'deleteme' flag */
673 ObtainWriteLock(&afs_xuser, 419);
674 afs_GCPAGs_UIDBaseTokenCount = 0;
675 for (i = 0; i < NUSERS; i++) {
676 for (pu = afs_users[i]; pu; pu = pu->next) {
677 pu->states |= TMP_UPAGNotReferenced;
678 if (((pu->uid >> 24) & 0xff) != 'A') {
679 /* this is a uid-based token, */
680 /* increment the count */
681 afs_GCPAGs_UIDBaseTokenCount++;
686 /* Now, iterate through the systems process table,
687 * for each process, mark it's PAGs (if any) in use.
688 * i.e. clear the temporary deleteme flag.
690 afs_GCPAGs_perproc_count = 0;
691 afs_GCPAGs_cred_count = 0;
693 afs_osi_TraverseProcTable();
695 /* If there is an internal problem and afs_GCPAGs_perproc_func()
696 * does not get called, disable gcpags so that we do not
697 * accidentally expire all the tokens in the system.
699 if (afs_gcpags == AFS_GCPAGS_OK && !afs_GCPAGs_perproc_count) {
700 afs_gcpags = AFS_GCPAGS_EPROCWALK;
703 if (afs_gcpags == AFS_GCPAGS_OK && !afs_GCPAGs_cred_count) {
704 afs_gcpags = AFS_GCPAGS_ECREDWALK;
707 /* Now, go through afs_users again, any that aren't in use
708 * (temp deleteme flag still set) will be marked for later deletion,
709 * by setting their expire times to 0.
711 for (i = 0; i < NUSERS; i++) {
712 for (pu = afs_users[i]; pu; pu = pu->next) {
713 if (pu->states & TMP_UPAGNotReferenced) {
715 /* clear the temp flag */
716 pu->states &= ~TMP_UPAGNotReferenced;
718 /* Is this entry on behalf of a 'remote' user ?
719 * i.e. nfs translator, etc.
721 if (!pu->exporter && afs_gcpags == AFS_GCPAGS_OK) {
722 /* set the expire times to 0, causes
723 * afs_GCUserData to remove this entry
725 pu->ct.EndTimestamp = 0;
728 (*ReleasedCount)++; /* remember how many we marked (info only) */
734 ReleaseWriteLock(&afs_xuser);
739 #endif /* AFS_GCPAGS */