dread-do-validation-20041012
[openafs.git] / src / afs / LINUX / osi_cred.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  * osi_cred.c - Linux cred handling routines.
12  *
13  */
14 #include <afsconfig.h>
15 #include "afs/param.h"
16
17 RCSID
18     ("$Header$");
19
20 #include "afs/sysincludes.h"
21 #include "afsincludes.h"
22
23 /* Setup a pool for creds. Allocate several at a time. */
24 #define CRED_ALLOC_STEP 29      /* at 140 bytes/cred = 4060 bytes. */
25
26
27 static cred_t *cred_pool = NULL;
28 int cred_allocs = 0;
29 int ncreds_inuse = 0;
30
31 /* Cred locking assumes current single threaded non-preemptive kernel.
32  * Also assuming a fast path through both down and up if no waiters. Otherwise,
33  * test if no creds in pool before grabbing lock in crfree().
34  */
35 #if defined(AFS_LINUX24_ENV)
36 static DECLARE_MUTEX(linux_cred_pool_lock);
37 #else
38 static struct semaphore linux_cred_pool_lock = MUTEX;
39 #endif
40 #define CRED_LOCK() down(&linux_cred_pool_lock)
41 #define CRED_UNLOCK() up(&linux_cred_pool_lock)
42
43 cred_t *
44 crget(void)
45 {
46     cred_t *tmp;
47     int i;
48
49     CRED_LOCK();
50     if (!cred_pool) {
51         cred_allocs++;
52         cred_pool = (cred_t *) osi_Alloc(CRED_ALLOC_STEP * sizeof(cred_t));
53         if (!cred_pool)
54             osi_Panic("crget: No more memory for creds!\n");
55
56         for (i = 0; i < CRED_ALLOC_STEP - 1; i++)
57             cred_pool[i].cr_ref = (long)&cred_pool[i + 1];
58         cred_pool[i].cr_ref = 0;
59     }
60     tmp = cred_pool;
61     cred_pool = (cred_t *) tmp->cr_ref;
62     ncreds_inuse++;
63     CRED_UNLOCK();
64
65     memset(tmp, 0, sizeof(cred_t));
66 #if defined(AFS_LINUX26_ENV)
67     tmp->cr_group_info = groups_alloc(0);
68 #endif
69     tmp->cr_ref = 1;
70     return tmp;
71 }
72
73 void
74 crfree(cred_t * cr)
75 {
76     if (cr->cr_ref > 1) {
77 #if defined(AFS_LINUX26_ENV)
78         put_group_info(cr->cr_group_info);
79 #endif
80         cr->cr_ref--;
81         return;
82     }
83
84     CRED_LOCK();
85     cr->cr_ref = (long)cred_pool;
86     cred_pool = cr;
87     CRED_UNLOCK();
88     ncreds_inuse--;
89 }
90
91
92 /* Return a duplicate of the cred. */
93 cred_t *
94 crdup(cred_t * cr)
95 {
96     cred_t *tmp = crget();
97
98     tmp->cr_uid = cr->cr_uid;
99     tmp->cr_ruid = cr->cr_ruid;
100     tmp->cr_gid = cr->cr_gid;
101 #if defined(AFS_LINUX26_ENV)
102 {
103     struct group_info *old_info;
104
105     old_info = tmp->cr_group_info;
106     get_group_info(cr->cr_group_info);
107     tmp->cr_group_info = cr->cr_group_info;
108     put_group_info(old_info);
109 }
110 #else
111     memcpy(tmp->cr_groups, cr->cr_groups, NGROUPS * sizeof(gid_t));
112     tmp->cr_ngroups = cr->cr_ngroups;
113 #endif
114
115     tmp->cr_ref = 1;
116     return tmp;
117 }
118
119 cred_t *
120 crref(void)
121 {
122     cred_t *cr = crget();
123
124     cr->cr_uid = current->fsuid;
125     cr->cr_ruid = current->uid;
126     cr->cr_gid = current->fsgid;
127     cr->cr_rgid = current->gid;
128 #if defined(AFS_LINUX26_ENV)
129 {
130     struct group_info *old_info;
131
132     old_info = cr->cr_group_info;
133     get_group_info(current->group_info);
134     cr->cr_group_info = current->group_info;
135     put_group_info(old_info);
136 }
137 #else
138     memcpy(cr->cr_groups, current->groups, NGROUPS * sizeof(gid_t));
139     cr->cr_ngroups = current->ngroups;
140 #endif
141     return cr;
142 }
143
144
145 /* Set the cred info into the current task */
146 void
147 crset(cred_t * cr)
148 {
149     current->fsuid = cr->cr_uid;
150     current->uid = cr->cr_ruid;
151     current->fsgid = cr->cr_gid;
152     current->gid = cr->cr_rgid;
153 #if defined(AFS_LINUX26_ENV)
154 {
155     struct group_info *old_info;
156
157     /* using set_current_groups() will sort the groups */
158     old_info = current->group_info;
159     get_group_info(cr->cr_group_info);
160     current->group_info = cr->cr_group_info;
161     put_group_info(old_info);
162 }
163 #else
164     memcpy(current->groups, cr->cr_groups, NGROUPS * sizeof(gid_t));
165     current->ngroups = cr->cr_ngroups;
166 #endif
167 }