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