kern_prot.c revision 53518
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 * $FreeBSD: head/sys/kern/kern_prot.c 53518 1999-11-21 19:03:20Z phk $
40 */
41
42/*
43 * System calls related to processes and protection
44 */
45
46#include "opt_compat.h"
47
48#include <sys/param.h>
49#include <sys/acct.h>
50#include <sys/systm.h>
51#include <sys/sysproto.h>
52#include <sys/kernel.h>
53#include <sys/proc.h>
54#include <sys/malloc.h>
55#include <sys/pioctl.h>
56
57static MALLOC_DEFINE(M_CRED, "cred", "credentials");
58
59#ifndef _SYS_SYSPROTO_H_
60struct getpid_args {
61	int	dummy;
62};
63#endif
64
65/* ARGSUSED */
66int
67getpid(p, uap)
68	struct proc *p;
69	struct getpid_args *uap;
70{
71
72	p->p_retval[0] = p->p_pid;
73#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
74	p->p_retval[1] = p->p_pptr->p_pid;
75#endif
76	return (0);
77}
78
79#ifndef _SYS_SYSPROTO_H_
80struct getppid_args {
81        int     dummy;
82};
83#endif
84/* ARGSUSED */
85int
86getppid(p, uap)
87	struct proc *p;
88	struct getppid_args *uap;
89{
90
91	p->p_retval[0] = p->p_pptr->p_pid;
92	return (0);
93}
94
95/* Get process group ID; note that POSIX getpgrp takes no parameter */
96#ifndef _SYS_SYSPROTO_H_
97struct getpgrp_args {
98        int     dummy;
99};
100#endif
101
102int
103getpgrp(p, uap)
104	struct proc *p;
105	struct getpgrp_args *uap;
106{
107
108	p->p_retval[0] = p->p_pgrp->pg_id;
109	return (0);
110}
111
112/* Get an arbitary pid's process group id */
113#ifndef _SYS_SYSPROTO_H_
114struct getpgid_args {
115	pid_t	pid;
116};
117#endif
118
119int
120getpgid(p, uap)
121	struct proc *p;
122	struct getpgid_args *uap;
123{
124	struct proc *pt;
125
126	pt = p;
127	if (uap->pid == 0)
128		goto found;
129
130	if ((pt = pfind(uap->pid)) == 0)
131		return ESRCH;
132found:
133	p->p_retval[0] = pt->p_pgrp->pg_id;
134	return 0;
135}
136
137/*
138 * Get an arbitary pid's session id.
139 */
140#ifndef _SYS_SYSPROTO_H_
141struct getsid_args {
142	pid_t	pid;
143};
144#endif
145
146int
147getsid(p, uap)
148	struct proc *p;
149	struct getsid_args *uap;
150{
151	struct proc *pt;
152
153	pt = p;
154	if (uap->pid == 0)
155		goto found;
156
157	if ((pt == pfind(uap->pid)) == 0)
158		return ESRCH;
159found:
160	p->p_retval[0] = pt->p_session->s_sid;
161	return 0;
162}
163
164
165#ifndef _SYS_SYSPROTO_H_
166struct getuid_args {
167        int     dummy;
168};
169#endif
170
171/* ARGSUSED */
172int
173getuid(p, uap)
174	struct proc *p;
175	struct getuid_args *uap;
176{
177
178	p->p_retval[0] = p->p_cred->p_ruid;
179#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
180	p->p_retval[1] = p->p_ucred->cr_uid;
181#endif
182	return (0);
183}
184
185#ifndef _SYS_SYSPROTO_H_
186struct geteuid_args {
187        int     dummy;
188};
189#endif
190
191/* ARGSUSED */
192int
193geteuid(p, uap)
194	struct proc *p;
195	struct geteuid_args *uap;
196{
197
198	p->p_retval[0] = p->p_ucred->cr_uid;
199	return (0);
200}
201
202#ifndef _SYS_SYSPROTO_H_
203struct getgid_args {
204        int     dummy;
205};
206#endif
207
208/* ARGSUSED */
209int
210getgid(p, uap)
211	struct proc *p;
212	struct getgid_args *uap;
213{
214
215	p->p_retval[0] = p->p_cred->p_rgid;
216#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
217	p->p_retval[1] = p->p_ucred->cr_groups[0];
218#endif
219	return (0);
220}
221
222/*
223 * Get effective group ID.  The "egid" is groups[0], and could be obtained
224 * via getgroups.  This syscall exists because it is somewhat painful to do
225 * correctly in a library function.
226 */
227#ifndef _SYS_SYSPROTO_H_
228struct getegid_args {
229        int     dummy;
230};
231#endif
232
233/* ARGSUSED */
234int
235getegid(p, uap)
236	struct proc *p;
237	struct getegid_args *uap;
238{
239
240	p->p_retval[0] = p->p_ucred->cr_groups[0];
241	return (0);
242}
243
244#ifndef _SYS_SYSPROTO_H_
245struct getgroups_args {
246	u_int	gidsetsize;
247	gid_t	*gidset;
248};
249#endif
250int
251getgroups(p, uap)
252	struct proc *p;
253	register struct	getgroups_args *uap;
254{
255	register struct pcred *pc = p->p_cred;
256	register u_int ngrp;
257	int error;
258
259	if ((ngrp = uap->gidsetsize) == 0) {
260		p->p_retval[0] = pc->pc_ucred->cr_ngroups;
261		return (0);
262	}
263	if (ngrp < pc->pc_ucred->cr_ngroups)
264		return (EINVAL);
265	ngrp = pc->pc_ucred->cr_ngroups;
266	if ((error = copyout((caddr_t)pc->pc_ucred->cr_groups,
267	    (caddr_t)uap->gidset, ngrp * sizeof(gid_t))))
268		return (error);
269	p->p_retval[0] = ngrp;
270	return (0);
271}
272
273#ifndef _SYS_SYSPROTO_H_
274struct setsid_args {
275        int     dummy;
276};
277#endif
278
279/* ARGSUSED */
280int
281setsid(p, uap)
282	register struct proc *p;
283	struct setsid_args *uap;
284{
285
286	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
287		return (EPERM);
288	} else {
289		(void)enterpgrp(p, p->p_pid, 1);
290		p->p_retval[0] = p->p_pid;
291		return (0);
292	}
293}
294
295/*
296 * set process group (setpgid/old setpgrp)
297 *
298 * caller does setpgid(targpid, targpgid)
299 *
300 * pid must be caller or child of caller (ESRCH)
301 * if a child
302 *	pid must be in same session (EPERM)
303 *	pid can't have done an exec (EACCES)
304 * if pgid != pid
305 * 	there must exist some pid in same session having pgid (EPERM)
306 * pid must not be session leader (EPERM)
307 */
308#ifndef _SYS_SYSPROTO_H_
309struct setpgid_args {
310	int	pid;	/* target process id */
311	int	pgid;	/* target pgrp id */
312};
313#endif
314/* ARGSUSED */
315int
316setpgid(curp, uap)
317	struct proc *curp;
318	register struct setpgid_args *uap;
319{
320	register struct proc *targp;		/* target process */
321	register struct pgrp *pgrp;		/* target pgrp */
322
323	if (uap->pgid < 0)
324		return (EINVAL);
325	if (uap->pid != 0 && uap->pid != curp->p_pid) {
326		if ((targp = pfind(uap->pid)) == 0 || !inferior(targp))
327			return (ESRCH);
328		if (targp->p_pgrp == NULL ||  targp->p_session != curp->p_session)
329			return (EPERM);
330		if (targp->p_flag & P_EXEC)
331			return (EACCES);
332	} else
333		targp = curp;
334	if (SESS_LEADER(targp))
335		return (EPERM);
336	if (uap->pgid == 0)
337		uap->pgid = targp->p_pid;
338	else if (uap->pgid != targp->p_pid)
339		if ((pgrp = pgfind(uap->pgid)) == 0 ||
340	            pgrp->pg_session != curp->p_session)
341			return (EPERM);
342	return (enterpgrp(targp, uap->pgid, 0));
343}
344
345/*
346 * Use the clause in B.4.2.2 that allows setuid/setgid to be 4.2/4.3BSD
347 * compatable.  It says that setting the uid/gid to euid/egid is a special
348 * case of "appropriate privilege".  Once the rules are expanded out, this
349 * basically means that setuid(nnn) sets all three id's, in all permitted
350 * cases unless _POSIX_SAVED_IDS is enabled.  In that case, setuid(getuid())
351 * does not set the saved id - this is dangerous for traditional BSD
352 * programs.  For this reason, we *really* do not want to set
353 * _POSIX_SAVED_IDS and do not want to clear POSIX_APPENDIX_B_4_2_2.
354 */
355#define POSIX_APPENDIX_B_4_2_2
356
357#ifndef _SYS_SYSPROTO_H_
358struct setuid_args {
359	uid_t	uid;
360};
361#endif
362/* ARGSUSED */
363int
364setuid(p, uap)
365	struct proc *p;
366	struct setuid_args *uap;
367{
368	register struct pcred *pc = p->p_cred;
369	register uid_t uid;
370	int error;
371
372	/*
373	 * See if we have "permission" by POSIX 1003.1 rules.
374	 *
375	 * Note that setuid(geteuid()) is a special case of
376	 * "appropriate privileges" in appendix B.4.2.2.  We need
377	 * to use this clause to be compatable with traditional BSD
378	 * semantics.  Basically, it means that "setuid(xx)" sets all
379	 * three id's (assuming you have privs).
380	 *
381	 * Notes on the logic.  We do things in three steps.
382	 * 1: We determine if the euid is going to change, and do EPERM
383	 *    right away.  We unconditionally change the euid later if this
384	 *    test is satisfied, simplifying that part of the logic.
385	 * 2: We determine if the real and/or saved uid's are going to
386	 *    change.  Determined by compile options.
387	 * 3: Change euid last. (after tests in #2 for "appropriate privs")
388	 */
389	uid = uap->uid;
390	if (uid != pc->p_ruid &&		/* allow setuid(getuid()) */
391#ifdef _POSIX_SAVED_IDS
392	    uid != pc->p_svuid &&		/* allow setuid(saved gid) */
393#endif
394#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
395	    uid != pc->pc_ucred->cr_uid &&	/* allow setuid(geteuid()) */
396#endif
397	    (error = suser_xxx(0, p, PRISON_ROOT)))
398		return (error);
399
400#ifdef _POSIX_SAVED_IDS
401	/*
402	 * Do we have "appropriate privileges" (are we root or uid == euid)
403	 * If so, we are changing the real uid and/or saved uid.
404	 */
405	if (
406#ifdef POSIX_APPENDIX_B_4_2_2	/* Use the clause from B.4.2.2 */
407	    uid == pc->pc_ucred->cr_uid ||
408#endif
409	    suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */
410#endif
411	{
412		/*
413		 * Transfer proc count to new user.
414		 */
415		if (uid != pc->p_ruid) {
416			(void)chgproccnt(pc->p_ruid, -1);
417			(void)chgproccnt(uid, 1);
418		}
419		/*
420		 * Set real uid
421		 */
422		if (uid != pc->p_ruid) {
423			pc->p_ruid = uid;
424			setsugid(p);
425		}
426		/*
427		 * Set saved uid
428		 *
429		 * XXX always set saved uid even if not _POSIX_SAVED_IDS, as
430		 * the security of seteuid() depends on it.  B.4.2.2 says it
431		 * is important that we should do this.
432		 */
433		if (pc->p_svuid != uid) {
434			pc->p_svuid = uid;
435			setsugid(p);
436		}
437	}
438
439	/*
440	 * In all permitted cases, we are changing the euid.
441	 * Copy credentials so other references do not see our changes.
442	 */
443	if (pc->pc_ucred->cr_uid != uid) {
444		pc->pc_ucred = crcopy(pc->pc_ucred);
445		pc->pc_ucred->cr_uid = uid;
446		setsugid(p);
447	}
448	return (0);
449}
450
451#ifndef _SYS_SYSPROTO_H_
452struct seteuid_args {
453	uid_t	euid;
454};
455#endif
456/* ARGSUSED */
457int
458seteuid(p, uap)
459	struct proc *p;
460	struct seteuid_args *uap;
461{
462	register struct pcred *pc = p->p_cred;
463	register uid_t euid;
464	int error;
465
466	euid = uap->euid;
467	if (euid != pc->p_ruid &&		/* allow seteuid(getuid()) */
468	    euid != pc->p_svuid &&		/* allow seteuid(saved uid) */
469	    (error = suser_xxx(0, p, PRISON_ROOT)))
470		return (error);
471	/*
472	 * Everything's okay, do it.  Copy credentials so other references do
473	 * not see our changes.
474	 */
475	if (pc->pc_ucred->cr_uid != euid) {
476		pc->pc_ucred = crcopy(pc->pc_ucred);
477		pc->pc_ucred->cr_uid = euid;
478		setsugid(p);
479	}
480	return (0);
481}
482
483#ifndef _SYS_SYSPROTO_H_
484struct setgid_args {
485	gid_t	gid;
486};
487#endif
488/* ARGSUSED */
489int
490setgid(p, uap)
491	struct proc *p;
492	struct setgid_args *uap;
493{
494	register struct pcred *pc = p->p_cred;
495	register gid_t gid;
496	int error;
497
498	/*
499	 * See if we have "permission" by POSIX 1003.1 rules.
500	 *
501	 * Note that setgid(getegid()) is a special case of
502	 * "appropriate privileges" in appendix B.4.2.2.  We need
503	 * to use this clause to be compatable with traditional BSD
504	 * semantics.  Basically, it means that "setgid(xx)" sets all
505	 * three id's (assuming you have privs).
506	 *
507	 * For notes on the logic here, see setuid() above.
508	 */
509	gid = uap->gid;
510	if (gid != pc->p_rgid &&		/* allow setgid(getgid()) */
511#ifdef _POSIX_SAVED_IDS
512	    gid != pc->p_svgid &&		/* allow setgid(saved gid) */
513#endif
514#ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
515	    gid != pc->pc_ucred->cr_groups[0] && /* allow setgid(getegid()) */
516#endif
517	    (error = suser_xxx(0, p, PRISON_ROOT)))
518		return (error);
519
520#ifdef _POSIX_SAVED_IDS
521	/*
522	 * Do we have "appropriate privileges" (are we root or gid == egid)
523	 * If so, we are changing the real uid and saved gid.
524	 */
525	if (
526#ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
527	    gid == pc->pc_ucred->cr_groups[0] ||
528#endif
529	    suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */
530#endif
531	{
532		/*
533		 * Set real gid
534		 */
535		if (pc->p_rgid != gid) {
536			pc->p_rgid = gid;
537			setsugid(p);
538		}
539		/*
540		 * Set saved gid
541		 *
542		 * XXX always set saved gid even if not _POSIX_SAVED_IDS, as
543		 * the security of setegid() depends on it.  B.4.2.2 says it
544		 * is important that we should do this.
545		 */
546		if (pc->p_svgid != gid) {
547			pc->p_svgid = gid;
548			setsugid(p);
549		}
550	}
551	/*
552	 * In all cases permitted cases, we are changing the egid.
553	 * Copy credentials so other references do not see our changes.
554	 */
555	if (pc->pc_ucred->cr_groups[0] != gid) {
556		pc->pc_ucred = crcopy(pc->pc_ucred);
557		pc->pc_ucred->cr_groups[0] = gid;
558		setsugid(p);
559	}
560	return (0);
561}
562
563#ifndef _SYS_SYSPROTO_H_
564struct setegid_args {
565	gid_t	egid;
566};
567#endif
568/* ARGSUSED */
569int
570setegid(p, uap)
571	struct proc *p;
572	struct setegid_args *uap;
573{
574	register struct pcred *pc = p->p_cred;
575	register gid_t egid;
576	int error;
577
578	egid = uap->egid;
579	if (egid != pc->p_rgid &&		/* allow setegid(getgid()) */
580	    egid != pc->p_svgid &&		/* allow setegid(saved gid) */
581	    (error = suser_xxx(0, p, PRISON_ROOT)))
582		return (error);
583	if (pc->pc_ucred->cr_groups[0] != egid) {
584		pc->pc_ucred = crcopy(pc->pc_ucred);
585		pc->pc_ucred->cr_groups[0] = egid;
586		setsugid(p);
587	}
588	return (0);
589}
590
591#ifndef _SYS_SYSPROTO_H_
592struct setgroups_args {
593	u_int	gidsetsize;
594	gid_t	*gidset;
595};
596#endif
597/* ARGSUSED */
598int
599setgroups(p, uap)
600	struct proc *p;
601	struct setgroups_args *uap;
602{
603	register struct pcred *pc = p->p_cred;
604	register u_int ngrp;
605	int error;
606
607	if ((error = suser_xxx(0, p, PRISON_ROOT)))
608		return (error);
609	ngrp = uap->gidsetsize;
610	if (ngrp > NGROUPS)
611		return (EINVAL);
612	/*
613	 * XXX A little bit lazy here.  We could test if anything has
614	 * changed before crcopy() and setting P_SUGID.
615	 */
616	pc->pc_ucred = crcopy(pc->pc_ucred);
617	if (ngrp < 1) {
618		/*
619		 * setgroups(0, NULL) is a legitimate way of clearing the
620		 * groups vector on non-BSD systems (which generally do not
621		 * have the egid in the groups[0]).  We risk security holes
622		 * when running non-BSD software if we do not do the same.
623		 */
624		pc->pc_ucred->cr_ngroups = 1;
625	} else {
626		if ((error = copyin((caddr_t)uap->gidset,
627		    (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t))))
628			return (error);
629		pc->pc_ucred->cr_ngroups = ngrp;
630	}
631	setsugid(p);
632	return (0);
633}
634
635#ifndef _SYS_SYSPROTO_H_
636struct setreuid_args {
637	uid_t	ruid;
638	uid_t	euid;
639};
640#endif
641/* ARGSUSED */
642int
643setreuid(p, uap)
644	register struct proc *p;
645	struct setreuid_args *uap;
646{
647	register struct pcred *pc = p->p_cred;
648	register uid_t ruid, euid;
649	int error;
650
651	ruid = uap->ruid;
652	euid = uap->euid;
653	if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid) ||
654	     (euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid &&
655	     euid != pc->p_ruid && euid != pc->p_svuid)) &&
656	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
657		return (error);
658
659	if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) {
660		pc->pc_ucred = crcopy(pc->pc_ucred);
661		pc->pc_ucred->cr_uid = euid;
662		setsugid(p);
663	}
664	if (ruid != (uid_t)-1 && pc->p_ruid != ruid) {
665		(void)chgproccnt(pc->p_ruid, -1);
666		(void)chgproccnt(ruid, 1);
667		pc->p_ruid = ruid;
668		setsugid(p);
669	}
670	if ((ruid != (uid_t)-1 || pc->pc_ucred->cr_uid != pc->p_ruid) &&
671	    pc->p_svuid != pc->pc_ucred->cr_uid) {
672		pc->p_svuid = pc->pc_ucred->cr_uid;
673		setsugid(p);
674	}
675	return (0);
676}
677
678#ifndef _SYS_SYSPROTO_H_
679struct setregid_args {
680	gid_t	rgid;
681	gid_t	egid;
682};
683#endif
684/* ARGSUSED */
685int
686setregid(p, uap)
687	register struct proc *p;
688	struct setregid_args *uap;
689{
690	register struct pcred *pc = p->p_cred;
691	register gid_t rgid, egid;
692	int error;
693
694	rgid = uap->rgid;
695	egid = uap->egid;
696	if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid) ||
697	     (egid != (gid_t)-1 && egid != pc->pc_ucred->cr_groups[0] &&
698	     egid != pc->p_rgid && egid != pc->p_svgid)) &&
699	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
700		return (error);
701
702	if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) {
703		pc->pc_ucred = crcopy(pc->pc_ucred);
704		pc->pc_ucred->cr_groups[0] = egid;
705		setsugid(p);
706	}
707	if (rgid != (gid_t)-1 && pc->p_rgid != rgid) {
708		pc->p_rgid = rgid;
709		setsugid(p);
710	}
711	if ((rgid != (gid_t)-1 || pc->pc_ucred->cr_groups[0] != pc->p_rgid) &&
712	    pc->p_svgid != pc->pc_ucred->cr_groups[0]) {
713		pc->p_svgid = pc->pc_ucred->cr_groups[0];
714		setsugid(p);
715	}
716	return (0);
717}
718
719#ifndef _SYS_SYSPROTO_H_
720struct issetugid_args {
721	int dummy;
722};
723#endif
724/* ARGSUSED */
725int
726issetugid(p, uap)
727	register struct proc *p;
728	struct issetugid_args *uap;
729{
730	/*
731	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
732	 * we use P_SUGID because we consider changing the owners as
733	 * "tainting" as well.
734	 * This is significant for procs that start as root and "become"
735	 * a user without an exec - programs cannot know *everything*
736	 * that libc *might* have put in their data segment.
737	 */
738	if (p->p_flag & P_SUGID)
739		return (1);
740	return (0);
741}
742
743/*
744 * Check if gid is a member of the group set.
745 */
746int
747groupmember(gid, cred)
748	gid_t gid;
749	register struct ucred *cred;
750{
751	register gid_t *gp;
752	gid_t *egp;
753
754	egp = &(cred->cr_groups[cred->cr_ngroups]);
755	for (gp = cred->cr_groups; gp < egp; gp++)
756		if (*gp == gid)
757			return (1);
758	return (0);
759}
760
761/*
762 * Test whether the specified credentials imply "super-user"
763 * privilege; if so, and we have accounting info, set the flag
764 * indicating use of super-powers.
765 * Returns 0 or error.
766 */
767int
768suser(p)
769	struct proc *p;
770{
771	return suser_xxx(0, p, 0);
772}
773
774int
775suser_xxx(cred, proc, flag)
776	struct ucred *cred;
777	struct proc *proc;
778	int flag;
779{
780	if (!cred && !proc) {
781		printf("suser_xxx(): THINK!\n");
782		return (EPERM);
783	}
784	if (!cred)
785		cred = proc->p_ucred;
786	if (cred->cr_uid != 0)
787		return (EPERM);
788	if (proc && proc->p_prison && !(flag & PRISON_ROOT))
789		return (EPERM);
790	if (proc)
791		proc->p_acflag |= ASU;
792	return (0);
793}
794
795/*
796 * Return zero if p1 can fondle p2, return errno (EPERM/ESRCH) otherwise.
797 */
798
799int
800p_trespass(struct proc *p1, struct proc *p2)
801{
802
803	if (p1 == p2)
804		return (0);
805	if (!PRISON_CHECK(p1, p2))
806		return (ESRCH);
807	if (p1->p_cred->p_ruid == p2->p_cred->p_ruid)
808		return (0);
809	if (p1->p_ucred->cr_uid == p2->p_cred->p_ruid)
810		return (0);
811	if (p1->p_cred->p_ruid == p2->p_ucred->cr_uid)
812		return (0);
813	if (p1->p_ucred->cr_uid == p2->p_ucred->cr_uid)
814		return (0);
815	if (!suser_xxx(0, p1, PRISON_ROOT))
816		return (0);
817	return (EPERM);
818}
819
820/*
821 * Allocate a zeroed cred structure.
822 */
823struct ucred *
824crget()
825{
826	register struct ucred *cr;
827
828	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
829	bzero((caddr_t)cr, sizeof(*cr));
830	cr->cr_ref = 1;
831	return (cr);
832}
833
834/*
835 * Free a cred structure.
836 * Throws away space when ref count gets to 0.
837 */
838void
839crfree(cr)
840	struct ucred *cr;
841{
842	if (--cr->cr_ref == 0)
843		FREE((caddr_t)cr, M_CRED);
844}
845
846/*
847 * Copy cred structure to a new one and free the old one.
848 */
849struct ucred *
850crcopy(cr)
851	struct ucred *cr;
852{
853	struct ucred *newcr;
854
855	if (cr->cr_ref == 1)
856		return (cr);
857	newcr = crget();
858	*newcr = *cr;
859	crfree(cr);
860	newcr->cr_ref = 1;
861	return (newcr);
862}
863
864/*
865 * Dup cred struct to a new held one.
866 */
867struct ucred *
868crdup(cr)
869	struct ucred *cr;
870{
871	struct ucred *newcr;
872
873	newcr = crget();
874	*newcr = *cr;
875	newcr->cr_ref = 1;
876	return (newcr);
877}
878
879/*
880 * Get login name, if available.
881 */
882#ifndef _SYS_SYSPROTO_H_
883struct getlogin_args {
884	char	*namebuf;
885	u_int	namelen;
886};
887#endif
888/* ARGSUSED */
889int
890getlogin(p, uap)
891	struct proc *p;
892	struct getlogin_args *uap;
893{
894
895	if (uap->namelen > MAXLOGNAME)
896		uap->namelen = MAXLOGNAME;
897	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
898	    (caddr_t) uap->namebuf, uap->namelen));
899}
900
901/*
902 * Set login name.
903 */
904#ifndef _SYS_SYSPROTO_H_
905struct setlogin_args {
906	char	*namebuf;
907};
908#endif
909/* ARGSUSED */
910int
911setlogin(p, uap)
912	struct proc *p;
913	struct setlogin_args *uap;
914{
915	int error;
916	char logintmp[MAXLOGNAME];
917
918	if ((error = suser_xxx(0, p, PRISON_ROOT)))
919		return (error);
920	error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp,
921	    sizeof(logintmp), (size_t *)0);
922	if (error == ENAMETOOLONG)
923		error = EINVAL;
924	else if (!error)
925		(void) memcpy(p->p_pgrp->pg_session->s_login, logintmp,
926		    sizeof(logintmp));
927	return (error);
928}
929
930void
931setsugid(p)
932     struct proc *p;
933{
934	p->p_flag |= P_SUGID;
935	if (!(p->p_pfsflags & PF_ISUGID))
936		p->p_stops = 0;
937}
938