xref: /csrg-svn/sys/kern/kern_prot.c (revision 44405)
123372Smckusick /*
243393Skarels  * Copyright (c) 1982, 1986, 1989, 1990 Regents of the University of California.
337578Smckusick  * All rights reserved.
423372Smckusick  *
537578Smckusick  * Redistribution and use in source and binary forms are permitted
637578Smckusick  * provided that the above copyright notice and this paragraph are
737578Smckusick  * duplicated in all such forms and that any documentation,
837578Smckusick  * advertising materials, and other materials related to such
937578Smckusick  * distribution and use acknowledge that the software was developed
1037578Smckusick  * by the University of California, Berkeley.  The name of the
1137578Smckusick  * University may not be used to endorse or promote products derived
1237578Smckusick  * from this software without specific prior written permission.
1337578Smckusick  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1437578Smckusick  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1537578Smckusick  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1637578Smckusick  *
17*44405Skarels  *	@(#)kern_prot.c	7.12 (Berkeley) 06/28/90
1823372Smckusick  */
197420Sroot 
207420Sroot /*
217498Sroot  * System calls related to processes and protection
227420Sroot  */
237420Sroot 
2417092Sbloom #include "param.h"
2537578Smckusick #include "acct.h"
2617092Sbloom #include "systm.h"
27*44405Skarels #include "user.h"
2817092Sbloom #include "proc.h"
2917092Sbloom #include "timeb.h"
3017092Sbloom #include "times.h"
3137578Smckusick #include "malloc.h"
327420Sroot 
3343393Skarels /* ARGSUSED */
3443393Skarels getpid(p, uap, retval)
3543393Skarels 	struct proc *p;
3643393Skarels 	void *uap;
3743393Skarels 	int *retval;
3843393Skarels {
3937579Smckusick 
4043393Skarels 	*retval = p->p_pid;
4143393Skarels #ifdef COMPAT_43
4243393Skarels 	retval[1] = p->p_ppid;
4343393Skarels #endif
44*44405Skarels 	return (0);
4543393Skarels }
4643393Skarels 
4743393Skarels /* ARGSUSED */
4843393Skarels getppid(p, uap, retval)
4943393Skarels 	struct proc *p;
5043393Skarels 	void *uap;
5143393Skarels 	int *retval;
527498Sroot {
537498Sroot 
5443393Skarels 	*retval = p->p_ppid;
55*44405Skarels 	return (0);
567498Sroot }
577498Sroot 
5843393Skarels getpgrp(p, uap, retval)
5943393Skarels 	struct proc *p;
6043393Skarels 	struct args {
6143393Skarels 		int	pid;
6243393Skarels 	} *uap;
6343393Skarels 	int *retval;
647498Sroot {
657498Sroot 
6643393Skarels 	if (uap->pid != 0 && (p = pfind(uap->pid)) == 0)
67*44405Skarels 		return (ESRCH);
6843393Skarels 	*retval = p->p_pgrp->pg_id;
69*44405Skarels 	return (0);
707498Sroot }
717498Sroot 
7243393Skarels /* ARGSUSED */
7343393Skarels getuid(p, uap, retval)
7443393Skarels 	struct proc *p;
7543393Skarels 	void *uap;
7643393Skarels 	int *retval;
777420Sroot {
787420Sroot 
7943393Skarels 	*retval = p->p_ruid;
8043393Skarels #ifdef COMPAT_43
8143393Skarels 	retval[1] = u.u_cred->cr_uid;
8243393Skarels #endif
83*44405Skarels 	return (0);
847420Sroot }
857420Sroot 
8643393Skarels /* ARGSUSED */
8743393Skarels geteuid(p, uap, retval)
8843393Skarels 	struct proc *p;
8943393Skarels 	void *uap;
9043393Skarels 	int *retval;
917498Sroot {
927498Sroot 
9343393Skarels 	*retval = u.u_cred->cr_uid;
94*44405Skarels 	return (0);
957498Sroot }
967498Sroot 
9743393Skarels /* ARGSUSED */
9843393Skarels getgid(p, uap, retval)
9943393Skarels 	struct proc *p;
10043393Skarels 	void *uap;
10143393Skarels 	int *retval;
1027498Sroot {
10343393Skarels 
10443393Skarels 	*retval = p->p_rgid;
10543393Skarels #ifdef COMPAT_43
10643393Skarels 	retval[1] = u.u_cred->cr_groups[0];
10743393Skarels #endif
108*44405Skarels 	return (0);
10943393Skarels }
11043393Skarels 
11143393Skarels /*
11243393Skarels  * Get effective group ID.
11343393Skarels  * The "egid" is groups[0], and thus could be obtained via getgroups;
11443393Skarels  * this is somewhat painful to do correctly in a library function,
11543393Skarels  * this the existence of this syscall.
11643393Skarels  */
11743393Skarels /* ARGSUSED */
11843393Skarels getegid(p, uap, retval)
11943393Skarels 	struct proc *p;
12043393Skarels 	void *uap;
12143393Skarels 	int *retval;
12243393Skarels {
12343393Skarels 
12443393Skarels 	*retval = u.u_cred->cr_groups[0];
125*44405Skarels 	return (0);
12643393Skarels }
12743393Skarels 
12843393Skarels getgroups(p, uap, retval)
12943393Skarels 	struct proc *p;
13043393Skarels 	register struct	arg {
1318624Sroot 		u_int	gidsetsize;
13243393Skarels 		int	*gidset;		/* XXX not yet POSIX */
13343393Skarels 	} *uap;
13443393Skarels 	int *retval;
13543393Skarels {
13618362Skarels 	register gid_t *gp;
13718362Skarels 	register int *lp;
13818362Skarels 	int groups[NGROUPS];
13943393Skarels 	int error;
1407498Sroot 
14137578Smckusick 	if (uap->gidsetsize == 0) {
14243393Skarels 		*retval = u.u_cred->cr_ngroups;
143*44405Skarels 		return (0);
14437578Smckusick 	}
14543393Skarels 	if (uap->gidsetsize < u.u_cred->cr_ngroups)
146*44405Skarels 		return (EINVAL);
14740667Skarels 	uap->gidsetsize = u.u_cred->cr_ngroups;
14840667Skarels 	gp = u.u_cred->cr_groups;
14937578Smckusick 	for (lp = groups; lp < &groups[uap->gidsetsize]; )
15018362Skarels 		*lp++ = *gp++;
15143393Skarels 	if (error = copyout((caddr_t)groups, (caddr_t)uap->gidset,
15243393Skarels 	    uap->gidsetsize * sizeof (groups[0])))
153*44405Skarels 		return (error);
15443393Skarels 	*retval = uap->gidsetsize;
155*44405Skarels 	return (0);
1567498Sroot }
1577498Sroot 
15843393Skarels /* ARGSUSED */
15943393Skarels setsid(p, uap, retval)
16043393Skarels 	struct proc *p;
16143393Skarels 	void *uap;
16243393Skarels 	int *retval;
16337579Smckusick {
16437579Smckusick 
16543393Skarels 	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
166*44405Skarels 		return (EPERM);
16743393Skarels 	} else {
16837579Smckusick 		pgmv(p, p->p_pid, 1);
16943393Skarels 		*retval = p->p_pid;
170*44405Skarels 		return (0);
17137579Smckusick 	}
17237579Smckusick }
17337579Smckusick 
17437579Smckusick /*
17543393Skarels  * set process group (setpgrp/setpgid)
17637579Smckusick  *
17740667Skarels  * caller does setpgrp(pid, pgid)
17840667Skarels  *
17940667Skarels  * pid must be caller or child of caller (ESRCH)
18040667Skarels  * if a child
18140667Skarels  *	pid must be in same session (EPERM)
18240667Skarels  *	pid can't have done an exec (EACCES)
18340667Skarels  * if pgid != pid
18440667Skarels  * 	there must exist some pid in same session having pgid (EPERM)
18540667Skarels  * pid must not be session leader (EPERM)
18637579Smckusick  */
18743393Skarels /* ARGSUSED */
18843393Skarels setpgrp(cp, uap, retval)
18943393Skarels 	struct proc *cp;
19043393Skarels 	register struct args {
1917498Sroot 		int	pid;
19237579Smckusick 		int	pgid;
19343393Skarels 	} *uap;
19443393Skarels 	int *retval;
19543393Skarels {
19637579Smckusick 	register struct proc *p;
19737579Smckusick 	register struct pgrp *pgrp;
1987498Sroot 
19943393Skarels 	if (uap->pid != 0) {
20043393Skarels 		if ((p = pfind(uap->pid)) == 0 || !inferior(p))
201*44405Skarels 			return (ESRCH);
20243393Skarels 		if (p->p_session != cp->p_session)
203*44405Skarels 			return (EPERM);
20443393Skarels 		if (p->p_flag&SEXEC)
205*44405Skarels 			return (EACCES);
20643393Skarels 	} else
20743393Skarels 		p = cp;
20843393Skarels 	if (SESS_LEADER(p))
209*44405Skarels 		return (EPERM);
21037579Smckusick 	if (uap->pgid == 0)
21137579Smckusick 		uap->pgid = p->p_pid;
21237579Smckusick 	else if ((uap->pgid != p->p_pid) &&
21337579Smckusick 		(((pgrp = pgfind(uap->pgid)) == 0) ||
21437579Smckusick 		   pgrp->pg_mem == NULL ||
21543393Skarels 	           pgrp->pg_session != u.u_procp->p_session))
216*44405Skarels 		return (EPERM);
21737579Smckusick 	/*
21843393Skarels 	 * done checking, now do it
21937579Smckusick 	 */
22037579Smckusick 	pgmv(p, uap->pgid, 0);
221*44405Skarels 	return (0);
2227498Sroot }
2237498Sroot 
22443393Skarels /* ARGSUSED */
22543393Skarels setuid(p, uap, retval)
22643393Skarels 	register struct proc *p;
22743393Skarels 	struct args {
22843393Skarels 		int	uid;
22943393Skarels 	} *uap;
23043393Skarels 	int *retval;
2317420Sroot {
23243393Skarels 	register uid_t uid;
23343393Skarels 	int error;
23443393Skarels 
23543393Skarels 	uid = uap->uid;
23643393Skarels 	if (uid != p->p_ruid && (error = suser(u.u_cred, &u.u_acflag)))
237*44405Skarels 		return (error);
23843393Skarels 	/*
23943393Skarels 	 * Everything's okay, do it.
24043393Skarels 	 * Copy credentials so other references do not
24143393Skarels 	 * see our changes.
24243393Skarels 	 */
24343393Skarels 	if (u.u_cred->cr_ref > 1)
24443393Skarels 		u.u_cred = crcopy(u.u_cred);
24543393Skarels 	u.u_cred->cr_uid = uid;
24643393Skarels 	p->p_uid = uid;
24743393Skarels 	p->p_ruid = uid;
24843393Skarels 	p->p_svuid = uid;
249*44405Skarels 	return (0);
25043393Skarels }
25143393Skarels 
25243393Skarels /* ARGSUSED */
25343393Skarels seteuid(p, uap, retval)
25443393Skarels 	register struct proc *p;
25543393Skarels 	struct args {
25643393Skarels 		int	euid;
25743393Skarels 	} *uap;
25843393Skarels 	int *retval;
25943393Skarels {
26043393Skarels 	register uid_t euid;
26143393Skarels 	int error;
26243393Skarels 
26343393Skarels 	euid = uap->euid;
26443393Skarels 	if (euid != p->p_ruid && euid != p->p_svuid &&
26543393Skarels 	    (error = suser(u.u_cred, &u.u_acflag)))
266*44405Skarels 		return (error);
26743393Skarels 	/*
26843393Skarels 	 * Everything's okay, do it.
26943393Skarels 	 * Copy credentials so other references do not
27043393Skarels 	 * see our changes.
27143393Skarels 	 */
27243393Skarels 	if (u.u_cred->cr_ref > 1)
27343393Skarels 		u.u_cred = crcopy(u.u_cred);
27443393Skarels 	u.u_cred->cr_uid = euid;
27543393Skarels 	p->p_uid = euid;
276*44405Skarels 	return (0);
27743393Skarels }
27843393Skarels 
27943393Skarels /* ARGSUSED */
28043393Skarels setgid(p, uap, retval)
28143393Skarels 	struct proc *p;
28243393Skarels 	struct args {
28343393Skarels 		int	gid;
28443393Skarels 	} *uap;
28543393Skarels 	int *retval;
28643393Skarels {
28743393Skarels 	register gid_t gid;
28843393Skarels 	int error;
28943393Skarels 
29043393Skarels 	gid = uap->gid;
29143393Skarels 	if (gid != p->p_rgid && (error = suser(u.u_cred, &u.u_acflag)))
292*44405Skarels 		return (error);
29343393Skarels 	if (u.u_cred->cr_ref > 1)
29443393Skarels 		u.u_cred = crcopy(u.u_cred);
29543393Skarels 	p->p_rgid = gid;
29643393Skarels 	u.u_cred->cr_groups[0] = gid;
29743393Skarels 	p->p_svgid = gid;		/* ??? */
298*44405Skarels 	return (0);
29943393Skarels }
30043393Skarels 
30143393Skarels /* ARGSUSED */
30243393Skarels setegid(p, uap, retval)
30343393Skarels 	struct proc *p;
30443393Skarels 	struct args {
30543393Skarels 		int	egid;
30643393Skarels 	} *uap;
30743393Skarels 	int *retval;
30843393Skarels {
30943393Skarels 	register gid_t egid;
31043393Skarels 	int error;
31143393Skarels 
31243393Skarels 	egid = uap->egid;
31343393Skarels 	if (egid != p->p_rgid && egid != p->p_svgid &&
31443393Skarels 	    (error = suser(u.u_cred, &u.u_acflag)))
315*44405Skarels 		return (error);
31643393Skarels 	if (u.u_cred->cr_ref > 1)
31743393Skarels 		u.u_cred = crcopy(u.u_cred);
31843393Skarels 	u.u_cred->cr_groups[0] = egid;
319*44405Skarels 	return (0);
32043393Skarels }
32143393Skarels 
32243393Skarels #ifdef COMPAT_43
32343393Skarels /* ARGSUSED */
32443393Skarels osetreuid(p, uap, retval)
32543393Skarels 	register struct proc *p;
32643393Skarels 	struct args {
3279160Ssam 		int	ruid;
3289160Ssam 		int	euid;
3299160Ssam 	} *uap;
33043393Skarels 	int *retval;
33143393Skarels {
33243393Skarels 	register uid_t ruid, euid;
33343393Skarels 	int error;
3349160Ssam 
33543393Skarels 	if (uap->ruid == -1)
33640667Skarels 		ruid = p->p_ruid;
33743393Skarels 	else
33843393Skarels 		ruid = uap->ruid;
33943393Skarels 	/*
34043393Skarels 	 * Allow setting real uid to previous effective,
34143393Skarels 	 * for swapping real and effective.
34243393Skarels 	 * This should be:
34343393Skarels 	 *   if (ruid != p->p_ruid && (error = suser(u.u_cred, &u.u_acflag)))
34443393Skarels 	 */
34540667Skarels 	if (ruid != p->p_ruid && ruid != u.u_cred->cr_uid /* XXX */ &&
34643393Skarels 	    (error = suser(u.u_cred, &u.u_acflag)))
347*44405Skarels 		return (error);
34843393Skarels 	if (uap->euid == -1)
34940667Skarels 		euid = u.u_cred->cr_uid;
35043393Skarels 	else
35143393Skarels 		euid = uap->euid;
35240667Skarels 	if (euid != u.u_cred->cr_uid && euid != p->p_ruid &&
35343393Skarels 	    euid != p->p_svuid && (error = suser(u.u_cred, &u.u_acflag)))
354*44405Skarels 		return (error);
3559160Ssam 	/*
3569160Ssam 	 * Everything's okay, do it.
35737578Smckusick 	 * Copy credentials so other references do not
35837578Smckusick 	 * see our changes.
3599160Ssam 	 */
36037578Smckusick 	if (u.u_cred->cr_ref > 1)
36137578Smckusick 		u.u_cred = crcopy(u.u_cred);
36240667Skarels 	u.u_cred->cr_uid = euid;
36340667Skarels 	p->p_uid = euid;
36440667Skarels 	p->p_ruid = ruid;
365*44405Skarels 	return (0);
3669160Ssam }
3679160Ssam 
36843393Skarels /* ARGSUSED */
36943393Skarels osetregid(p, uap, retval)
37043393Skarels 	struct proc *p;
37143393Skarels 	struct args {
3729160Ssam 		int	rgid;
3739160Ssam 		int	egid;
3749160Ssam 	} *uap;
37543393Skarels 	int *retval;
37643393Skarels {
37743393Skarels 	register gid_t rgid, egid;
37843393Skarels 	int error;
3799160Ssam 
38043393Skarels 	if (uap->rgid == -1)
38140667Skarels 		rgid = p->p_rgid;
38243393Skarels 	else
38343393Skarels 		rgid = uap->rgid;
38443393Skarels 	/*
38543393Skarels 	 * Allow setting real gid to previous effective,
38643393Skarels 	 * for swapping real and effective.  This didn't really work
38743393Skarels 	 * correctly in 4.[23], but is preserved so old stuff doesn't fail.
38843393Skarels 	 * This should be:
38943393Skarels 	 *  if (rgid != p->p_rgid && (error = suser(u.u_cred, &u.u_acflag)))
39043393Skarels 	 */
39140667Skarels 	if (rgid != p->p_rgid && rgid != u.u_cred->cr_groups[0] /* XXX */ &&
39243393Skarels 	    (error = suser(u.u_cred, &u.u_acflag)))
393*44405Skarels 		return (error);
39443393Skarels 	if (uap->egid == -1)
39540667Skarels 		egid = u.u_cred->cr_groups[0];
39643393Skarels 	else
39743393Skarels 		egid = uap->egid;
39840667Skarels 	if (egid != u.u_cred->cr_groups[0] && egid != p->p_rgid &&
39943393Skarels 	    egid != p->p_svgid && (error = suser(u.u_cred, &u.u_acflag)))
400*44405Skarels 		return (error);
40137578Smckusick 	if (u.u_cred->cr_ref > 1)
40237578Smckusick 		u.u_cred = crcopy(u.u_cred);
40340667Skarels 	p->p_rgid = rgid;
40440667Skarels 	u.u_cred->cr_groups[0] = egid;
405*44405Skarels 	return (0);
4069160Ssam }
40743393Skarels #endif
4089160Ssam 
40943393Skarels /* ARGSUSED */
41043393Skarels setgroups(p, uap, retval)
41143393Skarels 	struct proc *p;
41243393Skarels 	struct args {
4138624Sroot 		u_int	gidsetsize;
4147498Sroot 		int	*gidset;
41543393Skarels 	} *uap;
41643393Skarels 	int *retval;
41743393Skarels {
41818362Skarels 	register gid_t *gp;
41918362Skarels 	register int *lp;
42043393Skarels 	int error, ngrp, groups[NGROUPS];
4217498Sroot 
42243393Skarels 	if (error = suser(u.u_cred, &u.u_acflag))
423*44405Skarels 		return (error);
42440667Skarels 	ngrp = uap->gidsetsize;
42543393Skarels 	if (ngrp > NGROUPS)
426*44405Skarels 		return (EINVAL);
42743393Skarels 	error = copyin((caddr_t)uap->gidset, (caddr_t)groups,
42818362Skarels 	    uap->gidsetsize * sizeof (groups[0]));
42943393Skarels 	if (error)
430*44405Skarels 		return (error);
43140667Skarels 	gp = u.u_cred->cr_groups;
43237578Smckusick 	for (lp = groups; lp < &groups[uap->gidsetsize]; )
43318362Skarels 		*gp++ = *lp++;
43440667Skarels 	u.u_cred->cr_ngroups = ngrp;
435*44405Skarels 	return (0);
4367498Sroot }
4377498Sroot 
4387498Sroot /*
43937578Smckusick  * Check if gid is a member of the group set.
44011810Ssam  */
44137578Smckusick groupmember(gid, cred)
44226275Skarels 	gid_t gid;
44337578Smckusick 	register struct ucred *cred;
4447866Sroot {
44518362Skarels 	register gid_t *gp;
44637578Smckusick 	gid_t *egp;
4477866Sroot 
44837578Smckusick 	egp = &(cred->cr_groups[cred->cr_ngroups]);
44937578Smckusick 	for (gp = cred->cr_groups; gp < egp; gp++)
4507866Sroot 		if (*gp == gid)
45137578Smckusick 			return (1);
45237578Smckusick 	return (0);
4537866Sroot }
4547866Sroot 
45511810Ssam /*
45637578Smckusick  * Test if the current user is the super user.
45711810Ssam  */
45837578Smckusick suser(cred, acflag)
45937578Smckusick 	struct ucred *cred;
46037578Smckusick 	short *acflag;
4617866Sroot {
4627866Sroot 
46337578Smckusick 	if (cred->cr_uid == 0) {
46437578Smckusick 		if (acflag)
46537578Smckusick 			*acflag |= ASU;
46637578Smckusick 		return (0);
46718362Skarels 	}
46837578Smckusick 	return (EPERM);
4697866Sroot }
47011810Ssam 
47111810Ssam /*
47237578Smckusick  * Allocate a zeroed cred structure.
47311810Ssam  */
47437578Smckusick struct ucred *
47537578Smckusick crget()
47611810Ssam {
47737578Smckusick 	register struct ucred *cr;
47811810Ssam 
47937578Smckusick 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
48037578Smckusick 	bzero((caddr_t)cr, sizeof(*cr));
48137578Smckusick 	cr->cr_ref = 1;
48243393Skarels 	return (cr);
48311810Ssam }
48437085Skfall 
48537085Skfall /*
48637578Smckusick  * Free a cred structure.
48737578Smckusick  * Throws away space when ref count gets to 0.
48837085Skfall  */
48937578Smckusick crfree(cr)
49037578Smckusick 	struct ucred *cr;
49137578Smckusick {
49243393Skarels 	int s = splimp();
49337085Skfall 
49437578Smckusick 	if (--cr->cr_ref != 0) {
49537578Smckusick 		(void) splx(s);
49637578Smckusick 		return;
49737578Smckusick 	}
49837578Smckusick 	FREE((caddr_t)cr, M_CRED);
49937578Smckusick 	(void) splx(s);
50037578Smckusick }
50137578Smckusick 
50237578Smckusick /*
50337578Smckusick  * Copy cred structure to a new one and free the old one.
50437578Smckusick  */
50537578Smckusick struct ucred *
50637578Smckusick crcopy(cr)
50737578Smckusick 	struct ucred *cr;
50837085Skfall {
50937578Smckusick 	struct ucred *newcr;
51037085Skfall 
51137578Smckusick 	newcr = crget();
51237578Smckusick 	*newcr = *cr;
51337578Smckusick 	crfree(cr);
51437578Smckusick 	newcr->cr_ref = 1;
51543393Skarels 	return (newcr);
51637085Skfall }
51737085Skfall 
51837085Skfall /*
51937578Smckusick  * Dup cred struct to a new held one.
52037085Skfall  */
52137578Smckusick struct ucred *
52237578Smckusick crdup(cr)
52337578Smckusick 	struct ucred *cr;
52437085Skfall {
52537578Smckusick 	struct ucred *newcr;
52637085Skfall 
52737578Smckusick 	newcr = crget();
52837578Smckusick 	*newcr = *cr;
52937578Smckusick 	newcr->cr_ref = 1;
53043393Skarels 	return (newcr);
53137085Skfall }
53237579Smckusick 
53337579Smckusick /*
53440667Skarels  * Get login name, if available.
53537579Smckusick  */
53643393Skarels /* ARGSUSED */
53743393Skarels getlogin(p, uap, retval)
53843393Skarels 	struct proc *p;
53943393Skarels 	struct args {
54037579Smckusick 		char	*namebuf;
54137579Smckusick 		u_int	namelen;
54243393Skarels 	} *uap;
54343393Skarels 	int *retval;
54443393Skarels {
54537579Smckusick 
54643393Skarels 	if (uap->namelen > sizeof (p->p_logname))
54743393Skarels 		uap->namelen = sizeof (p->p_logname);
548*44405Skarels 	return (copyout((caddr_t)p->p_logname, (caddr_t)uap->namebuf,
54943393Skarels 	    uap->namelen));
55037579Smckusick }
55137579Smckusick 
55237579Smckusick /*
55340667Skarels  * Set login name.
55437579Smckusick  */
55543393Skarels /* ARGSUSED */
55643393Skarels setlogin(p, uap, retval)
55743393Skarels 	struct proc *p;
55843393Skarels 	struct args {
55943393Skarels 		char	*namebuf;
56043393Skarels 	} *uap;
56143393Skarels 	int *retval;
56237579Smckusick {
56340667Skarels 	int error;
56437579Smckusick 
56543393Skarels 	if (error = suser(u.u_cred, &u.u_acflag))
566*44405Skarels 		return (error);
56743393Skarels 	error = copyinstr((caddr_t)uap->namebuf, (caddr_t)p->p_logname,
56843393Skarels 	    sizeof (p->p_logname) - 1, (int *) 0);
56940667Skarels 	if (error == ENOENT)		/* name too long */
57040667Skarels 		error = EINVAL;
571*44405Skarels 	return (error);
57237579Smckusick }
573