xref: /freebsd/sys/kern/kern_prot.c (revision 17ee9d00bc1ae1e598c38f25826f861e4bc6c3ce)
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.4 1994/09/25 19:33:41 phk 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 &&
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 	(void)chgproccnt(pc->p_ruid, -1);
273 	(void)chgproccnt(uid, 1);
274 	pc->pc_ucred = crcopy(pc->pc_ucred);
275 	pc->pc_ucred->cr_uid = uid;
276 	pc->p_ruid = uid;
277 	pc->p_svuid = uid;
278 	p->p_flag |= P_SUGID;
279 	return (0);
280 }
281 
282 struct seteuid_args {
283 	uid_t	euid;
284 };
285 /* ARGSUSED */
286 int
287 seteuid(p, uap, retval)
288 	struct proc *p;
289 	struct seteuid_args *uap;
290 	int *retval;
291 {
292 	register struct pcred *pc = p->p_cred;
293 	register uid_t euid;
294 	int error;
295 
296 	euid = uap->euid;
297 	if (euid != pc->p_ruid && euid != pc->p_svuid &&
298 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
299 		return (error);
300 	/*
301 	 * Everything's okay, do it.  Copy credentials so other references do
302 	 * not see our changes.
303 	 */
304 	pc->pc_ucred = crcopy(pc->pc_ucred);
305 	pc->pc_ucred->cr_uid = euid;
306 	p->p_flag |= P_SUGID;
307 	return (0);
308 }
309 
310 struct setgid_args {
311 	gid_t	gid;
312 };
313 /* ARGSUSED */
314 int
315 setgid(p, uap, retval)
316 	struct proc *p;
317 	struct setgid_args *uap;
318 	int *retval;
319 {
320 	register struct pcred *pc = p->p_cred;
321 	register gid_t gid;
322 	int error;
323 
324 	gid = uap->gid;
325 	if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag)))
326 		return (error);
327 	pc->pc_ucred = crcopy(pc->pc_ucred);
328 	pc->pc_ucred->cr_groups[0] = gid;
329 	pc->p_rgid = gid;
330 	pc->p_svgid = gid;		/* ??? */
331 	p->p_flag |= P_SUGID;
332 	return (0);
333 }
334 
335 struct setegid_args {
336 	gid_t	egid;
337 };
338 /* ARGSUSED */
339 int
340 setegid(p, uap, retval)
341 	struct proc *p;
342 	struct setegid_args *uap;
343 	int *retval;
344 {
345 	register struct pcred *pc = p->p_cred;
346 	register gid_t egid;
347 	int error;
348 
349 	egid = uap->egid;
350 	if (egid != pc->p_rgid && egid != pc->p_svgid &&
351 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
352 		return (error);
353 	pc->pc_ucred = crcopy(pc->pc_ucred);
354 	pc->pc_ucred->cr_groups[0] = egid;
355 	p->p_flag |= P_SUGID;
356 	return (0);
357 }
358 
359 struct setgroups_args {
360 	u_int	gidsetsize;
361 	gid_t	*gidset;
362 };
363 /* ARGSUSED */
364 int
365 setgroups(p, uap, retval)
366 	struct proc *p;
367 	struct setgroups_args *uap;
368 	int *retval;
369 {
370 	register struct pcred *pc = p->p_cred;
371 	register u_int ngrp;
372 	int error;
373 
374 	if ((error = suser(pc->pc_ucred, &p->p_acflag)))
375 		return (error);
376 	if ((ngrp = uap->gidsetsize) > NGROUPS)
377 		return (EINVAL);
378 	pc->pc_ucred = crcopy(pc->pc_ucred);
379 	if ((error = copyin((caddr_t)uap->gidset,
380 	    (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t))))
381 		return (error);
382 	pc->pc_ucred->cr_ngroups = ngrp;
383 	p->p_flag |= P_SUGID;
384 	return (0);
385 }
386 
387 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2)
388 struct setreuid_args {
389 	int	ruid;
390 	int	euid;
391 };
392 /* ARGSUSED */
393 int
394 osetreuid(p, uap, retval)
395 	register struct proc *p;
396 	struct setreuid_args *uap;
397 	int *retval;
398 {
399 	register struct pcred *pc = p->p_cred;
400 	struct seteuid_args args;
401 
402 	/*
403 	 * we assume that the intent of setting ruid is to be able to get
404 	 * back ruid priviledge. So we make sure that we will be able to
405 	 * do so, but do not actually set the ruid.
406 	 */
407 	if (uap->ruid != (uid_t)-1 && uap->ruid != pc->p_ruid &&
408 	    uap->ruid != pc->p_svuid)
409 		return (EPERM);
410 	if (uap->euid == (uid_t)-1)
411 		return (0);
412 	args.euid = uap->euid;
413 	return (seteuid(p, &args, retval));
414 }
415 
416 struct setregid_args {
417 	int	rgid;
418 	int	egid;
419 };
420 /* ARGSUSED */
421 int
422 osetregid(p, uap, retval)
423 	register struct proc *p;
424 	struct setregid_args *uap;
425 	int *retval;
426 {
427 	register struct pcred *pc = p->p_cred;
428 	struct setegid_args args;
429 
430 	/*
431 	 * we assume that the intent of setting rgid is to be able to get
432 	 * back rgid priviledge. So we make sure that we will be able to
433 	 * do so, but do not actually set the rgid.
434 	 */
435 	if (uap->rgid != (gid_t)-1 && uap->rgid != pc->p_rgid &&
436 	    uap->rgid != pc->p_svgid)
437 		return (EPERM);
438 	if (uap->egid == (gid_t)-1)
439 		return (0);
440 	args.egid = uap->egid;
441 	return (setegid(p, &args, retval));
442 }
443 #endif /*defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2)*/
444 
445 /*
446  * Check if gid is a member of the group set.
447  */
448 int
449 groupmember(gid, cred)
450 	gid_t gid;
451 	register struct ucred *cred;
452 {
453 	register gid_t *gp;
454 	gid_t *egp;
455 
456 	egp = &(cred->cr_groups[cred->cr_ngroups]);
457 	for (gp = cred->cr_groups; gp < egp; gp++)
458 		if (*gp == gid)
459 			return (1);
460 	return (0);
461 }
462 
463 /*
464  * Test whether the specified credentials imply "super-user"
465  * privilege; if so, and we have accounting info, set the flag
466  * indicating use of super-powers.
467  * Returns 0 or error.
468  */
469 int
470 suser(cred, acflag)
471 	struct ucred *cred;
472 	short *acflag;
473 {
474 	if (cred->cr_uid == 0) {
475 		if (acflag)
476 			*acflag |= ASU;
477 		return (0);
478 	}
479 	return (EPERM);
480 }
481 
482 /*
483  * Allocate a zeroed cred structure.
484  */
485 struct ucred *
486 crget()
487 {
488 	register struct ucred *cr;
489 
490 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
491 	bzero((caddr_t)cr, sizeof(*cr));
492 	cr->cr_ref = 1;
493 	return (cr);
494 }
495 
496 /*
497  * Free a cred structure.
498  * Throws away space when ref count gets to 0.
499  */
500 void
501 crfree(cr)
502 	struct ucred *cr;
503 {
504 	int s;
505 
506 	s = splimp();				/* ??? */
507 	if (--cr->cr_ref == 0)
508 		FREE((caddr_t)cr, M_CRED);
509 	(void) splx(s);
510 }
511 
512 /*
513  * Copy cred structure to a new one and free the old one.
514  */
515 struct ucred *
516 crcopy(cr)
517 	struct ucred *cr;
518 {
519 	struct ucred *newcr;
520 
521 	if (cr->cr_ref == 1)
522 		return (cr);
523 	newcr = crget();
524 	*newcr = *cr;
525 	crfree(cr);
526 	newcr->cr_ref = 1;
527 	return (newcr);
528 }
529 
530 /*
531  * Dup cred struct to a new held one.
532  */
533 struct ucred *
534 crdup(cr)
535 	struct ucred *cr;
536 {
537 	struct ucred *newcr;
538 
539 	newcr = crget();
540 	*newcr = *cr;
541 	newcr->cr_ref = 1;
542 	return (newcr);
543 }
544 
545 /*
546  * Get login name, if available.
547  */
548 struct getlogin_args {
549 	char	*namebuf;
550 	u_int	namelen;
551 };
552 /* ARGSUSED */
553 int
554 getlogin(p, uap, retval)
555 	struct proc *p;
556 	struct getlogin_args *uap;
557 	int *retval;
558 {
559 
560 	if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login))
561 		uap->namelen = sizeof (p->p_pgrp->pg_session->s_login);
562 	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
563 	    (caddr_t) uap->namebuf, uap->namelen));
564 }
565 
566 /*
567  * Set login name.
568  */
569 struct setlogin_args {
570 	char	*namebuf;
571 };
572 /* ARGSUSED */
573 int
574 setlogin(p, uap, retval)
575 	struct proc *p;
576 	struct setlogin_args *uap;
577 	int *retval;
578 {
579 	int error;
580 
581 	if ((error = suser(p->p_ucred, &p->p_acflag)))
582 		return (error);
583 	error = copyinstr((caddr_t) uap->namebuf,
584 	    (caddr_t) p->p_pgrp->pg_session->s_login,
585 	    sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0);
586 	if (error == ENAMETOOLONG)
587 		error = EINVAL;
588 	return (error);
589 }
590