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.
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.
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]
22 * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
26 * Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
29 #include <sys/param.h>
30 #include <sys/types.h>
31 #include <sys/sysmacros.h>
32 #include <sys/systm.h>
33 #include <sys/tuneable.h>
34 #include <sys/cred_impl.h>
35 #include <sys/errno.h>
37 #include <sys/signal.h>
38 #include <sys/debug.h>
39 #include <sys/policy.h>
52 zoneid_t zoneid
= getzoneid();
54 zone_t
*zone
= crgetzone(CRED());
56 if (!VALID_UID(uid
, zone
))
57 return (set_errno(EINVAL
));
60 if (ksid_lookupbyuid(zone
, uid
, &ksid
) != 0)
61 return (set_errno(EINVAL
));
67 * Need to pre-allocate the new cred structure before grabbing
68 * the p_crlock mutex. We can't hold on to the p_crlock for most
69 * if this though, now that we allow kernel upcalls from the
72 newcr
= cralloc_ksid();
74 p
= ttoproc(curthread
);
77 mutex_enter(&p
->p_crlock
);
81 mutex_exit(&p
->p_crlock
);
83 if ((uid
== cr
->cr_ruid
|| uid
== cr
->cr_suid
) &&
84 secpolicy_allow_setid(cr
, uid
, B_TRUE
) != 0) {
85 mutex_enter(&p
->p_crlock
);
93 crsetsid(newcr
, ksp
, KSID_USER
);
94 mutex_exit(&p
->p_crlock
);
95 } else if ((error
= secpolicy_allow_setid(cr
, uid
, B_FALSE
)) == 0) {
96 mutex_enter(&p
->p_crlock
);
100 if (!uidchge
&& uid
!= cr
->cr_ruid
) {
102 * The ruid of the process is going to change. In order
103 * to avoid a race condition involving the
104 * process-count associated with the newly given ruid,
105 * we increment the count before assigning the
106 * credential to the process.
107 * To do that, we'll have to take pidlock, so we first
110 mutex_exit(&p
->p_crlock
);
112 mutex_enter(&pidlock
);
113 upcount_inc(uid
, zoneid
);
114 mutex_exit(&pidlock
);
116 * As we released p_crlock we can't rely on the cr
117 * we read. So retry the whole thing.
122 * A privileged process that gives up its privilege
123 * must be marked to produce no core dump.
125 if (cr
->cr_uid
!= uid
||
126 cr
->cr_ruid
!= uid
||
129 oldruid
= cr
->cr_ruid
;
130 crcopy_to(cr
, newcr
);
132 newcr
->cr_ruid
= uid
;
133 newcr
->cr_suid
= uid
;
136 /* Remove the PRIV_PFEXEC, we changed the real uid. */
138 CR_FLAGS(newcr
) &= ~PRIV_PFEXEC
;
140 crsetsid(newcr
, ksp
, KSID_USER
);
142 priv_reset_PA(newcr
, B_TRUE
);
144 ASSERT(uid
!= oldruid
? uidchge
: 1);
145 mutex_exit(&p
->p_crlock
);
154 * We decrement the number of processes associated with the oldruid
155 * to match the increment above, even if the ruid of the process
156 * did not change or an error occurred (oldruid == uid).
159 mutex_enter(&pidlock
);
160 upcount_dec(oldruid
, zoneid
);
161 mutex_exit(&pidlock
);
166 mutex_enter(&p
->p_lock
);
168 mutex_exit(&p
->p_lock
);
170 crset(p
, newcr
); /* broadcast to process threads */
173 return (set_errno(error
));
182 cr
= curthread
->t_cred
;
183 r
.r_val1
= cr
->cr_ruid
;
184 r
.r_val2
= cr
->cr_uid
;
196 zone_t
*zone
= crgetzone(CRED());
198 if (!VALID_UID(uid
, zone
))
199 return (set_errno(EINVAL
));
202 if (ksid_lookupbyuid(zone
, uid
, &ksid
) != 0)
203 return (set_errno(EINVAL
));
210 * Need to pre-allocate the new cred structure before grabbing
211 * the p_crlock mutex.
213 newcr
= cralloc_ksid();
214 p
= ttoproc(curthread
);
215 mutex_enter(&p
->p_crlock
);
217 crhold(cr
= p
->p_cred
);
218 mutex_exit(&p
->p_crlock
);
220 if (uid
== cr
->cr_ruid
|| uid
== cr
->cr_uid
|| uid
== cr
->cr_suid
||
221 (error
= secpolicy_allow_setid(cr
, uid
, B_FALSE
)) == 0) {
223 * A privileged process that makes itself look like a
224 * set-uid process must be marked to produce no core dump,
225 * if the effective uid did changed.
227 mutex_enter(&p
->p_crlock
);
231 if (cr
->cr_uid
!= uid
&& error
== 0)
234 crcopy_to(cr
, newcr
);
237 crsetsid(newcr
, ksp
, KSID_USER
);
238 priv_reset_PA(newcr
, B_FALSE
);
239 mutex_exit(&p
->p_crlock
);
241 mutex_enter(&p
->p_lock
);
243 mutex_exit(&p
->p_lock
);
245 crset(p
, newcr
); /* broadcast to process threads */
253 return (set_errno(error
));
257 * Buy-back from SunOS 4.x
259 * Like setuid() and seteuid() combined -except- that non-root users
260 * can change cr_ruid to cr_uid, and the semantics of cr_suid are
264 setreuid(uid_t ruid
, uid_t euid
)
270 uid_t oldruid
= ruid
;
272 zoneid_t zoneid
= getzoneid();
274 zone_t
*zone
= crgetzone(CRED());
276 if ((ruid
!= -1 && !VALID_UID(ruid
, zone
)) ||
277 (euid
!= -1 && !VALID_UID(euid
, zone
)))
278 return (set_errno(EINVAL
));
280 if (euid
!= -1 && euid
> MAXUID
) {
281 if (ksid_lookupbyuid(zone
, euid
, &ksid
) != 0)
282 return (set_errno(EINVAL
));
289 * Need to pre-allocate the new cred structure before grabbing
290 * the p_crlock mutex.
292 newcr
= cralloc_ksid();
294 p
= ttoproc(curthread
);
297 mutex_enter(&p
->p_crlock
);
299 crhold(cr
= p
->p_cred
);
300 mutex_exit(&p
->p_crlock
);
302 if (ruid
!= -1 && ruid
!= cr
->cr_ruid
&& ruid
!= cr
->cr_uid
&&
303 secpolicy_allow_setid(cr
, ruid
, B_FALSE
) != 0) {
304 mutex_enter(&p
->p_crlock
);
309 } else if (euid
!= -1 &&
310 euid
!= cr
->cr_ruid
&& euid
!= cr
->cr_uid
&&
311 euid
!= cr
->cr_suid
&& secpolicy_allow_setid(cr
, euid
, B_FALSE
)) {
312 mutex_enter(&p
->p_crlock
);
318 mutex_enter(&p
->p_crlock
);
322 if (!uidchge
&& ruid
!= -1 && cr
->cr_ruid
!= ruid
) {
324 * The ruid of the process is going to change. In order
325 * to avoid a race condition involving the
326 * process-count associated with the newly given ruid,
327 * we increment the count before assigning the
328 * credential to the process.
329 * To do that, we'll have to take pidlock, so we first
332 mutex_exit(&p
->p_crlock
);
334 mutex_enter(&pidlock
);
335 upcount_inc(ruid
, zoneid
);
336 mutex_exit(&pidlock
);
338 * As we released p_crlock we can't rely on the cr
339 * we read. So retry the whole thing.
344 crcopy_to(cr
, newcr
);
348 newcr
->cr_uid
= euid
;
349 crsetsid(newcr
, ksp
, KSID_USER
);
352 /* Remove the PRIV_PFEXEC, we changed the real uid. */
354 CR_FLAGS(newcr
) &= ~PRIV_PFEXEC
;
356 oldruid
= newcr
->cr_ruid
;
357 newcr
->cr_ruid
= ruid
;
358 ASSERT(ruid
!= oldruid
? uidchge
: 1);
361 * "If the real uid is being changed, or the effective uid is
362 * being changed to a value not equal to the real uid, the
363 * saved uid is set to the new effective uid."
366 (euid
!= -1 && newcr
->cr_uid
!= newcr
->cr_ruid
))
367 newcr
->cr_suid
= newcr
->cr_uid
;
369 * A process that gives up its privilege
370 * must be marked to produce no core dump.
372 if ((cr
->cr_uid
!= newcr
->cr_uid
||
373 cr
->cr_ruid
!= newcr
->cr_ruid
||
374 cr
->cr_suid
!= newcr
->cr_suid
))
377 priv_reset_PA(newcr
, ruid
!= -1 && euid
!= -1 && ruid
== euid
);
380 mutex_exit(&p
->p_crlock
);
383 * We decrement the number of processes associated with the oldruid
384 * to match the increment above, even if the ruid of the process
385 * did not change or an error occurred (oldruid == uid).
388 ASSERT(oldruid
!= -1 && ruid
!= -1);
389 mutex_enter(&pidlock
);
390 upcount_dec(oldruid
, zoneid
);
391 mutex_exit(&pidlock
);
396 mutex_enter(&p
->p_lock
);
398 mutex_exit(&p
->p_lock
);
400 crset(p
, newcr
); /* broadcast to process threads */
406 return (set_errno(error
));