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
17 * afs_get_pag_from_groups
18 * afs_get_groups_from_pag
22 #include <afsconfig.h>
23 #include "afs/param.h"
26 #include "afs/sysincludes.h" /* Standard vendor system headers */
27 #include "afsincludes.h" /* Afs-based standard headers */
28 #include "afs/afs_stats.h" /* statistics */
29 #include "afs/afs_cbqueue.h"
30 #include "afs/nfsclient.h"
31 #include "afs/afs_osidnlc.h"
34 /* Imported variables */
35 extern enum afs_shutdown_state afs_shuttingdown
;
37 /* Exported variables */
40 afs_uint32 pagCounter
= 1;
42 afs_uint32 pagCounter
= 0;
46 * Pags are implemented as follows: the set of groups whose long
47 * representation is '41XXXXXX' hex are used to represent the pags.
48 * Being a member of such a group means you are authenticated as pag
49 * XXXXXX (0x41 == 'A', for Andrew). You are never authenticated as
50 * multiple pags at once.
52 * The function afs_InitReq takes a credential field and formats the
53 * corresponding venus request structure. The uid field in the
54 * vrequest structure is set to the *pag* you are authenticated as, or
55 * the uid, if you aren't authenticated with a pag.
57 * The basic motivation behind pags is this: just because your unix
58 * uid is N doesn't mean that you should have the same privileges as
59 * anyone logged in on the machine as user N, since this would enable
60 * the superuser on the machine to sneak in and make use of anyone's
61 * authentication info, even that which is only accidentally left
62 * behind when someone leaves a public workstation.
64 * AFS doesn't use the unix uid for anything except
65 * a handle with which to find the actual authentication tokens
66 * anyway, so the pag is an alternative handle which is somewhat more
67 * secure (although of course not absolutely secure).
74 #ifdef AFS_LINUX20_ENV
75 /* Ensure unique PAG's (mod 200 days) when reloading the client. */
76 return (('A' << 24) + ((pag_epoch
+ pagCounter
++) & 0xffffff));
77 #else /* AFS_LINUX20_ENV */
78 return (('A' << 24) + (pagCounter
++ & 0xffffff));
79 #endif /* AFS_LINUX20_ENV */
86 #ifdef AFS_LINUX20_ENV
87 /* Ensure unique PAG's (mod 200 days) when reloading the client. */
88 return (('A' << 24) + ((pag_epoch
+ pagCounter
) & 0xffffff));
90 return (('A' << 24) + (pagCounter
& 0xffffff));
96 /* Web enhancement: we don't need to restrict pags to 41XXXXXX since
97 * we are not sharing the space with anyone. So we use the full 32 bits. */
103 #ifdef AFS_LINUX20_ENV
104 return (pag_epoch
+ pagCounter
++);
106 return (pagCounter
++);
107 #endif /* AFS_LINUX20_ENV */
114 #ifdef AFS_LINUX20_ENV
115 /* Ensure unique PAG's (mod 200 days) when reloading the client. */
116 return (pag_epoch
+ pagCounter
);
123 /* used to require 10 seconds between each setpag to guarantee that
124 * PAGs never wrap - which would be a security hole. If we presume
125 * that in ordinary operation, the average rate of PAG allocation
126 * will not exceed one per second, the 24 bits provided will be
127 * sufficient for ~200 days. Unfortunately, if we merely assume that,
128 * there will be an opportunity for attack. So we must enforce it.
129 * If we need to increase the average rate of PAG allocation, we
130 * should increase the number of bits in a PAG, and/or reduce our
131 * window in which we guarantee that the PAG counter won't wrap.
132 * By permitting an average of one new PAG per second, new PAGs can
133 * be allocated VERY frequently over a short period relative to total uptime.
134 * Of course, there's only an issue here if one user stays logged (and re-
135 * activates tokens repeatedly) for that entire period.
138 static int afs_pag_sleepcnt
= 0;
139 static int afs_pag_timewarn
= 0;
142 afs_pag_sleep(afs_ucred_t
**acred
)
146 if (!afs_suser(acred
)) {
147 if(osi_Time() - pag_epoch
< pagCounter
) {
150 if (rv
&& (osi_Time() < pag_epoch
)) {
151 if (!afs_pag_timewarn
) {
152 afs_pag_timewarn
= 1;
153 afs_warn("clock went backwards, not PAG throttling");
163 afs_pag_wait(afs_ucred_t
**acred
)
165 if (afs_pag_sleep(acred
)) {
166 if (!afs_pag_sleepcnt
) {
167 afs_warn("%s() PAG throttling triggered, pid %d... sleeping. sleepcnt %d\n",
168 "afs_pag_wait", osi_getpid(), afs_pag_sleepcnt
);
174 /* XXX spins on EINTR */
175 afs_osi_Wait(1000, (struct afs_osi_WaitHandle
*)0, 0);
176 } while (afs_pag_sleep(acred
));
185 #if defined(AFS_SUN5_ENV)
186 afs_setpag(afs_ucred_t
**credpp
)
187 #elif defined(AFS_FBSD_ENV)
188 afs_setpag(struct thread
*td
, void *args
)
189 #elif defined(AFS_NBSD_ENV)
190 afs_setpag(afs_proc_t
*p
, const void *args
, register_t
*retval
)
191 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
192 afs_setpag(afs_proc_t
*p
, void *args
, int *retval
)
198 #if defined(AFS_SUN5_ENV)
199 afs_ucred_t
**acred
= *credpp
;
200 #elif defined(AFS_OBSD_ENV)
201 afs_ucred_t
**acred
= &p
->p_ucred
;
203 afs_ucred_t
**acred
= NULL
;
208 #if defined(AFS_SGI53_ENV) && defined(MP)
209 /* This is our first chance to get the global lock. */
211 #endif /* defined(AFS_SGI53_ENV) && defined(MP) */
213 AFS_STATCNT(afs_setpag
);
218 #if defined(AFS_SUN5_ENV)
219 code
= AddPag(genpag(), credpp
);
220 #elif defined(AFS_FBSD_ENV)
221 code
= AddPag(td
, genpag(), &td
->td_ucred
);
222 #elif defined(AFS_NBSD40_ENV)
223 code
= AddPag(p
, genpag(), &p
->l_proc
->p_cred
);
224 #elif defined(AFS_XBSD_ENV)
225 code
= AddPag(p
, genpag(), &p
->p_rcred
);
226 #elif defined(AFS_AIX41_ENV)
229 struct ucred
*credp0
;
233 code
= AddPag(genpag(), &credp
);
234 /* If AddPag() didn't make a new cred, then free our cred ref */
235 if (credp
== credp0
) {
239 #elif defined(AFS_HPUX110_ENV)
241 struct ucred
*credp
= p_cred(u
.u_procp
);
242 code
= AddPag(genpag(), &credp
);
244 #elif defined(AFS_SGI_ENV)
247 credp
= OSI_GET_CURRENT_CRED();
248 code
= AddPag(genpag(), &credp
);
250 #elif defined(AFS_LINUX20_ENV)
252 afs_ucred_t
*credp
= crref();
253 code
= AddPag(genpag(), &credp
);
256 #elif defined(AFS_DARWIN80_ENV)
258 afs_ucred_t
*credp
= kauth_cred_proc_ref(p
);
259 code
= AddPag(p
, genpag(), &credp
);
262 #elif defined(AFS_DARWIN_ENV)
264 afs_ucred_t
*credp
= crdup(p
->p_cred
->pc_ucred
);
265 code
= AddPag(p
, genpag(), &credp
);
268 #elif defined(UKERNEL)
269 code
= AddPag(genpag(), &(get_user_struct()->u_cred
));
271 code
= AddPag(genpag(), &u
.u_cred
);
274 afs_Trace1(afs_iclSetp
, CM_TRACE_SETPAG
, ICL_TYPE_INT32
, code
);
276 #if defined(KERNEL_HAVE_UERROR)
281 #if defined(AFS_SGI53_ENV) && defined(MP)
283 #endif /* defined(AFS_SGI53_ENV) && defined(MP) */
291 * This function is like setpag but sets the current thread's pag id to a
292 * caller-provided value instead of calling genpag(). This implements a
293 * form of token caching since the caller can recall a particular pag value
294 * for the thread to restore tokens, rather than reauthenticating.
297 #if defined(AFS_SUN5_ENV)
298 afs_setpag_val(afs_ucred_t
**credpp
, int pagval
)
299 #elif defined(AFS_FBSD_ENV)
300 afs_setpag_val(struct thread
*td
, void *args
, int pagval
)
301 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
302 afs_setpag_val(afs_proc_t
*p
, void *args
, int *retval
, int pagval
)
304 afs_setpag_val(int pagval
)
308 #if defined(AFS_SUN5_ENV)
309 afs_ucred_t
**acred
= *credp
;
310 #elif defined(AFS_OBSD_ENV)
311 afs_ucred_t
**acred
= &p
->p_ucred
;
313 afs_ucred_t
**acred
= NULL
;
318 #if defined(AFS_SGI53_ENV) && defined(MP)
319 /* This is our first chance to get the global lock. */
321 #endif /* defined(AFS_SGI53_ENV) && defined(MP) */
323 AFS_STATCNT(afs_setpag
);
327 #if defined(AFS_SUN5_ENV)
328 code
= AddPag(pagval
, credpp
);
329 #elif defined(AFS_FBSD_ENV)
330 code
= AddPag(td
, pagval
, &td
->td_ucred
);
331 #elif defined(AFS_XBSD_ENV)
332 code
= AddPag(p
, pagval
, &p
->p_rcred
);
333 #elif defined(AFS_AIX41_ENV)
336 struct ucred
*credp0
;
340 code
= AddPag(pagval
, &credp
);
341 /* If AddPag() didn't make a new cred, then free our cred ref */
342 if (credp
== credp0
) {
346 #elif defined(AFS_HPUX110_ENV)
348 struct ucred
*credp
= p_cred(u
.u_procp
);
349 code
= AddPag(pagval
, &credp
);
351 #elif defined(AFS_SGI_ENV)
354 credp
= OSI_GET_CURRENT_CRED();
355 code
= AddPag(pagval
, &credp
);
357 #elif defined(AFS_LINUX20_ENV)
359 afs_ucred_t
*credp
= crref();
360 code
= AddPag(pagval
, &credp
);
363 #elif defined(AFS_DARWIN_ENV)
365 struct ucred
*credp
= crdup(p
->p_cred
->pc_ucred
);
366 code
= AddPag(p
, pagval
, &credp
);
369 #elif defined(UKERNEL)
370 code
= AddPag(pagval
, &(get_user_struct()->u_cred
));
372 code
= AddPag(pagval
, &u
.u_cred
);
375 afs_Trace1(afs_iclSetp
, CM_TRACE_SETPAG
, ICL_TYPE_INT32
, code
);
376 #if defined(KERNEL_HAVE_UERROR)
380 #if defined(AFS_SGI53_ENV) && defined(MP)
382 #endif /* defined(AFS_SGI53_ENV) && defined(MP) */
386 #ifndef AFS_PAG_ONEGROUP_ENV
392 afs_ucred_t
*credp
= get_user_struct()->u_cred
;
394 afs_ucred_t
*credp
= u
.u_cred
;
396 gid_t gidset0
, gidset1
;
397 #ifdef AFS_SUN510_ENV
400 gids
= crgetgroups(*credp
);
404 gidset0
= credp
->cr_groups
[0];
405 gidset1
= credp
->cr_groups
[1];
407 pagvalue
= afs_get_pag_from_groups(gidset0
, gidset1
);
414 /* Note - needs to be available on AIX, others can be static - rework this */
416 #if defined(AFS_FBSD_ENV)
417 AddPag(struct thread
*p
, afs_int32 aval
, afs_ucred_t
**credpp
)
418 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
419 AddPag(afs_proc_t
*p
, afs_int32 aval
, afs_ucred_t
**credpp
)
421 AddPag(afs_int32 aval
, afs_ucred_t
**credpp
)
428 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
429 if ((code
= setpag(p
, credpp
, aval
, &newpag
, 0)))
431 if ((code
= setpag(credpp
, aval
, &newpag
, 0)))
433 #if defined(KERNEL_HAVE_UERROR)
434 return (setuerror(code
), code
);
443 afs_InitReq(struct vrequest
*av
, afs_ucred_t
*acred
)
445 #if defined(AFS_LINUX26_ENV) && !defined(AFS_NONFSTRANS)
449 AFS_STATCNT(afs_InitReq
);
450 memset(av
, 0, sizeof(*av
));
451 if (afs_shuttingdown
== AFS_SHUTDOWN
)
454 #ifdef AFS_LINUX26_ENV
455 #if !defined(AFS_NONFSTRANS)
456 if (osi_linux_nfs_initreq(av
, acred
, &code
))
461 av
->uid
= PagInCred(acred
);
462 if (av
->uid
== NOPAG
) {
463 /* Afs doesn't use the unix uid for anuthing except a handle
464 * with which to find the actual authentication tokens so I
465 * think it's ok to use the real uid to make setuid
466 * programs (without setpag) to work properly.
468 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
470 av
->uid
= -2; /* XXX nobody... ? */
472 av
->uid
= afs_cr_uid(acred
); /* bsd creds don't have ruid */
473 #elif defined(AFS_SUN510_ENV)
474 av
->uid
= crgetruid(acred
);
476 av
->uid
= afs_cr_ruid(acred
); /* default when no pag is set */
483 * Allocate and setup a vrequest.
485 * \note The caller must free the allocated vrequest with
486 * afs_DestroyReq() if this function returns successfully (zero).
488 * \note The GLOCK must be held on platforms which require the GLOCK
489 * for osi_AllocSmallSpace() and osi_FreeSmallSpace().
491 * \param[out] avpp address of the vrequest pointer
492 * \param[in] acred user credentials to setup the vrequest
493 * afs_osi_credp should be used for anonymous connections
494 * \return 0 on success
497 afs_CreateReq(struct vrequest
**avpp
, afs_ucred_t
*acred
)
500 struct vrequest
*treq
= NULL
;
502 if (afs_shuttingdown
== AFS_SHUTDOWN
) {
505 if (!avpp
|| !acred
) {
508 treq
= osi_AllocSmallSpace(sizeof(struct vrequest
));
512 code
= afs_InitReq(treq
, acred
);
514 osi_FreeSmallSpace(treq
);
522 * Deallocate a vrequest.
524 * \note The GLOCK must be held on platforms which require the GLOCK
525 * for osi_FreeSmallSpace().
527 * \param[in] av pointer to the vrequest to free; may be NULL
530 afs_DestroyReq(struct vrequest
*av
)
533 osi_FreeSmallSpace(av
);
538 afs_get_pag_from_groups(gid_t g0a
, gid_t g1a
)
542 afs_uint32 h
, l
, ret
;
544 AFS_STATCNT(afs_get_pag_from_groups
);
548 if (g0
< 0xc000 && g1
< 0xc000) {
549 l
= ((g0
& 0x3fff) << 14) | (g1
& 0x3fff);
551 h
= (g1
>> 14) + h
+ h
+ h
;
552 ret
= ((h
<< 28) | l
);
553 # if defined(UKERNEL)
556 /* Additional testing */
557 if (((ret
>> 24) & 0xff) == 'A')
559 # endif /* UKERNEL */
564 #ifndef AFS_PAG_ONEGROUP_ENV
566 afs_get_groups_from_pag(afs_uint32 pag
, gid_t
* g0p
, gid_t
* g1p
)
568 unsigned short g0
, g1
;
570 AFS_STATCNT(afs_get_groups_from_pag
);
573 # if !defined(UKERNEL)
575 # endif /* UKERNEL */
576 g0
= 0x3fff & (pag
>> 14);
578 g0
|= ((pag
>> 28) / 3) << 14;
579 g1
|= ((pag
>> 28) % 3) << 14;
585 afs_get_groups_from_pag(afs_uint32 pag
, gid_t
*g0p
, gid_t
*g1p
)
587 AFS_STATCNT(afs_get_groups_from_pag
);
593 #ifdef AFS_LINUX26_ENV
594 /* osi_get_group_pag is defined in <ARCH>/osi_groups.c */
595 #elif defined(AFS_PAG_ONEGROUP_ENV)
596 /* osi_get_group_pag is defined in <ARCH>/osi_groups.c */
597 #elif defined(AFS_DARWIN110_ENV)
598 /* We don't have pags, so we do not define an osi_get_group_pag */
601 osi_get_group_pag(afs_ucred_t
*cred
)
603 afs_int32 pag
= NOPAG
;
605 #if defined(AFS_SUN510_ENV)
610 #if defined(AFS_SUN510_ENV)
611 gids
= crgetgroups(cred
);
612 ngroups
= crgetngroups(cred
);
614 #if defined(AFS_NBSD40_ENV)
615 if (cred
== NOCRED
|| cred
== FSCRED
)
617 if (osi_crngroups(cred
) < 3)
619 g0
= osi_crgroupbyid(cred
, 1);
620 g1
= osi_crgroupbyid(cred
, 2);
621 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
622 if (cred
== NOCRED
|| cred
== FSCRED
)
624 if (cred
->cr_ngroups
< 3)
626 /* gid is stored in cr_groups[0] */
627 g0
= cred
->cr_groups
[1];
628 g1
= cred
->cr_groups
[2];
630 # if defined(AFS_AIX_ENV)
631 if (cred
->cr_ngrps
< 2)
633 # elif defined(AFS_LINUX26_ENV)
634 if (afs_cr_group_info(cred
)->ngroups
< AFS_NUMPAGGROUPS
)
636 # elif defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_LINUX20_ENV) || defined(AFS_XBSD_ENV)
637 # if defined(AFS_SUN510_ENV)
640 if (cred
->cr_ngroups
< 2) {
645 # if defined(AFS_AIX51_ENV)
646 g0
= cred
->cr_groupset
.gs_union
.un_groups
[0];
647 g1
= cred
->cr_groupset
.gs_union
.un_groups
[1];
648 #elif defined(AFS_SUN510_ENV)
652 g0
= cred
->cr_groups
[0];
653 g1
= cred
->cr_groups
[1];
656 pag
= (afs_int32
) afs_get_pag_from_groups(g0
, g1
);
663 PagInCred(afs_ucred_t
*cred
)
665 afs_int32 pag
= NOPAG
;
667 AFS_STATCNT(PagInCred
);
668 if (cred
== NULL
|| cred
== afs_osi_credp
) {
671 #ifndef AFS_DARWIN110_ENV
672 #if defined(AFS_LINUX26_ENV) && defined(LINUX_KEYRING_SUPPORT)
674 * If linux keyrings are in use and we carry the session keyring in our credentials
675 * structure, they should be the only criteria for determining
676 * if we're in a PAG. Groups are updated for legacy reasons only for now,
677 * and should not be used to infer PAG membership
678 * With keyrings but no kernel credentials, look at groups first and fall back
679 * to looking at the keyrings.
681 # if !defined(STRUCT_TASK_STRUCT_HAS_CRED)
682 pag
= osi_get_group_pag(cred
);
685 pag
= osi_get_keyring_pag(cred
);
686 #elif defined(AFS_AIX51_ENV)
687 if (kcred_getpag(cred
, PAG_AFS
, &pag
) < 0 || pag
== 0)
690 pag
= osi_get_group_pag(cred
);