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