1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
28 */
29
30 #pragma ident "%Z%%M% %I% %E% SMI"
31
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/sysmacros.h>
35 #include <sys/systm.h>
36 #include <sys/cred_impl.h>
37 #include <sys/errno.h>
38 #include <sys/proc.h>
39 #include <sys/debug.h>
40 #include <sys/policy.h>
41
42
43 int
setgid(gid_t gid)44 setgid(gid_t gid)
45 {
46 proc_t *p;
47 int error;
48 int do_nocd = 0;
49 cred_t *cr, *newcr;
50 ksid_t ksid, *ksp;
51 zone_t *zone = crgetzone(CRED());
52
53
54 if (!VALID_GID(gid, zone))
55 return (set_errno(EINVAL));
56
57 if (gid > MAXUID) {
58 if (ksid_lookupbygid(zone, gid, &ksid) != 0)
59 return (set_errno(EINVAL));
60 ksp = &ksid;
61 } else {
62 ksp = NULL;
63 }
64
65 /*
66 * Need to pre-allocate the new cred structure before grabbing
67 * the p_crlock mutex. We cannot hold the mutex across the
68 * secpolicy functions.
69 */
70 newcr = cralloc_ksid();
71 p = ttoproc(curthread);
72 mutex_enter(&p->p_crlock);
73 retry:
74 cr = p->p_cred;
75 crhold(cr);
76 mutex_exit(&p->p_crlock);
77
78
79 if ((gid == cr->cr_rgid || gid == cr->cr_sgid) &&
80 secpolicy_allow_setid(cr, -1, B_TRUE) != 0) {
81 mutex_enter(&p->p_crlock);
82 crfree(cr);
83 if (cr != p->p_cred)
84 goto retry;
85 error = 0;
86 crcopy_to(cr, newcr);
87 p->p_cred = newcr;
88 newcr->cr_gid = gid;
89 crsetsid(newcr, ksp, KSID_GROUP);
90 mutex_exit(&p->p_crlock);
91 } else if ((error = secpolicy_allow_setid(cr, -1, B_FALSE)) == 0) {
92 mutex_enter(&p->p_crlock);
93 crfree(cr);
94 if (cr != p->p_cred)
95 goto retry;
96 /*
97 * A privileged process that makes itself look like a
98 * set-gid process must be marked to produce no core dump.
99 */
100 if (cr->cr_gid != gid ||
101 cr->cr_rgid != gid ||
102 cr->cr_sgid != gid)
103 do_nocd = 1;
104 crcopy_to(cr, newcr);
105 p->p_cred = newcr;
106 newcr->cr_gid = gid;
107 newcr->cr_rgid = gid;
108 newcr->cr_sgid = gid;
109 crsetsid(newcr, ksp, KSID_GROUP);
110 mutex_exit(&p->p_crlock);
111 } else {
112 crfree(newcr);
113 crfree(cr);
114 if (ksp != NULL)
115 ksid_rele(ksp);
116
117 }
118
119 if (error == 0) {
120 if (do_nocd) {
121 mutex_enter(&p->p_lock);
122 p->p_flag |= SNOCD;
123 mutex_exit(&p->p_lock);
124 }
125 crset(p, newcr); /* broadcast to process threads */
126 return (0);
127 }
128 return (set_errno(error));
129 }
130
131 int64_t
getgid(void)132 getgid(void)
133 {
134 rval_t r;
135 cred_t *cr;
136
137 cr = curthread->t_cred;
138 r.r_val1 = cr->cr_rgid;
139 r.r_val2 = cr->cr_gid;
140 return (r.r_vals);
141 }
142
143 int
setegid(gid_t gid)144 setegid(gid_t gid)
145 {
146 proc_t *p;
147 cred_t *cr, *newcr;
148 int error = EPERM;
149 int do_nocd = 0;
150 ksid_t ksid, *ksp;
151 zone_t *zone = crgetzone(CRED());
152
153 if (!VALID_GID(gid, zone))
154 return (set_errno(EINVAL));
155
156 if (gid > MAXUID) {
157 if (ksid_lookupbygid(zone, gid, &ksid) != 0)
158 return (set_errno(EINVAL));
159 ksp = &ksid;
160 } else {
161 ksp = NULL;
162 }
163 /*
164 * Need to pre-allocate the new cred structure before grabbing
165 * the p_crlock mutex.
166 */
167 newcr = cralloc_ksid();
168 p = ttoproc(curthread);
169 mutex_enter(&p->p_crlock);
170 retry:
171 crhold(cr = p->p_cred);
172 mutex_exit(&p->p_crlock);
173
174 if (gid == cr->cr_rgid || gid == cr->cr_gid || gid == cr->cr_sgid ||
175 (error = secpolicy_allow_setid(cr, -1, B_FALSE)) == 0) {
176 mutex_enter(&p->p_crlock);
177 crfree(cr);
178 if (cr != p->p_cred)
179 goto retry;
180 /*
181 * A privileged process that makes itself look like a
182 * set-gid process must be marked to produce no core dump.
183 */
184 if (cr->cr_gid != gid && error == 0)
185 do_nocd = 1;
186 error = 0;
187 crcopy_to(cr, newcr);
188 p->p_cred = newcr;
189 newcr->cr_gid = gid;
190 crsetsid(newcr, ksp, KSID_GROUP);
191 mutex_exit(&p->p_crlock);
192 } else {
193 crfree(newcr);
194 crfree(cr);
195 if (ksp != NULL)
196 ksid_rele(ksp);
197 }
198
199 if (error == 0) {
200 if (do_nocd) {
201 mutex_enter(&p->p_lock);
202 p->p_flag |= SNOCD;
203 mutex_exit(&p->p_lock);
204 }
205 crset(p, newcr); /* broadcast to process threads */
206 return (0);
207 }
208 return (set_errno(error));
209 }
210
211 /*
212 * Buy-back from SunOS 4.x
213 *
214 * Like setgid() and setegid() combined -except- that non-root users
215 * can change cr_rgid to cr_gid, and the semantics of cr_sgid are
216 * subtly different.
217 */
218 int
setregid(gid_t rgid,gid_t egid)219 setregid(gid_t rgid, gid_t egid)
220 {
221 proc_t *p;
222 int error = EPERM;
223 int do_nocd = 0;
224 cred_t *cr, *newcr;
225 ksid_t ksid, *ksp;
226 zone_t *zone = crgetzone(CRED());
227
228 if ((rgid != -1 && !VALID_GID(rgid, zone)) ||
229 (egid != -1 && !VALID_GID(egid, zone)))
230 return (set_errno(EINVAL));
231
232 if (egid != -1 && egid > MAXUID) {
233 if (ksid_lookupbygid(zone, egid, &ksid) != 0)
234 return (set_errno(EINVAL));
235 ksp = &ksid;
236 } else {
237 ksp = NULL;
238 }
239 /*
240 * Need to pre-allocate the new cred structure before grabbing
241 * the p_crlock mutex.
242 */
243 newcr = cralloc_ksid();
244
245 p = ttoproc(curthread);
246 mutex_enter(&p->p_crlock);
247 cr = p->p_cred;
248
249 if ((rgid == -1 ||
250 rgid == cr->cr_rgid || rgid == cr->cr_gid || rgid == cr->cr_sgid) &&
251 (egid == -1 || egid == cr->cr_rgid || egid == cr->cr_gid ||
252 egid == cr->cr_sgid) ||
253 (error = secpolicy_allow_setid(cr, -1, B_FALSE)) == 0) {
254 crhold(cr);
255 crcopy_to(cr, newcr);
256 p->p_cred = newcr;
257
258 if (egid != -1) {
259 newcr->cr_gid = egid;
260 crsetsid(newcr, ksp, KSID_GROUP);
261 }
262 if (rgid != -1)
263 newcr->cr_rgid = rgid;
264 /*
265 * "If the real gid is being changed, or the effective gid is
266 * being changed to a value not equal to the real gid, the
267 * saved gid is set to the new effective gid."
268 */
269 if (rgid != -1 ||
270 (egid != -1 && newcr->cr_gid != newcr->cr_rgid))
271 newcr->cr_sgid = newcr->cr_gid;
272 /*
273 * A privileged process that makes itself look like a
274 * set-gid process must be marked to produce no core dump.
275 */
276 if ((cr->cr_gid != newcr->cr_gid ||
277 cr->cr_rgid != newcr->cr_rgid ||
278 cr->cr_sgid != newcr->cr_sgid) && error == 0)
279 do_nocd = 1;
280 error = 0;
281 crfree(cr);
282 }
283 mutex_exit(&p->p_crlock);
284
285 if (error == 0) {
286 if (do_nocd) {
287 mutex_enter(&p->p_lock);
288 p->p_flag |= SNOCD;
289 mutex_exit(&p->p_lock);
290 }
291 crset(p, newcr); /* broadcast to process threads */
292 return (0);
293 }
294 crfree(newcr);
295 if (ksp != NULL)
296 ksid_rele(ksp);
297 return (set_errno(error));
298 }
299