Linux: Mark our super block as not updating access time
[openafs.git] / src / afs / LINUX24 / osi_groups.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  * setgroups (syscall)
13  * setpag
14  *
15  */
16 #include <afsconfig.h>
17 #include "afs/param.h"
18 #ifdef LINUX_KEYRING_SUPPORT
19 #include <linux/seq_file.h>
20 #endif
21
22
23 #include "afs/sysincludes.h"
24 #include "afsincludes.h"
25 #include "afs/afs_stats.h"      /* statistics */
26 #include "afs/nfsclient.h"
27 #ifdef AFS_LINUX22_ENV
28 #include "h/smp_lock.h"
29 #endif
30
31 #define NUMPAGGROUPS 2
32
33 static int
34 afs_setgroups(cred_t **cr, int ngroups, gid_t * gidset, int change_parent)
35 {
36     int ngrps;
37     int i;
38     gid_t *gp;
39
40     AFS_STATCNT(afs_setgroups);
41
42     if (ngroups > NGROUPS)
43         return EINVAL;
44
45     gp = (*cr)->cr_groups;
46     if (ngroups < NGROUPS)
47         gp[ngroups] = (gid_t) NOGROUP;
48
49     for (i = ngroups; i > 0; i--) {
50         *gp++ = *gidset++;
51     }
52
53     (*cr)->cr_ngroups = ngroups;
54     crset(*cr);
55     return (0);
56 }
57
58 /* Returns number of groups. And we trust groups to be large enough to
59  * hold all the groups.
60  */
61 static int
62 afs_getgroups(cred_t *cr, gid_t *groups)
63 {
64     int i;
65     int n;
66     gid_t *gp;
67
68     AFS_STATCNT(afs_getgroups);
69
70     gp = cr->cr_groups;
71     n = cr->cr_ngroups;
72
73     for (i = 0; (i < n) && (*gp != (gid_t) NOGROUP); i++)
74         *groups++ = *gp++;
75     return i;
76 }
77
78 /* Only propogate the PAG to the parent process. Unix's propogate to 
79  * all processes sharing the cred.
80  */
81 int
82 set_pag_in_parent(int pag, int g0, int g1)
83 {
84     int i;
85 #ifdef STRUCT_TASK_STRUCT_HAS_PARENT
86     gid_t *gp = current->parent->groups;
87     int ngroups = current->parent->ngroups;
88 #else
89     gid_t *gp = current->p_pptr->groups;
90     int ngroups = current->p_pptr->ngroups;
91 #endif
92
93     if ((ngroups < 2) || (afs_get_pag_from_groups(gp[0], gp[1]) == NOPAG)) {
94         /* We will have to shift grouplist to make room for pag */
95         if (ngroups + 2 > NGROUPS) {
96             return EINVAL;
97         }
98         for (i = ngroups - 1; i >= 0; i--) {
99             gp[i + 2] = gp[i];
100         }
101         ngroups += 2;
102     }
103     gp[0] = g0;
104     gp[1] = g1;
105     if (ngroups < NGROUPS)
106         gp[ngroups] = NOGROUP;
107
108 #ifdef STRUCT_TASK_STRUCT_HAS_PARENT
109     current->parent->ngroups = ngroups;
110 #else
111     current->p_pptr->ngroups = ngroups;
112 #endif
113     return 0;
114 }
115
116 int
117 __setpag(cred_t **cr, afs_uint32 pagvalue, afs_uint32 *newpag,
118          int change_parent)
119 {
120     gid_t *gidset;
121     afs_int32 ngroups, code = 0;
122     int j;
123
124     gidset = (gid_t *) osi_Alloc(NGROUPS * sizeof(gidset[0]));
125     ngroups = afs_getgroups(*cr, gidset);
126
127     if (afs_get_pag_from_groups(gidset[0], gidset[1]) == NOPAG) {
128         /* We will have to shift grouplist to make room for pag */
129         if (ngroups + 2 > NGROUPS) {
130             osi_Free((char *)gidset, NGROUPS * sizeof(int));
131             return EINVAL;
132         }
133         for (j = ngroups - 1; j >= 0; j--) {
134             gidset[j + 2] = gidset[j];
135         }
136         ngroups += 2;
137     }
138     *newpag = (pagvalue == -1 ? genpag() : pagvalue);
139     afs_get_groups_from_pag(*newpag, &gidset[0], &gidset[1]);
140     code = afs_setgroups(cr, ngroups, gidset, change_parent);
141
142     /* If change_parent is set, then we should set the pag in the parent as
143      * well.
144      */
145     if (change_parent && !code) {
146         code = set_pag_in_parent(*newpag, gidset[0], gidset[1]);
147     }
148
149     osi_Free((char *)gidset, NGROUPS * sizeof(int));
150     return code;
151 }
152
153 int
154 setpag(cred_t **cr, afs_uint32 pagvalue, afs_uint32 *newpag,
155        int change_parent)
156 {
157     int code;
158
159     AFS_STATCNT(setpag);
160
161     code = __setpag(cr, pagvalue, newpag, change_parent);
162
163     return code;
164 }
165
166
167 /* Intercept the standard system call. */
168 extern asmlinkage long (*sys_setgroupsp) (int gidsetsize, gid_t * grouplist);
169 asmlinkage long
170 afs_xsetgroups(int gidsetsize, gid_t * grouplist)
171 {
172     long code;
173     cred_t *cr = crref();
174     afs_uint32 junk;
175     int old_pag;
176
177     lock_kernel();
178     old_pag = PagInCred(cr);
179     crfree(cr);
180     unlock_kernel();
181
182     code = (*sys_setgroupsp) (gidsetsize, grouplist);
183     if (code) {
184         return code;
185     }
186
187     lock_kernel();
188     cr = crref();
189     if (old_pag != NOPAG && PagInCred(cr) == NOPAG) {
190         /* re-install old pag if there's room. */
191         code = __setpag(&cr, old_pag, &junk, 0);
192     }
193     crfree(cr);
194     unlock_kernel();
195
196     /* Linux syscall ABI returns errno as negative */
197     return (-code);
198 }
199
200 #if defined(AFS_LINUX24_ENV)
201 /* Intercept the standard uid32 system call. */
202 extern asmlinkage long (*sys_setgroups32p) (int gidsetsize, gid_t * grouplist);
203 asmlinkage long
204 afs_xsetgroups32(int gidsetsize, gid_t * grouplist)
205 {
206     long code;
207     cred_t *cr = crref();
208     afs_uint32 junk;
209     int old_pag;
210
211     lock_kernel();
212     old_pag = PagInCred(cr);
213     crfree(cr);
214     unlock_kernel();
215
216     code = (*sys_setgroups32p) (gidsetsize, grouplist);
217
218     if (code) {
219         return code;
220     }
221
222     lock_kernel();
223     cr = crref();
224     if (old_pag != NOPAG && PagInCred(cr) == NOPAG) {
225         /* re-install old pag if there's room. */
226         code = __setpag(&cr, old_pag, &junk, 0);
227     }
228     crfree(cr);
229     unlock_kernel();
230
231     /* Linux syscall ABI returns errno as negative */
232     return (-code);
233 }
234 #endif
235
236 #if defined(AFS_PPC64_LINUX20_ENV)
237 /* Intercept the uid16 system call as used by 32bit programs. */
238 extern long (*sys32_setgroupsp)(int gidsetsize, gid_t *grouplist);
239 asmlinkage long afs32_xsetgroups(int gidsetsize, gid_t *grouplist)
240 {
241     long code;
242     cred_t *cr = crref();
243     afs_uint32 junk;
244     int old_pag;
245     
246     lock_kernel();
247     old_pag = PagInCred(cr);
248     crfree(cr);
249     unlock_kernel();
250     
251     code = (*sys32_setgroupsp)(gidsetsize, grouplist);
252     if (code) {
253         return code;
254     }
255     
256     lock_kernel();
257     cr = crref();
258     if (old_pag != NOPAG && PagInCred(cr) == NOPAG) {
259         /* re-install old pag if there's room. */
260         code = __setpag(&cr, old_pag, &junk, 0);
261     }
262     crfree(cr);
263     unlock_kernel();
264     
265     /* Linux syscall ABI returns errno as negative */
266     return (-code);
267 }
268 #endif
269
270 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_AMD64_LINUX20_ENV)
271 /* Intercept the uid16 system call as used by 32bit programs. */
272 extern long (*sys32_setgroupsp) (int gidsetsize, u16 * grouplist);
273 asmlinkage long
274 afs32_xsetgroups(int gidsetsize, u16 * grouplist)
275 {
276     long code;
277     cred_t *cr = crref();
278     afs_uint32 junk;
279     int old_pag;
280     
281     lock_kernel();
282     old_pag = PagInCred(cr);
283     crfree(cr);
284     unlock_kernel();
285     
286     code = (*sys32_setgroupsp) (gidsetsize, grouplist);
287     if (code) {
288         return code;
289     }
290     
291     lock_kernel();
292     cr = crref();
293     if (old_pag != NOPAG && PagInCred(cr) == NOPAG) {
294         /* re-install old pag if there's room. */
295         code = __setpag(&cr, old_pag, &junk, 0);
296     }
297     crfree(cr);
298     unlock_kernel();
299     
300     /* Linux syscall ABI returns errno as negative */
301     return (-code);
302 }
303
304 #ifdef AFS_LINUX24_ENV
305 /* Intercept the uid32 system call as used by 32bit programs. */
306 extern long (*sys32_setgroups32p) (int gidsetsize, gid_t * grouplist);
307 asmlinkage long
308 afs32_xsetgroups32(int gidsetsize, gid_t * grouplist)
309 {
310     long code;
311     cred_t *cr = crref();
312     afs_uint32 junk;
313     int old_pag;
314
315     lock_kernel();
316     old_pag = PagInCred(cr);
317     crfree(cr);
318     unlock_kernel();
319
320     code = (*sys32_setgroups32p) (gidsetsize, grouplist);
321     if (code) {
322         return code;
323     }
324
325     lock_kernel();
326     cr = crref();
327     if (old_pag != NOPAG && PagInCred(cr) == NOPAG) {
328         /* re-install old pag if there's room. */
329         code = __setpag(&cr, old_pag, &junk, 0);
330     }
331     crfree(cr);
332     unlock_kernel();
333
334     /* Linux syscall ABI returns errno as negative */
335     return (-code);
336 }
337 #endif
338 #endif