xref: /illumos-gate/usr/src/uts/common/syscall/gid.c (revision 3d63ea05)
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 2007 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
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 
52 	if (!VALID_GID(gid))
53 		return (set_errno(EINVAL));
54 
55 	if (gid > MAXUID) {
56 		if (ksid_lookupbygid(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.
66 	 */
67 	newcr = cralloc_ksid();
68 	p = ttoproc(curthread);
69 	mutex_enter(&p->p_crlock);
70 	cr = p->p_cred;
71 
72 	if ((gid == cr->cr_rgid || gid == cr->cr_sgid) &&
73 	    secpolicy_allow_setid(cr, -1, B_TRUE) != 0) {
74 		error = 0;
75 		crcopy_to(cr, newcr);
76 		p->p_cred = newcr;
77 		newcr->cr_gid = gid;
78 		crsetsid(newcr, ksp, KSID_GROUP);
79 	} else if ((error = secpolicy_allow_setid(cr, -1, B_FALSE)) == 0) {
80 		/*
81 		 * A privileged process that makes itself look like a
82 		 * set-gid process must be marked to produce no core dump.
83 		 */
84 		if (cr->cr_gid != gid ||
85 		    cr->cr_rgid != gid ||
86 		    cr->cr_sgid != gid)
87 			do_nocd = 1;
88 		crcopy_to(cr, newcr);
89 		p->p_cred = newcr;
90 		newcr->cr_gid = gid;
91 		newcr->cr_rgid = gid;
92 		newcr->cr_sgid = gid;
93 		crsetsid(newcr, ksp, KSID_GROUP);
94 	} else {
95 		crfree(newcr);
96 		if (ksp != NULL)
97 			ksid_rele(ksp);
98 
99 	}
100 
101 	mutex_exit(&p->p_crlock);
102 
103 	if (error == 0) {
104 		if (do_nocd) {
105 			mutex_enter(&p->p_lock);
106 			p->p_flag |= SNOCD;
107 			mutex_exit(&p->p_lock);
108 		}
109 		crset(p, newcr);	/* broadcast to process threads */
110 		return (0);
111 	}
112 	return (set_errno(error));
113 }
114 
115 int64_t
116 getgid(void)
117 {
118 	rval_t	r;
119 	cred_t	*cr;
120 
121 	cr = curthread->t_cred;
122 	r.r_val1 = cr->cr_rgid;
123 	r.r_val2 = cr->cr_gid;
124 	return (r.r_vals);
125 }
126 
127 int
128 setegid(gid_t gid)
129 {
130 	proc_t *p;
131 	cred_t	*cr, *newcr;
132 	int error = EPERM;
133 	int do_nocd = 0;
134 	ksid_t ksid, *ksp;
135 
136 	if (!VALID_GID(gid))
137 		return (set_errno(EINVAL));
138 
139 	if (gid > MAXUID) {
140 		if (ksid_lookupbygid(gid, &ksid) != 0)
141 			return (set_errno(EINVAL));
142 		ksp = &ksid;
143 	} else {
144 		ksp = NULL;
145 	}
146 	/*
147 	 * Need to pre-allocate the new cred structure before grabbing
148 	 * the p_crlock mutex.
149 	 */
150 	newcr = cralloc_ksid();
151 	p = ttoproc(curthread);
152 	mutex_enter(&p->p_crlock);
153 	cr = p->p_cred;
154 	if (gid == cr->cr_rgid || gid == cr->cr_gid || gid == cr->cr_sgid ||
155 	    (error = secpolicy_allow_setid(cr, -1, B_FALSE)) == 0) {
156 		/*
157 		 * A privileged process that makes itself look like a
158 		 * set-gid process must be marked to produce no core dump.
159 		 */
160 		if (cr->cr_gid != gid && error == 0)
161 			do_nocd = 1;
162 		error = 0;
163 		crcopy_to(cr, newcr);
164 		p->p_cred = newcr;
165 		newcr->cr_gid = gid;
166 		crsetsid(newcr, ksp, KSID_GROUP);
167 	} else {
168 		crfree(newcr);
169 		if (ksp != NULL)
170 			ksid_rele(ksp);
171 	}
172 
173 	mutex_exit(&p->p_crlock);
174 
175 	if (error == 0) {
176 		if (do_nocd) {
177 			mutex_enter(&p->p_lock);
178 			p->p_flag |= SNOCD;
179 			mutex_exit(&p->p_lock);
180 		}
181 		crset(p, newcr);	/* broadcast to process threads */
182 		return (0);
183 	}
184 	return (set_errno(error));
185 }
186 
187 /*
188  * Buy-back from SunOS 4.x
189  *
190  * Like setgid() and setegid() combined -except- that non-root users
191  * can change cr_rgid to cr_gid, and the semantics of cr_sgid are
192  * subtly different.
193  */
194 int
195 setregid(gid_t rgid, gid_t egid)
196 {
197 	proc_t *p;
198 	int error = EPERM;
199 	int do_nocd = 0;
200 	cred_t *cr, *newcr;
201 	ksid_t ksid, *ksp;
202 
203 	if ((rgid != -1 && !VALID_GID(rgid)) ||
204 	    (egid != -1 && !VALID_GID(egid)))
205 		return (set_errno(EINVAL));
206 
207 	if (egid != -1 && egid > MAXUID) {
208 		if (ksid_lookupbygid(egid, &ksid) != 0)
209 			return (set_errno(EINVAL));
210 		ksp = &ksid;
211 	} else {
212 		ksp = NULL;
213 	}
214 	/*
215 	 * Need to pre-allocate the new cred structure before grabbing
216 	 * the p_crlock mutex.
217 	 */
218 	newcr = cralloc_ksid();
219 
220 	p = ttoproc(curthread);
221 	mutex_enter(&p->p_crlock);
222 	cr = p->p_cred;
223 
224 	if ((rgid == -1 ||
225 	    rgid == cr->cr_rgid || rgid == cr->cr_gid || rgid == cr->cr_sgid) &&
226 	    (egid == -1 || egid == cr->cr_rgid || egid == cr->cr_gid ||
227 	    egid == cr->cr_sgid) ||
228 	    (error = secpolicy_allow_setid(cr, -1, B_FALSE)) == 0) {
229 		crhold(cr);
230 		crcopy_to(cr, newcr);
231 		p->p_cred = newcr;
232 
233 		if (egid != -1) {
234 			newcr->cr_gid = egid;
235 			crsetsid(newcr, ksp, KSID_GROUP);
236 		}
237 		if (rgid != -1)
238 			newcr->cr_rgid = rgid;
239 		/*
240 		 * "If the real gid is being changed, or the effective gid is
241 		 * being changed to a value not equal to the real gid, the
242 		 * saved gid is set to the new effective gid."
243 		 */
244 		if (rgid != -1 ||
245 		    (egid != -1 && newcr->cr_gid != newcr->cr_rgid))
246 			newcr->cr_sgid = newcr->cr_gid;
247 		/*
248 		 * A privileged process that makes itself look like a
249 		 * set-gid process must be marked to produce no core dump.
250 		 */
251 		if ((cr->cr_gid != newcr->cr_gid ||
252 		    cr->cr_rgid != newcr->cr_rgid ||
253 		    cr->cr_sgid != newcr->cr_sgid) && error == 0)
254 			do_nocd = 1;
255 		error = 0;
256 		crfree(cr);
257 	}
258 	mutex_exit(&p->p_crlock);
259 
260 	if (error == 0) {
261 		if (do_nocd) {
262 			mutex_enter(&p->p_lock);
263 			p->p_flag |= SNOCD;
264 			mutex_exit(&p->p_lock);
265 		}
266 		crset(p, newcr);	/* broadcast to process threads */
267 		return (0);
268 	}
269 	crfree(newcr);
270 	if (ksp != NULL)
271 		ksid_rele(ksp);
272 	return (set_errno(error));
273 }
274