Commit | Line | Data |
---|---|---|
805e021f CE |
1 | /* |
2 | * Copyright 2000, International Business Machines Corporation and others. | |
3 | * All Rights Reserved. | |
4 | * | |
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 | |
8 | */ | |
9 | ||
10 | /* | |
11 | * Implements: | |
12 | */ | |
13 | #include <afsconfig.h> | |
14 | #include "afs/param.h" | |
15 | ||
16 | ||
17 | #include "afs/stds.h" | |
18 | #include "afs/sysincludes.h" /* Standard vendor system headers */ | |
19 | ||
20 | #if !defined(UKERNEL) | |
21 | #if !defined(AFS_LINUX20_ENV) | |
22 | #include <net/if.h> | |
23 | #endif | |
24 | #include <netinet/in.h> | |
25 | ||
26 | #ifdef AFS_SGI62_ENV | |
27 | #include "h/hashing.h" | |
28 | #endif | |
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) */ | |
33 | ||
34 | #include "afsincludes.h" /* Afs-based standard headers */ | |
35 | #include "afs/afs_stats.h" /* afs statistics */ | |
36 | ||
37 | #if defined(AFS_SUN5_ENV) | |
38 | #include <inet/led.h> | |
39 | #include <inet/common.h> | |
40 | #include <netinet/ip6.h> | |
41 | #include <inet/ip.h> | |
42 | #endif | |
43 | ||
44 | #include "afs/afs_axscache.h" | |
45 | ||
46 | /* Exported variables */ | |
47 | afs_rwlock_t afs_xuser; | |
48 | struct unixuser *afs_users[NUSERS]; | |
49 | ||
50 | ||
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 */ | |
55 | ||
56 | ||
57 | /* Called from afs_Daemon to garbage collect unixusers no longer using system, | |
58 | * and their conns. | |
59 | */ | |
60 | void | |
61 | afs_GCUserData(void) | |
62 | { | |
63 | struct unixuser *tu, **lu, *nu; | |
64 | int i; | |
65 | afs_int32 now, delFlag; | |
66 | ||
67 | AFS_STATCNT(afs_GCUserData); | |
68 | /* Obtain locks in valid order */ | |
69 | ObtainWriteLock(&afs_xuser, 95); | |
70 | #ifndef AFS_PAG_MANAGER | |
71 | ObtainReadLock(&afs_xserver); | |
72 | ObtainWriteLock(&afs_xconn, 96); | |
73 | #endif | |
74 | now = osi_Time(); | |
75 | for (i = 0; i < NUSERS; i++) { | |
76 | for (lu = &afs_users[i], tu = *lu; tu; tu = nu) { | |
77 | delFlag = 0; /* should we delete this dude? */ | |
78 | /* Don't garbage collect users in use now (refCount) */ | |
79 | if (tu->refCount == 0) { | |
80 | if (tu->tokens) { | |
81 | /* Need to walk the token stack, and dispose of | |
82 | * all expired tokens */ | |
83 | afs_DiscardExpiredTokens(&tu->tokens, now); | |
84 | if (!afs_HasUsableTokens(tu->tokens, now)) | |
85 | delFlag = 1; | |
86 | } else { | |
87 | if (tu->tokenTime < now - NOTOKTIMEOUT) | |
88 | delFlag = 1; | |
89 | } | |
90 | } | |
91 | nu = tu->next; | |
92 | if (delFlag) { | |
93 | *lu = tu->next; | |
94 | #ifndef AFS_PAG_MANAGER | |
95 | afs_ReleaseConnsUser(tu); | |
96 | #endif | |
97 | afs_FreeTokens(&tu->tokens); | |
98 | ||
99 | if (tu->exporter) | |
100 | EXP_RELE(tu->exporter); | |
101 | afs_osi_Free(tu, sizeof(struct unixuser)); | |
102 | } else { | |
103 | lu = &tu->next; | |
104 | } | |
105 | } | |
106 | } | |
107 | #ifndef AFS_PAG_MANAGER | |
108 | ReleaseWriteLock(&afs_xconn); | |
109 | #endif | |
110 | #ifndef AFS_PAG_MANAGER | |
111 | ReleaseReadLock(&afs_xserver); | |
112 | #endif | |
113 | ReleaseWriteLock(&afs_xuser); | |
114 | ||
115 | } /*afs_GCUserData */ | |
116 | ||
117 | static struct unixuser * | |
118 | afs_FindUserNoLock(afs_int32 auid, afs_int32 acell) | |
119 | { | |
120 | struct unixuser *tu; | |
121 | afs_int32 i; | |
122 | ||
123 | AFS_STATCNT(afs_FindUser); | |
124 | i = UHash(auid); | |
125 | for (tu = afs_users[i]; tu; tu = tu->next) { | |
126 | if (tu->uid == auid && ((tu->cell == acell) || (acell == -1))) { | |
127 | tu->refCount++; | |
128 | return tu; | |
129 | } | |
130 | } | |
131 | return NULL; | |
132 | ||
133 | } | |
134 | ||
135 | #ifndef AFS_PAG_MANAGER | |
136 | /* | |
137 | * Check for unixusers who encountered bad tokens, and reset the access | |
138 | * cache for these guys. Can't do this when token expiration detected, | |
139 | * since too many locks are set then. | |
140 | */ | |
141 | void | |
142 | afs_CheckTokenCache(void) | |
143 | { | |
144 | int i; | |
145 | struct unixuser *tu; | |
146 | afs_int32 now; | |
147 | struct vcache *tvc; | |
148 | struct axscache *tofreelist; | |
149 | int do_scan = 0; | |
150 | ||
151 | AFS_STATCNT(afs_CheckCacheResets); | |
152 | ObtainReadLock(&afs_xvcache); | |
153 | ObtainReadLock(&afs_xuser); | |
154 | now = osi_Time(); | |
155 | for (i = 0; i < NUSERS; i++) { | |
156 | for (tu = afs_users[i]; tu; tu = tu->next) { | |
157 | /* | |
158 | * If tokens are still good and user has Kerberos tickets, | |
159 | * check expiration | |
160 | */ | |
161 | if ((tu->states & UHasTokens) && !(tu->states & UTokensBad)) { | |
162 | if (!afs_HasUsableTokens(tu->tokens, now)) { | |
163 | /* | |
164 | * This token has expired, warn users and reset access | |
165 | * cache. | |
166 | */ | |
167 | tu->states |= (UTokensBad | UNeedsReset); | |
168 | } | |
169 | } | |
170 | if (tu->states & UNeedsReset) | |
171 | do_scan = 1; | |
172 | } | |
173 | } | |
174 | /* Skip the potentially expensive scan if nothing to do */ | |
175 | if (!do_scan) | |
176 | goto done; | |
177 | ||
178 | tofreelist = NULL; | |
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) { | |
184 | struct axscache **ac, **nac; | |
185 | ||
186 | for ( ac = &tvc->Access; *ac;) { | |
187 | nac = &(*ac)->next; | |
188 | tu = afs_FindUserNoLock((*ac)->uid, tvc->f.fid.Cell); | |
189 | if (tu == NULL || (tu->states & UNeedsReset)) { | |
190 | struct axscache *tmp; | |
191 | tmp = *ac; | |
192 | *ac = *nac; | |
193 | tmp->next = tofreelist; | |
194 | tofreelist = tmp; | |
195 | } else | |
196 | ac = nac; | |
197 | if (tu != NULL) | |
198 | tu->refCount--; | |
199 | } | |
200 | } | |
201 | } | |
202 | } | |
203 | afs_FreeAllAxs(&tofreelist); | |
204 | for (i = 0; i < NUSERS; i++) { | |
205 | for (tu = afs_users[i]; tu; tu = tu->next) { | |
206 | if (tu->states & UNeedsReset) | |
207 | tu->states &= ~UNeedsReset; | |
208 | } | |
209 | } | |
210 | ||
211 | done: | |
212 | ReleaseReadLock(&afs_xuser); | |
213 | ReleaseReadLock(&afs_xvcache); | |
214 | } /*afs_CheckTokenCache */ | |
215 | ||
216 | ||
217 | /* Remove any access caches associated with this uid+cell | |
218 | * by scanning the entire vcache table. Specify cell=-1 | |
219 | * to remove all access caches associated with this uid | |
220 | * regardless of cell. | |
221 | */ | |
222 | void | |
223 | afs_ResetAccessCache(afs_int32 uid, afs_int32 cell, int alock) | |
224 | { | |
225 | int i; | |
226 | struct vcache *tvc; | |
227 | struct axscache *ac; | |
228 | ||
229 | AFS_STATCNT(afs_ResetAccessCache); | |
230 | if (alock) | |
231 | ObtainReadLock(&afs_xvcache); | |
232 | for (i = 0; i < VCSIZE; i++) { | |
233 | for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) { | |
234 | /* really should do this under cache write lock, but that. | |
235 | * is hard to under locking hierarchy */ | |
236 | if (tvc->Access && (cell == -1 || tvc->f.fid.Cell == cell)) { | |
237 | ac = afs_FindAxs(tvc->Access, uid); | |
238 | if (ac) { | |
239 | afs_RemoveAxs(&tvc->Access, ac); | |
240 | } | |
241 | } | |
242 | } | |
243 | } | |
244 | if (alock) | |
245 | ReleaseReadLock(&afs_xvcache); | |
246 | ||
247 | } /*afs_ResetAccessCache */ | |
248 | ||
249 | ||
250 | /* | |
251 | * Ensure all connections make use of new tokens. Discard incorrectly-cached | |
252 | * access info. | |
253 | */ | |
254 | void | |
255 | afs_ResetUserConns(struct unixuser *auser) | |
256 | { | |
257 | int i, j; | |
258 | struct srvAddr *sa; | |
259 | struct sa_conn_vector *tcv; | |
260 | ||
261 | AFS_STATCNT(afs_ResetUserConns); | |
262 | ObtainReadLock(&afs_xsrvAddr); | |
263 | ObtainWriteLock(&afs_xconn, 98); | |
264 | ||
265 | for (i = 0; i < NSERVERS; i++) { | |
266 | for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) { | |
267 | for (tcv = sa->conns; tcv; tcv = tcv->next) { | |
268 | if (tcv->user == auser) { | |
269 | for(j = 0; j < CVEC_LEN; ++j) { | |
270 | (tcv->cvec[j]).forceConnectFS = 1; | |
271 | } | |
272 | } | |
273 | } | |
274 | } | |
275 | } | |
276 | ||
277 | ReleaseWriteLock(&afs_xconn); | |
278 | ReleaseReadLock(&afs_xsrvAddr); | |
279 | afs_ResetAccessCache(auser->uid, auser->cell, 1); | |
280 | auser->states &= ~UNeedsReset; | |
281 | } /*afs_ResetUserConns */ | |
282 | #endif /* !AFS_PAG_MANAGER */ | |
283 | ||
284 | ||
285 | struct unixuser * | |
286 | afs_FindUser(afs_int32 auid, afs_int32 acell, afs_int32 locktype) | |
287 | { | |
288 | struct unixuser *tu; | |
289 | ||
290 | ObtainWriteLock(&afs_xuser, 99); | |
291 | tu = afs_FindUserNoLock(auid, acell); | |
292 | ReleaseWriteLock(&afs_xuser); | |
293 | if (tu) | |
294 | afs_LockUser(tu, locktype, 365); | |
295 | return tu; | |
296 | } /*afs_FindUser */ | |
297 | ||
298 | ||
299 | /*------------------------------------------------------------------------ | |
300 | * EXPORTED afs_ComputePAGStats | |
301 | * | |
302 | * Description: | |
303 | * Compute a set of stats concerning PAGs used by this machine. | |
304 | * | |
305 | * Arguments: | |
306 | * None. | |
307 | * | |
308 | * Returns: | |
309 | * Nothing. | |
310 | * | |
311 | * Environment: | |
312 | * The results are put in the structure responsible for keeping | |
313 | * detailed CM stats. Note: entries corresponding to a single PAG | |
314 | * will appear on the identical hash chain, so sweeping the chain | |
315 | * will find all entries related to a single PAG. | |
316 | * | |
317 | * Side Effects: | |
318 | * As advertised. | |
319 | *------------------------------------------------------------------------*/ | |
320 | ||
321 | void | |
322 | afs_ComputePAGStats(void) | |
323 | { | |
324 | struct unixuser *currPAGP; /*Ptr to curr PAG */ | |
325 | struct unixuser *cmpPAGP; /*Ptr to PAG being compared */ | |
326 | struct afs_stats_AuthentInfo *authP; /*Ptr to stats area */ | |
327 | int curr_Record; /*Curr record */ | |
328 | int currChain; /*Curr hash chain */ | |
329 | int currChainLen; /*Length of curr hash chain */ | |
330 | int currPAGRecords; /*# records in curr PAG */ | |
331 | ||
332 | /* | |
333 | * Lock out everyone else from scribbling on the PAG entries. | |
334 | */ | |
335 | ObtainReadLock(&afs_xuser); | |
336 | ||
337 | /* | |
338 | * Initialize the tallies, then sweep through each hash chain. We | |
339 | * can't bzero the structure, since some fields are cumulative over | |
340 | * the CM's lifetime. | |
341 | */ | |
342 | curr_Record = 0; | |
343 | authP = &(afs_stats_cmfullperf.authent); | |
344 | authP->curr_PAGs = 0; | |
345 | authP->curr_Records = 0; | |
346 | authP->curr_AuthRecords = 0; | |
347 | authP->curr_UnauthRecords = 0; | |
348 | authP->curr_MaxRecordsInPAG = 0; | |
349 | authP->curr_LongestChain = 0; | |
350 | ||
351 | for (currChain = 0; currChain < NUSERS; currChain++) { | |
352 | currChainLen = 0; | |
353 | for (currPAGP = afs_users[currChain]; currPAGP; | |
354 | currPAGP = currPAGP->next) { | |
355 | /* | |
356 | * Bump the number of records on this current chain, along with | |
357 | * the total number of records in existence. | |
358 | */ | |
359 | currChainLen++; | |
360 | curr_Record++; | |
361 | /* | |
362 | * We've found a previously-uncounted PAG. If it's been deleted | |
363 | * but just not garbage-collected yet, we step over it. | |
364 | */ | |
365 | if (!(currPAGP->states & UHasTokens)) | |
366 | continue; | |
367 | ||
368 | /* | |
369 | * If this PAG record has already been ``counted', namely | |
370 | * associated with a PAG and tallied, clear its bit and move on. | |
371 | */ | |
372 | (authP->curr_Records)++; | |
373 | if (currPAGP->states & UPAGCounted) { | |
374 | currPAGP->states &= ~UPAGCounted; | |
375 | continue; | |
376 | } | |
377 | ||
378 | ||
379 | ||
380 | /*We've counted this one already */ | |
381 | /* | |
382 | * Jot initial info down, then sweep down the rest of the hash | |
383 | * chain, looking for matching PAG entries. Note: to properly | |
384 | * ``count'' the current record, we first compare it to itself | |
385 | * in the following loop. | |
386 | */ | |
387 | (authP->curr_PAGs)++; | |
388 | currPAGRecords = 0; | |
389 | ||
390 | for (cmpPAGP = currPAGP; cmpPAGP; cmpPAGP = cmpPAGP->next) { | |
391 | if (currPAGP->uid == cmpPAGP->uid) { | |
392 | /* | |
393 | * The records belong to the same PAG. First, mark the | |
394 | * new record as ``counted'' and bump the PAG size. | |
395 | * Then, record the state of its ticket, if any. | |
396 | */ | |
397 | cmpPAGP->states |= UPAGCounted; | |
398 | currPAGRecords++; | |
399 | if ((cmpPAGP->states & UHasTokens) | |
400 | && !(cmpPAGP->states & UTokensBad)) | |
401 | (authP->curr_AuthRecords)++; | |
402 | else | |
403 | (authP->curr_UnauthRecords)++; | |
404 | } /*Records belong to same PAG */ | |
405 | } /*Compare to rest of PAG records in chain */ | |
406 | ||
407 | /* | |
408 | * In the above comparisons, the current PAG record has been | |
409 | * marked as counted. Erase this mark before moving on. | |
410 | */ | |
411 | currPAGP->states &= ~UPAGCounted; | |
412 | ||
413 | /* | |
414 | * We've compared our current PAG record with all remaining | |
415 | * PAG records in the hash chain. Update our tallies, and | |
416 | * perhaps even our lifetime high water marks. After that, | |
417 | * remove our search mark and advance to the next comparison | |
418 | * pair. | |
419 | */ | |
420 | if (currPAGRecords > authP->curr_MaxRecordsInPAG) { | |
421 | authP->curr_MaxRecordsInPAG = currPAGRecords; | |
422 | if (currPAGRecords > authP->HWM_MaxRecordsInPAG) | |
423 | authP->HWM_MaxRecordsInPAG = currPAGRecords; | |
424 | } | |
425 | } /*Sweep a hash chain */ | |
426 | ||
427 | /* | |
428 | * If the chain we just finished zipping through is the longest we've | |
429 | * seen yet, remember this fact before advancing to the next chain. | |
430 | */ | |
431 | if (currChainLen > authP->curr_LongestChain) { | |
432 | authP->curr_LongestChain = currChainLen; | |
433 | if (currChainLen > authP->HWM_LongestChain) | |
434 | authP->HWM_LongestChain = currChainLen; | |
435 | } | |
436 | ||
437 | } /*For each hash chain in afs_user */ | |
438 | ||
439 | /* | |
440 | * Now that we've counted everything up, we can consider all-time | |
441 | * numbers. | |
442 | */ | |
443 | if (authP->curr_PAGs > authP->HWM_PAGs) | |
444 | authP->HWM_PAGs = authP->curr_PAGs; | |
445 | if (authP->curr_Records > authP->HWM_Records) | |
446 | authP->HWM_Records = authP->curr_Records; | |
447 | ||
448 | /* | |
449 | * People are free to manipulate the PAG structures now. | |
450 | */ | |
451 | ReleaseReadLock(&afs_xuser); | |
452 | ||
453 | } /*afs_ComputePAGStats */ | |
454 | ||
455 | /*! | |
456 | * Obtain a unixuser for the specified uid and cell; | |
457 | * if no existing match found, allocate a new one. | |
458 | * | |
459 | * \param[in] auid uid/PAG value | |
460 | * \param[in] acell cell number; if -1, match on auid only | |
461 | * \param[in] locktype locktype desired on returned unixuser | |
462 | * | |
463 | * \post unixuser is chained in afs_users[], returned with <locktype> held | |
464 | * | |
465 | * \note Maintain unixusers in sorted order within hash bucket to enable | |
466 | * small lookup optimizations. | |
467 | */ | |
468 | ||
469 | struct unixuser * | |
470 | afs_GetUser(afs_int32 auid, afs_int32 acell, afs_int32 locktype) | |
471 | { | |
472 | struct unixuser *tu, *xu = 0, *pu = 0; | |
473 | afs_int32 i; | |
474 | afs_int32 RmtUser = 0; | |
475 | ||
476 | AFS_STATCNT(afs_GetUser); | |
477 | i = UHash(auid); | |
478 | ObtainWriteLock(&afs_xuser, 104); | |
479 | /* unixusers are sorted by uid in each hash bucket */ | |
480 | for (tu = afs_users[i]; tu && (tu->uid <= auid) ; xu = tu, tu = tu->next) { | |
481 | if (tu->uid == auid) { | |
482 | RmtUser = 0; | |
483 | pu = NULL; | |
484 | if (tu->exporter) { | |
485 | RmtUser = 1; | |
486 | pu = tu; | |
487 | } | |
488 | if (tu->cell == -1 && acell != -1) { | |
489 | /* Here we setup the real cell for the client */ | |
490 | tu->cell = acell; | |
491 | tu->refCount++; | |
492 | goto done; | |
493 | } else if (tu->cell == acell || acell == -1) { | |
494 | tu->refCount++; | |
495 | goto done; | |
496 | } | |
497 | } | |
498 | } | |
499 | /* no matching unixuser found; repurpose the tu pointer to | |
500 | * allocate a new unixuser. | |
501 | * xu will be insertion point for our new unixuser. | |
502 | */ | |
503 | tu = afs_osi_Alloc(sizeof(struct unixuser)); | |
504 | osi_Assert(tu != NULL); | |
505 | #ifndef AFS_NOSTATS | |
506 | afs_stats_cmfullperf.authent.PAGCreations++; | |
507 | #endif /* AFS_NOSTATS */ | |
508 | memset(tu, 0, sizeof(struct unixuser)); | |
509 | AFS_RWLOCK_INIT(&tu->lock, "unixuser lock"); | |
510 | /* insert new nu in sorted order after xu */ | |
511 | if (xu == NULL) { | |
512 | tu->next = afs_users[i]; | |
513 | afs_users[i] = tu; | |
514 | } else { | |
515 | tu->next = xu->next; | |
516 | xu->next = tu; | |
517 | } | |
518 | if (RmtUser) { | |
519 | /* | |
520 | * This is for the case where an additional unixuser struct is | |
521 | * created because the remote client is accessing a different cell; | |
522 | * we simply rerecord relevant information from the original | |
523 | * structure | |
524 | */ | |
525 | if (pu && pu->exporter) { | |
526 | tu->exporter = pu->exporter; | |
527 | (void)EXP_HOLD(tu->exporter); | |
528 | } | |
529 | } | |
530 | tu->uid = auid; | |
531 | tu->cell = acell; | |
532 | tu->viceId = UNDEFVID; | |
533 | tu->refCount = 1; | |
534 | tu->tokenTime = osi_Time(); | |
535 | /* fall through to return the new one */ | |
536 | ||
537 | done: | |
538 | ReleaseWriteLock(&afs_xuser); | |
539 | afs_LockUser(tu, locktype, 364); | |
540 | return tu; | |
541 | ||
542 | } /*afs_GetUser */ | |
543 | ||
544 | void | |
545 | afs_LockUser(struct unixuser *au, afs_int32 locktype, | |
546 | unsigned int src_indicator) | |
547 | { | |
548 | switch (locktype) { | |
549 | case READ_LOCK: | |
550 | ObtainReadLock(&au->lock); | |
551 | break; | |
552 | case WRITE_LOCK: | |
553 | ObtainWriteLock(&au->lock, src_indicator); | |
554 | break; | |
555 | case SHARED_LOCK: | |
556 | ObtainSharedLock(&au->lock, src_indicator); | |
557 | break; | |
558 | default: | |
559 | /* noop */ | |
560 | break; | |
561 | } | |
562 | } | |
563 | ||
564 | void | |
565 | afs_PutUser(struct unixuser *au, afs_int32 locktype) | |
566 | { | |
567 | AFS_STATCNT(afs_PutUser); | |
568 | ||
569 | switch (locktype) { | |
570 | case READ_LOCK: | |
571 | ReleaseReadLock(&au->lock); | |
572 | break; | |
573 | case WRITE_LOCK: | |
574 | ReleaseWriteLock(&au->lock); | |
575 | break; | |
576 | case SHARED_LOCK: | |
577 | ReleaseSharedLock(&au->lock); | |
578 | break; | |
579 | default: | |
580 | /* noop */ | |
581 | break; | |
582 | } | |
583 | ||
584 | --au->refCount; | |
585 | } /*afs_PutUser */ | |
586 | ||
587 | ||
588 | /* | |
589 | * Set the primary flag on a unixuser structure, ensuring that exactly one | |
590 | * dude has the flag set at any time for a particular unix uid. | |
591 | */ | |
592 | void | |
593 | afs_SetPrimary(struct unixuser *au, int aflag) | |
594 | { | |
595 | struct unixuser *tu; | |
596 | int i; | |
597 | struct unixuser *pu; | |
598 | ||
599 | AFS_STATCNT(afs_SetPrimary); | |
600 | i = UHash(au->uid); | |
601 | pu = NULL; | |
602 | ObtainWriteLock(&afs_xuser, 105); | |
603 | /* | |
604 | * See if anyone is this uid's primary cell yet; recording in pu the | |
605 | * corresponding user | |
606 | */ | |
607 | for (tu = afs_users[i]; tu; tu = tu->next) { | |
608 | if (tu->uid == au->uid && (tu->states & UPrimary)) { | |
609 | pu = tu; | |
610 | } | |
611 | } | |
612 | if (pu && !(pu->states & UHasTokens)) { | |
613 | /* | |
614 | * Primary user has unlogged, don't treat him as primary any longer; | |
615 | * note that we want to treat him as primary until now, so that | |
616 | * people see a primary identity until now. | |
617 | */ | |
618 | pu->states &= ~UPrimary; | |
619 | pu = NULL; | |
620 | } | |
621 | if (aflag == 1) { | |
622 | /* setting au to be primary */ | |
623 | if (pu) | |
624 | pu->states &= ~UPrimary; | |
625 | au->states |= UPrimary; | |
626 | } else if (aflag == 0) { | |
627 | /* we don't know if we're supposed to be primary or not */ | |
628 | if (!pu || au == pu) { | |
629 | au->states |= UPrimary; | |
630 | } else | |
631 | au->states &= ~UPrimary; | |
632 | } | |
633 | ReleaseWriteLock(&afs_xuser); | |
634 | ||
635 | } /*afs_SetPrimary */ | |
636 | ||
637 | void | |
638 | afs_NotifyUser(struct unixuser *auser, int event) | |
639 | { | |
640 | #ifdef AFS_DARWIN_ENV | |
641 | darwin_notify_perms(auser, event); | |
642 | #endif | |
643 | } | |
644 | ||
645 | /** | |
646 | * Mark all of the unixuser records held for a particular PAG as | |
647 | * expired | |
648 | * | |
649 | * @param[in] pag | |
650 | * PAG to expire records for | |
651 | */ | |
652 | void | |
653 | afs_MarkUserExpired(afs_int32 pag) | |
654 | { | |
655 | afs_int32 i; | |
656 | struct unixuser *tu; | |
657 | ||
658 | i = UHash(pag); | |
659 | ObtainWriteLock(&afs_xuser, 9); | |
660 | for (tu = afs_users[i]; tu; tu = tu->next) { | |
661 | if (tu->uid == pag) { | |
662 | tu->states &= ~UHasTokens; | |
663 | tu->tokenTime = 0; | |
664 | } | |
665 | } | |
666 | ReleaseWriteLock(&afs_xuser); | |
667 | } | |
668 | ||
669 | ||
670 | #if AFS_GCPAGS | |
671 | ||
672 | /* | |
673 | * Called by osi_TraverseProcTable (from afs_GCPAGs) for each | |
674 | * process in the system. | |
675 | * If the specified process uses a PAG, clear that PAG's temporary | |
676 | * 'deleteme' flag. | |
677 | */ | |
678 | ||
679 | /* | |
680 | * This variable keeps track of the number of UID-base | |
681 | * tokens in the afs_users table. When it's zero | |
682 | * the per process loop in GCPAGs doesn't have to | |
683 | * check processes without pags against the afs_users table. | |
684 | */ | |
685 | static afs_int32 afs_GCPAGs_UIDBaseTokenCount = 0; | |
686 | ||
687 | /* | |
688 | * These variables keep track of the number of times | |
689 | * afs_GCPAGs_perproc_func() is called. If it is not called at all when | |
690 | * walking the process table, there is something wrong and we should not | |
691 | * prematurely expire any tokens. | |
692 | */ | |
693 | static size_t afs_GCPAGs_perproc_count = 0; | |
694 | static size_t afs_GCPAGs_cred_count = 0; | |
695 | ||
696 | /* | |
697 | * LOCKS: afs_GCPAGs_perproc_func requires write lock on afs_xuser | |
698 | */ | |
699 | #if !defined(LINUX_KEYRING_SUPPORT) && (!defined(STRUCT_TASK_STRUCT_HAS_CRED) || defined(HAVE_LINUX_RCU_READ_LOCK)) | |
700 | void | |
701 | afs_GCPAGs_perproc_func(afs_proc_t * pproc) | |
702 | { | |
703 | afs_int32 pag, hash, uid; | |
704 | const afs_ucred_t *pcred; | |
705 | ||
706 | afs_GCPAGs_perproc_count++; | |
707 | ||
708 | pcred = afs_osi_proc2cred(pproc); | |
709 | if (!pcred) | |
710 | return; | |
711 | ||
712 | afs_GCPAGs_cred_count++; | |
713 | ||
714 | pag = PagInCred(pcred); | |
715 | #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV) || defined(AFS_LINUX22_ENV) | |
716 | uid = (pag != NOPAG ? pag : afs_cr_uid(pcred)); | |
717 | #elif defined(AFS_SUN510_ENV) | |
718 | uid = (pag != NOPAG ? pag : crgetruid(pcred)); | |
719 | #else | |
720 | uid = (pag != NOPAG ? pag : afs_cr_ruid(pcred)); | |
721 | #endif | |
722 | hash = UHash(uid); | |
723 | ||
724 | /* if this token is PAG based, or it's UID based and | |
725 | * UID-based tokens exist */ | |
726 | if ((pag != NOPAG) || (afs_GCPAGs_UIDBaseTokenCount)) { | |
727 | /* find the entries for this uid in all cells and clear the not | |
728 | * referenced flag. Can't use afs_FindUser, because it just returns | |
729 | * the specific cell asked for, or the first one found. | |
730 | */ | |
731 | struct unixuser *pu; | |
732 | for (pu = afs_users[hash]; pu; pu = pu->next) { | |
733 | if (pu->uid == uid) { | |
734 | if (pu->states & TMP_UPAGNotReferenced) { | |
735 | /* clear the 'deleteme' flag for this entry */ | |
736 | pu->states &= ~TMP_UPAGNotReferenced; | |
737 | if (pag == NOPAG) { | |
738 | /* This is a uid based token that hadn't | |
739 | * previously been cleared, so decrement the | |
740 | * outstanding uid based token count */ | |
741 | afs_GCPAGs_UIDBaseTokenCount--; | |
742 | } | |
743 | } | |
744 | } | |
745 | } | |
746 | } | |
747 | } | |
748 | #endif | |
749 | ||
750 | /* | |
751 | * Go through the process table, find all unused PAGs | |
752 | * and cause them to be deleted during the next GC. | |
753 | * | |
754 | * returns the number of PAGs marked for deletion | |
755 | * | |
756 | * On AIX we free PAGs when the last accessing process exits, | |
757 | * so this routine is not needed. | |
758 | * | |
759 | * In AFS WebSecure, we explicitly call unlog when we remove | |
760 | * an entry in the login cache, so this routine is not needed. | |
761 | */ | |
762 | ||
763 | afs_int32 | |
764 | afs_GCPAGs(afs_int32 * ReleasedCount) | |
765 | { | |
766 | struct unixuser *pu; | |
767 | int i; | |
768 | ||
769 | if (afs_gcpags != AFS_GCPAGS_OK) { | |
770 | return 0; | |
771 | } | |
772 | ||
773 | *ReleasedCount = 0; | |
774 | ||
775 | /* first, loop through afs_users, setting the temporary 'deleteme' flag */ | |
776 | ObtainWriteLock(&afs_xuser, 419); | |
777 | afs_GCPAGs_UIDBaseTokenCount = 0; | |
778 | for (i = 0; i < NUSERS; i++) { | |
779 | for (pu = afs_users[i]; pu; pu = pu->next) { | |
780 | pu->states |= TMP_UPAGNotReferenced; | |
781 | if (((pu->uid >> 24) & 0xff) != 'A') { | |
782 | /* this is a uid-based token, */ | |
783 | /* increment the count */ | |
784 | afs_GCPAGs_UIDBaseTokenCount++; | |
785 | } | |
786 | } | |
787 | } | |
788 | ||
789 | /* Now, iterate through the systems process table, | |
790 | * for each process, mark it's PAGs (if any) in use. | |
791 | * i.e. clear the temporary deleteme flag. | |
792 | */ | |
793 | afs_GCPAGs_perproc_count = 0; | |
794 | afs_GCPAGs_cred_count = 0; | |
795 | ||
796 | afs_osi_TraverseProcTable(); | |
797 | ||
798 | /* If there is an internal problem and afs_GCPAGs_perproc_func() | |
799 | * does not get called, disable gcpags so that we do not | |
800 | * accidentally expire all the tokens in the system. | |
801 | */ | |
802 | if (afs_gcpags == AFS_GCPAGS_OK && !afs_GCPAGs_perproc_count) { | |
803 | afs_gcpags = AFS_GCPAGS_EPROCWALK; | |
804 | } | |
805 | ||
806 | if (afs_gcpags == AFS_GCPAGS_OK && !afs_GCPAGs_cred_count) { | |
807 | afs_gcpags = AFS_GCPAGS_ECREDWALK; | |
808 | } | |
809 | ||
810 | /* Now, go through afs_users again, any that aren't in use | |
811 | * (temp deleteme flag still set) will be marked for later deletion, | |
812 | * by setting their expire times to 0. | |
813 | */ | |
814 | for (i = 0; i < NUSERS; i++) { | |
815 | for (pu = afs_users[i]; pu; pu = pu->next) { | |
816 | if (pu->states & TMP_UPAGNotReferenced) { | |
817 | ||
818 | /* clear the temp flag */ | |
819 | pu->states &= ~TMP_UPAGNotReferenced; | |
820 | ||
821 | /* Is this entry on behalf of a 'remote' user ? | |
822 | * i.e. nfs translator, etc. | |
823 | */ | |
824 | if (!pu->exporter && afs_gcpags == AFS_GCPAGS_OK) { | |
825 | /* make afs_GCUserData remove this entry */ | |
826 | pu->states &= ~UHasTokens; | |
827 | pu->tokenTime = 0; | |
828 | ||
829 | (*ReleasedCount)++; /* remember how many we marked (info only) */ | |
830 | } | |
831 | } | |
832 | } | |
833 | } | |
834 | ||
835 | ReleaseWriteLock(&afs_xuser); | |
836 | ||
837 | return 0; | |
838 | } | |
839 | ||
840 | #endif /* AFS_GCPAGS */ |