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_SUN56_ENV)
39 #include <inet/common.h>
40 #if defined(AFS_SUN58_ENV)
41 #include <netinet/ip6.h>
47 /* Exported variables */
48 afs_rwlock_t afs_xuser;
49 struct unixuser *afs_users[NUSERS];
52 #ifndef AFS_PAG_MANAGER
53 /* Forward declarations */
54 void afs_ResetAccessCache(afs_int32 uid, int alock);
55 #endif /* !AFS_PAG_MANAGER */
58 /* Called from afs_Daemon to garbage collect unixusers no longer using system,
59 * and their conns. The aforce parameter tells the function to flush all
60 * *unauthenticated* conns, no matter what their expiration time; it exists
61 * because after we choose our final rx epoch, we want to stop using calls with
62 * other epochs as soon as possible (old file servers act bizarrely when they
66 afs_GCUserData(int aforce)
68 struct unixuser *tu, **lu, *nu;
70 afs_int32 now, delFlag;
72 AFS_STATCNT(afs_GCUserData);
73 /* Obtain locks in valid order */
74 ObtainWriteLock(&afs_xuser, 95);
75 #ifndef AFS_PAG_MANAGER
76 ObtainReadLock(&afs_xserver);
77 ObtainWriteLock(&afs_xconn, 96);
80 for (i = 0; i < NUSERS; i++) {
81 for (lu = &afs_users[i], tu = *lu; tu; tu = nu) {
82 delFlag = 0; /* should we delete this dude? */
83 /* Don't garbage collect users in use now (refCount) */
84 if (tu->refCount == 0) {
86 /* Need to walk the token stack, and dispose of
87 * all expired tokens */
88 afs_DiscardExpiredTokens(&tu->tokens, now);
89 if (!afs_HasUsableTokens(tu->tokens, now))
92 if (aforce || (tu->tokenTime < now - NOTOKTIMEOUT))
99 #ifndef AFS_PAG_MANAGER
100 afs_ReleaseConnsUser(tu);
102 afs_FreeTokens(&tu->tokens);
105 EXP_RELE(tu->exporter);
106 afs_osi_Free(tu, sizeof(struct unixuser));
112 #ifndef AFS_PAG_MANAGER
113 ReleaseWriteLock(&afs_xconn);
115 #ifndef AFS_PAG_MANAGER
116 ReleaseReadLock(&afs_xserver);
118 ReleaseWriteLock(&afs_xuser);
120 } /*afs_GCUserData */
123 #ifndef AFS_PAG_MANAGER
125 * Check for unixusers who encountered bad tokens, and reset the access
126 * cache for these guys. Can't do this when token expiration detected,
127 * since too many locks are set then.
130 afs_CheckTokenCache(void)
136 AFS_STATCNT(afs_CheckCacheResets);
137 ObtainReadLock(&afs_xvcache);
138 ObtainReadLock(&afs_xuser);
140 for (i = 0; i < NUSERS; i++) {
141 for (tu = afs_users[i]; tu; tu = tu->next) {
145 * If tokens are still good and user has Kerberos tickets,
148 if ((tu->states & UHasTokens) && !(tu->states & UTokensBad)) {
149 if (!afs_HasUsableTokens(tu->tokens, now)) {
151 * This token has expired, warn users and reset access
154 tu->states |= (UTokensBad | UNeedsReset);
157 if (tu->states & UNeedsReset) {
158 tu->states &= ~UNeedsReset;
160 afs_ResetAccessCache(uid, 0);
164 ReleaseReadLock(&afs_xuser);
165 ReleaseReadLock(&afs_xvcache);
166 } /*afs_CheckTokenCache */
170 afs_ResetAccessCache(afs_int32 uid, int alock)
176 AFS_STATCNT(afs_ResetAccessCache);
178 ObtainReadLock(&afs_xvcache);
179 for (i = 0; i < VCSIZE; i++) {
180 for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
181 /* really should do this under cache write lock, but that.
182 * is hard to under locking hierarchy */
183 if (tvc->Access && (ac = afs_FindAxs(tvc->Access, uid))) {
184 afs_RemoveAxs(&tvc->Access, ac);
189 ReleaseReadLock(&afs_xvcache);
191 } /*afs_ResetAccessCache */
195 * Ensure all connections make use of new tokens. Discard incorrectly-cached
199 afs_ResetUserConns(struct unixuser *auser)
203 struct sa_conn_vector *tcv;
205 AFS_STATCNT(afs_ResetUserConns);
206 ObtainReadLock(&afs_xsrvAddr);
207 ObtainWriteLock(&afs_xconn, 98);
209 for (i = 0; i < NSERVERS; i++) {
210 for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
211 for (tcv = sa->conns; tcv; tcv = tcv->next) {
212 if (tcv->user == auser) {
213 for(j = 0; j < CVEC_LEN; ++j) {
214 (tcv->cvec[j]).forceConnectFS = 1;
221 ReleaseWriteLock(&afs_xconn);
222 ReleaseReadLock(&afs_xsrvAddr);
223 afs_ResetAccessCache(auser->uid, 1);
224 auser->states &= ~UNeedsReset;
225 } /*afs_ResetUserConns */
226 #endif /* !AFS_PAG_MANAGER */
230 afs_FindUser(afs_int32 auid, afs_int32 acell, afs_int32 locktype)
235 AFS_STATCNT(afs_FindUser);
237 ObtainWriteLock(&afs_xuser, 99);
238 for (tu = afs_users[i]; tu; tu = tu->next) {
239 if (tu->uid == auid && ((tu->cell == acell) || (acell == -1))) {
241 ReleaseWriteLock(&afs_xuser);
245 ReleaseWriteLock(&afs_xuser);
251 /*------------------------------------------------------------------------
252 * EXPORTED afs_ComputePAGStats
255 * Compute a set of stats concerning PAGs used by this machine.
264 * The results are put in the structure responsible for keeping
265 * detailed CM stats. Note: entries corresponding to a single PAG
266 * will appear on the identical hash chain, so sweeping the chain
267 * will find all entries related to a single PAG.
271 *------------------------------------------------------------------------*/
274 afs_ComputePAGStats(void)
276 struct unixuser *currPAGP; /*Ptr to curr PAG */
277 struct unixuser *cmpPAGP; /*Ptr to PAG being compared */
278 struct afs_stats_AuthentInfo *authP; /*Ptr to stats area */
279 int curr_Record; /*Curr record */
280 int currChain; /*Curr hash chain */
281 int currChainLen; /*Length of curr hash chain */
282 int currPAGRecords; /*# records in curr PAG */
285 * Lock out everyone else from scribbling on the PAG entries.
287 ObtainReadLock(&afs_xuser);
290 * Initialize the tallies, then sweep through each hash chain. We
291 * can't bzero the structure, since some fields are cumulative over
295 authP = &(afs_stats_cmfullperf.authent);
296 authP->curr_PAGs = 0;
297 authP->curr_Records = 0;
298 authP->curr_AuthRecords = 0;
299 authP->curr_UnauthRecords = 0;
300 authP->curr_MaxRecordsInPAG = 0;
301 authP->curr_LongestChain = 0;
303 for (currChain = 0; currChain < NUSERS; currChain++) {
305 for (currPAGP = afs_users[currChain]; currPAGP;
306 currPAGP = currPAGP->next) {
308 * Bump the number of records on this current chain, along with
309 * the total number of records in existence.
314 * We've found a previously-uncounted PAG. If it's been deleted
315 * but just not garbage-collected yet, we step over it.
317 if (!(currPAGP->states & UHasTokens))
321 * If this PAG record has already been ``counted', namely
322 * associated with a PAG and tallied, clear its bit and move on.
324 (authP->curr_Records)++;
325 if (currPAGP->states & UPAGCounted) {
326 currPAGP->states &= ~UPAGCounted;
332 /*We've counted this one already */
334 * Jot initial info down, then sweep down the rest of the hash
335 * chain, looking for matching PAG entries. Note: to properly
336 * ``count'' the current record, we first compare it to itself
337 * in the following loop.
339 (authP->curr_PAGs)++;
342 for (cmpPAGP = currPAGP; cmpPAGP; cmpPAGP = cmpPAGP->next) {
343 if (currPAGP->uid == cmpPAGP->uid) {
345 * The records belong to the same PAG. First, mark the
346 * new record as ``counted'' and bump the PAG size.
347 * Then, record the state of its ticket, if any.
349 cmpPAGP->states |= UPAGCounted;
351 if ((cmpPAGP->states & UHasTokens)
352 && !(cmpPAGP->states & UTokensBad))
353 (authP->curr_AuthRecords)++;
355 (authP->curr_UnauthRecords)++;
356 } /*Records belong to same PAG */
357 } /*Compare to rest of PAG records in chain */
360 * In the above comparisons, the current PAG record has been
361 * marked as counted. Erase this mark before moving on.
363 currPAGP->states &= ~UPAGCounted;
366 * We've compared our current PAG record with all remaining
367 * PAG records in the hash chain. Update our tallies, and
368 * perhaps even our lifetime high water marks. After that,
369 * remove our search mark and advance to the next comparison
372 if (currPAGRecords > authP->curr_MaxRecordsInPAG) {
373 authP->curr_MaxRecordsInPAG = currPAGRecords;
374 if (currPAGRecords > authP->HWM_MaxRecordsInPAG)
375 authP->HWM_MaxRecordsInPAG = currPAGRecords;
377 } /*Sweep a hash chain */
380 * If the chain we just finished zipping through is the longest we've
381 * seen yet, remember this fact before advancing to the next chain.
383 if (currChainLen > authP->curr_LongestChain) {
384 authP->curr_LongestChain = currChainLen;
385 if (currChainLen > authP->HWM_LongestChain)
386 authP->HWM_LongestChain = currChainLen;
389 } /*For each hash chain in afs_user */
392 * Now that we've counted everything up, we can consider all-time
395 if (authP->curr_PAGs > authP->HWM_PAGs)
396 authP->HWM_PAGs = authP->curr_PAGs;
397 if (authP->curr_Records > authP->HWM_Records)
398 authP->HWM_Records = authP->curr_Records;
401 * People are free to manipulate the PAG structures now.
403 ReleaseReadLock(&afs_xuser);
405 } /*afs_ComputePAGStats */
409 afs_GetUser(afs_int32 auid, afs_int32 acell, afs_int32 locktype)
411 struct unixuser *tu, *pu = 0;
413 afs_int32 RmtUser = 0;
415 AFS_STATCNT(afs_GetUser);
417 ObtainWriteLock(&afs_xuser, 104);
418 for (tu = afs_users[i]; tu; tu = tu->next) {
419 if (tu->uid == auid) {
426 if (tu->cell == -1 && acell != -1) {
427 /* Here we setup the real cell for the client */
430 ReleaseWriteLock(&afs_xuser);
432 } else if (tu->cell == acell || acell == -1) {
434 ReleaseWriteLock(&afs_xuser);
439 tu = afs_osi_Alloc(sizeof(struct unixuser));
440 osi_Assert(tu != NULL);
442 afs_stats_cmfullperf.authent.PAGCreations++;
443 #endif /* AFS_NOSTATS */
444 memset(tu, 0, sizeof(struct unixuser));
445 tu->next = afs_users[i];
449 * This is for the case where an additional unixuser struct is
450 * created because the remote client is accessing a different cell;
451 * we simply rerecord relevant information from the original
454 if (pu && pu->exporter) {
455 tu->exporter = pu->exporter;
456 (void)EXP_HOLD(tu->exporter);
461 tu->viceId = UNDEFVID;
463 tu->tokenTime = osi_Time();
464 ReleaseWriteLock(&afs_xuser);
471 afs_PutUser(struct unixuser *au, afs_int32 locktype)
473 AFS_STATCNT(afs_PutUser);
479 * Set the primary flag on a unixuser structure, ensuring that exactly one
480 * dude has the flag set at any time for a particular unix uid.
483 afs_SetPrimary(struct unixuser *au, int aflag)
489 AFS_STATCNT(afs_SetPrimary);
492 ObtainWriteLock(&afs_xuser, 105);
494 * See if anyone is this uid's primary cell yet; recording in pu the
497 for (tu = afs_users[i]; tu; tu = tu->next) {
498 if (tu->uid == au->uid && (tu->states & UPrimary)) {
502 if (pu && !(pu->states & UHasTokens)) {
504 * Primary user has unlogged, don't treat him as primary any longer;
505 * note that we want to treat him as primary until now, so that
506 * people see a primary identity until now.
508 pu->states &= ~UPrimary;
512 /* setting au to be primary */
514 pu->states &= ~UPrimary;
515 au->states |= UPrimary;
516 } else if (aflag == 0) {
517 /* we don't know if we're supposed to be primary or not */
518 if (!pu || au == pu) {
519 au->states |= UPrimary;
521 au->states &= ~UPrimary;
523 ReleaseWriteLock(&afs_xuser);
525 } /*afs_SetPrimary */
528 afs_NotifyUser(struct unixuser *auser, int event)
530 #ifdef AFS_DARWIN_ENV
531 darwin_notify_perms(auser, event);
536 * Mark all of the unixuser records held for a particular PAG as
540 * PAG to expire records for
543 afs_MarkUserExpired(afs_int32 pag)
549 ObtainWriteLock(&afs_xuser, 9);
550 for (tu = afs_users[i]; tu; tu = tu->next) {
551 if (tu->uid == pag) {
552 tu->states &= ~UHasTokens;
556 ReleaseWriteLock(&afs_xuser);
563 * Called by osi_TraverseProcTable (from afs_GCPAGs) for each
564 * process in the system.
565 * If the specified process uses a PAG, clear that PAG's temporary
570 * This variable keeps track of the number of UID-base
571 * tokens in the afs_users table. When it's zero
572 * the per process loop in GCPAGs doesn't have to
573 * check processes without pags against the afs_users table.
575 static afs_int32 afs_GCPAGs_UIDBaseTokenCount = 0;
578 * These variables keep track of the number of times
579 * afs_GCPAGs_perproc_func() is called. If it is not called at all when
580 * walking the process table, there is something wrong and we should not
581 * prematurely expire any tokens.
583 static size_t afs_GCPAGs_perproc_count = 0;
584 static size_t afs_GCPAGs_cred_count = 0;
587 * LOCKS: afs_GCPAGs_perproc_func requires write lock on afs_xuser
589 #if !defined(LINUX_KEYRING_SUPPORT) && (!defined(STRUCT_TASK_STRUCT_HAS_CRED) || defined(HAVE_LINUX_RCU_READ_LOCK))
591 afs_GCPAGs_perproc_func(afs_proc_t * pproc)
593 afs_int32 pag, hash, uid;
594 const afs_ucred_t *pcred;
596 afs_GCPAGs_perproc_count++;
598 pcred = afs_osi_proc2cred(pproc);
602 afs_GCPAGs_cred_count++;
604 pag = PagInCred(pcred);
605 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV) || defined(AFS_LINUX22_ENV)
606 uid = (pag != NOPAG ? pag : afs_cr_uid(pcred));
607 #elif defined(AFS_SUN510_ENV)
608 uid = (pag != NOPAG ? pag : crgetruid(pcred));
610 uid = (pag != NOPAG ? pag : afs_cr_ruid(pcred));
614 /* if this token is PAG based, or it's UID based and
615 * UID-based tokens exist */
616 if ((pag != NOPAG) || (afs_GCPAGs_UIDBaseTokenCount)) {
617 /* find the entries for this uid in all cells and clear the not
618 * referenced flag. Can't use afs_FindUser, because it just returns
619 * the specific cell asked for, or the first one found.
622 for (pu = afs_users[hash]; pu; pu = pu->next) {
623 if (pu->uid == uid) {
624 if (pu->states & TMP_UPAGNotReferenced) {
625 /* clear the 'deleteme' flag for this entry */
626 pu->states &= ~TMP_UPAGNotReferenced;
628 /* This is a uid based token that hadn't
629 * previously been cleared, so decrement the
630 * outstanding uid based token count */
631 afs_GCPAGs_UIDBaseTokenCount--;
641 * Go through the process table, find all unused PAGs
642 * and cause them to be deleted during the next GC.
644 * returns the number of PAGs marked for deletion
646 * On AIX we free PAGs when the last accessing process exits,
647 * so this routine is not needed.
649 * In AFS WebSecure, we explicitly call unlog when we remove
650 * an entry in the login cache, so this routine is not needed.
654 afs_GCPAGs(afs_int32 * ReleasedCount)
659 if (afs_gcpags != AFS_GCPAGS_OK) {
665 /* first, loop through afs_users, setting the temporary 'deleteme' flag */
666 ObtainWriteLock(&afs_xuser, 419);
667 afs_GCPAGs_UIDBaseTokenCount = 0;
668 for (i = 0; i < NUSERS; i++) {
669 for (pu = afs_users[i]; pu; pu = pu->next) {
670 pu->states |= TMP_UPAGNotReferenced;
671 if (((pu->uid >> 24) & 0xff) != 'A') {
672 /* this is a uid-based token, */
673 /* increment the count */
674 afs_GCPAGs_UIDBaseTokenCount++;
679 /* Now, iterate through the systems process table,
680 * for each process, mark it's PAGs (if any) in use.
681 * i.e. clear the temporary deleteme flag.
683 afs_GCPAGs_perproc_count = 0;
684 afs_GCPAGs_cred_count = 0;
686 afs_osi_TraverseProcTable();
688 /* If there is an internal problem and afs_GCPAGs_perproc_func()
689 * does not get called, disable gcpags so that we do not
690 * accidentally expire all the tokens in the system.
692 if (afs_gcpags == AFS_GCPAGS_OK && !afs_GCPAGs_perproc_count) {
693 afs_gcpags = AFS_GCPAGS_EPROCWALK;
696 if (afs_gcpags == AFS_GCPAGS_OK && !afs_GCPAGs_cred_count) {
697 afs_gcpags = AFS_GCPAGS_ECREDWALK;
700 /* Now, go through afs_users again, any that aren't in use
701 * (temp deleteme flag still set) will be marked for later deletion,
702 * by setting their expire times to 0.
704 for (i = 0; i < NUSERS; i++) {
705 for (pu = afs_users[i]; pu; pu = pu->next) {
706 if (pu->states & TMP_UPAGNotReferenced) {
708 /* clear the temp flag */
709 pu->states &= ~TMP_UPAGNotReferenced;
711 /* Is this entry on behalf of a 'remote' user ?
712 * i.e. nfs translator, etc.
714 if (!pu->exporter && afs_gcpags == AFS_GCPAGS_OK) {
715 /* make afs_GCUserData remove this entry */
716 pu->states &= ~UHasTokens;
719 (*ReleasedCount)++; /* remember how many we marked (info only) */
725 ReleaseWriteLock(&afs_xuser);
730 #endif /* AFS_GCPAGS */