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