xref: /openbsd-src/sys/kern/kern_prot.c (revision a4afd6dad3fba28f80e70208181c06c482259988)
1 /*	$OpenBSD: kern_prot.c,v 1.7 1996/10/27 04:51:37 tholo Exp $	*/
2 /*	$NetBSD: kern_prot.c,v 1.33 1996/02/09 18:59:42 christos Exp $	*/
3 
4 /*
5  * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  * (c) UNIX System Laboratories, Inc.
8  * All or some portions of this file are derived from material licensed
9  * to the University of California by American Telephone and Telegraph
10  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
11  * the permission of UNIX System Laboratories, Inc.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. All advertising materials mentioning features or use of this software
22  *    must display the following acknowledgement:
23  *	This product includes software developed by the University of
24  *	California, Berkeley and its contributors.
25  * 4. Neither the name of the University nor the names of its contributors
26  *    may be used to endorse or promote products derived from this software
27  *    without specific prior written permission.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39  * SUCH DAMAGE.
40  *
41  *	@(#)kern_prot.c	8.6 (Berkeley) 1/21/94
42  */
43 
44 /*
45  * System calls related to processes and protection
46  */
47 
48 #include <sys/param.h>
49 #include <sys/acct.h>
50 #include <sys/systm.h>
51 #include <sys/ucred.h>
52 #include <sys/proc.h>
53 #include <sys/timeb.h>
54 #include <sys/times.h>
55 #include <sys/malloc.h>
56 
57 #include <sys/mount.h>
58 #include <sys/syscallargs.h>
59 
60 /* ARGSUSED */
61 int
62 sys_getpid(p, v, retval)
63 	struct proc *p;
64 	void *v;
65 	register_t *retval;
66 {
67 
68 	*retval = p->p_pid;
69 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2) || \
70     defined(COMPAT_FREEBSD)
71 	retval[1] = p->p_pptr->p_pid;
72 #endif
73 	return (0);
74 }
75 
76 /* ARGSUSED */
77 int
78 sys_getppid(p, v, retval)
79 	struct proc *p;
80 	void *v;
81 	register_t *retval;
82 {
83 
84 	*retval = p->p_pptr->p_pid;
85 	return (0);
86 }
87 
88 /* Get process group ID; note that POSIX getpgrp takes no parameter */
89 int
90 sys_getpgrp(p, v, retval)
91 	struct proc *p;
92 	void *v;
93 	register_t *retval;
94 {
95 
96 	*retval = p->p_pgrp->pg_id;
97 	return (0);
98 }
99 
100 /* ARGSUSED */
101 int
102 sys_getuid(p, v, retval)
103 	struct proc *p;
104 	void *v;
105 	register_t *retval;
106 {
107 
108 	*retval = p->p_cred->p_ruid;
109 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2) || \
110     defined(COMPAT_FREEBSD)
111 	retval[1] = p->p_ucred->cr_uid;
112 #endif
113 	return (0);
114 }
115 
116 /* ARGSUSED */
117 int
118 sys_geteuid(p, v, retval)
119 	struct proc *p;
120 	void *v;
121 	register_t *retval;
122 {
123 
124 	*retval = p->p_ucred->cr_uid;
125 	return (0);
126 }
127 
128 /* ARGSUSED */
129 int
130 sys_issetugid(p, v, retval)
131 	struct proc *p;
132 	void *v;
133 	register_t *retval;
134 {
135 	if (p->p_flag & P_SUGIDEXEC)
136 		return (1);
137 	return (0);
138 }
139 
140 /* ARGSUSED */
141 int
142 sys_getgid(p, v, retval)
143 	struct proc *p;
144 	void *v;
145 	register_t *retval;
146 {
147 
148 	*retval = p->p_cred->p_rgid;
149 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_FREEBSD)
150 	retval[1] = p->p_ucred->cr_gid;
151 #endif
152 	return (0);
153 }
154 
155 /*
156  * Get effective group ID.  The "egid" is groups[0], and could be obtained
157  * via getgroups.  This syscall exists because it is somewhat painful to do
158  * correctly in a library function.
159  */
160 /* ARGSUSED */
161 int
162 sys_getegid(p, v, retval)
163 	struct proc *p;
164 	void *v;
165 	register_t *retval;
166 {
167 
168 	*retval = p->p_ucred->cr_gid;
169 	return (0);
170 }
171 
172 int
173 sys_getgroups(p, v, retval)
174 	struct proc *p;
175 	void *v;
176 	register_t *retval;
177 {
178 	register struct sys_getgroups_args /* {
179 		syscallarg(u_int) gidsetsize;
180 		syscallarg(gid_t *) gidset;
181 	} */ *uap = v;
182 	register struct pcred *pc = p->p_cred;
183 	register u_int ngrp;
184 	int error;
185 
186 	if ((ngrp = SCARG(uap, gidsetsize)) == 0) {
187 		*retval = pc->pc_ucred->cr_ngroups;
188 		return (0);
189 	}
190 	if (ngrp < pc->pc_ucred->cr_ngroups)
191 		return (EINVAL);
192 	ngrp = pc->pc_ucred->cr_ngroups;
193 	error = copyout((caddr_t)pc->pc_ucred->cr_groups,
194 			(caddr_t)SCARG(uap, gidset), ngrp * sizeof(gid_t));
195 	if (error)
196 		return (error);
197 	*retval = ngrp;
198 	return (0);
199 }
200 
201 /* ARGSUSED */
202 int
203 sys_setsid(p, v, retval)
204 	register struct proc *p;
205 	void *v;
206 	register_t *retval;
207 {
208 
209 	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
210 		return (EPERM);
211 	} else {
212 		(void)enterpgrp(p, p->p_pid, 1);
213 		*retval = p->p_pid;
214 		return (0);
215 	}
216 }
217 
218 /*
219  * set process group (setpgid/old setpgrp)
220  *
221  * caller does setpgid(targpid, targpgid)
222  *
223  * pid must be caller or child of caller (ESRCH)
224  * if a child
225  *	pid must be in same session (EPERM)
226  *	pid can't have done an exec (EACCES)
227  * if pgid != pid
228  * 	there must exist some pid in same session having pgid (EPERM)
229  * pid must not be session leader (EPERM)
230  */
231 /* ARGSUSED */
232 int
233 sys_setpgid(curp, v, retval)
234 	struct proc *curp;
235 	void *v;
236 	register_t *retval;
237 {
238 	register struct sys_setpgid_args /* {
239 		syscallarg(int) pid;
240 		syscallarg(int) pgid;
241 	} */ *uap = v;
242 	register struct proc *targp;		/* target process */
243 	register struct pgrp *pgrp;		/* target pgrp */
244 
245 #ifdef COMPAT_09
246 	SCARG(uap, pid)  = (short) SCARG(uap, pid);		/* XXX */
247 	SCARG(uap, pgid) = (short) SCARG(uap, pgid);		/* XXX */
248 #endif
249 
250 	if (SCARG(uap, pgid) < 0)
251 		return (EINVAL);
252 
253 	if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != curp->p_pid) {
254 		if ((targp = pfind(SCARG(uap, pid))) == 0 || !inferior(targp))
255 			return (ESRCH);
256 		if (targp->p_session != curp->p_session)
257 			return (EPERM);
258 		if (targp->p_flag & P_EXEC)
259 			return (EACCES);
260 	} else
261 		targp = curp;
262 	if (SESS_LEADER(targp))
263 		return (EPERM);
264 	if (SCARG(uap, pgid) == 0)
265 		SCARG(uap, pgid) = targp->p_pid;
266 	else if (SCARG(uap, pgid) != targp->p_pid)
267 		if ((pgrp = pgfind(SCARG(uap, pgid))) == 0 ||
268 	            pgrp->pg_session != curp->p_session)
269 			return (EPERM);
270 	return (enterpgrp(targp, SCARG(uap, pgid), 0));
271 }
272 
273 /* ARGSUSED */
274 int
275 sys_setuid(p, v, retval)
276 	struct proc *p;
277 	void *v;
278 	register_t *retval;
279 {
280 	struct sys_setuid_args /* {
281 		syscallarg(uid_t) uid;
282 	} */ *uap = v;
283 	register struct pcred *pc = p->p_cred;
284 	register uid_t uid;
285 	int error;
286 
287 #ifdef COMPAT_09				/* XXX */
288 	uid = (u_short)SCARG(uap, uid);
289 #else
290 	uid = SCARG(uap, uid);
291 #endif
292 	if (uid != pc->p_ruid &&
293 	    uid != pc->p_svuid &&
294 	    uid != pc->pc_ucred->cr_uid &&
295 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
296 		return (error);
297 	/*
298 	 * Everything's okay, do it.
299 	 */
300 	if (uid == pc->pc_ucred->cr_uid ||
301 	    suser(pc->pc_ucred, &p->p_acflag) == 0) {
302 		/*
303 		 * Transfer proc count to new user.
304 		 */
305 		if (uid != pc->p_ruid) {
306 			(void)chgproccnt(pc->p_ruid, -1);
307 			(void)chgproccnt(uid, 1);
308 		}
309 		pc->p_ruid = uid;
310 		pc->p_svuid = uid;
311 	}
312 	/*
313 	 * Copy credentials so other references do not see our changes.
314 	 */
315 	pc->pc_ucred = crcopy(pc->pc_ucred);
316 	pc->pc_ucred->cr_uid = uid;
317 	p->p_flag |= P_SUGID;
318 	return (0);
319 }
320 
321 /* ARGSUSED */
322 int
323 sys_seteuid(p, v, retval)
324 	struct proc *p;
325 	void *v;
326 	register_t *retval;
327 {
328 	struct sys_seteuid_args /* {
329 		syscallarg(uid_t) euid;
330 	} */ *uap = v;
331 	register struct pcred *pc = p->p_cred;
332 	register uid_t euid;
333 	int error;
334 
335 #ifdef COMPAT_09				/* XXX */
336 	euid = (u_short)SCARG(uap, euid);
337 #else
338 	euid = SCARG(uap, euid);
339 #endif
340 	if (euid != pc->p_ruid && euid != pc->p_svuid &&
341 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
342 		return (error);
343 	/*
344 	 * Everything's okay, do it.  Copy credentials so other references do
345 	 * not see our changes.
346 	 */
347 	pc->pc_ucred = crcopy(pc->pc_ucred);
348 	pc->pc_ucred->cr_uid = euid;
349 	p->p_flag |= P_SUGID;
350 	return (0);
351 }
352 
353 /* ARGSUSED */
354 int
355 sys_setgid(p, v, retval)
356 	struct proc *p;
357 	void *v;
358 	register_t *retval;
359 {
360 	struct sys_setgid_args /* {
361 		syscallarg(gid_t) gid;
362 	} */ *uap = v;
363 	register struct pcred *pc = p->p_cred;
364 	register gid_t gid;
365 	int error;
366 
367 #ifdef COMPAT_09				/* XXX */
368 	gid = (u_short)SCARG(uap, gid);
369 #else
370 	gid = SCARG(uap, gid);
371 #endif
372 	if (gid != pc->p_rgid &&
373 	    gid != pc->p_svgid &&
374 	    gid != pc->pc_ucred->cr_gid &&
375 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
376 		return (error);
377 	if (gid == pc->pc_ucred->cr_gid ||
378 	    suser(pc->pc_ucred, &p->p_acflag) == 0) {
379 		pc->p_rgid = gid;
380 		pc->p_svgid = gid;
381 	}
382 	pc->pc_ucred = crcopy(pc->pc_ucred);
383 	pc->pc_ucred->cr_gid = gid;
384 	p->p_flag |= P_SUGID;
385 	return (0);
386 }
387 
388 /* ARGSUSED */
389 int
390 sys_setegid(p, v, retval)
391 	struct proc *p;
392 	void *v;
393 	register_t *retval;
394 {
395 	struct sys_setegid_args /* {
396 		syscallarg(gid_t) egid;
397 	} */ *uap = v;
398 	register struct pcred *pc = p->p_cred;
399 	register gid_t egid;
400 	int error;
401 
402 #ifdef COMPAT_09				/* XXX */
403 	egid = (u_short)SCARG(uap, egid);
404 #else
405 	egid = SCARG(uap, egid);
406 #endif
407 	if (egid != pc->p_rgid && egid != pc->p_svgid &&
408 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
409 		return (error);
410 	pc->pc_ucred = crcopy(pc->pc_ucred);
411 	pc->pc_ucred->cr_gid = egid;
412 	p->p_flag |= P_SUGID;
413 	return (0);
414 }
415 
416 /* ARGSUSED */
417 int
418 sys_setgroups(p, v, retval)
419 	struct proc *p;
420 	void *v;
421 	register_t *retval;
422 {
423 	struct sys_setgroups_args /* {
424 		syscallarg(u_int) gidsetsize;
425 		syscallarg(gid_t *) gidset;
426 	} */ *uap = v;
427 	register struct pcred *pc = p->p_cred;
428 	register u_int ngrp;
429 	int error;
430 
431 	if ((error = suser(pc->pc_ucred, &p->p_acflag)) != 0)
432 		return (error);
433 	ngrp = SCARG(uap, gidsetsize);
434 	if (ngrp > NGROUPS)
435 		return (EINVAL);
436 	pc->pc_ucred = crcopy(pc->pc_ucred);
437 	error = copyin((caddr_t)SCARG(uap, gidset),
438 		       (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t));
439 	if (error)
440 		return (error);
441 	pc->pc_ucred->cr_ngroups = ngrp;
442 	p->p_flag |= P_SUGID;
443 	return (0);
444 }
445 
446 /*
447  * Check if gid is a member of the group set.
448  */
449 int
450 groupmember(gid, cred)
451 	gid_t gid;
452 	register struct ucred *cred;
453 {
454 	register gid_t *gp;
455 	gid_t *egp;
456 
457 	egp = &(cred->cr_groups[cred->cr_ngroups]);
458 	for (gp = cred->cr_groups; gp < egp; gp++)
459 		if (*gp == gid)
460 			return (1);
461 	return (0);
462 }
463 
464 /*
465  * Test whether the specified credentials imply "super-user"
466  * privilege; if so, and we have accounting info, set the flag
467  * indicating use of super-powers.
468  * Returns 0 or error.
469  */
470 int
471 suser(cred, acflag)
472 	struct ucred *cred;
473 	u_short *acflag;
474 {
475 	if (cred->cr_uid == 0) {
476 		if (acflag)
477 			*acflag |= ASU;
478 		return (0);
479 	}
480 	return (EPERM);
481 }
482 
483 /*
484  * Allocate a zeroed cred structure.
485  */
486 struct ucred *
487 crget()
488 {
489 	register struct ucred *cr;
490 
491 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
492 	bzero((caddr_t)cr, sizeof(*cr));
493 	cr->cr_ref = 1;
494 	return (cr);
495 }
496 
497 /*
498  * Free a cred structure.
499  * Throws away space when ref count gets to 0.
500  */
501 void
502 crfree(cr)
503 	struct ucred *cr;
504 {
505 	int s;
506 
507 	s = splimp();				/* ??? */
508 	if (--cr->cr_ref == 0)
509 		FREE((caddr_t)cr, M_CRED);
510 	(void) splx(s);
511 }
512 
513 /*
514  * Copy cred structure to a new one and free the old one.
515  */
516 struct ucred *
517 crcopy(cr)
518 	struct ucred *cr;
519 {
520 	struct ucred *newcr;
521 
522 	if (cr->cr_ref == 1)
523 		return (cr);
524 	newcr = crget();
525 	*newcr = *cr;
526 	crfree(cr);
527 	newcr->cr_ref = 1;
528 	return (newcr);
529 }
530 
531 /*
532  * Dup cred struct to a new held one.
533  */
534 struct ucred *
535 crdup(cr)
536 	struct ucred *cr;
537 {
538 	struct ucred *newcr;
539 
540 	newcr = crget();
541 	*newcr = *cr;
542 	newcr->cr_ref = 1;
543 	return (newcr);
544 }
545 
546 /*
547  * Get login name, if available.
548  */
549 /* ARGSUSED */
550 int
551 sys_getlogin(p, v, retval)
552 	struct proc *p;
553 	void *v;
554 	register_t *retval;
555 {
556 	struct sys_getlogin_args /* {
557 		syscallarg(char *) namebuf;
558 		syscallarg(u_int) namelen;
559 	} */ *uap = v;
560 
561 	if (SCARG(uap, namelen) > sizeof (p->p_pgrp->pg_session->s_login))
562 		SCARG(uap, namelen) = sizeof (p->p_pgrp->pg_session->s_login);
563 	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
564 	    (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen)));
565 }
566 
567 /*
568  * Set login name.
569  */
570 /* ARGSUSED */
571 int
572 sys_setlogin(p, v, retval)
573 	struct proc *p;
574 	void *v;
575 	register_t *retval;
576 {
577 	struct sys_setlogin_args /* {
578 		syscallarg(char *) namebuf;
579 	} */ *uap = v;
580 	int error;
581 
582 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
583 		return (error);
584 	error = copyinstr((caddr_t) SCARG(uap, namebuf),
585 	    (caddr_t) p->p_pgrp->pg_session->s_login,
586 	    sizeof (p->p_pgrp->pg_session->s_login), (size_t *)0);
587 	if (error == ENAMETOOLONG)
588 		error = EINVAL;
589 	return (error);
590 }
591