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 #include <sys/param.h>
31 #include <sys/types.h>
32 #include <sys/sysmacros.h>
33 #include <sys/systm.h>
34 #include <sys/cred_impl.h>
35 #include <sys/errno.h>
36 #include <sys/proc.h>
37 #include <sys/debug.h>
38 #include <sys/policy.h>
39
40
41 int
setgid(gid_t gid)42 setgid(gid_t gid)
43 {
44 proc_t *p;
45 int error;
46 int do_nocd = 0;
47 cred_t *cr, *newcr;
48 ksid_t ksid, *ksp;
49 zone_t *zone = crgetzone(CRED());
50
51
52 if (!VALID_GID(gid, zone))
53 return (set_errno(EINVAL));
54
55 if (gid > MAXUID) {
56 if (ksid_lookupbygid(zone, gid, &ksid) != 0)
57 return (set_errno(EINVAL));
58 ksp = &ksid;
59 } else {
60 ksp = NULL;
61 }
62
63 /*
64 * Need to pre-allocate the new cred structure before grabbing
65 * the p_crlock mutex. We cannot hold the mutex across the
66 * secpolicy functions.
67 */
68 newcr = cralloc_ksid();
69 p = ttoproc(curthread);
70 mutex_enter(&p->p_crlock);
71 retry:
72 cr = p->p_cred;
73 crhold(cr);
74 mutex_exit(&p->p_crlock);
75
76
77 if ((gid == cr->cr_rgid || gid == cr->cr_sgid) &&
78 secpolicy_allow_setid(cr, -1, B_TRUE) != 0) {
79 mutex_enter(&p->p_crlock);
80 crfree(cr);
81 if (cr != p->p_cred)
82 goto retry;
83 error = 0;
84 crcopy_to(cr, newcr);
85 p->p_cred = newcr;
86 newcr->cr_gid = gid;
87 crsetsid(newcr, ksp, KSID_GROUP);
88 mutex_exit(&p->p_crlock);
89 } else if ((error = secpolicy_allow_setid(cr, -1, B_FALSE)) == 0) {
90 mutex_enter(&p->p_crlock);
91 crfree(cr);
92 if (cr != p->p_cred)
93 goto retry;
94 /*
95 * A privileged process that makes itself look like a
96 * set-gid process must be marked to produce no core dump.
97 */
98 if (cr->cr_gid != gid ||
99 cr->cr_rgid != gid ||
100 cr->cr_sgid != gid)
101 do_nocd = 1;
102 crcopy_to(cr, newcr);
103 p->p_cred = newcr;
104 newcr->cr_gid = gid;
105 newcr->cr_rgid = gid;
106 newcr->cr_sgid = gid;
107 crsetsid(newcr, ksp, KSID_GROUP);
108 mutex_exit(&p->p_crlock);
109 } else {
110 crfree(newcr);
111 crfree(cr);
112 if (ksp != NULL)
113 ksid_rele(ksp);
114
115 }
116
117 if (error == 0) {
118 if (do_nocd) {
119 mutex_enter(&p->p_lock);
120 p->p_flag |= SNOCD;
121 mutex_exit(&p->p_lock);
122 }
123 crset(p, newcr); /* broadcast to process threads */
124 return (0);
125 }
126 return (set_errno(error));
127 }
128
129 int64_t
getgid(void)130 getgid(void)
131 {
132 rval_t r;
133 cred_t *cr;
134
135 cr = curthread->t_cred;
136 r.r_val1 = cr->cr_rgid;
137 r.r_val2 = cr->cr_gid;
138 return (r.r_vals);
139 }
140
141 int
setegid(gid_t gid)142 setegid(gid_t gid)
143 {
144 proc_t *p;
145 cred_t *cr, *newcr;
146 int error = EPERM;
147 int do_nocd = 0;
148 ksid_t ksid, *ksp;
149 zone_t *zone = crgetzone(CRED());
150
151 if (!VALID_GID(gid, zone))
152 return (set_errno(EINVAL));
153
154 if (gid > MAXUID) {
155 if (ksid_lookupbygid(zone, gid, &ksid) != 0)
156 return (set_errno(EINVAL));
157 ksp = &ksid;
158 } else {
159 ksp = NULL;
160 }
161 /*
162 * Need to pre-allocate the new cred structure before grabbing
163 * the p_crlock mutex.
164 */
165 newcr = cralloc_ksid();
166 p = ttoproc(curthread);
167 mutex_enter(&p->p_crlock);
168 retry:
169 crhold(cr = p->p_cred);
170 mutex_exit(&p->p_crlock);
171
172 if (gid == cr->cr_rgid || gid == cr->cr_gid || gid == cr->cr_sgid ||
173 (error = secpolicy_allow_setid(cr, -1, B_FALSE)) == 0) {
174 mutex_enter(&p->p_crlock);
175 crfree(cr);
176 if (cr != p->p_cred)
177 goto retry;
178 /*
179 * A privileged process that makes itself look like a
180 * set-gid process must be marked to produce no core dump.
181 */
182 if (cr->cr_gid != gid && error == 0)
183 do_nocd = 1;
184 error = 0;
185 crcopy_to(cr, newcr);
186 p->p_cred = newcr;
187 newcr->cr_gid = gid;
188 crsetsid(newcr, ksp, KSID_GROUP);
189 mutex_exit(&p->p_crlock);
190 } else {
191 crfree(newcr);
192 crfree(cr);
193 if (ksp != NULL)
194 ksid_rele(ksp);
195 }
196
197 if (error == 0) {
198 if (do_nocd) {
199 mutex_enter(&p->p_lock);
200 p->p_flag |= SNOCD;
201 mutex_exit(&p->p_lock);
202 }
203 crset(p, newcr); /* broadcast to process threads */
204 return (0);
205 }
206 return (set_errno(error));
207 }
208
209 /*
210 * Buy-back from SunOS 4.x
211 *
212 * Like setgid() and setegid() combined -except- that non-root users
213 * can change cr_rgid to cr_gid, and the semantics of cr_sgid are
214 * subtly different.
215 */
216 int
setregid(gid_t rgid,gid_t egid)217 setregid(gid_t rgid, gid_t egid)
218 {
219 proc_t *p;
220 int error = EPERM;
221 int do_nocd = 0;
222 cred_t *cr, *newcr;
223 ksid_t ksid, *ksp;
224 zone_t *zone = crgetzone(CRED());
225
226 if ((rgid != -1 && !VALID_GID(rgid, zone)) ||
227 (egid != -1 && !VALID_GID(egid, zone)))
228 return (set_errno(EINVAL));
229
230 if (egid != -1 && egid > MAXUID) {
231 if (ksid_lookupbygid(zone, egid, &ksid) != 0)
232 return (set_errno(EINVAL));
233 ksp = &ksid;
234 } else {
235 ksp = NULL;
236 }
237 /*
238 * Need to pre-allocate the new cred structure before grabbing
239 * the p_crlock mutex.
240 */
241 newcr = cralloc_ksid();
242
243 p = ttoproc(curthread);
244 mutex_enter(&p->p_crlock);
245 cr = p->p_cred;
246
247 if ((rgid == -1 ||
248 rgid == cr->cr_rgid || rgid == cr->cr_gid || rgid == cr->cr_sgid) &&
249 (egid == -1 || egid == cr->cr_rgid || egid == cr->cr_gid ||
250 egid == cr->cr_sgid) ||
251 (error = secpolicy_allow_setid(cr, -1, B_FALSE)) == 0) {
252 crhold(cr);
253 crcopy_to(cr, newcr);
254 p->p_cred = newcr;
255
256 if (egid != -1) {
257 newcr->cr_gid = egid;
258 crsetsid(newcr, ksp, KSID_GROUP);
259 }
260 if (rgid != -1)
261 newcr->cr_rgid = rgid;
262 /*
263 * "If the real gid is being changed, or the effective gid is
264 * being changed to a value not equal to the real gid, the
265 * saved gid is set to the new effective gid."
266 */
267 if (rgid != -1 ||
268 (egid != -1 && newcr->cr_gid != newcr->cr_rgid))
269 newcr->cr_sgid = newcr->cr_gid;
270 /*
271 * A privileged process that makes itself look like a
272 * set-gid process must be marked to produce no core dump.
273 */
274 if ((cr->cr_gid != newcr->cr_gid ||
275 cr->cr_rgid != newcr->cr_rgid ||
276 cr->cr_sgid != newcr->cr_sgid) && error == 0)
277 do_nocd = 1;
278 error = 0;
279 crfree(cr);
280 }
281 mutex_exit(&p->p_crlock);
282
283 if (error == 0) {
284 if (do_nocd) {
285 mutex_enter(&p->p_lock);
286 p->p_flag |= SNOCD;
287 mutex_exit(&p->p_lock);
288 }
289 crset(p, newcr); /* broadcast to process threads */
290 return (0);
291 }
292 crfree(newcr);
293 if (ksp != NULL)
294 ksid_rele(ksp);
295 return (set_errno(error));
296 }
297