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