xref: /openbsd-src/sys/kern/kern_prot.c (revision 45afbba0fac9815b34097edbe51db410c213f632)
1 /*	$OpenBSD: kern_prot.c,v 1.4 1996/08/25 09:51:37 deraadt 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, pid) != 0 && SCARG(uap, pid) != curp->p_pid) {
251 		if ((targp = pfind(SCARG(uap, pid))) == 0 || !inferior(targp))
252 			return (ESRCH);
253 		if (targp->p_session != curp->p_session)
254 			return (EPERM);
255 		if (targp->p_flag & P_EXEC)
256 			return (EACCES);
257 	} else
258 		targp = curp;
259 	if (SESS_LEADER(targp))
260 		return (EPERM);
261 	if (SCARG(uap, pgid) == 0)
262 		SCARG(uap, pgid) = targp->p_pid;
263 	else if (SCARG(uap, pgid) != targp->p_pid)
264 		if ((pgrp = pgfind(SCARG(uap, pgid))) == 0 ||
265 	            pgrp->pg_session != curp->p_session)
266 			return (EPERM);
267 	return (enterpgrp(targp, SCARG(uap, pgid), 0));
268 }
269 
270 /* ARGSUSED */
271 int
272 sys_setuid(p, v, retval)
273 	struct proc *p;
274 	void *v;
275 	register_t *retval;
276 {
277 	struct sys_setuid_args /* {
278 		syscallarg(uid_t) uid;
279 	} */ *uap = v;
280 	register struct pcred *pc = p->p_cred;
281 	register uid_t uid;
282 	int error;
283 
284 #ifdef COMPAT_09				/* XXX */
285 	uid = (u_short)SCARG(uap, uid);
286 #else
287 	uid = SCARG(uap, uid);
288 #endif
289 	if (uid != pc->p_ruid &&
290 	    uid != pc->pc_ucred->cr_uid &&
291 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
292 		return (error);
293 	/*
294 	 * Everything's okay, do it.
295 	 */
296 	if (uid == pc->pc_ucred->cr_uid ||
297 	    suser(pc->pc_ucred, &p->p_acflag) == 0) {
298 		/*
299 		 * Transfer proc count to new user.
300 		 */
301 		if (uid != pc->p_ruid) {
302 			(void)chgproccnt(pc->p_ruid, -1);
303 			(void)chgproccnt(uid, 1);
304 		}
305 		pc->p_ruid = uid;
306 		pc->p_svuid = uid;
307 	}
308 	/*
309 	 * Copy credentials so other references do not see our changes.
310 	 */
311 	pc->pc_ucred = crcopy(pc->pc_ucred);
312 	pc->pc_ucred->cr_uid = uid;
313 	p->p_flag |= P_SUGID;
314 	return (0);
315 }
316 
317 /* ARGSUSED */
318 int
319 sys_seteuid(p, v, retval)
320 	struct proc *p;
321 	void *v;
322 	register_t *retval;
323 {
324 	struct sys_seteuid_args /* {
325 		syscallarg(uid_t) euid;
326 	} */ *uap = v;
327 	register struct pcred *pc = p->p_cred;
328 	register uid_t euid;
329 	int error;
330 
331 #ifdef COMPAT_09				/* XXX */
332 	euid = (u_short)SCARG(uap, euid);
333 #else
334 	euid = SCARG(uap, euid);
335 #endif
336 	if (euid != pc->p_ruid && euid != pc->p_svuid &&
337 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
338 		return (error);
339 	/*
340 	 * Everything's okay, do it.  Copy credentials so other references do
341 	 * not see our changes.
342 	 */
343 	pc->pc_ucred = crcopy(pc->pc_ucred);
344 	pc->pc_ucred->cr_uid = euid;
345 	p->p_flag |= P_SUGID;
346 	return (0);
347 }
348 
349 /* ARGSUSED */
350 int
351 sys_setgid(p, v, retval)
352 	struct proc *p;
353 	void *v;
354 	register_t *retval;
355 {
356 	struct sys_setgid_args /* {
357 		syscallarg(gid_t) gid;
358 	} */ *uap = v;
359 	register struct pcred *pc = p->p_cred;
360 	register gid_t gid;
361 	int error;
362 
363 #ifdef COMPAT_09				/* XXX */
364 	gid = (u_short)SCARG(uap, gid);
365 #else
366 	gid = SCARG(uap, gid);
367 #endif
368 	if (gid != pc->p_rgid &&
369 	    gid != pc->pc_ucred->cr_gid &&
370 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
371 		return (error);
372 	if (gid == pc->pc_ucred->cr_gid ||
373 	    suser(pc->pc_ucred, &p->p_acflag) == 0) {
374 		pc->p_rgid = gid;
375 		pc->p_svgid = gid;
376 	}
377 	pc->pc_ucred = crcopy(pc->pc_ucred);
378 	pc->pc_ucred->cr_gid = gid;
379 	p->p_flag |= P_SUGID;
380 	return (0);
381 }
382 
383 /* ARGSUSED */
384 int
385 sys_setegid(p, v, retval)
386 	struct proc *p;
387 	void *v;
388 	register_t *retval;
389 {
390 	struct sys_setegid_args /* {
391 		syscallarg(gid_t) egid;
392 	} */ *uap = v;
393 	register struct pcred *pc = p->p_cred;
394 	register gid_t egid;
395 	int error;
396 
397 #ifdef COMPAT_09				/* XXX */
398 	egid = (u_short)SCARG(uap, egid);
399 #else
400 	egid = SCARG(uap, egid);
401 #endif
402 	if (egid != pc->p_rgid && egid != pc->p_svgid &&
403 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
404 		return (error);
405 	pc->pc_ucred = crcopy(pc->pc_ucred);
406 	pc->pc_ucred->cr_gid = egid;
407 	p->p_flag |= P_SUGID;
408 	return (0);
409 }
410 
411 /* ARGSUSED */
412 int
413 sys_setgroups(p, v, retval)
414 	struct proc *p;
415 	void *v;
416 	register_t *retval;
417 {
418 	struct sys_setgroups_args /* {
419 		syscallarg(u_int) gidsetsize;
420 		syscallarg(gid_t *) gidset;
421 	} */ *uap = v;
422 	register struct pcred *pc = p->p_cred;
423 	register u_int ngrp;
424 	int error;
425 
426 	if ((error = suser(pc->pc_ucred, &p->p_acflag)) != 0)
427 		return (error);
428 	ngrp = SCARG(uap, gidsetsize);
429 	if (ngrp > NGROUPS)
430 		return (EINVAL);
431 	pc->pc_ucred = crcopy(pc->pc_ucred);
432 	error = copyin((caddr_t)SCARG(uap, gidset),
433 		       (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t));
434 	if (error)
435 		return (error);
436 	pc->pc_ucred->cr_ngroups = ngrp;
437 	p->p_flag |= P_SUGID;
438 	return (0);
439 }
440 
441 /*
442  * Check if gid is a member of the group set.
443  */
444 int
445 groupmember(gid, cred)
446 	gid_t gid;
447 	register struct ucred *cred;
448 {
449 	register gid_t *gp;
450 	gid_t *egp;
451 
452 	egp = &(cred->cr_groups[cred->cr_ngroups]);
453 	for (gp = cred->cr_groups; gp < egp; gp++)
454 		if (*gp == gid)
455 			return (1);
456 	return (0);
457 }
458 
459 /*
460  * Test whether the specified credentials imply "super-user"
461  * privilege; if so, and we have accounting info, set the flag
462  * indicating use of super-powers.
463  * Returns 0 or error.
464  */
465 int
466 suser(cred, acflag)
467 	struct ucred *cred;
468 	u_short *acflag;
469 {
470 	if (cred->cr_uid == 0) {
471 		if (acflag)
472 			*acflag |= ASU;
473 		return (0);
474 	}
475 	return (EPERM);
476 }
477 
478 /*
479  * Allocate a zeroed cred structure.
480  */
481 struct ucred *
482 crget()
483 {
484 	register struct ucred *cr;
485 
486 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
487 	bzero((caddr_t)cr, sizeof(*cr));
488 	cr->cr_ref = 1;
489 	return (cr);
490 }
491 
492 /*
493  * Free a cred structure.
494  * Throws away space when ref count gets to 0.
495  */
496 void
497 crfree(cr)
498 	struct ucred *cr;
499 {
500 	int s;
501 
502 	s = splimp();				/* ??? */
503 	if (--cr->cr_ref == 0)
504 		FREE((caddr_t)cr, M_CRED);
505 	(void) splx(s);
506 }
507 
508 /*
509  * Copy cred structure to a new one and free the old one.
510  */
511 struct ucred *
512 crcopy(cr)
513 	struct ucred *cr;
514 {
515 	struct ucred *newcr;
516 
517 	if (cr->cr_ref == 1)
518 		return (cr);
519 	newcr = crget();
520 	*newcr = *cr;
521 	crfree(cr);
522 	newcr->cr_ref = 1;
523 	return (newcr);
524 }
525 
526 /*
527  * Dup cred struct to a new held one.
528  */
529 struct ucred *
530 crdup(cr)
531 	struct ucred *cr;
532 {
533 	struct ucred *newcr;
534 
535 	newcr = crget();
536 	*newcr = *cr;
537 	newcr->cr_ref = 1;
538 	return (newcr);
539 }
540 
541 /*
542  * Get login name, if available.
543  */
544 /* ARGSUSED */
545 int
546 sys_getlogin(p, v, retval)
547 	struct proc *p;
548 	void *v;
549 	register_t *retval;
550 {
551 	struct sys_getlogin_args /* {
552 		syscallarg(char *) namebuf;
553 		syscallarg(u_int) namelen;
554 	} */ *uap = v;
555 
556 	if (SCARG(uap, namelen) > sizeof (p->p_pgrp->pg_session->s_login))
557 		SCARG(uap, namelen) = sizeof (p->p_pgrp->pg_session->s_login);
558 	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
559 	    (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen)));
560 }
561 
562 /*
563  * Set login name.
564  */
565 /* ARGSUSED */
566 int
567 sys_setlogin(p, v, retval)
568 	struct proc *p;
569 	void *v;
570 	register_t *retval;
571 {
572 	struct sys_setlogin_args /* {
573 		syscallarg(char *) namebuf;
574 	} */ *uap = v;
575 	int error;
576 
577 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
578 		return (error);
579 	error = copyinstr((caddr_t) SCARG(uap, namebuf),
580 	    (caddr_t) p->p_pgrp->pg_session->s_login,
581 	    sizeof (p->p_pgrp->pg_session->s_login) - 1, (size_t *)0);
582 	if (error == ENAMETOOLONG)
583 		error = EINVAL;
584 	return (error);
585 }
586