xref: /netbsd-src/sys/kern/kern_prot.c (revision 7c7c171d130af9949261bc7dce2150a03c3d239c)
1 /*	$NetBSD: kern_prot.c,v 1.44 1998/03/01 02:22:29 fvdl 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.9 (Berkeley) 2/14/95
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 /*
100  * Return the process group ID of the session leader (session ID)
101  * for the specified process.
102  */
103 int
104 sys_getsid(p, v, retval)
105 	struct proc *p;
106 	void *v;
107 	register_t *retval;
108 {
109 	struct sys_getsid_args /* {
110 		syscalldarg(pid_t) pid;
111 	} */ *uap = v;
112 
113 	if (SCARG(uap, pid) == 0)
114 		goto found;
115 	if ((p = pfind(SCARG(uap, pid))) == 0)
116 		return (ESRCH);
117 found:
118 	*retval = p->p_session->s_sid;
119 	return 0;
120 }
121 
122 int
123 sys_getpgid(p, v, retval)
124 	struct proc *p;
125 	void *v;
126 	register_t *retval;
127 {
128 	register struct sys_getpgid_args /* {
129 		syscallarg(pid_t) pid;
130 	} */ *uap = v;
131 
132 	if (SCARG(uap, pid) == 0)
133 		goto found;
134 	if ((p = pfind(SCARG(uap, pid))) == 0)
135 		return (ESRCH);
136 found:
137 	*retval = p->p_pgid;
138 	return 0;
139 }
140 
141 /* ARGSUSED */
142 int
143 sys_getuid(p, v, retval)
144 	struct proc *p;
145 	void *v;
146 	register_t *retval;
147 {
148 
149 	*retval = p->p_cred->p_ruid;
150 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2) || \
151     defined(COMPAT_FREEBSD)
152 	retval[1] = p->p_ucred->cr_uid;
153 #endif
154 	return (0);
155 }
156 
157 /* ARGSUSED */
158 int
159 sys_geteuid(p, v, retval)
160 	struct proc *p;
161 	void *v;
162 	register_t *retval;
163 {
164 
165 	*retval = p->p_ucred->cr_uid;
166 	return (0);
167 }
168 
169 /* ARGSUSED */
170 int
171 sys_getgid(p, v, retval)
172 	struct proc *p;
173 	void *v;
174 	register_t *retval;
175 {
176 
177 	*retval = p->p_cred->p_rgid;
178 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_FREEBSD)
179 	retval[1] = p->p_ucred->cr_gid;
180 #endif
181 	return (0);
182 }
183 
184 /*
185  * Get effective group ID.  The "egid" is groups[0], and could be obtained
186  * via getgroups.  This syscall exists because it is somewhat painful to do
187  * correctly in a library function.
188  */
189 /* ARGSUSED */
190 int
191 sys_getegid(p, v, retval)
192 	struct proc *p;
193 	void *v;
194 	register_t *retval;
195 {
196 
197 	*retval = p->p_ucred->cr_gid;
198 	return (0);
199 }
200 
201 int
202 sys_getgroups(p, v, retval)
203 	struct proc *p;
204 	void *v;
205 	register_t *retval;
206 {
207 	register struct sys_getgroups_args /* {
208 		syscallarg(int) gidsetsize;
209 		syscallarg(gid_t *) gidset;
210 	} */ *uap = v;
211 	register struct pcred *pc = p->p_cred;
212 	register int ngrp;
213 	int error;
214 
215 	ngrp = SCARG(uap, gidsetsize);
216 	if (ngrp == 0) {
217 		*retval = pc->pc_ucred->cr_ngroups;
218 		return (0);
219 	}
220 	if (ngrp < pc->pc_ucred->cr_ngroups)
221 		return (EINVAL);
222 	ngrp = pc->pc_ucred->cr_ngroups;
223 	error = copyout((caddr_t)pc->pc_ucred->cr_groups,
224 			(caddr_t)SCARG(uap, gidset), ngrp * sizeof(gid_t));
225 	if (error)
226 		return (error);
227 	*retval = ngrp;
228 	return (0);
229 }
230 
231 /* ARGSUSED */
232 int
233 sys_setsid(p, v, retval)
234 	register struct proc *p;
235 	void *v;
236 	register_t *retval;
237 {
238 
239 	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
240 		return (EPERM);
241 	} else {
242 		(void)enterpgrp(p, p->p_pid, 1);
243 		*retval = p->p_pid;
244 		return (0);
245 	}
246 }
247 
248 /*
249  * set process group (setpgid/old setpgrp)
250  *
251  * caller does setpgid(targpid, targpgid)
252  *
253  * pgid must be in valid range (EINVAL)
254  * pid must be caller or child of caller (ESRCH)
255  * if a child
256  *	pid must be in same session (EPERM)
257  *	pid can't have done an exec (EACCES)
258  * if pgid != pid
259  * 	there must exist some pid in same session having pgid (EPERM)
260  * pid must not be session leader (EPERM)
261  */
262 /* ARGSUSED */
263 int
264 sys_setpgid(curp, v, retval)
265 	struct proc *curp;
266 	void *v;
267 	register_t *retval;
268 {
269 	register struct sys_setpgid_args /* {
270 		syscallarg(int) pid;
271 		syscallarg(int) pgid;
272 	} */ *uap = v;
273 	register struct proc *targp;		/* target process */
274 	register struct pgrp *pgrp;		/* target pgrp */
275 
276 	if (SCARG(uap, pgid) < 0)
277 		return (EINVAL);
278 
279 	if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != curp->p_pid) {
280 		if ((targp = pfind(SCARG(uap, pid))) == 0 || !inferior(targp))
281 			return (ESRCH);
282 		if (targp->p_session != curp->p_session)
283 			return (EPERM);
284 		if (targp->p_flag & P_EXEC)
285 			return (EACCES);
286 	} else
287 		targp = curp;
288 	if (SESS_LEADER(targp))
289 		return (EPERM);
290 	if (SCARG(uap, pgid) == 0)
291 		SCARG(uap, pgid) = targp->p_pid;
292 	else if (SCARG(uap, pgid) != targp->p_pid)
293 		if ((pgrp = pgfind(SCARG(uap, pgid))) == 0 ||
294 	            pgrp->pg_session != curp->p_session)
295 			return (EPERM);
296 	return (enterpgrp(targp, SCARG(uap, pgid), 0));
297 }
298 
299 /* ARGSUSED */
300 int
301 sys_setuid(p, v, retval)
302 	struct proc *p;
303 	void *v;
304 	register_t *retval;
305 {
306 	struct sys_setuid_args /* {
307 		syscallarg(uid_t) uid;
308 	} */ *uap = v;
309 	register struct pcred *pc = p->p_cred;
310 	register uid_t uid;
311 	int error;
312 
313 	uid = SCARG(uap, uid);
314 	if (uid != pc->p_ruid &&
315 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
316 		return (error);
317 	/*
318 	 * Everything's okay, do it.
319 	 * Transfer proc count to new user.
320 	 * Copy credentials so other references do not see our changes.
321 	 */
322 	(void)chgproccnt(pc->p_ruid, -1);
323 	(void)chgproccnt(uid, 1);
324 	pc->pc_ucred = crcopy(pc->pc_ucred);
325 	pc->pc_ucred->cr_uid = uid;
326 	pc->p_ruid = uid;
327 	pc->p_svuid = uid;
328 	p->p_flag |= P_SUGID;
329 	return (0);
330 }
331 
332 /* ARGSUSED */
333 int
334 sys_seteuid(p, v, retval)
335 	struct proc *p;
336 	void *v;
337 	register_t *retval;
338 {
339 	struct sys_seteuid_args /* {
340 		syscallarg(uid_t) euid;
341 	} */ *uap = v;
342 	register struct pcred *pc = p->p_cred;
343 	register uid_t euid;
344 	int error;
345 
346 	euid = SCARG(uap, euid);
347 	if (euid != pc->p_ruid && euid != pc->p_svuid &&
348 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
349 		return (error);
350 	/*
351 	 * Everything's okay, do it.  Copy credentials so other references do
352 	 * not see our changes.
353 	 */
354 	pc->pc_ucred = crcopy(pc->pc_ucred);
355 	pc->pc_ucred->cr_uid = euid;
356 	p->p_flag |= P_SUGID;
357 	return (0);
358 }
359 
360 int
361 sys_setreuid(p, v, retval)
362 	struct proc *p;
363 	void *v;
364 	register_t *retval;
365 {
366 	struct sys_setreuid_args /* {
367 		syscallarg(uid_t) ruid;
368 		syscallarg(uid_t) euid;
369 	} */ *uap = v;
370 	register struct pcred *pc = p->p_cred;
371 	register uid_t ruid, euid;
372 	int error;
373 
374 	ruid = SCARG(uap, ruid);
375 	euid = SCARG(uap, euid);
376 
377 	if (ruid != (uid_t)-1 &&
378 	    ruid != pc->p_ruid && ruid != pc->pc_ucred->cr_uid &&
379 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
380 		return (error);
381 
382 	if (euid != (uid_t)-1 &&
383 	    euid != pc->p_ruid && euid != pc->pc_ucred->cr_uid &&
384 	    euid != pc->p_svuid &&
385 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
386 		return (error);
387 
388 	if (euid != (uid_t)-1) {
389 		pc->pc_ucred = crcopy(pc->pc_ucred);
390 		pc->pc_ucred->cr_uid = euid;
391 	}
392 
393 	if (ruid != (uid_t)-1) {
394 		(void)chgproccnt(pc->p_ruid, -1);
395 		(void)chgproccnt(ruid, 1);
396 		pc->p_ruid = ruid;
397 		pc->p_svuid = pc->pc_ucred->cr_uid;
398 	}
399 
400 	if (euid != (uid_t)-1 && ruid != (uid_t)-1)
401 		p->p_flag |= P_SUGID;
402 	return (0);
403 }
404 
405 /* ARGSUSED */
406 int
407 sys_setgid(p, v, retval)
408 	struct proc *p;
409 	void *v;
410 	register_t *retval;
411 {
412 	struct sys_setgid_args /* {
413 		syscallarg(gid_t) gid;
414 	} */ *uap = v;
415 	register struct pcred *pc = p->p_cred;
416 	register gid_t gid;
417 	int error;
418 
419 	gid = SCARG(uap, gid);
420 	if (gid != pc->p_rgid &&
421 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
422 		return (error);
423 	pc->pc_ucred = crcopy(pc->pc_ucred);
424 	pc->pc_ucred->cr_gid = gid;
425 	pc->p_rgid = gid;
426 	pc->p_svgid = gid;
427 	p->p_flag |= P_SUGID;
428 	return (0);
429 }
430 
431 /* ARGSUSED */
432 int
433 sys_setegid(p, v, retval)
434 	struct proc *p;
435 	void *v;
436 	register_t *retval;
437 {
438 	struct sys_setegid_args /* {
439 		syscallarg(gid_t) egid;
440 	} */ *uap = v;
441 	register struct pcred *pc = p->p_cred;
442 	register gid_t egid;
443 	int error;
444 
445 	egid = SCARG(uap, egid);
446 	if (egid != pc->p_rgid && egid != pc->p_svgid &&
447 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
448 		return (error);
449 	pc->pc_ucred = crcopy(pc->pc_ucred);
450 	pc->pc_ucred->cr_gid = egid;
451 	p->p_flag |= P_SUGID;
452 	return (0);
453 }
454 
455 int
456 sys_setregid(p, v, retval)
457 	struct proc *p;
458 	void *v;
459 	register_t *retval;
460 {
461 	struct sys_setregid_args /* {
462 		syscallarg(gid_t) rgid;
463 		syscallarg(gid_t) egid;
464 	} */ *uap = v;
465 	register struct pcred *pc = p->p_cred;
466 	register gid_t rgid, egid;
467 	int error;
468 
469 	rgid = SCARG(uap, rgid);
470 	egid = SCARG(uap, egid);
471 
472 	if (rgid != (gid_t)-1 &&
473 	    rgid != pc->p_rgid && rgid != pc->pc_ucred->cr_gid &&
474 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
475 		return (error);
476 
477 	if (egid != (gid_t)-1 &&
478 	    egid != pc->p_rgid && egid != pc->pc_ucred->cr_gid &&
479 	    egid != pc->p_svgid &&
480 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
481 		return (error);
482 
483 	if (egid != (gid_t)-1) {
484 		pc->pc_ucred = crcopy(pc->pc_ucred);
485 		pc->pc_ucred->cr_gid = egid;
486 	}
487 
488 	if (rgid != (gid_t)-1) {
489 		pc->p_rgid = rgid;
490 		pc->p_svgid = pc->pc_ucred->cr_gid;
491 	}
492 
493 	if (egid != (gid_t)-1 && rgid != (gid_t)-1)
494 		p->p_flag |= P_SUGID;
495 	return (0);
496 }
497 
498 /* ARGSUSED */
499 int
500 sys_setgroups(p, v, retval)
501 	struct proc *p;
502 	void *v;
503 	register_t *retval;
504 {
505 	struct sys_setgroups_args /* {
506 		syscallarg(int) gidsetsize;
507 		syscallarg(const gid_t *) gidset;
508 	} */ *uap = v;
509 	register struct pcred *pc = p->p_cred;
510 	register int ngrp;
511 	int error;
512 
513 	if ((error = suser(pc->pc_ucred, &p->p_acflag)) != 0)
514 		return (error);
515 	ngrp = SCARG(uap, gidsetsize);
516 	if ((u_int)ngrp > NGROUPS)
517 		return (EINVAL);
518 	pc->pc_ucred = crcopy(pc->pc_ucred);
519 	error = copyin(SCARG(uap, gidset), pc->pc_ucred->cr_groups,
520 	    ngrp * sizeof(gid_t));
521 	if (error)
522 		return (error);
523 	pc->pc_ucred->cr_ngroups = ngrp;
524 	p->p_flag |= P_SUGID;
525 	return (0);
526 }
527 
528 /*
529  * Check if gid is a member of the group set.
530  */
531 int
532 groupmember(gid, cred)
533 	gid_t gid;
534 	register struct ucred *cred;
535 {
536 	register gid_t *gp;
537 	gid_t *egp;
538 
539 	egp = &(cred->cr_groups[cred->cr_ngroups]);
540 	for (gp = cred->cr_groups; gp < egp; gp++)
541 		if (*gp == gid)
542 			return (1);
543 	return (0);
544 }
545 
546 /*
547  * Test whether the specified credentials imply "super-user"
548  * privilege; if so, and we have accounting info, set the flag
549  * indicating use of super-powers.
550  * Returns 0 or error.
551  */
552 int
553 suser(cred, acflag)
554 	struct ucred *cred;
555 	u_short *acflag;
556 {
557 	if (cred->cr_uid == 0) {
558 		if (acflag)
559 			*acflag |= ASU;
560 		return (0);
561 	}
562 	return (EPERM);
563 }
564 
565 /*
566  * Allocate a zeroed cred structure.
567  */
568 struct ucred *
569 crget()
570 {
571 	register struct ucred *cr;
572 
573 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
574 	bzero((caddr_t)cr, sizeof(*cr));
575 	cr->cr_ref = 1;
576 	return (cr);
577 }
578 
579 /*
580  * Free a cred structure.
581  * Throws away space when ref count gets to 0.
582  */
583 void
584 crfree(cr)
585 	struct ucred *cr;
586 {
587 	int s;
588 
589 	s = splimp();				/* ??? */
590 	if (--cr->cr_ref == 0)
591 		FREE((caddr_t)cr, M_CRED);
592 	(void) splx(s);
593 }
594 
595 /*
596  * Copy cred structure to a new one and free the old one.
597  */
598 struct ucred *
599 crcopy(cr)
600 	struct ucred *cr;
601 {
602 	struct ucred *newcr;
603 
604 	if (cr->cr_ref == 1)
605 		return (cr);
606 	newcr = crget();
607 	*newcr = *cr;
608 	crfree(cr);
609 	newcr->cr_ref = 1;
610 	return (newcr);
611 }
612 
613 /*
614  * Dup cred struct to a new held one.
615  */
616 struct ucred *
617 crdup(cr)
618 	struct ucred *cr;
619 {
620 	struct ucred *newcr;
621 
622 	newcr = crget();
623 	*newcr = *cr;
624 	newcr->cr_ref = 1;
625 	return (newcr);
626 }
627 
628 /*
629  * Get login name, if available.
630  */
631 /* ARGSUSED */
632 int
633 sys___getlogin(p, v, retval)
634 	struct proc *p;
635 	void *v;
636 	register_t *retval;
637 {
638 	struct sys___getlogin_args /* {
639 		syscallarg(char *) namebuf;
640 		syscallarg(u_int) namelen;
641 	} */ *uap = v;
642 
643 	if (SCARG(uap, namelen) > sizeof (p->p_pgrp->pg_session->s_login))
644 		SCARG(uap, namelen) = sizeof (p->p_pgrp->pg_session->s_login);
645 	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
646 	    (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen)));
647 }
648 
649 /*
650  * Set login name.
651  */
652 /* ARGSUSED */
653 int
654 sys_setlogin(p, v, retval)
655 	struct proc *p;
656 	void *v;
657 	register_t *retval;
658 {
659 	struct sys_setlogin_args /* {
660 		syscallarg(const char *) namebuf;
661 	} */ *uap = v;
662 	int error;
663 
664 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
665 		return (error);
666 	error = copyinstr(SCARG(uap, namebuf), p->p_pgrp->pg_session->s_login,
667 	    sizeof (p->p_pgrp->pg_session->s_login) - 1, (size_t *)0);
668 	if (error == ENAMETOOLONG)
669 		error = EINVAL;
670 	return (error);
671 }
672