newvolumebyname-analyze-the-vrequest-actually-used-20020205
[openafs.git] / src / afs / afs_osi_pag.c
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  * genpag
13  * getpag
14  * afs_setpag
15  * AddPag
16  * afs_InitReq
17  * afs_get_pag_from_groups
18  * afs_get_groups_from_pag
19  * PagInCred
20  */
21
22 #include <afsconfig.h>
23 #include "../afs/param.h"
24
25 RCSID("$Header$");
26
27 #include "../afs/sysincludes.h" /* Standard vendor system headers */
28 #include "../afs/afsincludes.h" /* Afs-based standard headers */
29 #include "../afs/afs_stats.h" /* statistics */
30 #include "../afs/afs_cbqueue.h"
31 #include "../afs/nfsclient.h"
32 #include "../afs/afs_osidnlc.h"
33
34
35 /* Imported variables */
36 extern int afs_shuttingdown;
37
38 /* Exported variables */
39 afs_uint32 pag_epoch;
40 #if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS)
41 afs_uint32 pagCounter = 1;
42 #else
43 afs_uint32 pagCounter = 0;
44 #endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */
45
46 /* Local variables */
47
48 /*
49  * Pags are implemented as follows: the set of groups whose long
50  * representation is '41XXXXXX' hex are used to represent the pags.
51  * Being a member of such a group means you are authenticated as pag
52  * XXXXXX (0x41 == 'A', for Andrew).  You are never authenticated as
53  * multiple pags at once.
54  *
55  * The function afs_InitReq takes a credential field and formats the
56  * corresponding venus request structure.  The uid field in the
57  * vrequest structure is set to the *pag* you are authenticated as, or
58  * the uid, if you aren't authenticated with a pag.
59  *
60  * The basic motivation behind pags is this: just because your unix
61  * uid is N doesn't mean that you should have the same privileges as
62  * anyone logged in on the machine as user N, since this would enable
63  * the superuser on the machine to sneak in and make use of anyone's
64  * authentication info, even that which is only accidentally left
65  * behind when someone leaves a public workstation.
66  *
67  * AFS doesn't use the unix uid for anything except
68  * a handle with which to find the actual authentication tokens
69  * anyway, so the pag is an alternative handle which is somewhat more
70  * secure (although of course not absolutely secure).
71 */
72 #if !defined(UKERNEL) || !defined(AFS_WEB_ENHANCEMENTS)
73 afs_uint32 genpag(void) {
74     AFS_STATCNT(genpag);
75 #ifdef AFS_LINUX20_ENV
76     /* Ensure unique PAG's (mod 200 days) when reloading the client. */
77     return (('A' << 24) + ((pag_epoch + pagCounter++) & 0xffffff));
78 #else /* AFS_LINUX20_ENV */
79     return (('A' << 24) + (pagCounter++ & 0xffffff));
80 #endif /* AFS_LINUX20_ENV */
81 }
82
83 afs_uint32 getpag(void) {
84     AFS_STATCNT(getpag);
85 #ifdef AFS_LINUX20_ENV
86     /* Ensure unique PAG's (mod 200 days) when reloading the client. */
87     return (('A' << 24) + ((pag_epoch + pagCounter) & 0xffffff));
88 #else
89     return (('A' << 24) + (pagCounter & 0xffffff));
90 #endif
91 }
92
93 #else
94
95 /* Web enhancement: we don't need to restrict pags to 41XXXXXX since
96  * we are not sharing the space with anyone.  So we use the full 32 bits. */
97
98 afs_uint32 genpag(void) {
99     AFS_STATCNT(genpag);
100 #ifdef AFS_LINUX20_ENV
101     return (pag_epoch + pagCounter++);
102 #else
103     return (pagCounter++);
104 #endif /* AFS_LINUX20_ENV */
105 }
106
107 afs_uint32 getpag(void) {
108     AFS_STATCNT(getpag);
109 #ifdef AFS_LINUX20_ENV
110     /* Ensure unique PAG's (mod 200 days) when reloading the client. */
111     return (pag_epoch + pagCounter);
112 #else
113     return (pagCounter);
114 #endif
115 }
116 #endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */
117
118 /* used to require 10 seconds between each setpag to guarantee that
119  * PAGs never wrap - which would be a security hole.  If we presume
120  * that in ordinary operation, the average rate of PAG allocation
121  * will not exceed one per second, the 24 bits provided will be
122  * sufficient for ~200 days.  Unfortunately, if we merely assume that,
123  * there will be an opportunity for attack.  So we must enforce it.
124  * If we need to increase the average rate of PAG allocation, we
125  * should increase the number of bits in a PAG, and/or reduce our
126  * window in which we guarantee that the PAG counter won't wrap.
127  * By permitting an average of one new PAG per second, new PAGs can
128  * be allocated VERY frequently over a short period relative to total uptime.
129  * Of course, there's only an issue here if one user stays logged (and re-
130  * activates tokens repeatedly) for that entire period.
131  */
132
133 int
134 #if     defined(AFS_SUN5_ENV)
135 afs_setpag (struct AFS_UCRED **credpp)
136 #elif  defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
137 afs_setpag (struct proc *p, void *args, int *retval)
138 #else
139 afs_setpag (void) 
140 #endif
141 {
142     int code = 0;
143
144 #if defined(AFS_SGI53_ENV) && defined(MP)
145     /* This is our first chance to get the global lock. */
146     AFS_GLOCK();
147 #endif /* defined(AFS_SGI53_ENV) && defined(MP) */    
148
149     AFS_STATCNT(afs_setpag);
150 #ifdef AFS_SUN5_ENV
151     if (!afs_suser(*credpp))
152 #else
153     if (!afs_suser())
154 #endif
155     {
156         while (osi_Time() - pag_epoch < pagCounter ) {
157             afs_osi_Wait(1000, (struct afs_osi_WaitHandle *) 0, 0);
158         }       
159     }
160
161 #if     defined(AFS_SUN5_ENV)
162     code = AddPag(genpag(), credpp);
163 #elif   defined(AFS_OSF_ENV) || defined(AFS_FBSD_ENV)
164     code = AddPag(p, genpag(), &p->p_rcred);
165 #elif   defined(AFS_AIX41_ENV)
166     {
167         struct ucred *credp;
168         struct ucred *credp0;
169         
170         credp = crref();
171         credp0 = credp;
172         code = AddPag(genpag(), &credp);
173         /* If AddPag() didn't make a new cred, then free our cred ref */
174         if (credp == credp0) {
175             crfree(credp);
176         }
177     }
178 #elif   defined(AFS_HPUX110_ENV)
179     {
180         struct ucred *credp = p_cred(u.u_procp);
181         code = AddPag(genpag(), &credp);
182     }
183 #elif   defined(AFS_SGI_ENV)
184     {
185         cred_t *credp;
186         credp = OSI_GET_CURRENT_CRED();
187         code = AddPag(genpag(), &credp);
188     }
189 #elif   defined(AFS_LINUX20_ENV)
190     {
191         struct AFS_UCRED *credp = crref();
192         code = AddPag(genpag(), &credp);
193         crfree(credp);
194     }
195 #elif defined(AFS_DARWIN_ENV)  || defined(AFS_FBSD_ENV)
196     {
197        struct ucred *credp=crdup(p->p_cred->pc_ucred);
198        code=AddPag(p, genpag(), &credp);
199        crfree(credp);
200     }
201 #else
202     code = AddPag(genpag(), &u.u_cred);
203 #endif
204
205     afs_Trace1(afs_iclSetp, CM_TRACE_SETPAG, ICL_TYPE_INT32, code);
206 #if     defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_LINUX20_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
207 #if defined(AFS_SGI53_ENV) && defined(MP)
208     AFS_GUNLOCK();
209 #endif /* defined(AFS_SGI53_ENV) && defined(MP) */    
210     return (code);
211 #else
212     if (!getuerror())
213         setuerror(code);
214     return (code);
215 #endif
216 }
217
218 #if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS)
219 /*
220  * afs_setpag_val
221  * This function is like setpag but sets the current thread's pag id to a
222  * caller-provided value instead of calling genpag().  This implements a
223  * form of token caching since the caller can recall a particular pag value
224  * for the thread to restore tokens, rather than reauthenticating.
225  */
226 int
227 #if     defined(AFS_SUN5_ENV)
228 afs_setpag_val (struct AFS_UCRED **credpp, int pagval)
229 #elif  defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
230 afs_setpag_val (struct proc *p, void *args, int *retval, int pagval)
231 #else
232 afs_setpag_val (int pagval) 
233 #endif
234 {
235     int code = 0;
236
237 #if defined(AFS_SGI53_ENV) && defined(MP)
238     /* This is our first chance to get the global lock. */
239     AFS_GLOCK();
240 #endif /* defined(AFS_SGI53_ENV) && defined(MP) */    
241
242     AFS_STATCNT(afs_setpag);
243 #ifdef AFS_SUN5_ENV
244     if (!afs_suser(*credpp))
245 #else
246     if (!afs_suser())
247 #endif
248     {
249         while (osi_Time() - pag_epoch < pagCounter ) {
250             afs_osi_Wait(1000, (struct afs_osi_WaitHandle *) 0, 0);
251         }       
252     }
253
254 #if     defined(AFS_SUN5_ENV)
255     code = AddPag(pagval, credpp);
256 #elif   defined(AFS_OSF_ENV) || defined(AFS_FBSD_ENV)
257     code = AddPag(p, pagval, &p->p_rcred);
258 #elif   defined(AFS_AIX41_ENV)
259     {
260         struct ucred *credp;
261         struct ucred *credp0;
262         
263         credp = crref();
264         credp0 = credp;
265         code = AddPag(pagval, &credp);
266         /* If AddPag() didn't make a new cred, then free our cred ref */
267         if (credp == credp0) {
268             crfree(credp);
269         }
270     }
271 #elif   defined(AFS_HPUX110_ENV)
272     {
273         struct ucred *credp = p_cred(u.u_procp);
274         code = AddPag(pagval, &credp);
275     }
276 #elif   defined(AFS_SGI_ENV)
277     {
278         cred_t *credp;
279         credp = OSI_GET_CURRENT_CRED();
280         code = AddPag(pagval, &credp);
281     }
282 #elif   defined(AFS_LINUX20_ENV)
283     {
284         struct AFS_UCRED *credp = crref();
285         code = AddPag(pagval, &credp);
286         crfree(credp);
287     }
288 #elif defined(AFS_DARWIN_ENV)  || defined(AFS_FBSD_ENV)
289     {
290        struct ucred *credp=crdup(p->p_cred->pc_ucred);
291        code=AddPag(p, pagval, &credp);
292        crfree(credp);
293     }
294 #else
295     code = AddPag(pagval, &u.u_cred);
296 #endif
297
298     afs_Trace1(afs_iclSetp, CM_TRACE_SETPAG, ICL_TYPE_INT32, code);
299 #if     defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_LINUX20_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
300 #if defined(AFS_SGI53_ENV) && defined(MP)
301     AFS_GUNLOCK();
302 #endif /* defined(AFS_SGI53_ENV) && defined(MP) */    
303     return (code);
304 #else
305     if (!getuerror())
306         setuerror(code);
307     return (code);
308 #endif
309 }
310 #endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */
311
312 #if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS)
313 int afs_getpag_val()
314 {
315   int pagvalue;
316   struct AFS_UCRED *credp = u.u_cred;
317   int gidset0, gidset1;
318
319   gidset0 = credp->cr_groups[0];
320   gidset1 = credp->cr_groups[1];
321   pagvalue=afs_get_pag_from_groups(gidset0, gidset1);
322   return pagvalue;
323 }
324 #endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */
325
326
327 #if defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
328 int AddPag(struct proc *p, afs_int32 aval, struct AFS_UCRED **credpp)
329 #else   /* AFS_OSF_ENV || AFS_FBSD_ENV */
330 int AddPag(afs_int32 aval, struct AFS_UCRED **credpp)
331 #endif
332 {
333     afs_int32 newpag, code;
334     AFS_STATCNT(AddPag);
335 #if defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
336     if (code = setpag(p, credpp, aval, &newpag, 0))
337 #else   /* AFS_OSF_ENV */
338     if (code = setpag(credpp, aval, &newpag, 0))
339 #endif
340 #if     defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_LINUX20_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
341         return (code);
342 #else
343         return (setuerror(code), code);
344 #endif
345     return 0;
346 }
347
348
349 afs_InitReq(av, acred)
350     register struct vrequest *av;
351     struct AFS_UCRED *acred; {
352
353     AFS_STATCNT(afs_InitReq);
354     if (afs_shuttingdown) return EIO;
355     av->uid = PagInCred(acred);
356     if (av->uid == NOPAG) {
357         /* Afs doesn't use the unix uid for anuthing except a handle
358          * with which to find the actual authentication tokens so I
359          * think it's ok to use the real uid to make setuid
360          * programs (without setpag) to work properly.
361          */
362 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
363         av->uid = acred->cr_uid;    /* default when no pag is set */
364                                     /* bsd creds don't have ruid */
365 #else
366         av->uid = acred->cr_ruid;    /* default when no pag is set */
367 #endif
368     }
369     av->initd = 0;
370     return 0;
371 }
372
373
374
375 afs_uint32 afs_get_pag_from_groups(gid_t g0a, gid_t g1a)
376 {
377     afs_uint32 g0 = g0a;
378     afs_uint32 g1 = g1a;
379     afs_uint32 h, l, ret;
380
381     AFS_STATCNT(afs_get_pag_from_groups);
382     g0 -= 0x3f00;
383     g1 -= 0x3f00;
384     if (g0 < 0xc000 && g1 < 0xc000) {
385         l = ((g0 & 0x3fff) << 14) | (g1 & 0x3fff);
386         h = (g0 >> 14);
387         h = (g1 >> 14) + h + h + h;
388         ret = ((h << 28) | l);
389 #if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS)
390         return ret;
391 #else
392         /* Additional testing */
393         if (((ret >> 24) & 0xff) == 'A')
394             return ret;
395         else
396             return NOPAG;
397 #endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */
398     }
399     return NOPAG;
400 }
401
402
403 void afs_get_groups_from_pag(afs_uint32 pag, gid_t *g0p, gid_t *g1p)
404 {
405     unsigned short g0, g1;
406
407
408     AFS_STATCNT(afs_get_groups_from_pag);
409 #if !defined(UKERNEL) || !defined(AFS_WEB_ENHANCEMENTS)
410     pag &= 0x7fffffff;
411 #endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */
412     g0 = 0x3fff & (pag >> 14);
413     g1 = 0x3fff & pag;
414     g0 |= ((pag >> 28) / 3) << 14;
415     g1 |= ((pag >> 28) % 3) << 14;
416     *g0p = g0 + 0x3f00;
417     *g1p = g1 + 0x3f00;
418 }
419
420
421 afs_int32 PagInCred(const struct AFS_UCRED *cred)
422 {
423     afs_int32 pag;
424     gid_t g0, g1;
425
426     AFS_STATCNT(PagInCred);
427     if (cred == NULL) {
428         return NOPAG;
429     }
430 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
431     if (cred == NOCRED || cred == FSCRED) {
432         return NOPAG;
433     }
434     if (cred->cr_ngroups < 3) return NOPAG;
435     /* gid is stored in cr_groups[0] */
436     g0 = cred->cr_groups[1];
437     g1 = cred->cr_groups[2];
438 #else
439 #ifdef  AFS_AIX_ENV
440     if (cred->cr_ngrps < 2) {
441         return NOPAG;
442     }
443 #else
444 #if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_DUX40_ENV) || defined(AFS_LINUX_ENV) || defined(AFS_FBSD_ENV)
445     if (cred->cr_ngroups < 2) return NOPAG;
446 #endif
447 #endif
448     g0 = cred->cr_groups[0];
449     g1 = cred->cr_groups[1];
450 #endif
451     pag = (afs_int32)afs_get_pag_from_groups(g0, g1);
452     return pag;
453 }