xref: /titanic_50/usr/src/uts/common/syscall/gid.c (revision ddf7fe95b8ad67aa16deb427a0b78f4dd4ff22b1)
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