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/stds.h"
19 #include "../afs/sysincludes.h" /* Standard vendor system headers */
23 #include <netinet/in.h>
26 #include "../h/hashing.h"
28 #if !defined(AFS_HPUX110_ENV) && !defined(AFS_LINUX20_ENV)
29 #include <netinet/in_var.h>
30 #endif /* ! AFS_HPUX110_ENV */
31 #endif /* !defined(UKERNEL) */
33 #include "../afs/afsincludes.h" /* Afs-based standard headers */
34 #include "../afs/afs_stats.h" /* afs statistics */
36 #if defined(AFS_SUN56_ENV)
38 #include <inet/common.h>
39 #if defined(AFS_SUN58_ENV)
40 #include <netinet/ip6.h>
46 /* Imported variables */
47 extern afs_rwlock_t afs_xserver;
48 extern afs_rwlock_t afs_xsrvAddr;
49 extern afs_rwlock_t afs_xconn;
50 extern afs_rwlock_t afs_xvcache;
51 extern struct srvAddr *afs_srvAddrs[NSERVERS]; /* Hashed by server's ip */
52 extern struct server *afs_servers[NSERVERS];
54 /* Exported variables */
55 afs_rwlock_t afs_xuser;
56 struct unixuser *afs_users[NUSERS];
59 /* Forward declarations */
60 void afs_ResetAccessCache(afs_int32 uid, int alock);
63 * Called with afs_xuser, afs_xserver and afs_xconn locks held, to delete
64 * appropriate conn structures for au
66 static void RemoveUserConns(au)
67 register struct unixuser *au;
70 register struct server *ts;
71 register struct srvAddr *sa;
72 register struct conn *tc, **lc;
74 AFS_STATCNT(RemoveUserConns);
75 for (i=0;i<NSERVERS;i++) {
76 for (ts = afs_servers[i]; ts; ts=ts->next) {
77 for (sa = ts->addr; sa; sa = sa->next_sa) {
79 for (tc = *lc; tc; lc = &tc->next, tc = *lc) {
80 if (tc->user == au && tc->refCount == 0) {
83 rx_DestroyConnection(tc->id);
85 afs_osi_Free(tc, sizeof(struct conn));
86 break; /* at most one instance per server */
87 } /*Found unreferenced connection for user*/
88 } /*For each connection on the server*/
90 } /*For each server on chain*/
96 /* Called from afs_Daemon to garbage collect unixusers no longer using system,
97 * and their conns. The aforce parameter tells the function to flush all
98 * *unauthenticated* conns, no matter what their expiration time; it exists
99 * because after we choose our final rx epoch, we want to stop using calls with
100 * other epochs as soon as possible (old file servers act bizarrely when they
101 * see epoch changes).
103 void afs_GCUserData(aforce) {
104 register struct unixuser *tu, **lu, *nu;
106 afs_int32 now, delFlag;
108 AFS_STATCNT(afs_GCUserData);
109 /* Obtain locks in valid order */
110 ObtainWriteLock(&afs_xuser,95);
111 ObtainReadLock(&afs_xserver);
112 ObtainWriteLock(&afs_xconn,96);
114 for (i=0;i<NUSERS;i++) {
115 for (lu = &afs_users[i], tu = *lu; tu; tu = nu) {
116 delFlag = 0; /* should we delete this dude? */
117 /* Don't garbage collect users in use now (refCount) */
118 if (tu->refCount == 0) {
119 if (tu->states & UHasTokens) {
121 * Give ourselves a little extra slack, in case we
124 if (tu->ct.EndTimestamp < now - NOTOKTIMEOUT)
128 if (aforce || (tu->tokenTime < now - NOTOKTIMEOUT))
137 afs_osi_Free(tu->stp, tu->stLen);
139 EXP_RELE(tu->exporter);
140 afs_osi_Free(tu, sizeof(struct unixuser));
147 ReleaseWriteLock(&afs_xconn);
148 ReleaseWriteLock(&afs_xuser);
149 ReleaseReadLock(&afs_xserver);
155 * Check for unixusers who encountered bad tokens, and reset the access
156 * cache for these guys. Can't do this when token expiration detected,
157 * since too many locks are set then.
159 void afs_CheckTokenCache()
163 register struct unixuser *tu;
165 register struct cell *tcell;
167 AFS_STATCNT(afs_CheckCacheResets);
168 ObtainReadLock(&afs_xvcache);
169 ObtainReadLock(&afs_xuser);
171 for (i=0;i<NUSERS;i++) {
172 for (tu=afs_users[i]; tu; tu=tu->next) {
173 register afs_int32 uid;
176 * If tokens are still good and user has Kerberos tickets,
179 if (!(tu->states & UTokensBad) && tu->vid != UNDEFVID) {
180 if (tu->ct.EndTimestamp < now) {
182 * This token has expired, warn users and reset access
186 tcell = afs_GetCell(tu->cell);
187 /* I really hate this message - MLK */
188 afs_warn("afs: Tokens for user of AFS id %d for cell %s expired now\n",
189 tu->vid, tcell->cellName);
191 tu->states |= (UTokensBad | UNeedsReset);
194 if (tu->states & UNeedsReset) {
195 tu->states &= ~UNeedsReset;
197 afs_ResetAccessCache(uid, 0);
201 ReleaseReadLock(&afs_xuser);
202 ReleaseReadLock(&afs_xvcache);
204 } /*afs_CheckTokenCache*/
207 void afs_ResetAccessCache(afs_int32 uid, int alock)
210 register struct vcache *tvc;
213 AFS_STATCNT(afs_ResetAccessCache);
215 ObtainReadLock(&afs_xvcache);
216 for(i=0;i<VCSIZE;i++) {
217 for(tvc=afs_vhashT[i]; tvc; tvc=tvc->hnext) {
218 /* really should do this under cache write lock, but that.
219 is hard to under locking hierarchy */
220 if (tvc->Access && (ac = afs_FindAxs(tvc->Access, uid))) {
221 afs_RemoveAxs (&tvc->Access, ac);
226 ReleaseReadLock(&afs_xvcache);
228 } /*afs_ResetAccessCache*/
232 * Ensure all connections make use of new tokens. Discard incorrectly-cached
235 void afs_ResetUserConns (auser)
236 register struct unixuser *auser;
244 AFS_STATCNT(afs_ResetUserConns);
245 ObtainReadLock(&afs_xsrvAddr);
246 ObtainWriteLock(&afs_xconn,98);
248 for (i=0;i<NSERVERS;i++) {
249 for (sa = afs_srvAddrs[i]; sa; sa=sa->next_bkt) {
250 for (tc = sa->conns; tc; tc=tc->next) {
251 if (tc->user == auser) {
252 tc->forceConnectFS = 1;
258 ReleaseWriteLock(&afs_xconn);
259 ReleaseReadLock(&afs_xsrvAddr);
260 afs_ResetAccessCache(auser->uid, 1);
261 auser->states &= ~UNeedsReset;
262 } /*afs_ResetUserConns*/
265 struct unixuser *afs_FindUser(afs_int32 auid, afs_int32 acell, afs_int32 locktype)
267 register struct unixuser *tu;
268 register afs_int32 i;
270 AFS_STATCNT(afs_FindUser);
272 ObtainWriteLock(&afs_xuser,99);
273 for(tu = afs_users[i]; tu; tu = tu->next) {
274 if (tu->uid == auid && ((tu->cell == acell) || (acell == -1))) {
276 ReleaseWriteLock(&afs_xuser);
280 ReleaseWriteLock(&afs_xuser);
281 return (struct unixuser *) 0;
286 /*------------------------------------------------------------------------
287 * EXPORTED afs_ComputePAGStats
290 * Compute a set of stats concerning PAGs used by this machine.
299 * The results are put in the structure responsible for keeping
300 * detailed CM stats. Note: entries corresponding to a single PAG
301 * will appear on the identical hash chain, so sweeping the chain
302 * will find all entries related to a single PAG.
306 *------------------------------------------------------------------------*/
308 void afs_ComputePAGStats()
310 { /*afs_ComputePAGStats*/
312 register struct unixuser *currPAGP; /*Ptr to curr PAG*/
313 register struct unixuser *cmpPAGP; /*Ptr to PAG being compared*/
314 register struct afs_stats_AuthentInfo *authP; /*Ptr to stats area*/
315 int curr_Record; /*Curr record */
316 int currChain; /*Curr hash chain*/
317 int currChainLen; /*Length of curr hash chain*/
318 int currPAGRecords; /*# records in curr PAG*/
321 * Lock out everyone else from scribbling on the PAG entries.
323 ObtainReadLock(&afs_xuser);
326 * Initialize the tallies, then sweep through each hash chain. We
327 * can't bzero the structure, since some fields are cumulative over
331 authP = &(afs_stats_cmfullperf.authent);
332 authP->curr_PAGs = 0;
333 authP->curr_Records = 0;
334 authP->curr_AuthRecords = 0;
335 authP->curr_UnauthRecords = 0;
336 authP->curr_MaxRecordsInPAG = 0;
337 authP->curr_LongestChain = 0;
339 for (currChain = 0; currChain < NUSERS; currChain++) {
341 for (currPAGP = afs_users[currChain]; currPAGP;
342 currPAGP = currPAGP->next)
345 * Bump the number of records on this current chain, along with
346 * the total number of records in existence.
351 * We've found a previously-uncounted PAG. If it's been deleted
352 * but just not garbage-collected yet, we step over it.
354 if (currPAGP->vid == UNDEFVID)
358 * If this PAG record has already been ``counted', namely
359 * associated with a PAG and tallied, clear its bit and move on.
361 (authP->curr_Records)++;
362 if (currPAGP->states & UPAGCounted) {
363 currPAGP->states &= ~UPAGCounted;
365 } /*We've counted this one already*/
370 * Jot initial info down, then sweep down the rest of the hash
371 * chain, looking for matching PAG entries. Note: to properly
372 * ``count'' the current record, we first compare it to itself
373 * in the following loop.
375 (authP->curr_PAGs)++;
378 for (cmpPAGP = currPAGP; cmpPAGP; cmpPAGP = cmpPAGP->next) {
379 if (currPAGP->uid == cmpPAGP->uid) {
381 * The records belong to the same PAG. First, mark the
382 * new record as ``counted'' and bump the PAG size.
383 * Then, record the state of its ticket, if any.
385 cmpPAGP->states |= UPAGCounted;
387 if ((cmpPAGP->states & UHasTokens) &&
388 !(cmpPAGP->states & UTokensBad))
389 (authP->curr_AuthRecords)++;
391 (authP->curr_UnauthRecords)++;
392 } /*Records belong to same PAG*/
393 } /*Compare to rest of PAG records in chain*/
396 * In the above comparisons, the current PAG record has been
397 * marked as counted. Erase this mark before moving on.
399 currPAGP->states &= ~UPAGCounted;
402 * We've compared our current PAG record with all remaining
403 * PAG records in the hash chain. Update our tallies, and
404 * perhaps even our lifetime high water marks. After that,
405 * remove our search mark and advance to the next comparison
408 if (currPAGRecords > authP->curr_MaxRecordsInPAG) {
409 authP->curr_MaxRecordsInPAG = currPAGRecords;
410 if (currPAGRecords > authP->HWM_MaxRecordsInPAG)
411 authP->HWM_MaxRecordsInPAG = currPAGRecords;
413 } /*Sweep a hash chain*/
416 * If the chain we just finished zipping through is the longest we've
417 * seen yet, remember this fact before advancing to the next chain.
419 if (currChainLen > authP->curr_LongestChain) {
420 authP->curr_LongestChain = currChainLen;
421 if (currChainLen > authP->HWM_LongestChain)
422 authP->HWM_LongestChain = currChainLen;
425 } /*For each hash chain in afs_user*/
428 * Now that we've counted everything up, we can consider all-time
431 if (authP->curr_PAGs > authP->HWM_PAGs)
432 authP->HWM_PAGs = authP->curr_PAGs;
433 if (authP->curr_Records > authP->HWM_Records)
434 authP->HWM_Records = authP->curr_Records;
437 * People are free to manipulate the PAG structures now.
439 ReleaseReadLock(&afs_xuser);
441 } /*afs_ComputePAGStats*/
444 struct unixuser *afs_GetUser(auid, acell, locktype)
446 register afs_int32 auid;
449 register struct unixuser *tu, *pu=0;
450 register afs_int32 i;
451 register afs_int32 RmtUser = 0;
453 AFS_STATCNT(afs_GetUser);
455 ObtainWriteLock(&afs_xuser,104);
456 for (tu = afs_users[i]; tu; tu = tu->next) {
457 if (tu->uid == auid) {
459 pu = (struct unixuser *)0;
464 if (tu->cell == -1 && acell != -1) {
465 /* Here we setup the real cell for the client */
468 ReleaseWriteLock(&afs_xuser);
471 if (tu->cell == acell || acell == -1) {
473 ReleaseWriteLock(&afs_xuser);
478 tu = (struct unixuser *) afs_osi_Alloc(sizeof(struct unixuser));
480 afs_stats_cmfullperf.authent.PAGCreations++;
481 #endif /* AFS_NOSTATS */
482 memset((char *)tu, 0, sizeof(struct unixuser));
483 tu->next = afs_users[i];
487 * This is for the case where an additional unixuser struct is
488 * created because the remote client is accessing a different cell;
489 * we simply rerecord relevant information from the original
492 if (pu && pu->exporter) {
493 (void) EXP_HOLD(tu->exporter = pu->exporter);
500 tu->tokenTime = osi_Time();
501 ReleaseWriteLock(&afs_xuser);
507 void afs_PutUser(au, locktype)
508 register struct unixuser *au;
511 AFS_STATCNT(afs_PutUser);
517 * Set the primary flag on a unixuser structure, ensuring that exactly one
518 * dude has the flag set at any time for a particular unix uid.
520 void afs_SetPrimary(au, aflag)
521 register struct unixuser *au;
525 register struct unixuser *tu;
529 AFS_STATCNT(afs_SetPrimary);
531 pu = (struct unixuser *) 0;
532 ObtainWriteLock(&afs_xuser,105);
534 * See if anyone is this uid's primary cell yet; recording in pu the
537 for (tu=afs_users[i]; tu; tu=tu->next) {
538 if (tu->uid == au->uid && (tu->states & UPrimary)) {
542 if (pu && !(pu->states & UHasTokens)) {
544 * Primary user has unlogged, don't treat him as primary any longer;
545 * note that we want to treat him as primary until now, so that
546 * people see a primary identity until now.
548 pu->states &= ~UPrimary;
549 pu = (struct unixuser *) 0;
552 /* setting au to be primary */
553 if (pu) pu->states &= ~UPrimary;
554 au->states |= UPrimary;
558 /* we don't know if we're supposed to be primary or not */
559 if (!pu || au == pu) {
560 au->states |= UPrimary;
563 au->states &= ~UPrimary;
565 ReleaseWriteLock(&afs_xuser);
573 * Called by osi_TraverseProcTable (from afs_GCPAGs) for each
574 * process in the system.
575 * If the specified process uses a PAG, clear that PAG's temporary
580 * This variable keeps track of the number of UID-base
581 * tokens in the afs_users table. When it's zero
582 * the per process loop in GCPAGs doesn't have to
583 * check processes without pags against the afs_users table.
585 static afs_int32 afs_GCPAGs_UIDBaseTokenCount=0;
588 * These variables keep track of the number of times
589 * afs_GCPAGs_perproc_func() is called. If it is not called at all when
590 * walking the process table, there is something wrong and we should not
591 * prematurely expire any tokens.
593 static size_t afs_GCPAGs_perproc_count=0;
594 static size_t afs_GCPAGs_cred_count=0;
597 * LOCKS: afs_GCPAGs_perproc_func requires write lock on afs_xuser
599 void afs_GCPAGs_perproc_func(AFS_PROC *pproc)
601 afs_int32 pag, hash, uid;
602 const struct AFS_UCRED *pcred;
604 afs_GCPAGs_perproc_count++;
606 pcred = afs_osi_proc2cred(pproc);
610 afs_GCPAGs_cred_count++;
612 pag = PagInCred(pcred);
613 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD40_ENV)
614 uid = (pag != NOPAG ? pag : pcred->cr_uid);
616 uid = (pag != NOPAG ? pag : pcred->cr_ruid);
620 /* if this token is PAG based, or it's UID based and
621 UID-based tokens exist */
622 if((pag != NOPAG) || (afs_GCPAGs_UIDBaseTokenCount)) {
623 /* find the entries for this uid in all cells and clear the not
624 * referenced flag. Can't use afs_FindUser, because it just returns
625 * the specific cell asked for, or the first one found.
628 for(pu = afs_users[hash]; pu; pu = pu->next) {
629 if (pu->uid == uid) {
630 if(pu->states & TMP_UPAGNotReferenced) {
631 /* clear the 'deleteme' flag for this entry */
632 pu->states &= ~TMP_UPAGNotReferenced;
634 /* This is a uid based token that hadn't
635 previously been cleared, so decrement the
636 outstanding uid based token count */
637 afs_GCPAGs_UIDBaseTokenCount--;
646 * Go through the process table, find all unused PAGs
647 * and cause them to be deleted during the next GC.
649 * returns the number of PAGs marked for deletion
651 * On AIX we free PAGs when the last accessing process exits,
652 * so this routine is not needed.
654 * In AFS WebSecure, we explicitly call unlog when we remove
655 * an entry in the login cache, so this routine is not needed.
658 afs_int32 afs_GCPAGs(afs_int32 *ReleasedCount)
663 if (afs_gcpags != AFS_GCPAGS_OK) {
669 /* first, loop through afs_users, setting the temporary 'deleteme' flag */
670 ObtainWriteLock(&afs_xuser,419);
671 afs_GCPAGs_UIDBaseTokenCount=0;
672 for(i=0; i < NUSERS; i++) {
673 for(pu = afs_users[i]; pu; pu = pu->next) {
674 pu->states |= TMP_UPAGNotReferenced;
675 if (((pu->uid >> 24) & 0xff) != 'A') {
676 /* this is a uid-based token, */
677 /* increment the count */
678 afs_GCPAGs_UIDBaseTokenCount++;
683 /* Now, iterate through the systems process table,
684 * for each process, mark it's PAGs (if any) in use.
685 * i.e. clear the temporary deleteme flag.
687 afs_GCPAGs_perproc_count=0;
688 afs_GCPAGs_cred_count=0;
690 afs_osi_TraverseProcTable();
692 /* If there is an internal problem and afs_GCPAGs_perproc_func()
693 * does not get called, disable gcpags so that we do not
694 * accidentally expire all the tokens in the system.
696 if (afs_gcpags == AFS_GCPAGS_OK && !afs_GCPAGs_perproc_count) {
697 afs_gcpags = AFS_GCPAGS_EPROCWALK;
700 if (afs_gcpags == AFS_GCPAGS_OK && !afs_GCPAGs_cred_count) {
701 afs_gcpags = AFS_GCPAGS_ECREDWALK;
704 /* Now, go through afs_users again, any that aren't in use
705 * (temp deleteme flag still set) will be marked for later deletion,
706 * by setting their expire times to 0.
708 for(i=0; i < NUSERS; i++) {
709 for(pu = afs_users[i]; pu; pu = pu->next) {
710 if(pu->states & TMP_UPAGNotReferenced) {
712 /* clear the temp flag */
713 pu->states &= ~TMP_UPAGNotReferenced;
715 /* Is this entry on behalf of a 'remote' user ?
716 * i.e. nfs translator, etc.
718 if(!pu->exporter && afs_gcpags == AFS_GCPAGS_OK) {
719 /* set the expire times to 0, causes
720 * afs_GCUserData to remove this entry
722 pu->ct.EndTimestamp = 0;
725 (*ReleasedCount)++; /* remember how many we marked (info only) */
731 ReleaseWriteLock(&afs_xuser);
736 #endif /* AFS_GCPAGS */