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