Home | History | Annotate | Line # | Download | only in kern
kern_prot.c revision 1.58
      1 /*	$NetBSD: kern_prot.c,v 1.58 2000/05/27 00:40:46 sommerfeld Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  * (c) UNIX System Laboratories, Inc.
      7  * All or some portions of this file are derived from material licensed
      8  * to the University of California by American Telephone and Telegraph
      9  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
     10  * the permission of UNIX System Laboratories, Inc.
     11  *
     12  * Redistribution and use in source and binary forms, with or without
     13  * modification, are permitted provided that the following conditions
     14  * are met:
     15  * 1. Redistributions of source code must retain the above copyright
     16  *    notice, this list of conditions and the following disclaimer.
     17  * 2. Redistributions in binary form must reproduce the above copyright
     18  *    notice, this list of conditions and the following disclaimer in the
     19  *    documentation and/or other materials provided with the distribution.
     20  * 3. All advertising materials mentioning features or use of this software
     21  *    must display the following acknowledgement:
     22  *	This product includes software developed by the University of
     23  *	California, Berkeley and its contributors.
     24  * 4. Neither the name of the University nor the names of its contributors
     25  *    may be used to endorse or promote products derived from this software
     26  *    without specific prior written permission.
     27  *
     28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     38  * SUCH DAMAGE.
     39  *
     40  *	@(#)kern_prot.c	8.9 (Berkeley) 2/14/95
     41  */
     42 
     43 /*
     44  * System calls related to processes and protection
     45  */
     46 
     47 #include "opt_compat_freebsd.h"
     48 #include "opt_compat_ibcs2.h"
     49 #include "opt_compat_sunos.h"
     50 #include "opt_compat_linux.h"
     51 #include "opt_compat_43.h"
     52 #include "opt_compat_osf1.h"
     53 
     54 #include <sys/param.h>
     55 #include <sys/acct.h>
     56 #include <sys/systm.h>
     57 #include <sys/ucred.h>
     58 #include <sys/proc.h>
     59 #include <sys/timeb.h>
     60 #include <sys/times.h>
     61 #include <sys/malloc.h>
     62 
     63 #include <sys/mount.h>
     64 #include <sys/syscallargs.h>
     65 
     66 /* ARGSUSED */
     67 int
     68 sys_getpid(p, v, retval)
     69 	struct proc *p;
     70 	void *v;
     71 	register_t *retval;
     72 {
     73 
     74 	*retval = p->p_pid;
     75 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2) || \
     76     defined(COMPAT_FREEBSD) || defined(COMPAT_OSF1) || \
     77     (defined(COMPAT_LINUX) && defined(__alpha__))
     78 	retval[1] = p->p_pptr->p_pid;
     79 #endif
     80 	return (0);
     81 }
     82 
     83 /* ARGSUSED */
     84 int
     85 sys_getppid(p, v, retval)
     86 	struct proc *p;
     87 	void *v;
     88 	register_t *retval;
     89 {
     90 
     91 	*retval = p->p_pptr->p_pid;
     92 	return (0);
     93 }
     94 
     95 /* Get process group ID; note that POSIX getpgrp takes no parameter */
     96 int
     97 sys_getpgrp(p, v, retval)
     98 	struct proc *p;
     99 	void *v;
    100 	register_t *retval;
    101 {
    102 
    103 	*retval = p->p_pgrp->pg_id;
    104 	return (0);
    105 }
    106 
    107 /*
    108  * Return the process group ID of the session leader (session ID)
    109  * for the specified process.
    110  */
    111 int
    112 sys_getsid(p, v, retval)
    113 	struct proc *p;
    114 	void *v;
    115 	register_t *retval;
    116 {
    117 	struct sys_getsid_args /* {
    118 		syscalldarg(pid_t) pid;
    119 	} */ *uap = v;
    120 
    121 	if (SCARG(uap, pid) == 0)
    122 		goto found;
    123 	if ((p = pfind(SCARG(uap, pid))) == 0)
    124 		return (ESRCH);
    125 found:
    126 	*retval = p->p_session->s_sid;
    127 	return 0;
    128 }
    129 
    130 int
    131 sys_getpgid(p, v, retval)
    132 	struct proc *p;
    133 	void *v;
    134 	register_t *retval;
    135 {
    136 	struct sys_getpgid_args /* {
    137 		syscallarg(pid_t) pid;
    138 	} */ *uap = v;
    139 
    140 	if (SCARG(uap, pid) == 0)
    141 		goto found;
    142 	if ((p = pfind(SCARG(uap, pid))) == 0)
    143 		return (ESRCH);
    144 found:
    145 	*retval = p->p_pgid;
    146 	return 0;
    147 }
    148 
    149 /* ARGSUSED */
    150 int
    151 sys_getuid(p, v, retval)
    152 	struct proc *p;
    153 	void *v;
    154 	register_t *retval;
    155 {
    156 
    157 	*retval = p->p_cred->p_ruid;
    158 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2) || \
    159     defined(COMPAT_FREEBSD) || defined(COMPAT_OSF1) || \
    160     (defined(COMPAT_LINUX) && defined(__alpha__))
    161 	retval[1] = p->p_ucred->cr_uid;
    162 #endif
    163 	return (0);
    164 }
    165 
    166 /* ARGSUSED */
    167 int
    168 sys_geteuid(p, v, retval)
    169 	struct proc *p;
    170 	void *v;
    171 	register_t *retval;
    172 {
    173 
    174 	*retval = p->p_ucred->cr_uid;
    175 	return (0);
    176 }
    177 
    178 /* ARGSUSED */
    179 int
    180 sys_getgid(p, v, retval)
    181 	struct proc *p;
    182 	void *v;
    183 	register_t *retval;
    184 {
    185 
    186 	*retval = p->p_cred->p_rgid;
    187 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_FREEBSD) || \
    188     defined(COMPAT_OSF1) || (defined(COMPAT_LINUX) && defined(alpha))
    189 	retval[1] = p->p_ucred->cr_gid;
    190 #endif
    191 	return (0);
    192 }
    193 
    194 /*
    195  * Get effective group ID.  The "egid" is groups[0], and could be obtained
    196  * via getgroups.  This syscall exists because it is somewhat painful to do
    197  * correctly in a library function.
    198  */
    199 /* ARGSUSED */
    200 int
    201 sys_getegid(p, v, retval)
    202 	struct proc *p;
    203 	void *v;
    204 	register_t *retval;
    205 {
    206 
    207 	*retval = p->p_ucred->cr_gid;
    208 	return (0);
    209 }
    210 
    211 int
    212 sys_getgroups(p, v, retval)
    213 	struct proc *p;
    214 	void *v;
    215 	register_t *retval;
    216 {
    217 	struct sys_getgroups_args /* {
    218 		syscallarg(int) gidsetsize;
    219 		syscallarg(gid_t *) gidset;
    220 	} */ *uap = v;
    221 	struct pcred *pc = p->p_cred;
    222 	int ngrp;
    223 	int error;
    224 
    225 	ngrp = SCARG(uap, gidsetsize);
    226 	if (ngrp == 0) {
    227 		*retval = pc->pc_ucred->cr_ngroups;
    228 		return (0);
    229 	}
    230 	if (ngrp < pc->pc_ucred->cr_ngroups)
    231 		return (EINVAL);
    232 	ngrp = pc->pc_ucred->cr_ngroups;
    233 	error = copyout((caddr_t)pc->pc_ucred->cr_groups,
    234 			(caddr_t)SCARG(uap, gidset), ngrp * sizeof(gid_t));
    235 	if (error)
    236 		return (error);
    237 	*retval = ngrp;
    238 	return (0);
    239 }
    240 
    241 /* ARGSUSED */
    242 int
    243 sys_setsid(p, v, retval)
    244 	struct proc *p;
    245 	void *v;
    246 	register_t *retval;
    247 {
    248 
    249 	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
    250 		return (EPERM);
    251 	} else {
    252 		(void)enterpgrp(p, p->p_pid, 1);
    253 		*retval = p->p_pid;
    254 		return (0);
    255 	}
    256 }
    257 
    258 /*
    259  * set process group (setpgid/old setpgrp)
    260  *
    261  * caller does setpgid(targpid, targpgid)
    262  *
    263  * pgid must be in valid range (EINVAL)
    264  * pid must be caller or child of caller (ESRCH)
    265  * if a child
    266  *	pid must be in same session (EPERM)
    267  *	pid can't have done an exec (EACCES)
    268  * if pgid != pid
    269  * 	there must exist some pid in same session having pgid (EPERM)
    270  * pid must not be session leader (EPERM)
    271  */
    272 /* ARGSUSED */
    273 int
    274 sys_setpgid(curp, v, retval)
    275 	struct proc *curp;
    276 	void *v;
    277 	register_t *retval;
    278 {
    279 	struct sys_setpgid_args /* {
    280 		syscallarg(int) pid;
    281 		syscallarg(int) pgid;
    282 	} */ *uap = v;
    283 	struct proc *targp;			/* target process */
    284 	struct pgrp *pgrp;			/* target pgrp */
    285 
    286 	if (SCARG(uap, pgid) < 0)
    287 		return (EINVAL);
    288 
    289 	if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != curp->p_pid) {
    290 		if ((targp = pfind(SCARG(uap, pid))) == 0
    291 		    || !inferior(targp, curp))
    292 			return (ESRCH);
    293 		if (targp->p_session != curp->p_session)
    294 			return (EPERM);
    295 		if (targp->p_flag & P_EXEC)
    296 			return (EACCES);
    297 	} else
    298 		targp = curp;
    299 	if (SESS_LEADER(targp))
    300 		return (EPERM);
    301 	if (SCARG(uap, pgid) == 0)
    302 		SCARG(uap, pgid) = targp->p_pid;
    303 	else if (SCARG(uap, pgid) != targp->p_pid)
    304 		if ((pgrp = pgfind(SCARG(uap, pgid))) == 0 ||
    305 	            pgrp->pg_session != curp->p_session)
    306 			return (EPERM);
    307 	return (enterpgrp(targp, SCARG(uap, pgid), 0));
    308 }
    309 
    310 /* ARGSUSED */
    311 int
    312 sys_setuid(p, v, retval)
    313 	struct proc *p;
    314 	void *v;
    315 	register_t *retval;
    316 {
    317 	struct sys_setuid_args /* {
    318 		syscallarg(uid_t) uid;
    319 	} */ *uap = v;
    320 	struct pcred *pc = p->p_cred;
    321 	uid_t uid;
    322 	int error;
    323 
    324 	uid = SCARG(uap, uid);
    325 	if (uid != pc->p_ruid &&
    326 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
    327 		return (error);
    328 	/*
    329 	 * Everything's okay, do it.
    330 	 * Transfer proc count to new user.
    331 	 * Copy credentials so other references do not see our changes.
    332 	 */
    333 	(void)chgproccnt(pc->p_ruid, -1);
    334 	(void)chgproccnt(uid, 1);
    335 	pc->pc_ucred = crcopy(pc->pc_ucred);
    336 	pc->pc_ucred->cr_uid = uid;
    337 	pc->p_ruid = uid;
    338 	pc->p_svuid = uid;
    339 	p_sugid(p);
    340 	return (0);
    341 }
    342 
    343 /* ARGSUSED */
    344 int
    345 sys_seteuid(p, v, retval)
    346 	struct proc *p;
    347 	void *v;
    348 	register_t *retval;
    349 {
    350 	struct sys_seteuid_args /* {
    351 		syscallarg(uid_t) euid;
    352 	} */ *uap = v;
    353 	struct pcred *pc = p->p_cred;
    354 	uid_t euid;
    355 	int error;
    356 
    357 	euid = SCARG(uap, euid);
    358 	if (euid != pc->p_ruid && euid != pc->p_svuid &&
    359 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
    360 		return (error);
    361 	/*
    362 	 * Everything's okay, do it.  Copy credentials so other references do
    363 	 * not see our changes.
    364 	 */
    365 	pc->pc_ucred = crcopy(pc->pc_ucred);
    366 	pc->pc_ucred->cr_uid = euid;
    367 	p_sugid(p);
    368 	return (0);
    369 }
    370 
    371 int
    372 sys_setreuid(p, v, retval)
    373 	struct proc *p;
    374 	void *v;
    375 	register_t *retval;
    376 {
    377 	struct sys_setreuid_args /* {
    378 		syscallarg(uid_t) ruid;
    379 		syscallarg(uid_t) euid;
    380 	} */ *uap = v;
    381 	struct pcred *pc = p->p_cred;
    382 	uid_t ruid, euid;
    383 	int error;
    384 
    385 	ruid = SCARG(uap, ruid);
    386 	euid = SCARG(uap, euid);
    387 
    388 	if (ruid != (uid_t)-1 &&
    389 	    ruid != pc->p_ruid && ruid != pc->pc_ucred->cr_uid &&
    390 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
    391 		return (error);
    392 
    393 	if (euid != (uid_t)-1 &&
    394 	    euid != pc->p_ruid && euid != pc->pc_ucred->cr_uid &&
    395 	    euid != pc->p_svuid &&
    396 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
    397 		return (error);
    398 
    399 	if (euid != (uid_t)-1) {
    400 		pc->pc_ucred = crcopy(pc->pc_ucred);
    401 		pc->pc_ucred->cr_uid = euid;
    402 	}
    403 
    404 	if (ruid != (uid_t)-1) {
    405 		(void)chgproccnt(pc->p_ruid, -1);
    406 		(void)chgproccnt(ruid, 1);
    407 		pc->p_ruid = ruid;
    408 		pc->p_svuid = pc->pc_ucred->cr_uid;
    409 	}
    410 
    411 	if (euid != (uid_t)-1 && ruid != (uid_t)-1)
    412 		p_sugid(p);
    413 	return (0);
    414 }
    415 
    416 /* ARGSUSED */
    417 int
    418 sys_setgid(p, v, retval)
    419 	struct proc *p;
    420 	void *v;
    421 	register_t *retval;
    422 {
    423 	struct sys_setgid_args /* {
    424 		syscallarg(gid_t) gid;
    425 	} */ *uap = v;
    426 	struct pcred *pc = p->p_cred;
    427 	gid_t gid;
    428 	int error;
    429 
    430 	gid = SCARG(uap, gid);
    431 	if (gid != pc->p_rgid &&
    432 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
    433 		return (error);
    434 	pc->pc_ucred = crcopy(pc->pc_ucred);
    435 	pc->pc_ucred->cr_gid = gid;
    436 	pc->p_rgid = gid;
    437 	pc->p_svgid = gid;
    438 	p_sugid(p);
    439 	return (0);
    440 }
    441 
    442 /* ARGSUSED */
    443 int
    444 sys_setegid(p, v, retval)
    445 	struct proc *p;
    446 	void *v;
    447 	register_t *retval;
    448 {
    449 	struct sys_setegid_args /* {
    450 		syscallarg(gid_t) egid;
    451 	} */ *uap = v;
    452 	struct pcred *pc = p->p_cred;
    453 	gid_t egid;
    454 	int error;
    455 
    456 	egid = SCARG(uap, egid);
    457 	if (egid != pc->p_rgid && egid != pc->p_svgid &&
    458 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
    459 		return (error);
    460 	pc->pc_ucred = crcopy(pc->pc_ucred);
    461 	pc->pc_ucred->cr_gid = egid;
    462 	p_sugid(p);
    463 	return (0);
    464 }
    465 
    466 int
    467 sys_setregid(p, v, retval)
    468 	struct proc *p;
    469 	void *v;
    470 	register_t *retval;
    471 {
    472 	struct sys_setregid_args /* {
    473 		syscallarg(gid_t) rgid;
    474 		syscallarg(gid_t) egid;
    475 	} */ *uap = v;
    476 	struct pcred *pc = p->p_cred;
    477 	gid_t rgid, egid;
    478 	int error;
    479 
    480 	rgid = SCARG(uap, rgid);
    481 	egid = SCARG(uap, egid);
    482 
    483 	if (rgid != (gid_t)-1 &&
    484 	    rgid != pc->p_rgid && rgid != pc->pc_ucred->cr_gid &&
    485 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
    486 		return (error);
    487 
    488 	if (egid != (gid_t)-1 &&
    489 	    egid != pc->p_rgid && egid != pc->pc_ucred->cr_gid &&
    490 	    egid != pc->p_svgid &&
    491 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
    492 		return (error);
    493 
    494 	if (egid != (gid_t)-1) {
    495 		pc->pc_ucred = crcopy(pc->pc_ucred);
    496 		pc->pc_ucred->cr_gid = egid;
    497 	}
    498 
    499 	if (rgid != (gid_t)-1) {
    500 		pc->p_rgid = rgid;
    501 		pc->p_svgid = pc->pc_ucred->cr_gid;
    502 	}
    503 
    504 	if (egid != (gid_t)-1 && rgid != (gid_t)-1)
    505 		p_sugid(p);
    506 	return (0);
    507 }
    508 
    509 int
    510 sys_issetugid(p, v, retval)
    511 	struct proc *p;
    512 	void *v;
    513 	register_t *retval;
    514 {
    515 	/*
    516 	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
    517 	 * we use P_SUGID because we consider changing the owners as
    518 	 * "tainting" as well.
    519 	 * This is significant for procs that start as root and "become"
    520 	 * a user without an exec - programs cannot know *everything*
    521 	 * that libc *might* have put in their data segment.
    522 	 */
    523 	*retval = (p->p_flag & P_SUGID) != 0;
    524 	return 0;
    525 }
    526 
    527 /* ARGSUSED */
    528 int
    529 sys_setgroups(p, v, retval)
    530 	struct proc *p;
    531 	void *v;
    532 	register_t *retval;
    533 {
    534 	struct sys_setgroups_args /* {
    535 		syscallarg(int) gidsetsize;
    536 		syscallarg(const gid_t *) gidset;
    537 	} */ *uap = v;
    538 	struct pcred *pc = p->p_cred;
    539 	int ngrp;
    540 	int error;
    541 
    542 	if ((error = suser(pc->pc_ucred, &p->p_acflag)) != 0)
    543 		return (error);
    544 	ngrp = SCARG(uap, gidsetsize);
    545 	if ((u_int)ngrp > NGROUPS)
    546 		return (EINVAL);
    547 	pc->pc_ucred = crcopy(pc->pc_ucred);
    548 	error = copyin(SCARG(uap, gidset), pc->pc_ucred->cr_groups,
    549 	    ngrp * sizeof(gid_t));
    550 	if (error)
    551 		return (error);
    552 	pc->pc_ucred->cr_ngroups = ngrp;
    553 	p_sugid(p);
    554 	return (0);
    555 }
    556 
    557 /*
    558  * Check if gid is a member of the group set.
    559  */
    560 int
    561 groupmember(gid, cred)
    562 	gid_t gid;
    563 	struct ucred *cred;
    564 {
    565 	gid_t *gp;
    566 	gid_t *egp;
    567 
    568 	egp = &(cred->cr_groups[cred->cr_ngroups]);
    569 	for (gp = cred->cr_groups; gp < egp; gp++)
    570 		if (*gp == gid)
    571 			return (1);
    572 	return (0);
    573 }
    574 
    575 /*
    576  * Test whether the specified credentials imply "super-user"
    577  * privilege; if so, and we have accounting info, set the flag
    578  * indicating use of super-powers.
    579  * Returns 0 or error.
    580  */
    581 int
    582 suser(cred, acflag)
    583 	struct ucred *cred;
    584 	u_short *acflag;
    585 {
    586 	if (cred->cr_uid == 0) {
    587 		if (acflag)
    588 			*acflag |= ASU;
    589 		return (0);
    590 	}
    591 	return (EPERM);
    592 }
    593 
    594 /*
    595  * Allocate a zeroed cred structure.
    596  */
    597 struct ucred *
    598 crget()
    599 {
    600 	struct ucred *cr;
    601 
    602 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
    603 	memset((caddr_t)cr, 0, sizeof(*cr));
    604 	cr->cr_ref = 1;
    605 	return (cr);
    606 }
    607 
    608 /*
    609  * Free a cred structure.
    610  * Throws away space when ref count gets to 0.
    611  */
    612 void
    613 crfree(cr)
    614 	struct ucred *cr;
    615 {
    616 	int s;
    617 
    618 	s = splimp();				/* ??? */
    619 	if (--cr->cr_ref == 0)
    620 		FREE((caddr_t)cr, M_CRED);
    621 	(void) splx(s);
    622 }
    623 
    624 /*
    625  * Copy cred structure to a new one and free the old one.
    626  */
    627 struct ucred *
    628 crcopy(cr)
    629 	struct ucred *cr;
    630 {
    631 	struct ucred *newcr;
    632 
    633 	if (cr->cr_ref == 1)
    634 		return (cr);
    635 	newcr = crget();
    636 	*newcr = *cr;
    637 	crfree(cr);
    638 	newcr->cr_ref = 1;
    639 	return (newcr);
    640 }
    641 
    642 /*
    643  * Dup cred struct to a new held one.
    644  */
    645 struct ucred *
    646 crdup(cr)
    647 	struct ucred *cr;
    648 {
    649 	struct ucred *newcr;
    650 
    651 	newcr = crget();
    652 	*newcr = *cr;
    653 	newcr->cr_ref = 1;
    654 	return (newcr);
    655 }
    656 
    657 /*
    658  * Get login name, if available.
    659  */
    660 /* ARGSUSED */
    661 int
    662 sys___getlogin(p, v, retval)
    663 	struct proc *p;
    664 	void *v;
    665 	register_t *retval;
    666 {
    667 	struct sys___getlogin_args /* {
    668 		syscallarg(char *) namebuf;
    669 		syscallarg(size_t) namelen;
    670 	} */ *uap = v;
    671 
    672 	if (SCARG(uap, namelen) > sizeof(p->p_pgrp->pg_session->s_login))
    673 		SCARG(uap, namelen) = sizeof(p->p_pgrp->pg_session->s_login);
    674 	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
    675 	    (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen)));
    676 }
    677 
    678 /*
    679  * Set login name.
    680  */
    681 /* ARGSUSED */
    682 int
    683 sys_setlogin(p, v, retval)
    684 	struct proc *p;
    685 	void *v;
    686 	register_t *retval;
    687 {
    688 	struct sys_setlogin_args /* {
    689 		syscallarg(const char *) namebuf;
    690 	} */ *uap = v;
    691 	int error;
    692 
    693 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
    694 		return (error);
    695 	error = copyinstr(SCARG(uap, namebuf), p->p_pgrp->pg_session->s_login,
    696 	    sizeof(p->p_pgrp->pg_session->s_login) - 1, (size_t *)0);
    697 	if (error == ENAMETOOLONG)
    698 		error = EINVAL;
    699 	return (error);
    700 }
    701