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