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