xref: /freebsd/sys/kern/kern_prot.c (revision df7f5d4de4592a8948a25ce01e5bddfbb7ce39dc)
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.25 1997/03/03 22:46:16 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->pgid < 0)
279 		return (EINVAL);
280 	if (uap->pid != 0 && uap->pid != curp->p_pid) {
281 		if ((targp = pfind(uap->pid)) == 0 || !inferior(targp))
282 			return (ESRCH);
283 		if (targp->p_pgrp == NULL ||  targp->p_session != curp->p_session)
284 			return (EPERM);
285 		if (targp->p_flag & P_EXEC)
286 			return (EACCES);
287 	} else
288 		targp = curp;
289 	if (SESS_LEADER(targp))
290 		return (EPERM);
291 	if (uap->pgid == 0)
292 		uap->pgid = targp->p_pid;
293 	else if (uap->pgid != targp->p_pid)
294 		if ((pgrp = pgfind(uap->pgid)) == 0 ||
295 	            pgrp->pg_session != curp->p_session)
296 			return (EPERM);
297 	return (enterpgrp(targp, uap->pgid, 0));
298 }
299 
300 #ifndef _SYS_SYSPROTO_H_
301 struct setuid_args {
302 	uid_t	uid;
303 };
304 #endif
305 /* ARGSUSED */
306 int
307 setuid(p, uap, retval)
308 	struct proc *p;
309 	struct setuid_args *uap;
310 	int *retval;
311 {
312 	register struct pcred *pc = p->p_cred;
313 	register uid_t uid;
314 	int error;
315 
316 	uid = uap->uid;
317 	if (uid != pc->p_ruid &&
318 #ifdef _POSIX_SAVED_IDS
319 	    uid != pc->p_svuid &&
320 #endif
321 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
322 		return (error);
323 	/*
324 	 * Everything's okay, do it.
325 	 * Transfer proc count to new user.
326 	 * Copy credentials so other references do not see our changes.
327 	 */
328 	if (
329 #ifdef _POSIX_SAVED_IDS
330 	    pc->pc_ucred->cr_uid == 0 &&
331 #endif
332 	    uid != pc->p_ruid) {
333 		(void)chgproccnt(pc->p_ruid, -1);
334 		(void)chgproccnt(uid, 1);
335 	}
336 	pc->pc_ucred = crcopy(pc->pc_ucred);
337 #ifdef _POSIX_SAVED_IDS
338 	if (pc->pc_ucred->cr_uid == 0) {
339 #endif
340 		pc->p_ruid = uid;
341 		pc->p_svuid = uid;
342 #ifdef _POSIX_SAVED_IDS
343 	}
344 #endif
345 	pc->pc_ucred->cr_uid = uid;
346 	p->p_flag |= P_SUGID;
347 	return (0);
348 }
349 
350 #ifndef _SYS_SYSPROTO_H_
351 struct seteuid_args {
352 	uid_t	euid;
353 };
354 #endif
355 /* ARGSUSED */
356 int
357 seteuid(p, uap, retval)
358 	struct proc *p;
359 	struct seteuid_args *uap;
360 	int *retval;
361 {
362 	register struct pcred *pc = p->p_cred;
363 	register uid_t euid;
364 	int error;
365 
366 	euid = uap->euid;
367 	if (euid != pc->p_ruid && euid != pc->p_svuid &&
368 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
369 		return (error);
370 	/*
371 	 * Everything's okay, do it.  Copy credentials so other references do
372 	 * not see our changes.
373 	 */
374 	pc->pc_ucred = crcopy(pc->pc_ucred);
375 	pc->pc_ucred->cr_uid = euid;
376 	p->p_flag |= P_SUGID;
377 	return (0);
378 }
379 
380 #ifndef _SYS_SYSPROTO_H_
381 struct setgid_args {
382 	gid_t	gid;
383 };
384 #endif
385 /* ARGSUSED */
386 int
387 setgid(p, uap, retval)
388 	struct proc *p;
389 	struct setgid_args *uap;
390 	int *retval;
391 {
392 	register struct pcred *pc = p->p_cred;
393 	register gid_t gid;
394 	int error;
395 
396 	gid = uap->gid;
397 	if (gid != pc->p_rgid &&
398 #ifdef _POSIX_SAVED_IDS
399 	    gid != pc->p_svgid &&
400 #endif
401 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
402 		return (error);
403 	pc->pc_ucred = crcopy(pc->pc_ucred);
404 	pc->pc_ucred->cr_groups[0] = gid;
405 #ifdef _POSIX_SAVED_IDS
406 	if (pc->pc_ucred->cr_uid == 0) {
407 #endif
408 		pc->p_rgid = gid;
409 		pc->p_svgid = gid;
410 #ifdef _POSIX_SAVED_IDS
411 	}
412 #endif
413 	p->p_flag |= P_SUGID;
414 	return (0);
415 }
416 
417 #ifndef _SYS_SYSPROTO_H_
418 struct setegid_args {
419 	gid_t	egid;
420 };
421 #endif
422 /* ARGSUSED */
423 int
424 setegid(p, uap, retval)
425 	struct proc *p;
426 	struct setegid_args *uap;
427 	int *retval;
428 {
429 	register struct pcred *pc = p->p_cred;
430 	register gid_t egid;
431 	int error;
432 
433 	egid = uap->egid;
434 	if (egid != pc->p_rgid && egid != pc->p_svgid &&
435 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
436 		return (error);
437 	pc->pc_ucred = crcopy(pc->pc_ucred);
438 	pc->pc_ucred->cr_groups[0] = egid;
439 	p->p_flag |= P_SUGID;
440 	return (0);
441 }
442 
443 #ifndef _SYS_SYSPROTO_H_
444 struct setgroups_args {
445 	u_int	gidsetsize;
446 	gid_t	*gidset;
447 };
448 #endif
449 /* ARGSUSED */
450 int
451 setgroups(p, uap, retval)
452 	struct proc *p;
453 	struct setgroups_args *uap;
454 	int *retval;
455 {
456 	register struct pcred *pc = p->p_cred;
457 	register u_int ngrp;
458 	int error;
459 
460 	if ((error = suser(pc->pc_ucred, &p->p_acflag)))
461 		return (error);
462 	ngrp = uap->gidsetsize;
463 	if (ngrp < 1 || ngrp > NGROUPS)
464 		return (EINVAL);
465 	pc->pc_ucred = crcopy(pc->pc_ucred);
466 	if ((error = copyin((caddr_t)uap->gidset,
467 	    (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t))))
468 		return (error);
469 	pc->pc_ucred->cr_ngroups = ngrp;
470 	p->p_flag |= P_SUGID;
471 	return (0);
472 }
473 
474 #ifndef _SYS_SYSPROTO_H_
475 struct setreuid_args {
476 	uid_t	ruid;
477 	uid_t	euid;
478 };
479 #endif
480 /* ARGSUSED */
481 int
482 setreuid(p, uap, retval)
483 	register struct proc *p;
484 	struct setreuid_args *uap;
485 	int *retval;
486 {
487 	register struct pcred *pc = p->p_cred;
488 	register uid_t ruid, euid;
489 	int error;
490 
491 	ruid = uap->ruid;
492 	euid = uap->euid;
493 	if ((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid ||
494 	     euid != (uid_t)-1 && euid != pc->p_ruid && euid != pc->p_svuid) &&
495 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
496 		return (error);
497 
498 	pc->pc_ucred = crcopy(pc->pc_ucred);
499 	if (euid != (uid_t)-1)
500 		pc->pc_ucred->cr_uid = euid;
501 	if (ruid != (uid_t)-1 && ruid != pc->p_ruid) {
502 		(void)chgproccnt(pc->p_ruid, -1);
503 		(void)chgproccnt(ruid, 1);
504 		pc->p_ruid = ruid;
505 	}
506 	if (ruid != (uid_t)-1 || pc->pc_ucred->cr_uid != pc->p_ruid)
507 		pc->p_svuid = pc->pc_ucred->cr_uid;
508 	p->p_flag |= P_SUGID;
509 	return (0);
510 }
511 
512 #ifndef _SYS_SYSPROTO_H_
513 struct setregid_args {
514 	gid_t	rgid;
515 	gid_t	egid;
516 };
517 #endif
518 /* ARGSUSED */
519 int
520 setregid(p, uap, retval)
521 	register struct proc *p;
522 	struct setregid_args *uap;
523 	int *retval;
524 {
525 	register struct pcred *pc = p->p_cred;
526 	register gid_t rgid, egid;
527 	int error;
528 
529 	rgid = uap->rgid;
530 	egid = uap->egid;
531 	if ((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid ||
532 	     egid != (gid_t)-1 && egid != pc->p_rgid && egid != pc->p_svgid) &&
533 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
534 		return (error);
535 
536 	pc->pc_ucred = crcopy(pc->pc_ucred);
537 	if (egid != (gid_t)-1)
538 		pc->pc_ucred->cr_groups[0] = egid;
539 	if (rgid != (gid_t)-1)
540 		pc->p_rgid = rgid;
541 	if (rgid != (gid_t)-1 || pc->pc_ucred->cr_groups[0] != pc->p_rgid)
542 		pc->p_svgid = pc->pc_ucred->cr_groups[0];
543 	p->p_flag |= P_SUGID;
544 	return (0);
545 }
546 
547 /*
548  * Check if gid is a member of the group set.
549  */
550 int
551 groupmember(gid, cred)
552 	gid_t gid;
553 	register struct ucred *cred;
554 {
555 	register gid_t *gp;
556 	gid_t *egp;
557 
558 	egp = &(cred->cr_groups[cred->cr_ngroups]);
559 	for (gp = cred->cr_groups; gp < egp; gp++)
560 		if (*gp == gid)
561 			return (1);
562 	return (0);
563 }
564 
565 /*
566  * Test whether the specified credentials imply "super-user"
567  * privilege; if so, and we have accounting info, set the flag
568  * indicating use of super-powers.
569  * Returns 0 or error.
570  */
571 int
572 suser(cred, acflag)
573 	struct ucred *cred;
574 	u_short *acflag;
575 {
576 	if (cred->cr_uid == 0) {
577 		if (acflag)
578 			*acflag |= ASU;
579 		return (0);
580 	}
581 	return (EPERM);
582 }
583 
584 /*
585  * Allocate a zeroed cred structure.
586  */
587 struct ucred *
588 crget()
589 {
590 	register struct ucred *cr;
591 
592 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
593 	bzero((caddr_t)cr, sizeof(*cr));
594 	cr->cr_ref = 1;
595 	return (cr);
596 }
597 
598 /*
599  * Free a cred structure.
600  * Throws away space when ref count gets to 0.
601  */
602 void
603 crfree(cr)
604 	struct ucred *cr;
605 {
606 	int s;
607 
608 	s = splimp();				/* ??? */
609 	if (--cr->cr_ref == 0)
610 		FREE((caddr_t)cr, M_CRED);
611 	(void) splx(s);
612 }
613 
614 /*
615  * Copy cred structure to a new one and free the old one.
616  */
617 struct ucred *
618 crcopy(cr)
619 	struct ucred *cr;
620 {
621 	struct ucred *newcr;
622 
623 	if (cr->cr_ref == 1)
624 		return (cr);
625 	newcr = crget();
626 	*newcr = *cr;
627 	crfree(cr);
628 	newcr->cr_ref = 1;
629 	return (newcr);
630 }
631 
632 /*
633  * Dup cred struct to a new held one.
634  */
635 struct ucred *
636 crdup(cr)
637 	struct ucred *cr;
638 {
639 	struct ucred *newcr;
640 
641 	newcr = crget();
642 	*newcr = *cr;
643 	newcr->cr_ref = 1;
644 	return (newcr);
645 }
646 
647 /*
648  * Get login name, if available.
649  */
650 #ifndef _SYS_SYSPROTO_H_
651 struct getlogin_args {
652 	char	*namebuf;
653 	u_int	namelen;
654 };
655 #endif
656 /* ARGSUSED */
657 int
658 getlogin(p, uap, retval)
659 	struct proc *p;
660 	struct getlogin_args *uap;
661 	int *retval;
662 {
663 
664 	if (uap->namelen > MAXLOGNAME)
665 		uap->namelen = MAXLOGNAME;
666 	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
667 	    (caddr_t) uap->namebuf, uap->namelen));
668 }
669 
670 /*
671  * Set login name.
672  */
673 #ifndef _SYS_SYSPROTO_H_
674 struct setlogin_args {
675 	char	*namebuf;
676 };
677 #endif
678 /* ARGSUSED */
679 int
680 setlogin(p, uap, retval)
681 	struct proc *p;
682 	struct setlogin_args *uap;
683 	int *retval;
684 {
685 	int error;
686 	char logintmp[MAXLOGNAME];
687 
688 	if ((error = suser(p->p_ucred, &p->p_acflag)))
689 		return (error);
690 	error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp,
691 	    sizeof(logintmp), (u_int *)0);
692 	if (error == ENAMETOOLONG)
693 		error = EINVAL;
694 	else if (!error)
695 		(void) memcpy(p->p_pgrp->pg_session->s_login, logintmp,
696 		    sizeof(logintmp));
697 	return (error);
698 }
699