Standardize License information
[openafs.git] / src / afs / LINUX / 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 "../afs/param.h"
17 #include "../afs/sysincludes.h"
18 #include "../afs/afsincludes.h"
19 #include "../afs/afs_stats.h"  /* statistics */
20 #ifdef AFS_LINUX22_ENV
21 #include "../h/smp_lock.h"
22 #endif
23
24 static int afs_getgroups(cred_t *cr, gid_t *groups);
25 static int afs_setgroups(cred_t **cr, int ngroups, gid_t *gidset, int change_parent);
26
27 /* Only propogate the PAG to the parent process. Unix's propogate to 
28  * all processes sharing the cred.
29  */
30 int set_pag_in_parent(int pag, int g0, int g1)
31 {
32     gid_t *gp = current->p_pptr->groups;
33     int ngroups;
34     int i;
35
36     
37     ngroups = current->p_pptr->ngroups;
38     gp = current->p_pptr->groups;
39
40
41     if (afs_get_pag_from_groups(gp[0], gp[1]) == NOPAG) {
42         /* We will have to shift grouplist to make room for pag */
43         if (ngroups + 2 > NGROUPS) {
44             return EINVAL;
45         }
46         for (i = ngroups-1; i >= 0; i--) {
47             gp[i+2] = gp[i];
48         }
49         ngroups += 2;
50     }
51     gp[0] = g0;
52     gp[1] = g1;
53     if (ngroups < NGROUPS)
54         gp[ngroups] = NOGROUP;
55
56     current->p_pptr->ngroups = ngroups;
57     return 0;
58 }
59
60 int setpag(cred_t **cr, afs_uint32 pagvalue, afs_uint32 *newpag, int change_parent)
61 {
62     gid_t *gidset;
63     afs_int32 ngroups, code = 0;
64     int j;
65
66     AFS_STATCNT(setpag);
67
68     gidset = (gid_t *) osi_Alloc(NGROUPS*sizeof(gidset[0]));
69     ngroups = afs_getgroups(*cr, gidset);
70
71     if (afs_get_pag_from_groups(gidset[0], gidset[1]) == NOPAG) {
72         /* We will have to shift grouplist to make room for pag */
73         if (ngroups + 2 > NGROUPS) {
74             osi_Free((char *)gidset, NGROUPS*sizeof(int));
75             return EINVAL;
76         }
77         for (j = ngroups - 1; j >= 0; j--) {
78             gidset[j+2] = gidset[j];
79         }
80         ngroups += 2;
81     }
82     *newpag = (pagvalue == -1 ? genpag(): pagvalue);
83     afs_get_groups_from_pag(*newpag, &gidset[0], &gidset[1]);
84     code = afs_setgroups(cr, ngroups, gidset, change_parent);
85
86     /* If change_parent is set, then we should set the pag in the parent as
87      * well.
88      */
89     if (change_parent && !code) {
90         code = set_pag_in_parent(*newpag, gidset[0], gidset[1]);
91     }
92
93     osi_Free((char *)gidset, NGROUPS*sizeof(int));
94     return code;
95 }
96
97
98 /* Intercept the standard system call. */
99 extern int (*sys_setgroupsp)(int gidsetsize, gid_t *grouplist);
100 asmlinkage int afs_xsetgroups(int gidsetsize, gid_t *grouplist)
101 {
102     int code;
103     cred_t *cr = crref();
104     int junk;
105     int old_pag;
106
107     lock_kernel();
108     old_pag = PagInCred(cr);
109     crfree(cr);
110     unlock_kernel();
111
112     code = (*sys_setgroupsp)(gidsetsize, grouplist);
113     if (code) {
114         return code;
115     }
116
117     lock_kernel();
118     cr = crref();
119     if (old_pag != NOPAG && PagInCred(cr) == NOPAG) {
120         /* re-install old pag if there's room. */
121         code = setpag(&cr, old_pag, &junk, 0);
122     }
123     crfree(cr);
124     unlock_kernel();
125
126     return code;
127 }
128
129 static int afs_setgroups(cred_t **cr, int ngroups, gid_t *gidset, int change_parent)
130 {
131     int ngrps;
132     int i;
133     gid_t *gp;
134
135     AFS_STATCNT(afs_setgroups);
136
137     if (ngroups > NGROUPS)
138         return EINVAL;
139
140     gp = (*cr)->cr_groups;
141     if (ngroups < NGROUPS)
142         gp[ngroups] = (gid_t)NOGROUP;
143
144     for (i = ngroups; i > 0; i--) {
145         *gp++ = *gidset++;
146     }
147
148     (*cr)->cr_ngroups = ngroups;
149     crset(*cr);
150     return (0);
151 }
152
153 /* Returns number of groups. And we trust groups to be large enough to
154  * hold all the groups.
155  */
156 static int afs_getgroups(cred_t *cr, gid_t *groups)
157 {
158     int i;
159     gid_t *gp = cr->cr_groups;
160     int n = cr->cr_ngroups;
161     AFS_STATCNT(afs_getgroups);
162
163     for (i = 0; (i < n) && (*gp != (gid_t)NOGROUP); i++) {
164         *groups++ = *gp++;
165     }
166     return i;
167 }
168