2 * Copyright 2000, International Business Machines Corporation and others.
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
12 * afsDFS_SetPagInCred (shared with SGI)
13 * osi_DFSGetPagFromCred (shared with SGI)
14 * Afs_xsetgroups (syscall)
18 #include <afsconfig.h>
19 #include "afs/param.h"
24 #include "afs/sysincludes.h"
25 #include "afsincludes.h"
26 #include "afs/afs_stats.h" /* statistics */
30 afs_getgroups(struct ucred *cred, int ngroups, gid_t * gidset);
33 afs_setgroups(struct ucred **cred, int ngroups, gid_t * gidset,
37 /* This is common code between SGI's DFS and our AFS. Do *not* alter it's
38 * interface or semantics without notifying SGI.
41 /* fixup_pags returns error code if relevant or 0 on no error.
42 * Sets up the cred for the call to estgroups. This is pretty convoluted
43 * in order to avoid including the private proc.h header file.
46 fixup_pags(int **credpp, int ngroups, gid_t * gidset, int old_afs_pag,
54 gid_t groups[NGROUPS_UMAX];
57 if (ngroups < 0 || ngroups > ngroups_max)
61 AFS_COPYIN(gidset, groups, ngroups * sizeof(gid_t), code);
66 if (ngroups >= 2) { /* possibly an AFS PAG */
68 (afs_get_pag_from_groups(groups[0], groups[1]) != NOPAG);
70 if (ngroups >= 1) { /* possibly a DFS PAG */
71 new_dfs_pag = (int)groups[ngroups - 1];
72 if (((new_dfs_pag >> 24) & 0xff) == 'A')
73 new_dfs_pag = (int)groups[ngroups - 1];
78 /* Now compute the number of groups we will need. */
80 if (old_afs_pag && !new_afs_pag) /* prepend old AFS pag */
82 if (old_dfs_pag && !new_dfs_pag) /* append old DFS pag */
85 if (new > ngroups_max)
86 return EINVAL; /* sorry */
88 cr = crdup(OSI_GET_CURRENT_CRED()); /* we will replace all the groups. */
89 memset((char *)&cr->cr_groups, 0, ngroups_max * sizeof(gid_t));
91 /* Now cobble the new groups list together. */
94 if (old_afs_pag && !new_afs_pag) { /* prepend old AFS pag */
97 afs_get_groups_from_pag(old_afs_pag, &g0, &g1);
98 cr->cr_groups[new++] = g0;
99 cr->cr_groups[new++] = g1;
102 for (old = 0; old < ngroups; old++)
103 cr->cr_groups[new++] = groups[old];
105 if (old_dfs_pag && !new_dfs_pag) { /* append old DFS pag */
107 cr->cr_groups[new++] = old_dfs_pag;
110 /* Now, did we do anything? */
112 cr->cr_ngroups = new;
122 * Generic routine to set the PAG in the cred for AFS and DFS.
123 * If flag = 0 this is a DFS pag held in one group.
124 * If flag = 1 this is a AFS pag held in two group entries
127 afsDFS_SetPagInCred(struct ucred *credp, int pag, int flag)
133 struct ucred *newcredp;
134 int groups_taken = (flag ? 2 : 1);
136 ngrps = credp->cr_ngroups + groups_taken;
137 if (ngrps >= ngroups_max)
142 /* Break out the AFS pag into two groups */
143 afs_get_groups_from_pag(pag, &g0, &g1);
146 newcredp = crdup(credp);
147 newcredp->cr_ngroups = ngrps;
151 newcredp->cr_groups[0] = g0;
152 newcredp->cr_groups[1] = g1;
155 if (PagInCred(newcredp) != NOPAG) {
156 /* found an AFS PAG is set in this cred */
159 newcredp->cr_groups[n] = pag;
161 for (i = n; i < credp->cr_ngroups; i++)
162 newcredp->cr_groups[i + groups_taken] = credp->cr_groups[i];
164 /* estgroups sets current threads cred from newcredp and crfree's credp */
165 estgroups(credp, newcredp);
169 #endif /* AFS_SGI65_ENV */
171 /* SGI's osi_GetPagFromCred - They return a long. */
173 osi_DFSGetPagFromCred(struct ucred *credp)
179 * For IRIX, the PAG is stored in the first entry
180 * of the gruop list in the cred structure. gid_t's
181 * are 32 bits on 64 bit and 32 bit hardware types.
182 * As of Irix 6.5, the DFS pag is the last group in the list.
184 ngroups = credp->cr_ngroups;
188 * Keep in mind that we might be living with AFS here.
189 * This means we don't really know if our DFS PAG is in
190 * the first or third group entry.
193 pag = credp->cr_groups[ngroups - 1];
195 pag = credp->cr_groups[0];
196 if (PagInCred(credp) != NOPAG) {
197 /* AFS has a PAG value in the first two group entries */
200 pag = credp->cr_groups[2];
203 if (((pag >> 24) & 0xff) == 'A')
210 Afs_xsetgroups(int ngroups, gid_t * gidset)
212 int old_afs_pag = NOPAG;
213 int old_dfs_pag = NOPAG;
215 struct ucred *credp = OSI_GET_CURRENT_CRED();
216 struct ucred *modcredp;
219 credp = OSI_GET_CURRENT_CRED();
220 /* First get any old PAG's */
221 old_afs_pag = PagInCred(credp);
222 old_dfs_pag = osi_DFSGetPagFromCred(credp);
224 /* Set the passed in group list. */
225 if (code = setgroups(ngroups, gidset))
229 if (old_afs_pag == NOPAG && old_dfs_pag == NOPAG)
232 /* Well, we could get the cred, except it's in the proc struct which
233 * is not a publicly available header. And the cred won't be valid on
234 * the uthread until we return to user space. So, we examine the passed
235 * in groups in fixup_pags.
238 fixup_pags(&modcredp, ngroups, gidset,
239 (old_afs_pag == NOPAG) ? 0 : old_afs_pag,
240 (old_dfs_pag == NOPAG) ? 0 : old_dfs_pag);
241 if (!code && modcredp)
242 estgroups(OSI_GET_CURRENT_PROCP(), modcredp);
246 * The setgroups gave our curent thread a new cred pointer
247 * Get the value again
249 credp = OSI_GET_CURRENT_CRED();
250 if ((PagInCred(credp) == NOPAG) && (old_afs_pag != NOPAG)) {
251 /* reset the AFS PAG */
252 code = afsDFS_SetPagInCred(credp, old_afs_pag, 1);
255 * Once again get the credp because the afsDFS_SetPagInCred might have
256 * assigned a new one.
258 credp = OSI_GET_CURRENT_CRED();
259 if ((osi_DFSGetPagFromCred(credp) == NOPAG)
260 && (old_dfs_pag != NOPAG)) {
261 code = afsDFS_SetPagInCred(credp, old_dfs_pag, 0);
263 #endif /* AFS_SGI65_ENV */
269 setpag(cred, pagvalue, newpag, change_parent)
273 afs_uint32 change_parent;
275 gid_t gidset[NGROUPS];
281 ngroups = afs_getgroups(*cred, NGROUPS, gidset);
282 if (afs_get_pag_from_groups(gidset[0], gidset[1]) == NOPAG) {
283 /* We will have to shift grouplist to make room for pag */
284 if (ngroups + 2 > NGROUPS) {
285 #if defined(KERNEL_HAVE_UERROR)
286 return (setuerror(E2BIG), E2BIG);
291 for (j = ngroups - 1; j >= 0; j--) {
292 gidset[j + 2] = gidset[j];
296 *newpag = (pagvalue == -1 ? genpag() : pagvalue);
297 afs_get_groups_from_pag(*newpag, &gidset[0], &gidset[1]);
298 if (code = afs_setgroups(cred, ngroups, gidset, change_parent)) {
299 #if defined(KERNEL_HAVE_UERROR)
300 return (setuerror(code), code);
310 afs_getgroups(struct ucred *cred, int ngroups, gid_t * gidset)
312 int ngrps, savengrps;
315 gidset[0] = gidset[1] = 0;
316 AFS_STATCNT(afs_getgroups);
317 savengrps = ngrps = MIN(ngroups, cred->cr_ngroups);
318 gp = cred->cr_groups;
327 afs_setgroups(struct ucred **cred, int ngroups, gid_t * gidset,
333 AFS_STATCNT(afs_setgroups);
335 if (ngroups > ngroups_max)
342 newcr->cr_ngroups = ngroups;
343 gp = newcr->cr_groups;
346 if (!change_parent) {
348 estgroups(OSI_GET_CURRENT_PROCP(), newcr);
350 estgroups(cr, newcr);