kern_prot.c revision 8135
1193323Sed/*
2193323Sed * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
3193323Sed *	The Regents of the University of California.  All rights reserved.
4193323Sed * (c) UNIX System Laboratories, Inc.
5193323Sed * All or some portions of this file are derived from material licensed
6193323Sed * to the University of California by American Telephone and Telegraph
7193323Sed * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8193323Sed * the permission of UNIX System Laboratories, Inc.
9193323Sed *
10193323Sed * Redistribution and use in source and binary forms, with or without
11193323Sed * modification, are permitted provided that the following conditions
12193323Sed * are met:
13193323Sed * 1. Redistributions of source code must retain the above copyright
14193323Sed *    notice, this list of conditions and the following disclaimer.
15193323Sed * 2. Redistributions in binary form must reproduce the above copyright
16193323Sed *    notice, this list of conditions and the following disclaimer in the
17193323Sed *    documentation and/or other materials provided with the distribution.
18198090Srdivacky * 3. All advertising materials mentioning features or use of this software
19198090Srdivacky *    must display the following acknowledgement:
20193323Sed *	This product includes software developed by the University of
21193323Sed *	California, Berkeley and its contributors.
22193323Sed * 4. Neither the name of the University nor the names of its contributors
23193323Sed *    may be used to endorse or promote products derived from this software
24249423Sdim *    without specific prior written permission.
25198090Srdivacky *
26198090Srdivacky * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27193323Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28193323Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29193323Sed * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30193323Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31193323Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32193323Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33193323Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34202375Srdivacky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35198090Srdivacky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36202375Srdivacky * SUCH DAMAGE.
37193323Sed *
38193323Sed *	@(#)kern_prot.c	8.6 (Berkeley) 1/21/94
39193323Sed * $Id: kern_prot.c,v 1.8 1995/04/27 19:23:24 ache Exp $
40193323Sed */
41193323Sed
42202375Srdivacky/*
43198090Srdivacky * System calls related to processes and protection
44202375Srdivacky */
45193323Sed
46226633Sdim#include <sys/param.h>
47226633Sdim#include <sys/acct.h>
48193323Sed#include <sys/systm.h>
49226633Sdim#include <sys/ucred.h>
50218893Sdim#include <sys/proc.h>
51239462Sdim#include <sys/timeb.h>
52193323Sed#include <sys/times.h>
53193323Sed#include <sys/malloc.h>
54221345Sdim
55202375Srdivackystruct args {
56193323Sed	int	dummy;
57193323Sed};
58193323Sed
59193323Sed/* ARGSUSED */
60202375Srdivackyint
61234353Sdimgetpid(p, uap, retval)
62193323Sed	struct proc *p;
63193323Sed	struct args *uap;
64198090Srdivacky	int *retval;
65193323Sed{
66193323Sed
67221345Sdim	*retval = p->p_pid;
68193323Sed#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
69193323Sed	retval[1] = p->p_pptr->p_pid;
70193323Sed#endif
71193323Sed	return (0);
72221345Sdim}
73193323Sed
74221345Sdim/* ARGSUSED */
75221345Sdimint
76221345Sdimgetppid(p, uap, retval)
77221345Sdim	struct proc *p;
78221345Sdim	struct args *uap;
79221345Sdim	int *retval;
80221345Sdim{
81193323Sed
82221345Sdim	*retval = p->p_pptr->p_pid;
83193323Sed	return (0);
84193323Sed}
85221345Sdim
86193323Sed/* Get process group ID; note that POSIX getpgrp takes no parameter */
87193323Sedint
88193323Sedgetpgrp(p, uap, retval)
89221345Sdim	struct proc *p;
90193323Sed	struct args *uap;
91193323Sed	int *retval;
92221345Sdim{
93198090Srdivacky
94198090Srdivacky	*retval = p->p_pgrp->pg_id;
95198090Srdivacky	return (0);
96193323Sed}
97193323Sed
98193323Sed/* ARGSUSED */
99193323Sedint
100193323Sedgetuid(p, uap, retval)
101193323Sed	struct proc *p;
102193323Sed	struct args *uap;
103193323Sed	int *retval;
104193323Sed{
105193323Sed
106193323Sed	*retval = p->p_cred->p_ruid;
107193323Sed#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
108193323Sed	retval[1] = p->p_ucred->cr_uid;
109193323Sed#endif
110193323Sed	return (0);
111193323Sed}
112198090Srdivacky
113193323Sed/* ARGSUSED */
114193323Sedint
115198090Srdivackygeteuid(p, uap, retval)
116198090Srdivacky	struct proc *p;
117198090Srdivacky	struct args *uap;
118239462Sdim	int *retval;
119239462Sdim{
120239462Sdim
121193323Sed	*retval = p->p_ucred->cr_uid;
122193323Sed	return (0);
123193323Sed}
124193323Sed
125193323Sed/* ARGSUSED */
126193323Sedint
127193323Sedgetgid(p, uap, retval)
128193323Sed	struct proc *p;
129193323Sed	struct args *uap;
130193323Sed	int *retval;
131193323Sed{
132193323Sed
133193323Sed	*retval = p->p_cred->p_rgid;
134193323Sed#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
135239462Sdim	retval[1] = p->p_ucred->cr_groups[0];
136239462Sdim#endif
137239462Sdim	return (0);
138239462Sdim}
139239462Sdim
140239462Sdim/*
141239462Sdim * Get effective group ID.  The "egid" is groups[0], and could be obtained
142239462Sdim * via getgroups.  This syscall exists because it is somewhat painful to do
143226633Sdim * correctly in a library function.
144226633Sdim */
145226633Sdim/* ARGSUSED */
146226633Sdimint
147226633Sdimgetegid(p, uap, retval)
148226633Sdim	struct proc *p;
149218893Sdim	struct args *uap;
150198090Srdivacky	int *retval;
151218893Sdim{
152193323Sed
153193323Sed	*retval = p->p_ucred->cr_groups[0];
154193323Sed	return (0);
155239462Sdim}
156239462Sdim
157239462Sdimstruct getgroups_args {
158239462Sdim	u_int	gidsetsize;
159239462Sdim	gid_t	*gidset;
160239462Sdim};
161239462Sdimint
162239462Sdimgetgroups(p, uap, retval)
163239462Sdim	struct proc *p;
164239462Sdim	register struct	getgroups_args *uap;
165193323Sed	int *retval;
166198090Srdivacky{
167193323Sed	register struct pcred *pc = p->p_cred;
168193323Sed	register u_int ngrp;
169193323Sed	int error;
170193323Sed
171193323Sed	if ((ngrp = uap->gidsetsize) == 0) {
172193323Sed		*retval = pc->pc_ucred->cr_ngroups;
173193323Sed		return (0);
174193323Sed	}
175193323Sed	if (ngrp < pc->pc_ucred->cr_ngroups)
176193323Sed		return (EINVAL);
177193323Sed	ngrp = pc->pc_ucred->cr_ngroups;
178193323Sed	if ((error = copyout((caddr_t)pc->pc_ucred->cr_groups,
179193323Sed	    (caddr_t)uap->gidset, ngrp * sizeof(gid_t))))
180193323Sed		return (error);
181193323Sed	*retval = ngrp;
182221345Sdim	return (0);
183221345Sdim}
184221345Sdim
185221345Sdim/* ARGSUSED */
186221345Sdimint
187221345Sdimsetsid(p, uap, retval)
188221345Sdim	register struct proc *p;
189193323Sed	struct args *uap;
190193323Sed	int *retval;
191193323Sed{
192193323Sed
193193323Sed	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
194193323Sed		return (EPERM);
195193323Sed	} else {
196193323Sed		(void)enterpgrp(p, p->p_pid, 1);
197193323Sed		*retval = p->p_pid;
198193323Sed		return (0);
199198090Srdivacky	}
200193323Sed}
201193323Sed
202193323Sed/*
203193323Sed * set process group (setpgid/old setpgrp)
204193323Sed *
205193323Sed * caller does setpgid(targpid, targpgid)
206193323Sed *
207193323Sed * pid must be caller or child of caller (ESRCH)
208193323Sed * if a child
209210299Sed *	pid must be in same session (EPERM)
210193323Sed *	pid can't have done an exec (EACCES)
211193323Sed * if pgid != pid
212210299Sed * 	there must exist some pid in same session having pgid (EPERM)
213193323Sed * pid must not be session leader (EPERM)
214193323Sed */
215218893Sdimstruct setpgid_args {
216193323Sed	int	pid;	/* target process id */
217203954Srdivacky	int	pgid;	/* target pgrp id */
218234353Sdim};
219193323Sed/* ARGSUSED */
220193323Sedint
221193323Sedsetpgid(curp, uap, retval)
222193323Sed	struct proc *curp;
223193323Sed	register struct setpgid_args *uap;
224193323Sed	int *retval;
225193323Sed{
226193323Sed	register struct proc *targp;		/* target process */
227193323Sed	register struct pgrp *pgrp;		/* target pgrp */
228198090Srdivacky
229193323Sed	if (uap->pid != 0 && uap->pid != curp->p_pid) {
230193323Sed		if ((targp = pfind(uap->pid)) == 0 || !inferior(targp))
231193323Sed			return (ESRCH);
232193323Sed		if (targp->p_session != curp->p_session)
233202375Srdivacky			return (EPERM);
234202375Srdivacky		if (targp->p_flag & P_EXEC)
235202375Srdivacky			return (EACCES);
236202375Srdivacky	} else
237202375Srdivacky		targp = curp;
238202375Srdivacky	if (SESS_LEADER(targp))
239202375Srdivacky		return (EPERM);
240202375Srdivacky	if (uap->pgid == 0)
241193323Sed		uap->pgid = targp->p_pid;
242193323Sed	else if (uap->pgid != targp->p_pid)
243193323Sed		if ((pgrp = pgfind(uap->pgid)) == 0 ||
244198090Srdivacky	            pgrp->pg_session != curp->p_session)
245193323Sed			return (EPERM);
246193323Sed	return (enterpgrp(targp, uap->pgid, 0));
247193323Sed}
248193323Sed
249193323Sedstruct setuid_args {
250193323Sed	uid_t	uid;
251234353Sdim};
252234353Sdim/* ARGSUSED */
253234353Sdimint
254234353Sdimsetuid(p, uap, retval)
255234353Sdim	struct proc *p;
256234353Sdim	struct setuid_args *uap;
257234353Sdim	int *retval;
258234353Sdim{
259234353Sdim	register struct pcred *pc = p->p_cred;
260234353Sdim	register uid_t uid;
261234353Sdim	int error;
262234353Sdim
263234353Sdim	uid = uap->uid;
264234353Sdim	if (uid != pc->p_ruid &&
265234353Sdim	    (error = suser(pc->pc_ucred, &p->p_acflag)))
266234353Sdim		return (error);
267234353Sdim	/*
268234353Sdim	 * Everything's okay, do it.
269234353Sdim	 * Transfer proc count to new user.
270234353Sdim	 * Copy credentials so other references do not see our changes.
271234353Sdim	 */
272234353Sdim	(void)chgproccnt(pc->p_ruid, -1);
273234353Sdim	(void)chgproccnt(uid, 1);
274234353Sdim	pc->pc_ucred = crcopy(pc->pc_ucred);
275234353Sdim	pc->pc_ucred->cr_uid = uid;
276234353Sdim	pc->p_ruid = uid;
277234353Sdim	pc->p_svuid = uid;
278234353Sdim	p->p_flag |= P_SUGID;
279234353Sdim	return (0);
280234353Sdim}
281234353Sdim
282193323Sedstruct seteuid_args {
283193323Sed	uid_t	euid;
284193323Sed};
285193323Sed/* ARGSUSED */
286193323Sedint
287193323Sedseteuid(p, uap, retval)
288193323Sed	struct proc *p;
289193323Sed	struct seteuid_args *uap;
290193323Sed	int *retval;
291193323Sed{
292193323Sed	register struct pcred *pc = p->p_cred;
293193323Sed	register uid_t euid;
294193323Sed	int error;
295193323Sed
296193323Sed	euid = uap->euid;
297198090Srdivacky	if (euid != pc->p_ruid && euid != pc->p_svuid &&
298226633Sdim	    (error = suser(pc->pc_ucred, &p->p_acflag)))
299226633Sdim		return (error);
300226633Sdim	/*
301226633Sdim	 * Everything's okay, do it.  Copy credentials so other references do
302226633Sdim	 * not see our changes.
303226633Sdim	 */
304198090Srdivacky	pc->pc_ucred = crcopy(pc->pc_ucred);
305198090Srdivacky	pc->pc_ucred->cr_uid = euid;
306198090Srdivacky	p->p_flag |= P_SUGID;
307198090Srdivacky	return (0);
308198090Srdivacky}
309198090Srdivacky
310198090Srdivackystruct setgid_args {
311198090Srdivacky	gid_t	gid;
312193323Sed};
313193323Sed/* ARGSUSED */
314193323Sedint
315193323Sedsetgid(p, uap, retval)
316193323Sed	struct proc *p;
317193323Sed	struct setgid_args *uap;
318193323Sed	int *retval;
319193323Sed{
320193323Sed	register struct pcred *pc = p->p_cred;
321193323Sed	register gid_t gid;
322193323Sed	int error;
323193323Sed
324193323Sed	gid = uap->gid;
325193323Sed	if (gid != pc->p_rgid && (error = suser(pc->pc_ucred, &p->p_acflag)))
326226633Sdim		return (error);
327226633Sdim	pc->pc_ucred = crcopy(pc->pc_ucred);
328226633Sdim	pc->pc_ucred->cr_groups[0] = gid;
329226633Sdim	pc->p_rgid = gid;
330193323Sed	pc->p_svgid = gid;		/* ??? */
331193323Sed	p->p_flag |= P_SUGID;
332198090Srdivacky	return (0);
333198090Srdivacky}
334193323Sed
335193323Sedstruct setegid_args {
336226633Sdim	gid_t	egid;
337226633Sdim};
338226633Sdim/* ARGSUSED */
339226633Sdimint
340226633Sdimsetegid(p, uap, retval)
341226633Sdim	struct proc *p;
342226633Sdim	struct setegid_args *uap;
343193323Sed	int *retval;
344193323Sed{
345193323Sed	register struct pcred *pc = p->p_cred;
346193323Sed	register gid_t egid;
347193323Sed	int error;
348193323Sed
349193323Sed	egid = uap->egid;
350193323Sed	if (egid != pc->p_rgid && egid != pc->p_svgid &&
351202375Srdivacky	    (error = suser(pc->pc_ucred, &p->p_acflag)))
352198090Srdivacky		return (error);
353202375Srdivacky	pc->pc_ucred = crcopy(pc->pc_ucred);
354193323Sed	pc->pc_ucred->cr_groups[0] = egid;
355193323Sed	p->p_flag |= P_SUGID;
356193323Sed	return (0);
357193323Sed}
358193323Sed
359193323Sedstruct setgroups_args {
360202375Srdivacky	u_int	gidsetsize;
361198090Srdivacky	gid_t	*gidset;
362202375Srdivacky};
363193323Sed/* ARGSUSED */
364198090Srdivackyint
365218893Sdimsetgroups(p, uap, retval)
366218893Sdim	struct proc *p;
367198090Srdivacky	struct setgroups_args *uap;
368249423Sdim	int *retval;
369249423Sdim{
370249423Sdim	register struct pcred *pc = p->p_cred;
371249423Sdim	register u_int ngrp;
372249423Sdim	int error;
373193323Sed
374198090Srdivacky	if ((error = suser(pc->pc_ucred, &p->p_acflag)))
375198090Srdivacky		return (error);
376193323Sed	if ((ngrp = uap->gidsetsize) > NGROUPS)
377198090Srdivacky		return (EINVAL);
378198090Srdivacky	pc->pc_ucred = crcopy(pc->pc_ucred);
379193323Sed	if ((error = copyin((caddr_t)uap->gidset,
380198090Srdivacky	    (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t))))
381198090Srdivacky		return (error);
382193323Sed	pc->pc_ucred->cr_ngroups = ngrp;
383193323Sed	p->p_flag |= P_SUGID;
384193323Sed	return (0);
385193323Sed}
386193323Sed
387193323Sedstruct setreuid_args {
388193323Sed	int	ruid;
389193323Sed	int	euid;
390193323Sed};
391193323Sed/* ARGSUSED */
392193323Sedint
393193323Sedsetreuid(p, uap, retval)
394193323Sed	register struct proc *p;
395193323Sed	struct setreuid_args *uap;
396193323Sed	int *retval;
397193323Sed{
398193323Sed	register struct pcred *pc = p->p_cred;
399193323Sed	struct seteuid_args args;
400218893Sdim	int error;
401193323Sed
402218893Sdim	if (uap->ruid != (uid_t)-1 && uap->ruid != pc->p_ruid &&
403193323Sed	    uap->ruid != pc->p_svuid &&
404218893Sdim	    (error = suser(pc->pc_ucred, &p->p_acflag)))
405193323Sed		return (error);
406193323Sed	if (uap->euid != (uid_t)-1 && pc->pc_ucred->cr_uid != uap->euid) {
407193323Sed		args.euid = uap->euid;
408249423Sdim		if ((error = seteuid(p, &args, retval)))
409249423Sdim			return (error);
410249423Sdim		if (pc->pc_ucred->cr_uid != pc->p_ruid)
411249423Sdim			pc->p_svuid = pc->pc_ucred->cr_uid;
412249423Sdim	}
413249423Sdim	if (uap->ruid != (uid_t)-1 && uap->ruid != pc->p_ruid) {
414249423Sdim		(void)chgproccnt(pc->p_ruid, -1);
415249423Sdim		(void)chgproccnt(uap->ruid, 1);
416249423Sdim		pc->p_ruid = uap->ruid;
417249423Sdim		pc->p_svuid = pc->pc_ucred->cr_uid;
418249423Sdim		p->p_flag |= P_SUGID;
419249423Sdim	}
420249423Sdim	return (0);
421249423Sdim}
422249423Sdim
423193323Sedstruct setregid_args {
424193323Sed	int	rgid;
425193323Sed	int	egid;
426193323Sed};
427193323Sed/* ARGSUSED */
428193323Sedint
429193323Sedsetregid(p, uap, retval)
430193323Sed	register struct proc *p;
431193323Sed	struct setregid_args *uap;
432193323Sed	int *retval;
433193323Sed{
434193323Sed	register struct pcred *pc = p->p_cred;
435193323Sed	struct setegid_args args;
436193323Sed	int error;
437198090Srdivacky
438198090Srdivacky	if (uap->rgid != (gid_t)-1 && uap->rgid != pc->p_rgid &&
439198090Srdivacky	    uap->rgid != pc->p_svgid &&
440198090Srdivacky	    (error = suser(pc->pc_ucred, &p->p_acflag)))
441198090Srdivacky		return (error);
442193323Sed	if (uap->egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != uap->egid) {
443193323Sed		args.egid = uap->egid;
444193323Sed		if ((error = setegid(p, &args, retval)))
445193323Sed			return (error);
446193323Sed		if (pc->pc_ucred->cr_groups[0] != pc->p_rgid)
447193323Sed			pc->p_svgid = pc->pc_ucred->cr_groups[0];
448193323Sed	}
449193323Sed	if (uap->rgid != (gid_t)-1 && uap->rgid != pc->p_rgid) {
450193323Sed		pc->p_rgid = uap->rgid;
451193323Sed		pc->p_svgid = pc->pc_ucred->cr_groups[0];
452193323Sed		p->p_flag |= P_SUGID;
453193323Sed	}
454218893Sdim	return (0);
455193323Sed}
456203954Srdivacky
457203954Srdivacky/*
458193323Sed * Check if gid is a member of the group set.
459193323Sed */
460218893Sdimint
461203954Srdivackygroupmember(gid, cred)
462203954Srdivacky	gid_t gid;
463193323Sed	register struct ucred *cred;
464193323Sed{
465193323Sed	register gid_t *gp;
466193323Sed	gid_t *egp;
467193323Sed
468193323Sed	egp = &(cred->cr_groups[cred->cr_ngroups]);
469193323Sed	for (gp = cred->cr_groups; gp < egp; gp++)
470193323Sed		if (*gp == gid)
471193323Sed			return (1);
472193323Sed	return (0);
473193323Sed}
474193323Sed
475193323Sed/*
476202375Srdivacky * Test whether the specified credentials imply "super-user"
477198090Srdivacky * privilege; if so, and we have accounting info, set the flag
478202375Srdivacky * indicating use of super-powers.
479193323Sed * Returns 0 or error.
480239462Sdim */
481234353Sdimint
482234353Sdimsuser(cred, acflag)
483234353Sdim	struct ucred *cred;
484193323Sed	u_short *acflag;
485193323Sed{
486193323Sed	if (cred->cr_uid == 0) {
487193323Sed		if (acflag)
488202375Srdivacky			*acflag |= ASU;
489198090Srdivacky		return (0);
490202375Srdivacky	}
491193323Sed	return (EPERM);
492239462Sdim}
493239462Sdim
494193323Sed/*
495226633Sdim * Allocate a zeroed cred structure.
496226633Sdim */
497193323Sedstruct ucred *
498193323Sedcrget()
499193323Sed{
500218893Sdim	register struct ucred *cr;
501193323Sed
502193323Sed	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
503193323Sed	bzero((caddr_t)cr, sizeof(*cr));
504202375Srdivacky	cr->cr_ref = 1;
505193323Sed	return (cr);
506193323Sed}
507193323Sed
508202375Srdivacky/*
509198090Srdivacky * Free a cred structure.
510198090Srdivacky * Throws away space when ref count gets to 0.
511198090Srdivacky */
512198090Srdivackyvoid
513198090Srdivackycrfree(cr)
514198090Srdivacky	struct ucred *cr;
515193323Sed{
516198090Srdivacky	int s;
517198090Srdivacky
518193323Sed	s = splimp();				/* ??? */
519221345Sdim	if (--cr->cr_ref == 0)
520221345Sdim		FREE((caddr_t)cr, M_CRED);
521193323Sed	(void) splx(s);
522234353Sdim}
523234353Sdim
524234353Sdim/*
525193323Sed * Copy cred structure to a new one and free the old one.
526193323Sed */
527221345Sdimstruct ucred *
528193323Sedcrcopy(cr)
529221345Sdim	struct ucred *cr;
530221345Sdim{
531193323Sed	struct ucred *newcr;
532221345Sdim
533221345Sdim	if (cr->cr_ref == 1)
534221345Sdim		return (cr);
535193323Sed	newcr = crget();
536221345Sdim	*newcr = *cr;
537221345Sdim	crfree(cr);
538221345Sdim	newcr->cr_ref = 1;
539193323Sed	return (newcr);
540193323Sed}
541221345Sdim
542221345Sdim/*
543221345Sdim * Dup cred struct to a new held one.
544221345Sdim */
545221345Sdimstruct ucred *
546193323Sedcrdup(cr)
547221345Sdim	struct ucred *cr;
548198090Srdivacky{
549198090Srdivacky	struct ucred *newcr;
550198090Srdivacky
551198090Srdivacky	newcr = crget();
552193323Sed	*newcr = *cr;
553193323Sed	newcr->cr_ref = 1;
554193323Sed	return (newcr);
555193323Sed}
556193323Sed
557193323Sed/*
558193323Sed * Get login name, if available.
559193323Sed */
560193323Sedstruct getlogin_args {
561193323Sed	char	*namebuf;
562193323Sed	u_int	namelen;
563193323Sed};
564193323Sed/* ARGSUSED */
565193323Sedint
566193323Sedgetlogin(p, uap, retval)
567193323Sed	struct proc *p;
568193323Sed	struct getlogin_args *uap;
569193323Sed	int *retval;
570193323Sed{
571198090Srdivacky
572198090Srdivacky	if (uap->namelen > sizeof (p->p_pgrp->pg_session->s_login))
573198090Srdivacky		uap->namelen = sizeof (p->p_pgrp->pg_session->s_login);
574239462Sdim	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
575239462Sdim	    (caddr_t) uap->namebuf, uap->namelen));
576239462Sdim}
577193323Sed
578193323Sed/*
579193323Sed * Set login name.
580193323Sed */
581193323Sedstruct setlogin_args {
582193323Sed	char	*namebuf;
583193323Sed};
584193323Sed/* ARGSUSED */
585193323Sedint
586193323Sedsetlogin(p, uap, retval)
587193323Sed	struct proc *p;
588193323Sed	struct setlogin_args *uap;
589193323Sed	int *retval;
590193323Sed{
591193323Sed	int error;
592193323Sed
593193323Sed	if ((error = suser(p->p_ucred, &p->p_acflag)))
594193323Sed		return (error);
595193323Sed	error = copyinstr((caddr_t) uap->namebuf,
596239462Sdim	    (caddr_t) p->p_pgrp->pg_session->s_login,
597239462Sdim	    sizeof (p->p_pgrp->pg_session->s_login) - 1, (u_int *)0);
598239462Sdim	if (error == ENAMETOOLONG)
599239462Sdim		error = EINVAL;
600239462Sdim	return (error);
601239462Sdim}
602239462Sdim