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