no-copy-libafs-builds-20021015
[openafs.git] / src / afs / AIX / 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
19 RCSID("$Header$");
20
21 #include "afs/sysincludes.h"
22 #include "afsincludes.h"
23 #include "afs/afs_stats.h"  /* statistics */
24
25
26 static int
27 afs_getgroups(
28     struct ucred *cred,
29     int ngroups,
30     gid_t *gidset);
31
32 static int
33 afs_setgroups(
34     struct ucred **cred,
35     int ngroups,
36     gid_t *gidset,
37     int change_parent);
38
39 #ifndef AFS_AIX5_ENV
40 int
41 setgroups(ngroups, gidset)
42     int ngroups;
43     gid_t *gidset;
44 {
45     int code = 0;
46     struct vrequest treq;
47     struct ucred *credp;
48     struct ucred *credp0;
49
50     AFS_STATCNT(afs_xsetgroups);
51
52     credp = crref();
53     AFS_GLOCK();
54     code = afs_InitReq(&treq, credp);
55     AFS_GUNLOCK();
56     crfree(credp);
57     if (code) return code;
58
59     code = osetgroups(ngroups, gidset);
60
61     /* Note that if there is a pag already in the new groups we don't
62      * overwrite it with the old pag.
63      */
64     credp = crref();
65     credp0 = credp;
66
67     if (PagInCred(credp) == NOPAG) {
68         if (((treq.uid >> 24) & 0xff) == 'A') {
69             AFS_GLOCK();
70             AddPag(treq.uid, &credp);
71             AFS_GUNLOCK();
72         }
73     }
74
75     /* If AddPag() didn't make a new cred, then free our cred ref */
76     if (credp == credp0) {
77         crfree(credp);
78     }
79     return code;
80 }
81 #endif
82
83 int
84 setpag(cred, pagvalue, newpag, change_parent)
85     struct ucred **cred;
86     afs_uint32 pagvalue;
87     afs_uint32 *newpag;
88     afs_uint32 change_parent;
89 {
90     gid_t gidset[NGROUPS];
91     int ngroups, code;
92     int j;
93
94     AFS_STATCNT(setpag);
95 #ifndef AFS_AIX51_ENV
96     ngroups = afs_getgroups(*cred, NGROUPS, gidset);
97     if (afs_get_pag_from_groups(gidset[0], gidset[1]) == NOPAG) {
98         /* We will have to shift grouplist to make room for pag */
99         if (ngroups + 2 > NGROUPS) {
100             return (setuerror(E2BIG), E2BIG);
101         }
102         for (j = ngroups -1; j >= 0; j--) {
103             gidset[j+2] = gidset[j];
104         }
105         ngroups += 2;
106     }
107 #endif
108     *newpag = (pagvalue == -1 ? genpag(): pagvalue);
109 #ifdef AFS_AIX51_ENV
110     if (change_parent) {
111         code = kcred_setpag(*cred, PAG_AFS, *newpag);
112     } else {
113         struct ucred *newcr = crdup(*cred);
114
115         crset(newcr);
116         code = kcred_setpag(newcr, PAG_AFS, *newpag);
117         *cred = newcr;
118     }
119 #else
120     afs_get_groups_from_pag(*newpag, &gidset[0], &gidset[1]);
121     if (code = afs_setgroups(cred, ngroups, gidset, change_parent)) {
122         return (setuerror(code), code);
123     }
124 #endif
125     return code;
126 }
127
128
129 #ifndef AFS_AIX51_ENV
130 static int
131 afs_getgroups(
132     struct ucred *cred,
133     int ngroups,
134     gid_t *gidset)
135 {
136     int ngrps, savengrps;
137     gid_t *gp;
138
139     gidset[0] = gidset[1] = 0;
140     AFS_STATCNT(afs_getgroups);
141
142     savengrps = ngrps = MIN(ngroups, cred->cr_ngrps);
143     gp = cred->cr_groups;
144     while (ngrps--)
145         *gidset++ = *gp++;
146     return savengrps;
147 }
148
149 /* the caller is responsible for checking that ngroups <= NGROUPS */
150
151 static void
152 copy_to_cred(newcr, ngroups, gidset)
153     struct ucred *newcr;
154     int ngroups;
155     gid_t *gidset;
156 {
157     gid_t *gp;
158     int newngroups;
159
160     newngroups = ngroups;
161     gp = newcr->cr_groups;
162     while (ngroups--)
163         *gp++ = *gidset++;
164     newcr->cr_ngrps = newngroups;
165 }
166
167 /*
168  * If change_parent is true, then we want to affect the parent process as well
169  * as the current process.  We do this by writing into the given cred, on
170  * the assumption that it is shared with the parent process.
171  *
172  * Note that it is important that we do NOT actually do anything to the
173  * parent process, because the NFS/AFS translator uses this routine to
174  * write into a given cred, and it has no intention of affecting the parent
175  * process.
176  *
177  * If change_parent is false, then we want to affect only the current process.
178  */
179
180 static int
181 afs_setgroups(
182     struct ucred **cred,
183     int ngroups,
184     gid_t *gidset,
185     int change_parent)
186 {
187     AFS_STATCNT(afs_setgroups);
188
189     if (ngroups > NGROUPS)
190         return EINVAL;
191
192     if (change_parent) {
193
194         /*
195          * klog -setpag goes through this code to change the cred
196          * shared with the parent process.  Historically this did
197          * not work on AIX, but the problem in AIX has now been
198          * fixed.
199          *
200          * The NFS/AFS translator also uses this code in order to
201          * write into a given cred; it certainly doesn't use it
202          * in order to affect any other process.
203          */
204         copy_to_cred(*cred, ngroups, gidset);
205
206     } else {
207
208         struct ucred *newcr = crdup(*cred);
209
210         copy_to_cred(newcr, ngroups, gidset);
211
212         crset(newcr);
213         *cred = newcr;
214     }
215     return 0;
216 }
217 #endif