xref: /freebsd/sys/kern/kern_prot.c (revision 0ea3482342b4d7d6e71f3007ce4dafe445c639fd)
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.15 1995/11/11 06:53:08 bde 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 
56 #ifndef _SYS_SYSPROTO_H_
57 struct getpid_args {
58 	int	dummy;
59 };
60 #endif
61 
62 /* ARGSUSED */
63 int
64 getpid(p, uap, retval)
65 	struct proc *p;
66 	struct getpid_args *uap;
67 	int *retval;
68 {
69 
70 	*retval = p->p_pid;
71 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
72 	retval[1] = p->p_pptr->p_pid;
73 #endif
74 	return (0);
75 }
76 
77 #ifndef _SYS_SYSPROTO_H_
78 struct getppid_args {
79         int     dummy;
80 };
81 #endif
82 /* ARGSUSED */
83 int
84 getppid(p, uap, retval)
85 	struct proc *p;
86 	struct getppid_args *uap;
87 	int *retval;
88 {
89 
90 	*retval = p->p_pptr->p_pid;
91 	return (0);
92 }
93 
94 /* Get process group ID; note that POSIX getpgrp takes no parameter */
95 #ifndef _SYS_SYSPROTO_H_
96 struct getpgrp_args {
97         int     dummy;
98 };
99 #endif
100 
101 int
102 getpgrp(p, uap, retval)
103 	struct proc *p;
104 	struct getpgrp_args *uap;
105 	int *retval;
106 {
107 
108 	*retval = p->p_pgrp->pg_id;
109 	return (0);
110 }
111 
112 #ifndef _SYS_SYSPROTO_H_
113 struct getuid_args {
114         int     dummy;
115 };
116 #endif
117 
118 /* ARGSUSED */
119 int
120 getuid(p, uap, retval)
121 	struct proc *p;
122 	struct getuid_args *uap;
123 	int *retval;
124 {
125 
126 	*retval = p->p_cred->p_ruid;
127 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
128 	retval[1] = p->p_ucred->cr_uid;
129 #endif
130 	return (0);
131 }
132 
133 #ifndef _SYS_SYSPROTO_H_
134 struct geteuid_args {
135         int     dummy;
136 };
137 #endif
138 
139 /* ARGSUSED */
140 int
141 geteuid(p, uap, retval)
142 	struct proc *p;
143 	struct geteuid_args *uap;
144 	int *retval;
145 {
146 
147 	*retval = p->p_ucred->cr_uid;
148 	return (0);
149 }
150 
151 #ifndef _SYS_SYSPROTO_H_
152 struct getgid_args {
153         int     dummy;
154 };
155 #endif
156 
157 /* ARGSUSED */
158 int
159 getgid(p, uap, retval)
160 	struct proc *p;
161 	struct getgid_args *uap;
162 	int *retval;
163 {
164 
165 	*retval = p->p_cred->p_rgid;
166 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
167 	retval[1] = p->p_ucred->cr_groups[0];
168 #endif
169 	return (0);
170 }
171 
172 /*
173  * Get effective group ID.  The "egid" is groups[0], and could be obtained
174  * via getgroups.  This syscall exists because it is somewhat painful to do
175  * correctly in a library function.
176  */
177 #ifndef _SYS_SYSPROTO_H_
178 struct getegid_args {
179         int     dummy;
180 };
181 #endif
182 
183 /* ARGSUSED */
184 int
185 getegid(p, uap, retval)
186 	struct proc *p;
187 	struct getegid_args *uap;
188 	int *retval;
189 {
190 
191 	*retval = p->p_ucred->cr_groups[0];
192 	return (0);
193 }
194 
195 #ifndef _SYS_SYSPROTO_H_
196 struct getgroups_args {
197 	u_int	gidsetsize;
198 	gid_t	*gidset;
199 };
200 #endif
201 int
202 getgroups(p, uap, retval)
203 	struct proc *p;
204 	register struct	getgroups_args *uap;
205 	int *retval;
206 {
207 	register struct pcred *pc = p->p_cred;
208 	register u_int ngrp;
209 	int error;
210 
211 	if ((ngrp = uap->gidsetsize) == 0) {
212 		*retval = pc->pc_ucred->cr_ngroups;
213 		return (0);
214 	}
215 	if (ngrp < pc->pc_ucred->cr_ngroups)
216 		return (EINVAL);
217 	ngrp = pc->pc_ucred->cr_ngroups;
218 	if ((error = copyout((caddr_t)pc->pc_ucred->cr_groups,
219 	    (caddr_t)uap->gidset, ngrp * sizeof(gid_t))))
220 		return (error);
221 	*retval = ngrp;
222 	return (0);
223 }
224 
225 #ifndef _SYS_SYSPROTO_H_
226 struct setsid_args {
227         int     dummy;
228 };
229 #endif
230 
231 /* ARGSUSED */
232 int
233 setsid(p, uap, retval)
234 	register struct proc *p;
235 	struct setsid_args *uap;
236 	int *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  * pid must be caller or child of caller (ESRCH)
254  * if a child
255  *	pid must be in same session (EPERM)
256  *	pid can't have done an exec (EACCES)
257  * if pgid != pid
258  * 	there must exist some pid in same session having pgid (EPERM)
259  * pid must not be session leader (EPERM)
260  */
261 #ifndef _SYS_SYSPROTO_H_
262 struct setpgid_args {
263 	int	pid;	/* target process id */
264 	int	pgid;	/* target pgrp id */
265 };
266 #endif
267 /* ARGSUSED */
268 int
269 setpgid(curp, uap, retval)
270 	struct proc *curp;
271 	register struct setpgid_args *uap;
272 	int *retval;
273 {
274 	register struct proc *targp;		/* target process */
275 	register struct pgrp *pgrp;		/* target pgrp */
276 
277 	if (uap->pid != 0 && uap->pid != curp->p_pid) {
278 		if ((targp = pfind(uap->pid)) == 0 || !inferior(targp))
279 			return (ESRCH);
280 		if (targp->p_session != curp->p_session)
281 			return (EPERM);
282 		if (targp->p_flag & P_EXEC)
283 			return (EACCES);
284 	} else
285 		targp = curp;
286 	if (SESS_LEADER(targp))
287 		return (EPERM);
288 	if (uap->pgid == 0)
289 		uap->pgid = targp->p_pid;
290 	else if (uap->pgid != targp->p_pid)
291 		if ((pgrp = pgfind(uap->pgid)) == 0 ||
292 	            pgrp->pg_session != curp->p_session)
293 			return (EPERM);
294 	return (enterpgrp(targp, uap->pgid, 0));
295 }
296 
297 #ifndef _SYS_SYSPROTO_H_
298 struct setuid_args {
299 	uid_t	uid;
300 };
301 #endif
302 /* ARGSUSED */
303 int
304 setuid(p, uap, retval)
305 	struct proc *p;
306 	struct setuid_args *uap;
307 	int *retval;
308 {
309 	register struct pcred *pc = p->p_cred;
310 	register uid_t uid;
311 	int error;
312 
313 	uid = uap->uid;
314 	if (uid != pc->p_ruid && uid != pc->p_svuid &&
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 	if (pc->pc_ucred->cr_uid == 0 && uid != pc->p_ruid) {
323 		(void)chgproccnt(pc->p_ruid, -1);
324 		(void)chgproccnt(uid, 1);
325 	}
326 	pc->pc_ucred = crcopy(pc->pc_ucred);
327 	if (pc->pc_ucred->cr_uid == 0) {
328 		pc->p_ruid = uid;
329 		pc->p_svuid = uid;
330 	}
331 	pc->pc_ucred->cr_uid = uid;
332 	p->p_flag |= P_SUGID;
333 	return (0);
334 }
335 
336 #ifndef _SYS_SYSPROTO_H_
337 struct seteuid_args {
338 	uid_t	euid;
339 };
340 #endif
341 /* ARGSUSED */
342 int
343 seteuid(p, uap, retval)
344 	struct proc *p;
345 	struct seteuid_args *uap;
346 	int *retval;
347 {
348 	register struct pcred *pc = p->p_cred;
349 	register uid_t euid;
350 	int error;
351 
352 	euid = uap->euid;
353 	if (euid != pc->p_ruid && euid != pc->p_svuid &&
354 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
355 		return (error);
356 	/*
357 	 * Everything's okay, do it.  Copy credentials so other references do
358 	 * not see our changes.
359 	 */
360 	pc->pc_ucred = crcopy(pc->pc_ucred);
361 	pc->pc_ucred->cr_uid = euid;
362 	p->p_flag |= P_SUGID;
363 	return (0);
364 }
365 
366 #ifndef _SYS_SYSPROTO_H_
367 struct setgid_args {
368 	gid_t	gid;
369 };
370 #endif
371 /* ARGSUSED */
372 int
373 setgid(p, uap, retval)
374 	struct proc *p;
375 	struct setgid_args *uap;
376 	int *retval;
377 {
378 	register struct pcred *pc = p->p_cred;
379 	register gid_t gid;
380 	int error;
381 
382 	gid = uap->gid;
383 	if (gid != pc->p_rgid && gid != pc->p_svgid &&
384 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
385 		return (error);
386 	pc->pc_ucred = crcopy(pc->pc_ucred);
387 	pc->pc_ucred->cr_groups[0] = gid;
388 	if (pc->pc_ucred->cr_uid == 0) {
389 		pc->p_rgid = gid;
390 		pc->p_svgid = gid;
391 	}
392 	p->p_flag |= P_SUGID;
393 	return (0);
394 }
395 
396 #ifndef _SYS_SYSPROTO_H_
397 struct setegid_args {
398 	gid_t	egid;
399 };
400 #endif
401 /* ARGSUSED */
402 int
403 setegid(p, uap, retval)
404 	struct proc *p;
405 	struct setegid_args *uap;
406 	int *retval;
407 {
408 	register struct pcred *pc = p->p_cred;
409 	register gid_t egid;
410 	int error;
411 
412 	egid = uap->egid;
413 	if (egid != pc->p_rgid && egid != pc->p_svgid &&
414 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
415 		return (error);
416 	pc->pc_ucred = crcopy(pc->pc_ucred);
417 	pc->pc_ucred->cr_groups[0] = egid;
418 	p->p_flag |= P_SUGID;
419 	return (0);
420 }
421 
422 #ifndef _SYS_SYSPROTO_H_
423 struct setgroups_args {
424 	u_int	gidsetsize;
425 	gid_t	*gidset;
426 };
427 #endif
428 /* ARGSUSED */
429 int
430 setgroups(p, uap, retval)
431 	struct proc *p;
432 	struct setgroups_args *uap;
433 	int *retval;
434 {
435 	register struct pcred *pc = p->p_cred;
436 	register u_int ngrp;
437 	int error;
438 
439 	if ((error = suser(pc->pc_ucred, &p->p_acflag)))
440 		return (error);
441 	ngrp = uap->gidsetsize;
442 	if (ngrp < 1 || ngrp > NGROUPS)
443 		return (EINVAL);
444 	pc->pc_ucred = crcopy(pc->pc_ucred);
445 	if ((error = copyin((caddr_t)uap->gidset,
446 	    (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t))))
447 		return (error);
448 	pc->pc_ucred->cr_ngroups = ngrp;
449 	p->p_flag |= P_SUGID;
450 	return (0);
451 }
452 
453 #ifndef _SYS_SYSPROTO_H_
454 struct setreuid_args {
455 	uid_t	ruid;
456 	uid_t	euid;
457 };
458 #endif
459 /* ARGSUSED */
460 int
461 setreuid(p, uap, retval)
462 	register struct proc *p;
463 	struct setreuid_args *uap;
464 	int *retval;
465 {
466 	register struct pcred *pc = p->p_cred;
467 	register uid_t ruid, euid;
468 	int error;
469 
470 	ruid = uap->ruid;
471 	euid = uap->euid;
472 	if ((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid ||
473 	     euid != (uid_t)-1 && euid != pc->p_ruid && euid != pc->p_svuid) &&
474 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
475 		return (error);
476 
477 	pc->pc_ucred = crcopy(pc->pc_ucred);
478 	if (euid != (uid_t)-1)
479 		pc->pc_ucred->cr_uid = euid;
480 	if (ruid != (uid_t)-1 && ruid != pc->p_ruid) {
481 		(void)chgproccnt(pc->p_ruid, -1);
482 		(void)chgproccnt(ruid, 1);
483 		pc->p_ruid = ruid;
484 	}
485 	if (ruid != (uid_t)-1 || pc->pc_ucred->cr_uid != pc->p_ruid)
486 		pc->p_svuid = pc->pc_ucred->cr_uid;
487 	p->p_flag |= P_SUGID;
488 	return (0);
489 }
490 
491 #ifndef _SYS_SYSPROTO_H_
492 struct setregid_args {
493 	gid_t	rgid;
494 	gid_t	egid;
495 };
496 #endif
497 /* ARGSUSED */
498 int
499 setregid(p, uap, retval)
500 	register struct proc *p;
501 	struct setregid_args *uap;
502 	int *retval;
503 {
504 	register struct pcred *pc = p->p_cred;
505 	register gid_t rgid, egid;
506 	int error;
507 
508 	rgid = uap->rgid;
509 	egid = uap->egid;
510 	if ((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid ||
511 	     egid != (gid_t)-1 && egid != pc->p_rgid && egid != pc->p_svgid) &&
512 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
513 		return (error);
514 
515 	pc->pc_ucred = crcopy(pc->pc_ucred);
516 	if (egid != (gid_t)-1)
517 		pc->pc_ucred->cr_groups[0] = egid;
518 	if (rgid != (gid_t)-1)
519 		pc->p_rgid = rgid;
520 	if (rgid != (gid_t)-1 || pc->pc_ucred->cr_groups[0] != pc->p_rgid)
521 		pc->p_svgid = pc->pc_ucred->cr_groups[0];
522 	p->p_flag |= P_SUGID;
523 	return (0);
524 }
525 
526 /*
527  * Check if gid is a member of the group set.
528  */
529 int
530 groupmember(gid, cred)
531 	gid_t gid;
532 	register struct ucred *cred;
533 {
534 	register gid_t *gp;
535 	gid_t *egp;
536 
537 	egp = &(cred->cr_groups[cred->cr_ngroups]);
538 	for (gp = cred->cr_groups; gp < egp; gp++)
539 		if (*gp == gid)
540 			return (1);
541 	return (0);
542 }
543 
544 /*
545  * Test whether the specified credentials imply "super-user"
546  * privilege; if so, and we have accounting info, set the flag
547  * indicating use of super-powers.
548  * Returns 0 or error.
549  */
550 int
551 suser(cred, acflag)
552 	struct ucred *cred;
553 	u_short *acflag;
554 {
555 	if (cred->cr_uid == 0) {
556 		if (acflag)
557 			*acflag |= ASU;
558 		return (0);
559 	}
560 	return (EPERM);
561 }
562 
563 /*
564  * Allocate a zeroed cred structure.
565  */
566 struct ucred *
567 crget()
568 {
569 	register struct ucred *cr;
570 
571 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
572 	bzero((caddr_t)cr, sizeof(*cr));
573 	cr->cr_ref = 1;
574 	return (cr);
575 }
576 
577 /*
578  * Free a cred structure.
579  * Throws away space when ref count gets to 0.
580  */
581 void
582 crfree(cr)
583 	struct ucred *cr;
584 {
585 	int s;
586 
587 	s = splimp();				/* ??? */
588 	if (--cr->cr_ref == 0)
589 		FREE((caddr_t)cr, M_CRED);
590 	(void) splx(s);
591 }
592 
593 /*
594  * Copy cred structure to a new one and free the old one.
595  */
596 struct ucred *
597 crcopy(cr)
598 	struct ucred *cr;
599 {
600 	struct ucred *newcr;
601 
602 	if (cr->cr_ref == 1)
603 		return (cr);
604 	newcr = crget();
605 	*newcr = *cr;
606 	crfree(cr);
607 	newcr->cr_ref = 1;
608 	return (newcr);
609 }
610 
611 /*
612  * Dup cred struct to a new held one.
613  */
614 struct ucred *
615 crdup(cr)
616 	struct ucred *cr;
617 {
618 	struct ucred *newcr;
619 
620 	newcr = crget();
621 	*newcr = *cr;
622 	newcr->cr_ref = 1;
623 	return (newcr);
624 }
625 
626 /*
627  * Get login name, if available.
628  */
629 #ifndef _SYS_SYSPROTO_H_
630 struct getlogin_args {
631 	char	*namebuf;
632 	u_int	namelen;
633 };
634 #endif
635 /* ARGSUSED */
636 int
637 getlogin(p, uap, retval)
638 	struct proc *p;
639 	struct getlogin_args *uap;
640 	int *retval;
641 {
642 
643 	if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login))
644 		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) uap->namebuf, uap->namelen));
647 }
648 
649 /*
650  * Set login name.
651  */
652 #ifndef _SYS_SYSPROTO_H_
653 struct setlogin_args {
654 	char	*namebuf;
655 };
656 #endif
657 /* ARGSUSED */
658 int
659 setlogin(p, uap, retval)
660 	struct proc *p;
661 	struct setlogin_args *uap;
662 	int *retval;
663 {
664 	int error;
665 
666 	if ((error = suser(p->p_ucred, &p->p_acflag)))
667 		return (error);
668 	error = copyinstr((caddr_t) uap->namebuf,
669 	    (caddr_t) p->p_pgrp->pg_session->s_login,
670 	    sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0);
671 	if (error == ENAMETOOLONG)
672 		error = EINVAL;
673 	return (error);
674 }
675