Linux: Fix prototypes for afs_xsetgroups and sys_setgroupsp and friends
[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 int (*sys_setgroups32p) (int gidsetsize,
203                                            __kernel_gid32_t * grouplist);
204 asmlinkage long
205 afs_xsetgroups32(int gidsetsize, gid_t * grouplist)
206 {
207     long code;
208     cred_t *cr = crref();
209     afs_uint32 junk;
210     int old_pag;
211
212     lock_kernel();
213     old_pag = PagInCred(cr);
214     crfree(cr);
215     unlock_kernel();
216
217     code = (*sys_setgroups32p) (gidsetsize, grouplist);
218
219     if (code) {
220         return code;
221     }
222
223     lock_kernel();
224     cr = crref();
225     if (old_pag != NOPAG && PagInCred(cr) == NOPAG) {
226         /* re-install old pag if there's room. */
227         code = __setpag(&cr, old_pag, &junk, 0);
228     }
229     crfree(cr);
230     unlock_kernel();
231
232     /* Linux syscall ABI returns errno as negative */
233     return (-code);
234 }
235 #endif
236
237 #if defined(AFS_PPC64_LINUX20_ENV)
238 /* Intercept the uid16 system call as used by 32bit programs. */
239 extern asmlinkage long (*sys32_setgroupsp)(int gidsetsize, gid_t *grouplist);
240 asmlinkage long afs32_xsetgroups(int gidsetsize, gid_t *grouplist)
241 {
242     long code;
243     cred_t *cr = crref();
244     afs_uint32 junk;
245     int old_pag;
246     
247     lock_kernel();
248     old_pag = PagInCred(cr);
249     crfree(cr);
250     unlock_kernel();
251     
252     code = (*sys32_setgroupsp)(gidsetsize, grouplist);
253     if (code) {
254         return code;
255     }
256     
257     lock_kernel();
258     cr = crref();
259     if (old_pag != NOPAG && PagInCred(cr) == NOPAG) {
260         /* re-install old pag if there's room. */
261         code = __setpag(&cr, old_pag, &junk, 0);
262     }
263     crfree(cr);
264     unlock_kernel();
265     
266     /* Linux syscall ABI returns errno as negative */
267     return (-code);
268 }
269 #endif
270
271 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_AMD64_LINUX20_ENV)
272 /* Intercept the uid16 system call as used by 32bit programs. */
273 #ifdef AFS_AMD64_LINUX20_ENV
274 extern asmlinkage long (*sys32_setgroupsp) (int gidsetsize, u16 * grouplist);
275 #endif /* AFS_AMD64_LINUX20_ENV */
276 #ifdef AFS_SPARC64_LINUX26_ENV
277 extern asmlinkage int (*sys32_setgroupsp) (int gidsetsize,
278                                            __kernel_gid32_t * grouplist);
279 #endif /* AFS_SPARC64_LINUX26_ENV */
280 asmlinkage long
281 afs32_xsetgroups(int gidsetsize, u16 * grouplist)
282 {
283     long code;
284     cred_t *cr = crref();
285     afs_uint32 junk;
286     int old_pag;
287     
288     lock_kernel();
289     old_pag = PagInCred(cr);
290     crfree(cr);
291     unlock_kernel();
292     
293     code = (*sys32_setgroupsp) (gidsetsize, grouplist);
294     if (code) {
295         return code;
296     }
297     
298     lock_kernel();
299     cr = crref();
300     if (old_pag != NOPAG && PagInCred(cr) == NOPAG) {
301         /* re-install old pag if there's room. */
302         code = __setpag(&cr, old_pag, &junk, 0);
303     }
304     crfree(cr);
305     unlock_kernel();
306     
307     /* Linux syscall ABI returns errno as negative */
308     return (-code);
309 }
310
311 #ifdef AFS_LINUX24_ENV
312 /* Intercept the uid32 system call as used by 32bit programs. */
313 #ifdef AFS_AMD64_LINUX20_ENV
314 extern asmlinkage long (*sys32_setgroups32p) (int gidsetsize, gid_t * grouplist);
315 #endif /* AFS_AMD64_LINUX20_ENV */
316 #ifdef AFS_SPARC64_LINUX26_ENV
317 extern asmlinkage int (*sys32_setgroups32p) (int gidsetsize,
318                                              __kernel_gid_t32 * grouplist);
319 #endif /* AFS_SPARC64_LINUX26_ENV */
320 asmlinkage long
321 afs32_xsetgroups32(int gidsetsize, gid_t * grouplist)
322 {
323     long code;
324     cred_t *cr = crref();
325     afs_uint32 junk;
326     int old_pag;
327
328     lock_kernel();
329     old_pag = PagInCred(cr);
330     crfree(cr);
331     unlock_kernel();
332
333     code = (*sys32_setgroups32p) (gidsetsize, grouplist);
334     if (code) {
335         return code;
336     }
337
338     lock_kernel();
339     cr = crref();
340     if (old_pag != NOPAG && PagInCred(cr) == NOPAG) {
341         /* re-install old pag if there's room. */
342         code = __setpag(&cr, old_pag, &junk, 0);
343     }
344     crfree(cr);
345     unlock_kernel();
346
347     /* Linux syscall ABI returns errno as negative */
348     return (-code);
349 }
350 #endif
351 #endif