kern_prot.c revision 22522
11541Srgrimes/*
21541Srgrimes * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes * (c) UNIX System Laboratories, Inc.
51541Srgrimes * All or some portions of this file are derived from material licensed
61541Srgrimes * to the University of California by American Telephone and Telegraph
71541Srgrimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with
81541Srgrimes * the permission of UNIX System Laboratories, Inc.
91541Srgrimes *
101541Srgrimes * Redistribution and use in source and binary forms, with or without
111541Srgrimes * modification, are permitted provided that the following conditions
121541Srgrimes * are met:
131541Srgrimes * 1. Redistributions of source code must retain the above copyright
141541Srgrimes *    notice, this list of conditions and the following disclaimer.
151541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
161541Srgrimes *    notice, this list of conditions and the following disclaimer in the
171541Srgrimes *    documentation and/or other materials provided with the distribution.
181541Srgrimes * 3. All advertising materials mentioning features or use of this software
191541Srgrimes *    must display the following acknowledgement:
201541Srgrimes *	This product includes software developed by the University of
211541Srgrimes *	California, Berkeley and its contributors.
221541Srgrimes * 4. Neither the name of the University nor the names of its contributors
231541Srgrimes *    may be used to endorse or promote products derived from this software
241541Srgrimes *    without specific prior written permission.
251541Srgrimes *
261541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
271541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
281541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
291541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
301541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
311541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
321541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
331541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
341541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
351541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
361541Srgrimes * SUCH DAMAGE.
371541Srgrimes *
381541Srgrimes *	@(#)kern_prot.c	8.6 (Berkeley) 1/21/94
3921673Sjkh * $FreeBSD: head/sys/kern/kern_prot.c 22522 1997-02-10 06:18:20Z davidn $
401541Srgrimes */
411541Srgrimes
421541Srgrimes/*
431541Srgrimes * System calls related to processes and protection
441541Srgrimes */
451541Srgrimes
461541Srgrimes#include <sys/param.h>
471541Srgrimes#include <sys/acct.h>
481541Srgrimes#include <sys/systm.h>
4912221Sbde#include <sys/sysproto.h>
501541Srgrimes#include <sys/ucred.h>
511541Srgrimes#include <sys/proc.h>
521541Srgrimes#include <sys/timeb.h>
531541Srgrimes#include <sys/times.h>
541541Srgrimes#include <sys/malloc.h>
5518013Sbde#include <sys/unistd.h>
561541Srgrimes
5712221Sbde#ifndef _SYS_SYSPROTO_H_
5811332Sswallacestruct getpid_args {
591541Srgrimes	int	dummy;
601541Srgrimes};
6112221Sbde#endif
621541Srgrimes
631541Srgrimes/* ARGSUSED */
641549Srgrimesint
651541Srgrimesgetpid(p, uap, retval)
661541Srgrimes	struct proc *p;
6711332Sswallace	struct getpid_args *uap;
681541Srgrimes	int *retval;
691541Srgrimes{
701541Srgrimes
711541Srgrimes	*retval = p->p_pid;
721541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
731541Srgrimes	retval[1] = p->p_pptr->p_pid;
741541Srgrimes#endif
751541Srgrimes	return (0);
761541Srgrimes}
771541Srgrimes
7812221Sbde#ifndef _SYS_SYSPROTO_H_
7911332Sswallacestruct getppid_args {
8011332Sswallace        int     dummy;
8111332Sswallace};
8212221Sbde#endif
831541Srgrimes/* ARGSUSED */
841549Srgrimesint
851541Srgrimesgetppid(p, uap, retval)
861541Srgrimes	struct proc *p;
8711332Sswallace	struct getppid_args *uap;
881541Srgrimes	int *retval;
891541Srgrimes{
901541Srgrimes
911541Srgrimes	*retval = p->p_pptr->p_pid;
921541Srgrimes	return (0);
931541Srgrimes}
941541Srgrimes
951541Srgrimes/* Get process group ID; note that POSIX getpgrp takes no parameter */
9612221Sbde#ifndef _SYS_SYSPROTO_H_
9711332Sswallacestruct getpgrp_args {
9811332Sswallace        int     dummy;
9911332Sswallace};
10012221Sbde#endif
10111332Sswallace
1021549Srgrimesint
1031541Srgrimesgetpgrp(p, uap, retval)
1041541Srgrimes	struct proc *p;
10511332Sswallace	struct getpgrp_args *uap;
1061541Srgrimes	int *retval;
1071541Srgrimes{
1081541Srgrimes
1091541Srgrimes	*retval = p->p_pgrp->pg_id;
1101541Srgrimes	return (0);
1111541Srgrimes}
1121541Srgrimes
11312221Sbde#ifndef _SYS_SYSPROTO_H_
11411332Sswallacestruct getuid_args {
11511332Sswallace        int     dummy;
11611332Sswallace};
11712221Sbde#endif
11811332Sswallace
1191541Srgrimes/* ARGSUSED */
1201549Srgrimesint
1211541Srgrimesgetuid(p, uap, retval)
1221541Srgrimes	struct proc *p;
12311332Sswallace	struct getuid_args *uap;
1241541Srgrimes	int *retval;
1251541Srgrimes{
1261541Srgrimes
1271541Srgrimes	*retval = p->p_cred->p_ruid;
1281541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1291541Srgrimes	retval[1] = p->p_ucred->cr_uid;
1301541Srgrimes#endif
1311541Srgrimes	return (0);
1321541Srgrimes}
1331541Srgrimes
13412221Sbde#ifndef _SYS_SYSPROTO_H_
13511332Sswallacestruct geteuid_args {
13611332Sswallace        int     dummy;
13711332Sswallace};
13812221Sbde#endif
13911332Sswallace
1401541Srgrimes/* ARGSUSED */
1411549Srgrimesint
1421541Srgrimesgeteuid(p, uap, retval)
1431541Srgrimes	struct proc *p;
14411332Sswallace	struct geteuid_args *uap;
1451541Srgrimes	int *retval;
1461541Srgrimes{
1471541Srgrimes
1481541Srgrimes	*retval = p->p_ucred->cr_uid;
1491541Srgrimes	return (0);
1501541Srgrimes}
1511541Srgrimes
15212221Sbde#ifndef _SYS_SYSPROTO_H_
15311332Sswallacestruct getgid_args {
15411332Sswallace        int     dummy;
15511332Sswallace};
15612221Sbde#endif
15711332Sswallace
1581541Srgrimes/* ARGSUSED */
1591549Srgrimesint
1601541Srgrimesgetgid(p, uap, retval)
1611541Srgrimes	struct proc *p;
16211332Sswallace	struct getgid_args *uap;
1631541Srgrimes	int *retval;
1641541Srgrimes{
1651541Srgrimes
1661541Srgrimes	*retval = p->p_cred->p_rgid;
1671541Srgrimes#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1681541Srgrimes	retval[1] = p->p_ucred->cr_groups[0];
1691541Srgrimes#endif
1701541Srgrimes	return (0);
1711541Srgrimes}
1721541Srgrimes
1731541Srgrimes/*
1741541Srgrimes * Get effective group ID.  The "egid" is groups[0], and could be obtained
1751541Srgrimes * via getgroups.  This syscall exists because it is somewhat painful to do
1761541Srgrimes * correctly in a library function.
1771541Srgrimes */
17812221Sbde#ifndef _SYS_SYSPROTO_H_
17911332Sswallacestruct getegid_args {
18011332Sswallace        int     dummy;
18111332Sswallace};
18212221Sbde#endif
18311332Sswallace
1841541Srgrimes/* ARGSUSED */
1851549Srgrimesint
1861541Srgrimesgetegid(p, uap, retval)
1871541Srgrimes	struct proc *p;
18811332Sswallace	struct getegid_args *uap;
1891541Srgrimes	int *retval;
1901541Srgrimes{
1911541Srgrimes
1921541Srgrimes	*retval = p->p_ucred->cr_groups[0];
1931541Srgrimes	return (0);
1941541Srgrimes}
1951541Srgrimes
19612221Sbde#ifndef _SYS_SYSPROTO_H_
1971541Srgrimesstruct getgroups_args {
1981541Srgrimes	u_int	gidsetsize;
1991541Srgrimes	gid_t	*gidset;
2001541Srgrimes};
20112221Sbde#endif
2021549Srgrimesint
2031541Srgrimesgetgroups(p, uap, retval)
2041541Srgrimes	struct proc *p;
2051541Srgrimes	register struct	getgroups_args *uap;
2061541Srgrimes	int *retval;
2071541Srgrimes{
2081541Srgrimes	register struct pcred *pc = p->p_cred;
2091541Srgrimes	register u_int ngrp;
2101541Srgrimes	int error;
2111541Srgrimes
2121541Srgrimes	if ((ngrp = uap->gidsetsize) == 0) {
2131541Srgrimes		*retval = pc->pc_ucred->cr_ngroups;
2141541Srgrimes		return (0);
2151541Srgrimes	}
2161541Srgrimes	if (ngrp < pc->pc_ucred->cr_ngroups)
2171541Srgrimes		return (EINVAL);
2181541Srgrimes	ngrp = pc->pc_ucred->cr_ngroups;
2193098Sphk	if ((error = copyout((caddr_t)pc->pc_ucred->cr_groups,
2203098Sphk	    (caddr_t)uap->gidset, ngrp * sizeof(gid_t))))
2211541Srgrimes		return (error);
2221541Srgrimes	*retval = ngrp;
2231541Srgrimes	return (0);
2241541Srgrimes}
2251541Srgrimes
22612221Sbde#ifndef _SYS_SYSPROTO_H_
22712207Sbdestruct setsid_args {
22811332Sswallace        int     dummy;
22911332Sswallace};
23012221Sbde#endif
23111332Sswallace
2321541Srgrimes/* ARGSUSED */
2331549Srgrimesint
2341541Srgrimessetsid(p, uap, retval)
2351541Srgrimes	register struct proc *p;
23612207Sbde	struct setsid_args *uap;
2371541Srgrimes	int *retval;
2381541Srgrimes{
2391541Srgrimes
2401541Srgrimes	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
2411541Srgrimes		return (EPERM);
2421541Srgrimes	} else {
2431541Srgrimes		(void)enterpgrp(p, p->p_pid, 1);
2441541Srgrimes		*retval = p->p_pid;
2451541Srgrimes		return (0);
2461541Srgrimes	}
2471541Srgrimes}
2481541Srgrimes
2491541Srgrimes/*
2501541Srgrimes * set process group (setpgid/old setpgrp)
2511541Srgrimes *
2521541Srgrimes * caller does setpgid(targpid, targpgid)
2531541Srgrimes *
2541541Srgrimes * pid must be caller or child of caller (ESRCH)
2551541Srgrimes * if a child
2561541Srgrimes *	pid must be in same session (EPERM)
2571541Srgrimes *	pid can't have done an exec (EACCES)
2581541Srgrimes * if pgid != pid
2591541Srgrimes * 	there must exist some pid in same session having pgid (EPERM)
2601541Srgrimes * pid must not be session leader (EPERM)
2611541Srgrimes */
26212221Sbde#ifndef _SYS_SYSPROTO_H_
2631541Srgrimesstruct setpgid_args {
2641541Srgrimes	int	pid;	/* target process id */
2651541Srgrimes	int	pgid;	/* target pgrp id */
2661541Srgrimes};
26712221Sbde#endif
2681541Srgrimes/* ARGSUSED */
2691549Srgrimesint
2701541Srgrimessetpgid(curp, uap, retval)
2711541Srgrimes	struct proc *curp;
2721541Srgrimes	register struct setpgid_args *uap;
2731541Srgrimes	int *retval;
2741541Srgrimes{
2751541Srgrimes	register struct proc *targp;		/* target process */
2761541Srgrimes	register struct pgrp *pgrp;		/* target pgrp */
2771541Srgrimes
27820677Sbde	if (uap->pgid < 0)
27920677Sbde		return (EINVAL);
2801541Srgrimes	if (uap->pid != 0 && uap->pid != curp->p_pid) {
2811541Srgrimes		if ((targp = pfind(uap->pid)) == 0 || !inferior(targp))
2821541Srgrimes			return (ESRCH);
28315985Sdg		if (targp->p_pgrp == NULL ||  targp->p_session != curp->p_session)
2841541Srgrimes			return (EPERM);
2851541Srgrimes		if (targp->p_flag & P_EXEC)
2861541Srgrimes			return (EACCES);
2871541Srgrimes	} else
2881541Srgrimes		targp = curp;
2891541Srgrimes	if (SESS_LEADER(targp))
2901541Srgrimes		return (EPERM);
2911541Srgrimes	if (uap->pgid == 0)
2921541Srgrimes		uap->pgid = targp->p_pid;
2931541Srgrimes	else if (uap->pgid != targp->p_pid)
2941541Srgrimes		if ((pgrp = pgfind(uap->pgid)) == 0 ||
2951541Srgrimes	            pgrp->pg_session != curp->p_session)
2961541Srgrimes			return (EPERM);
2971541Srgrimes	return (enterpgrp(targp, uap->pgid, 0));
2981541Srgrimes}
2991541Srgrimes
30012221Sbde#ifndef _SYS_SYSPROTO_H_
3011541Srgrimesstruct setuid_args {
3021541Srgrimes	uid_t	uid;
3031541Srgrimes};
30412221Sbde#endif
3051541Srgrimes/* ARGSUSED */
3061549Srgrimesint
3071541Srgrimessetuid(p, uap, retval)
3081541Srgrimes	struct proc *p;
3091541Srgrimes	struct setuid_args *uap;
3101541Srgrimes	int *retval;
3111541Srgrimes{
3121541Srgrimes	register struct pcred *pc = p->p_cred;
3131541Srgrimes	register uid_t uid;
3141541Srgrimes	int error;
3151541Srgrimes
3161541Srgrimes	uid = uap->uid;
31717994Sache	if (uid != pc->p_ruid &&
31817994Sache#ifdef _POSIX_SAVED_IDS
31917994Sache	    uid != pc->p_svuid &&
32017994Sache#endif
3218162Sache	    (error = suser(pc->pc_ucred, &p->p_acflag)))
3221541Srgrimes		return (error);
3231541Srgrimes	/*
3241541Srgrimes	 * Everything's okay, do it.
3251541Srgrimes	 * Transfer proc count to new user.
3261541Srgrimes	 * Copy credentials so other references do not see our changes.
3271541Srgrimes	 */
32817994Sache	if (
32917994Sache#ifdef _POSIX_SAVED_IDS
33017994Sache	    pc->pc_ucred->cr_uid == 0 &&
33117994Sache#endif
33217994Sache	    uid != pc->p_ruid) {
3338141Sache		(void)chgproccnt(pc->p_ruid, -1);
3348141Sache		(void)chgproccnt(uid, 1);
3358141Sache	}
3361541Srgrimes	pc->pc_ucred = crcopy(pc->pc_ucred);
33717994Sache#ifdef _POSIX_SAVED_IDS
3388162Sache	if (pc->pc_ucred->cr_uid == 0) {
33917994Sache#endif
3408141Sache		pc->p_ruid = uid;
3418141Sache		pc->p_svuid = uid;
34217994Sache#ifdef _POSIX_SAVED_IDS
3438141Sache	}
34417994Sache#endif
3458162Sache	pc->pc_ucred->cr_uid = uid;
3461541Srgrimes	p->p_flag |= P_SUGID;
3471541Srgrimes	return (0);
3481541Srgrimes}
3491541Srgrimes
35012221Sbde#ifndef _SYS_SYSPROTO_H_
3511541Srgrimesstruct seteuid_args {
3521541Srgrimes	uid_t	euid;
3531541Srgrimes};
35412221Sbde#endif
3551541Srgrimes/* ARGSUSED */
3561549Srgrimesint
3571541Srgrimesseteuid(p, uap, retval)
3581541Srgrimes	struct proc *p;
3591541Srgrimes	struct seteuid_args *uap;
3601541Srgrimes	int *retval;
3611541Srgrimes{
3621541Srgrimes	register struct pcred *pc = p->p_cred;
3631541Srgrimes	register uid_t euid;
3641541Srgrimes	int error;
3651541Srgrimes
3661541Srgrimes	euid = uap->euid;
3671541Srgrimes	if (euid != pc->p_ruid && euid != pc->p_svuid &&
3681541Srgrimes	    (error = suser(pc->pc_ucred, &p->p_acflag)))
3691541Srgrimes		return (error);
3701541Srgrimes	/*
3711541Srgrimes	 * Everything's okay, do it.  Copy credentials so other references do
3721541Srgrimes	 * not see our changes.
3731541Srgrimes	 */
3741541Srgrimes	pc->pc_ucred = crcopy(pc->pc_ucred);
3751541Srgrimes	pc->pc_ucred->cr_uid = euid;
3761541Srgrimes	p->p_flag |= P_SUGID;
3771541Srgrimes	return (0);
3781541Srgrimes}
3791541Srgrimes
38012221Sbde#ifndef _SYS_SYSPROTO_H_
3811541Srgrimesstruct setgid_args {
3821541Srgrimes	gid_t	gid;
3831541Srgrimes};
38412221Sbde#endif
3851541Srgrimes/* ARGSUSED */
3861549Srgrimesint
3871541Srgrimessetgid(p, uap, retval)
3881541Srgrimes	struct proc *p;
3891541Srgrimes	struct setgid_args *uap;
3901541Srgrimes	int *retval;
3911541Srgrimes{
3921541Srgrimes	register struct pcred *pc = p->p_cred;
3931541Srgrimes	register gid_t gid;
3941541Srgrimes	int error;
3951541Srgrimes
3961541Srgrimes	gid = uap->gid;
39717994Sache	if (gid != pc->p_rgid &&
39817994Sache#ifdef _POSIX_SAVED_IDS
39917994Sache	    gid != pc->p_svgid &&
40017994Sache#endif
4018162Sache	    (error = suser(pc->pc_ucred, &p->p_acflag)))
4021541Srgrimes		return (error);
4031541Srgrimes	pc->pc_ucred = crcopy(pc->pc_ucred);
4041541Srgrimes	pc->pc_ucred->cr_groups[0] = gid;
40517994Sache#ifdef _POSIX_SAVED_IDS
4068162Sache	if (pc->pc_ucred->cr_uid == 0) {
40717994Sache#endif
4088141Sache		pc->p_rgid = gid;
4098141Sache		pc->p_svgid = gid;
41017994Sache#ifdef _POSIX_SAVED_IDS
4118141Sache	}
41217994Sache#endif
4131541Srgrimes	p->p_flag |= P_SUGID;
4141541Srgrimes	return (0);
4151541Srgrimes}
4161541Srgrimes
41712221Sbde#ifndef _SYS_SYSPROTO_H_
4181541Srgrimesstruct setegid_args {
4191541Srgrimes	gid_t	egid;
4201541Srgrimes};
42112221Sbde#endif
4221541Srgrimes/* ARGSUSED */
4231549Srgrimesint
4241541Srgrimessetegid(p, uap, retval)
4251541Srgrimes	struct proc *p;
4261541Srgrimes	struct setegid_args *uap;
4271541Srgrimes	int *retval;
4281541Srgrimes{
4291541Srgrimes	register struct pcred *pc = p->p_cred;
4301541Srgrimes	register gid_t egid;
4311541Srgrimes	int error;
4321541Srgrimes
4331541Srgrimes	egid = uap->egid;
4341541Srgrimes	if (egid != pc->p_rgid && egid != pc->p_svgid &&
4351541Srgrimes	    (error = suser(pc->pc_ucred, &p->p_acflag)))
4361541Srgrimes		return (error);
4371541Srgrimes	pc->pc_ucred = crcopy(pc->pc_ucred);
4381541Srgrimes	pc->pc_ucred->cr_groups[0] = egid;
4391541Srgrimes	p->p_flag |= P_SUGID;
4401541Srgrimes	return (0);
4411541Srgrimes}
4421541Srgrimes
44312221Sbde#ifndef _SYS_SYSPROTO_H_
4441541Srgrimesstruct setgroups_args {
4451541Srgrimes	u_int	gidsetsize;
4461541Srgrimes	gid_t	*gidset;
4471541Srgrimes};
44812221Sbde#endif
4491541Srgrimes/* ARGSUSED */
4501549Srgrimesint
4511541Srgrimessetgroups(p, uap, retval)
4521541Srgrimes	struct proc *p;
4531541Srgrimes	struct setgroups_args *uap;
4541541Srgrimes	int *retval;
4551541Srgrimes{
4561541Srgrimes	register struct pcred *pc = p->p_cred;
4571541Srgrimes	register u_int ngrp;
4581541Srgrimes	int error;
4591541Srgrimes
4603098Sphk	if ((error = suser(pc->pc_ucred, &p->p_acflag)))
4611541Srgrimes		return (error);
46212063Sdg	ngrp = uap->gidsetsize;
46312063Sdg	if (ngrp < 1 || ngrp > NGROUPS)
4641541Srgrimes		return (EINVAL);
4651541Srgrimes	pc->pc_ucred = crcopy(pc->pc_ucred);
4663098Sphk	if ((error = copyin((caddr_t)uap->gidset,
4673098Sphk	    (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t))))
4681541Srgrimes		return (error);
4691541Srgrimes	pc->pc_ucred->cr_ngroups = ngrp;
4701541Srgrimes	p->p_flag |= P_SUGID;
4711541Srgrimes	return (0);
4721541Srgrimes}
4731541Srgrimes
47412221Sbde#ifndef _SYS_SYSPROTO_H_
4751541Srgrimesstruct setreuid_args {
4769238Sache	uid_t	ruid;
4779238Sache	uid_t	euid;
4781541Srgrimes};
47912221Sbde#endif
4801541Srgrimes/* ARGSUSED */
4811549Srgrimesint
4828019Sachesetreuid(p, uap, retval)
4831541Srgrimes	register struct proc *p;
4841541Srgrimes	struct setreuid_args *uap;
4851541Srgrimes	int *retval;
4861541Srgrimes{
4871541Srgrimes	register struct pcred *pc = p->p_cred;
4889238Sache	register uid_t ruid, euid;
4898135Sache	int error;
4901541Srgrimes
4919238Sache	ruid = uap->ruid;
4929238Sache	euid = uap->euid;
4939238Sache	if ((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid ||
4949238Sache	     euid != (uid_t)-1 && euid != pc->p_ruid && euid != pc->p_svuid) &&
4958135Sache	    (error = suser(pc->pc_ucred, &p->p_acflag)))
4968135Sache		return (error);
4979238Sache
4989238Sache	pc->pc_ucred = crcopy(pc->pc_ucred);
4999238Sache	if (euid != (uid_t)-1)
5009238Sache		pc->pc_ucred->cr_uid = euid;
5019238Sache	if (ruid != (uid_t)-1 && ruid != pc->p_ruid) {
5029238Sache		(void)chgproccnt(pc->p_ruid, -1);
5039238Sache		(void)chgproccnt(ruid, 1);
5049238Sache		pc->p_ruid = ruid;
5058135Sache	}
5069238Sache	if (ruid != (uid_t)-1 || pc->pc_ucred->cr_uid != pc->p_ruid)
5078111Sache		pc->p_svuid = pc->pc_ucred->cr_uid;
5089238Sache	p->p_flag |= P_SUGID;
5098135Sache	return (0);
5101541Srgrimes}
5111541Srgrimes
51212221Sbde#ifndef _SYS_SYSPROTO_H_
5131541Srgrimesstruct setregid_args {
5149238Sache	gid_t	rgid;
5159238Sache	gid_t	egid;
5161541Srgrimes};
51712221Sbde#endif
5181541Srgrimes/* ARGSUSED */
5191549Srgrimesint
5208019Sachesetregid(p, uap, retval)
5211541Srgrimes	register struct proc *p;
5221541Srgrimes	struct setregid_args *uap;
5231541Srgrimes	int *retval;
5241541Srgrimes{
5251541Srgrimes	register struct pcred *pc = p->p_cred;
5269238Sache	register gid_t rgid, egid;
5278135Sache	int error;
5281541Srgrimes
5299238Sache	rgid = uap->rgid;
5309238Sache	egid = uap->egid;
5319238Sache	if ((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid ||
5329238Sache	     egid != (gid_t)-1 && egid != pc->p_rgid && egid != pc->p_svgid) &&
5338135Sache	    (error = suser(pc->pc_ucred, &p->p_acflag)))
5348135Sache		return (error);
5359238Sache
5369238Sache	pc->pc_ucred = crcopy(pc->pc_ucred);
5379238Sache	if (egid != (gid_t)-1)
5389238Sache		pc->pc_ucred->cr_groups[0] = egid;
5399238Sache	if (rgid != (gid_t)-1)
5409238Sache		pc->p_rgid = rgid;
5419238Sache	if (rgid != (gid_t)-1 || pc->pc_ucred->cr_groups[0] != pc->p_rgid)
5428111Sache		pc->p_svgid = pc->pc_ucred->cr_groups[0];
5439238Sache	p->p_flag |= P_SUGID;
5448135Sache	return (0);
5451541Srgrimes}
5461541Srgrimes
5471541Srgrimes/*
5481541Srgrimes * Check if gid is a member of the group set.
5491541Srgrimes */
5501549Srgrimesint
5511541Srgrimesgroupmember(gid, cred)
5521541Srgrimes	gid_t gid;
5531541Srgrimes	register struct ucred *cred;
5541541Srgrimes{
5551541Srgrimes	register gid_t *gp;
5561541Srgrimes	gid_t *egp;
5571541Srgrimes
5581541Srgrimes	egp = &(cred->cr_groups[cred->cr_ngroups]);
5591541Srgrimes	for (gp = cred->cr_groups; gp < egp; gp++)
5601541Srgrimes		if (*gp == gid)
5611541Srgrimes			return (1);
5621541Srgrimes	return (0);
5631541Srgrimes}
5641541Srgrimes
5651541Srgrimes/*
5661541Srgrimes * Test whether the specified credentials imply "super-user"
5671541Srgrimes * privilege; if so, and we have accounting info, set the flag
5681541Srgrimes * indicating use of super-powers.
5691541Srgrimes * Returns 0 or error.
5701541Srgrimes */
5711549Srgrimesint
5721541Srgrimessuser(cred, acflag)
5731541Srgrimes	struct ucred *cred;
5748011Sbde	u_short *acflag;
5751541Srgrimes{
5761541Srgrimes	if (cred->cr_uid == 0) {
5771541Srgrimes		if (acflag)
5781541Srgrimes			*acflag |= ASU;
5791541Srgrimes		return (0);
5801541Srgrimes	}
5811541Srgrimes	return (EPERM);
5821541Srgrimes}
5831541Srgrimes
5841541Srgrimes/*
5851541Srgrimes * Allocate a zeroed cred structure.
5861541Srgrimes */
5871541Srgrimesstruct ucred *
5881541Srgrimescrget()
5891541Srgrimes{
5901541Srgrimes	register struct ucred *cr;
5911541Srgrimes
5921541Srgrimes	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
5931541Srgrimes	bzero((caddr_t)cr, sizeof(*cr));
5941541Srgrimes	cr->cr_ref = 1;
5951541Srgrimes	return (cr);
5961541Srgrimes}
5971541Srgrimes
5981541Srgrimes/*
5991541Srgrimes * Free a cred structure.
6001541Srgrimes * Throws away space when ref count gets to 0.
6011541Srgrimes */
6021549Srgrimesvoid
6031541Srgrimescrfree(cr)
6041541Srgrimes	struct ucred *cr;
6051541Srgrimes{
6061541Srgrimes	int s;
6071541Srgrimes
6081541Srgrimes	s = splimp();				/* ??? */
6091541Srgrimes	if (--cr->cr_ref == 0)
6101541Srgrimes		FREE((caddr_t)cr, M_CRED);
6111541Srgrimes	(void) splx(s);
6121541Srgrimes}
6131541Srgrimes
6141541Srgrimes/*
6151541Srgrimes * Copy cred structure to a new one and free the old one.
6161541Srgrimes */
6171541Srgrimesstruct ucred *
6181541Srgrimescrcopy(cr)
6191541Srgrimes	struct ucred *cr;
6201541Srgrimes{
6211541Srgrimes	struct ucred *newcr;
6221541Srgrimes
6231541Srgrimes	if (cr->cr_ref == 1)
6241541Srgrimes		return (cr);
6251541Srgrimes	newcr = crget();
6261541Srgrimes	*newcr = *cr;
6271541Srgrimes	crfree(cr);
6281541Srgrimes	newcr->cr_ref = 1;
6291541Srgrimes	return (newcr);
6301541Srgrimes}
6311541Srgrimes
6321541Srgrimes/*
6331541Srgrimes * Dup cred struct to a new held one.
6341541Srgrimes */
6351541Srgrimesstruct ucred *
6361541Srgrimescrdup(cr)
6371541Srgrimes	struct ucred *cr;
6381541Srgrimes{
6391541Srgrimes	struct ucred *newcr;
6401541Srgrimes
6411541Srgrimes	newcr = crget();
6421541Srgrimes	*newcr = *cr;
6431541Srgrimes	newcr->cr_ref = 1;
6441541Srgrimes	return (newcr);
6451541Srgrimes}
6461541Srgrimes
6471541Srgrimes/*
6481541Srgrimes * Get login name, if available.
6491541Srgrimes */
65012221Sbde#ifndef _SYS_SYSPROTO_H_
6511541Srgrimesstruct getlogin_args {
6521541Srgrimes	char	*namebuf;
6531541Srgrimes	u_int	namelen;
6541541Srgrimes};
65512221Sbde#endif
6561541Srgrimes/* ARGSUSED */
6571549Srgrimesint
6581541Srgrimesgetlogin(p, uap, retval)
6591541Srgrimes	struct proc *p;
6601541Srgrimes	struct getlogin_args *uap;
6611541Srgrimes	int *retval;
6621541Srgrimes{
6631541Srgrimes
6641541Srgrimes	if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login))
6651541Srgrimes		uap->namelen = sizeof (p->p_pgrp->pg_session->s_login);
6661541Srgrimes	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
6671541Srgrimes	    (caddr_t) uap->namebuf, uap->namelen));
6681541Srgrimes}
6691541Srgrimes
6701541Srgrimes/*
6711541Srgrimes * Set login name.
6721541Srgrimes */
67312221Sbde#ifndef _SYS_SYSPROTO_H_
6741541Srgrimesstruct setlogin_args {
6751541Srgrimes	char	*namebuf;
6761541Srgrimes};
67712221Sbde#endif
6781541Srgrimes/* ARGSUSED */
6791549Srgrimesint
6801541Srgrimessetlogin(p, uap, retval)
6811541Srgrimes	struct proc *p;
6821541Srgrimes	struct setlogin_args *uap;
6831541Srgrimes	int *retval;
6841541Srgrimes{
6851541Srgrimes	int error;
68622522Sdavidn	char logintmp[sizeof(p->p_pgrp->pg_session->s_login)];
6871541Srgrimes
6883098Sphk	if ((error = suser(p->p_ucred, &p->p_acflag)))
6891541Srgrimes		return (error);
69022522Sdavidn	error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp,
69122522Sdavidn	    sizeof(logintmp), (u_int *)0);
6921541Srgrimes	if (error == ENAMETOOLONG)
6931541Srgrimes		error = EINVAL;
69422522Sdavidn	else if (!error)
69522522Sdavidn		(void) memcpy(p->p_pgrp->pg_session->s_login, logintmp,
69622522Sdavidn		    sizeof(p->p_pgrp->pg_session->s_login));
6971541Srgrimes	return (error);
6981541Srgrimes}
699