Home | History | Annotate | Line # | Download | only in kern
kern_prot.c revision 1.63.2.1
      1 /*	$NetBSD: kern_prot.c,v 1.63.2.1 2001/03/05 22:49:41 nathanw 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_43.h"
     48 
     49 #include <sys/param.h>
     50 #include <sys/acct.h>
     51 #include <sys/systm.h>
     52 #include <sys/ucred.h>
     53 #include <sys/lwp.h>
     54 #include <sys/proc.h>
     55 #include <sys/timeb.h>
     56 #include <sys/times.h>
     57 #include <sys/malloc.h>
     58 
     59 #include <sys/mount.h>
     60 #include <sys/syscallargs.h>
     61 
     62 int	sys_getpid(struct lwp *, void *, register_t *);
     63 int	sys_getpid_with_ppid(struct lwp *, void *, register_t *);
     64 int	sys_getuid(struct lwp *, void *, register_t *);
     65 int	sys_getuid_with_euid(struct lwp *, void *, register_t *);
     66 int	sys_getgid(struct lwp *, void *, register_t *);
     67 int	sys_getgid_with_egid(struct lwp *, void *, register_t *);
     68 
     69 /* ARGSUSED */
     70 int
     71 sys_getpid(l, v, retval)
     72 	struct lwp *l;
     73 	void *v;
     74 	register_t *retval;
     75 {
     76 	struct proc *p = l->l_proc;
     77 
     78 	*retval = p->p_pid;
     79 	return (0);
     80 }
     81 
     82 /* ARGSUSED */
     83 int
     84 sys_getpid_with_ppid(l, v, retval)
     85 	struct lwp *l;
     86 	void *v;
     87 	register_t *retval;
     88 {
     89 	struct proc *p = l->l_proc;
     90 
     91 	retval[0] = p->p_pid;
     92 	retval[1] = p->p_pptr->p_pid;
     93 	return (0);
     94 }
     95 
     96 /* ARGSUSED */
     97 int
     98 sys_getppid(l, v, retval)
     99 	struct lwp *l;
    100 	void *v;
    101 	register_t *retval;
    102 {
    103 	struct proc *p = l->l_proc;
    104 
    105 	*retval = p->p_pptr->p_pid;
    106 	return (0);
    107 }
    108 
    109 /* Get process group ID; note that POSIX getpgrp takes no parameter */
    110 int
    111 sys_getpgrp(l, v, retval)
    112 	struct lwp *l;
    113 	void *v;
    114 	register_t *retval;
    115 {
    116 	struct proc *p = l->l_proc;
    117 
    118 	*retval = p->p_pgrp->pg_id;
    119 	return (0);
    120 }
    121 
    122 /*
    123  * Return the process group ID of the session leader (session ID)
    124  * for the specified process.
    125  */
    126 int
    127 sys_getsid(l, v, retval)
    128 	struct lwp *l;
    129 	void *v;
    130 	register_t *retval;
    131 {
    132 	struct sys_getsid_args /* {
    133 		syscalldarg(pid_t) pid;
    134 	} */ *uap = v;
    135 	struct proc *p = l->l_proc;
    136 
    137 	if (SCARG(uap, pid) == 0)
    138 		goto found;
    139 	if ((p = pfind(SCARG(uap, pid))) == 0)
    140 		return (ESRCH);
    141 found:
    142 	*retval = p->p_session->s_sid;
    143 	return (0);
    144 }
    145 
    146 int
    147 sys_getpgid(l, v, retval)
    148 	struct lwp *l;
    149 	void *v;
    150 	register_t *retval;
    151 {
    152 	struct sys_getpgid_args /* {
    153 		syscallarg(pid_t) pid;
    154 	} */ *uap = v;
    155 	struct proc *p = l->l_proc;
    156 
    157 	if (SCARG(uap, pid) == 0)
    158 		goto found;
    159 	if ((p = pfind(SCARG(uap, pid))) == 0)
    160 		return (ESRCH);
    161 found:
    162 	*retval = p->p_pgid;
    163 	return (0);
    164 }
    165 
    166 /* ARGSUSED */
    167 int
    168 sys_getuid(l, v, retval)
    169 	struct lwp *l;
    170 	void *v;
    171 	register_t *retval;
    172 {
    173 	struct proc *p = l->l_proc;
    174 
    175 	*retval = p->p_cred->p_ruid;
    176 	return (0);
    177 }
    178 
    179 /* ARGSUSED */
    180 int
    181 sys_getuid_with_euid(l, v, retval)
    182 	struct lwp *l;
    183 	void *v;
    184 	register_t *retval;
    185 {
    186 	struct proc *p = l->l_proc;
    187 
    188 	retval[0] = p->p_cred->p_ruid;
    189 	retval[1] = p->p_ucred->cr_uid;
    190 	return (0);
    191 }
    192 
    193 /* ARGSUSED */
    194 int
    195 sys_geteuid(l, v, retval)
    196 	struct lwp *l;
    197 	void *v;
    198 	register_t *retval;
    199 {
    200 	struct proc *p = l->l_proc;
    201 
    202 	*retval = p->p_ucred->cr_uid;
    203 	return (0);
    204 }
    205 
    206 /* ARGSUSED */
    207 int
    208 sys_getgid(l, v, retval)
    209 	struct lwp *l;
    210 	void *v;
    211 	register_t *retval;
    212 {
    213 	struct proc *p = l->l_proc;
    214 
    215 	*retval = p->p_cred->p_rgid;
    216 	return (0);
    217 }
    218 
    219 /* ARGSUSED */
    220 int
    221 sys_getgid_with_egid(l, v, retval)
    222 	struct lwp *l;
    223 	void *v;
    224 	register_t *retval;
    225 {
    226 	struct proc *p = l->l_proc;
    227 
    228 	retval[0] = p->p_cred->p_rgid;
    229 	retval[1] = p->p_ucred->cr_gid;
    230 	return (0);
    231 }
    232 
    233 /*
    234  * Get effective group ID.  The "egid" is groups[0], and could be obtained
    235  * via getgroups.  This syscall exists because it is somewhat painful to do
    236  * correctly in a library function.
    237  */
    238 /* ARGSUSED */
    239 int
    240 sys_getegid(l, v, retval)
    241 	struct lwp *l;
    242 	void *v;
    243 	register_t *retval;
    244 {
    245 	struct proc *p = l->l_proc;
    246 	*retval = p->p_ucred->cr_gid;
    247 	return (0);
    248 }
    249 
    250 int
    251 sys_getgroups(l, v, retval)
    252 	struct lwp *l;
    253 	void *v;
    254 	register_t *retval;
    255 {
    256 	struct sys_getgroups_args /* {
    257 		syscallarg(int) gidsetsize;
    258 		syscallarg(gid_t *) gidset;
    259 	} */ *uap = v;
    260 	struct proc *p = l->l_proc;
    261 	struct pcred *pc = p->p_cred;
    262 	int ngrp;
    263 	int error;
    264 
    265 	ngrp = SCARG(uap, gidsetsize);
    266 	if (ngrp == 0) {
    267 		*retval = pc->pc_ucred->cr_ngroups;
    268 		return (0);
    269 	}
    270 	if (ngrp < pc->pc_ucred->cr_ngroups)
    271 		return (EINVAL);
    272 	ngrp = pc->pc_ucred->cr_ngroups;
    273 	error = copyout((caddr_t)pc->pc_ucred->cr_groups,
    274 			(caddr_t)SCARG(uap, gidset), ngrp * sizeof(gid_t));
    275 	if (error)
    276 		return (error);
    277 	*retval = ngrp;
    278 	return (0);
    279 }
    280 
    281 /* ARGSUSED */
    282 int
    283 sys_setsid(l, v, retval)
    284 	struct lwp *l;
    285 	void *v;
    286 	register_t *retval;
    287 {
    288 	struct proc *p = l->l_proc;
    289 
    290 	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
    291 		return (EPERM);
    292 	} else {
    293 		(void)enterpgrp(p, p->p_pid, 1);
    294 		*retval = p->p_pid;
    295 		return (0);
    296 	}
    297 }
    298 
    299 /*
    300  * set process group (setpgid/old setpgrp)
    301  *
    302  * caller does setpgid(targpid, targpgid)
    303  *
    304  * pgid must be in valid range (EINVAL)
    305  * pid must be caller or child of caller (ESRCH)
    306  * if a child
    307  *	pid must be in same session (EPERM)
    308  *	pid can't have done an exec (EACCES)
    309  * if pgid != pid
    310  * 	there must exist some pid in same session having pgid (EPERM)
    311  * pid must not be session leader (EPERM)
    312  */
    313 /* ARGSUSED */
    314 int
    315 sys_setpgid(l, v, retval)
    316 	struct lwp *l;
    317 	void *v;
    318 	register_t *retval;
    319 {
    320 	struct sys_setpgid_args /* {
    321 		syscallarg(int) pid;
    322 		syscallarg(int) pgid;
    323 	} */ *uap = v;
    324 	struct proc *curp = l->l_proc;
    325 	struct proc *targp;			/* target process */
    326 	struct pgrp *pgrp;			/* target pgrp */
    327 
    328 	if (SCARG(uap, pgid) < 0)
    329 		return (EINVAL);
    330 
    331 	if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != curp->p_pid) {
    332 		if ((targp = pfind(SCARG(uap, pid))) == 0
    333 		    || !inferior(targp, curp))
    334 			return (ESRCH);
    335 		if (targp->p_session != curp->p_session)
    336 			return (EPERM);
    337 		if (targp->p_flag & P_EXEC)
    338 			return (EACCES);
    339 	} else
    340 		targp = curp;
    341 	if (SESS_LEADER(targp))
    342 		return (EPERM);
    343 	if (SCARG(uap, pgid) == 0)
    344 		SCARG(uap, pgid) = targp->p_pid;
    345 	else if (SCARG(uap, pgid) != targp->p_pid)
    346 		if ((pgrp = pgfind(SCARG(uap, pgid))) == 0 ||
    347 	            pgrp->pg_session != curp->p_session)
    348 			return (EPERM);
    349 	return (enterpgrp(targp, SCARG(uap, pgid), 0));
    350 }
    351 
    352 /* ARGSUSED */
    353 int
    354 sys_setuid(l, v, retval)
    355 	struct lwp *l;
    356 	void *v;
    357 	register_t *retval;
    358 {
    359 	struct sys_setuid_args /* {
    360 		syscallarg(uid_t) uid;
    361 	} */ *uap = v;
    362 	struct proc *p = l->l_proc;
    363 	struct pcred *pc = p->p_cred;
    364 	uid_t uid;
    365 	int error;
    366 
    367 	uid = SCARG(uap, uid);
    368 	if (uid != pc->p_ruid &&
    369 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
    370 		return (error);
    371 	/*
    372 	 * Check if we are all set, and this is a no-op.
    373 	 */
    374 	if (pc->p_ruid == uid && pc->p_svuid == uid &&
    375 	    pc->pc_ucred->cr_uid == uid)
    376 		return (0);
    377 	/*
    378 	 * Everything's okay, do it.
    379 	 * Transfer proc count to new user.
    380 	 * Copy credentials so other references do not see our changes.
    381 	 */
    382 	(void)chgproccnt(pc->p_ruid, -1);
    383 	(void)chgproccnt(uid, 1);
    384 	pc->pc_ucred = crcopy(pc->pc_ucred);
    385 	pc->pc_ucred->cr_uid = uid;
    386 	pc->p_ruid = uid;
    387 	pc->p_svuid = uid;
    388 	p_sugid(p);
    389 	return (0);
    390 }
    391 
    392 /* ARGSUSED */
    393 int
    394 sys_seteuid(l, v, retval)
    395 	struct lwp *l;
    396 	void *v;
    397 	register_t *retval;
    398 {
    399 	struct sys_seteuid_args /* {
    400 		syscallarg(uid_t) euid;
    401 	} */ *uap = v;
    402 	struct proc *p = l->l_proc;
    403 	struct pcred *pc = p->p_cred;
    404 	uid_t euid;
    405 	int error;
    406 
    407 	euid = SCARG(uap, euid);
    408 	if (euid != pc->p_ruid && euid != pc->p_svuid &&
    409 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
    410 		return (error);
    411 	/*
    412 	 * Check if we are all set, and this is a no-op.
    413 	 */
    414 	if (pc->pc_ucred->cr_uid == euid)
    415 		return (0);
    416 
    417 	/*
    418 	 * Everything's okay, do it.  Copy credentials so other references do
    419 	 * not see our changes.
    420 	 */
    421 	pc->pc_ucred = crcopy(pc->pc_ucred);
    422 	pc->pc_ucred->cr_uid = euid;
    423 	p_sugid(p);
    424 	return (0);
    425 }
    426 
    427 int
    428 sys_setreuid(l, v, retval)
    429 	struct lwp *l;
    430 	void *v;
    431 	register_t *retval;
    432 {
    433 	struct sys_setreuid_args /* {
    434 		syscallarg(uid_t) ruid;
    435 		syscallarg(uid_t) euid;
    436 	} */ *uap = v;
    437 	struct proc *p = l->l_proc;
    438 	struct pcred *pc = p->p_cred;
    439 	uid_t ruid, euid;
    440 	int error, changed = 0;
    441 
    442 	ruid = SCARG(uap, ruid);
    443 	euid = SCARG(uap, euid);
    444 
    445 	if (ruid != (uid_t)-1 &&
    446 	    ruid != pc->p_ruid && ruid != pc->pc_ucred->cr_uid &&
    447 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
    448 		return (error);
    449 
    450 	if (euid != (uid_t)-1 &&
    451 	    euid != pc->p_ruid && euid != pc->pc_ucred->cr_uid &&
    452 	    euid != pc->p_svuid &&
    453 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
    454 		return (error);
    455 
    456 	if (euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid) {
    457 		pc->pc_ucred = crcopy(pc->pc_ucred);
    458 		pc->pc_ucred->cr_uid = euid;
    459 		changed++;
    460 	}
    461 
    462 	if (ruid != (uid_t)-1 &&
    463 	    (pc->p_ruid != ruid || pc->p_svuid != pc->pc_ucred->cr_uid)) {
    464 		(void)chgproccnt(pc->p_ruid, -1);
    465 		(void)chgproccnt(ruid, 1);
    466 		pc->p_ruid = ruid;
    467 		pc->p_svuid = pc->pc_ucred->cr_uid;
    468 		changed++;
    469 	}
    470 
    471 	if (changed)
    472 		p_sugid(p);
    473 	return (0);
    474 }
    475 
    476 /* ARGSUSED */
    477 int
    478 sys_setgid(l, v, retval)
    479 	struct lwp *l;
    480 	void *v;
    481 	register_t *retval;
    482 {
    483 	struct sys_setgid_args /* {
    484 		syscallarg(gid_t) gid;
    485 	} */ *uap = v;
    486 	struct proc *p = l->l_proc;
    487 	struct pcred *pc = p->p_cred;
    488 	gid_t gid;
    489 	int error;
    490 
    491 	gid = SCARG(uap, gid);
    492 	if (gid != pc->p_rgid &&
    493 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
    494 		return (error);
    495 	/*
    496 	 * Check if we are all set, and this is a no-op.
    497 	 */
    498 	if (pc->pc_ucred->cr_gid == gid && pc->p_rgid == gid &&
    499 	    pc->p_svgid == gid)
    500 		return (0);
    501 
    502 	pc->pc_ucred = crcopy(pc->pc_ucred);
    503 	pc->pc_ucred->cr_gid = gid;
    504 	pc->p_rgid = gid;
    505 	pc->p_svgid = gid;
    506 	p_sugid(p);
    507 	return (0);
    508 }
    509 
    510 /* ARGSUSED */
    511 int
    512 sys_setegid(l, v, retval)
    513 	struct lwp *l;
    514 	void *v;
    515 	register_t *retval;
    516 {
    517 	struct sys_setegid_args /* {
    518 		syscallarg(gid_t) egid;
    519 	} */ *uap = v;
    520 	struct proc *p = l->l_proc;
    521 	struct pcred *pc = p->p_cred;
    522 	gid_t egid;
    523 	int error;
    524 
    525 	egid = SCARG(uap, egid);
    526 	if (egid != pc->p_rgid && egid != pc->p_svgid &&
    527 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
    528 		return (error);
    529 	/*
    530 	 * Check if we are all set, and this is a no-op.
    531 	 */
    532 	if (pc->pc_ucred->cr_gid == egid)
    533 		return (0);
    534 
    535 	pc->pc_ucred = crcopy(pc->pc_ucred);
    536 	pc->pc_ucred->cr_gid = egid;
    537 	p_sugid(p);
    538 	return (0);
    539 }
    540 
    541 int
    542 sys_setregid(l, v, retval)
    543 	struct lwp *l;
    544 	void *v;
    545 	register_t *retval;
    546 {
    547 	struct sys_setregid_args /* {
    548 		syscallarg(gid_t) rgid;
    549 		syscallarg(gid_t) egid;
    550 	} */ *uap = v;
    551 	struct proc *p = l->l_proc;
    552 	struct pcred *pc = p->p_cred;
    553 	gid_t rgid, egid;
    554 	int error, changed = 0;
    555 
    556 	rgid = SCARG(uap, rgid);
    557 	egid = SCARG(uap, egid);
    558 
    559 	if (rgid != (gid_t)-1 &&
    560 	    rgid != pc->p_rgid && rgid != pc->pc_ucred->cr_gid &&
    561 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
    562 		return (error);
    563 
    564 	if (egid != (gid_t)-1 &&
    565 	    egid != pc->p_rgid && egid != pc->pc_ucred->cr_gid &&
    566 	    egid != pc->p_svgid &&
    567 	    (error = suser(pc->pc_ucred, &p->p_acflag)))
    568 		return (error);
    569 
    570 	if (egid != (gid_t)-1 && pc->pc_ucred->cr_gid != egid) {
    571 		pc->pc_ucred = crcopy(pc->pc_ucred);
    572 		pc->pc_ucred->cr_gid = egid;
    573 		changed++;
    574 	}
    575 
    576 	if (rgid != (gid_t)-1 &&
    577 	    (pc->p_rgid != rgid || pc->p_svgid != pc->pc_ucred->cr_gid)) {
    578 		pc->p_rgid = rgid;
    579 		pc->p_svgid = pc->pc_ucred->cr_gid;
    580 		changed++;
    581 	}
    582 
    583 	if (changed)
    584 		p_sugid(p);
    585 	return (0);
    586 }
    587 
    588 int
    589 sys_issetugid(l, v, retval)
    590 	struct lwp *l;
    591 	void *v;
    592 	register_t *retval;
    593 {
    594 	struct proc *p = l->l_proc;
    595 	/*
    596 	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
    597 	 * we use P_SUGID because we consider changing the owners as
    598 	 * "tainting" as well.
    599 	 * This is significant for procs that start as root and "become"
    600 	 * a user without an exec - programs cannot know *everything*
    601 	 * that libc *might* have put in their data segment.
    602 	 */
    603 	*retval = (p->p_flag & P_SUGID) != 0;
    604 	return (0);
    605 }
    606 
    607 /* ARGSUSED */
    608 int
    609 sys_setgroups(l, v, retval)
    610 	struct lwp *l;
    611 	void *v;
    612 	register_t *retval;
    613 {
    614 	struct sys_setgroups_args /* {
    615 		syscallarg(int) gidsetsize;
    616 		syscallarg(const gid_t *) gidset;
    617 	} */ *uap = v;
    618 	struct proc *p = l->l_proc;
    619 	struct pcred *pc = p->p_cred;
    620 	int ngrp;
    621 	int error;
    622 	gid_t grp[NGROUPS];
    623 	size_t grsize;
    624 
    625 	if ((error = suser(pc->pc_ucred, &p->p_acflag)) != 0)
    626 		return (error);
    627 
    628 	ngrp = SCARG(uap, gidsetsize);
    629 	if ((u_int)ngrp > NGROUPS)
    630 		return (EINVAL);
    631 
    632 	grsize = ngrp * sizeof(gid_t);
    633 	error = copyin(SCARG(uap, gidset), grp, grsize);
    634 	if (error)
    635 		return (error);
    636 	/*
    637 	 * Check if this is a no-op.
    638 	 */
    639 	if (pc->pc_ucred->cr_ngroups == ngrp &&
    640 	    memcmp(grp, pc->pc_ucred->cr_groups, grsize) == 0)
    641 		return (0);
    642 
    643 	pc->pc_ucred = crcopy(pc->pc_ucred);
    644 	(void)memcpy(pc->pc_ucred->cr_groups, grp, grsize);
    645 	pc->pc_ucred->cr_ngroups = ngrp;
    646 	p_sugid(p);
    647 	return (0);
    648 }
    649 
    650 /*
    651  * Check if gid is a member of the group set.
    652  */
    653 int
    654 groupmember(gid, cred)
    655 	gid_t gid;
    656 	struct ucred *cred;
    657 {
    658 	gid_t *gp;
    659 	gid_t *egp;
    660 
    661 	egp = &(cred->cr_groups[cred->cr_ngroups]);
    662 	for (gp = cred->cr_groups; gp < egp; gp++)
    663 		if (*gp == gid)
    664 			return (1);
    665 	return (0);
    666 }
    667 
    668 /*
    669  * Test whether the specified credentials imply "super-user"
    670  * privilege; if so, and we have accounting info, set the flag
    671  * indicating use of super-powers.
    672  * Returns 0 or error.
    673  */
    674 int
    675 suser(cred, acflag)
    676 	struct ucred *cred;
    677 	u_short *acflag;
    678 {
    679 	if (cred->cr_uid == 0) {
    680 		if (acflag)
    681 			*acflag |= ASU;
    682 		return (0);
    683 	}
    684 	return (EPERM);
    685 }
    686 
    687 /*
    688  * Allocate a zeroed cred structure.
    689  */
    690 struct ucred *
    691 crget()
    692 {
    693 	struct ucred *cr;
    694 
    695 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
    696 	memset((caddr_t)cr, 0, sizeof(*cr));
    697 	cr->cr_ref = 1;
    698 	return (cr);
    699 }
    700 
    701 /*
    702  * Free a cred structure.
    703  * Throws away space when ref count gets to 0.
    704  */
    705 void
    706 crfree(cr)
    707 	struct ucred *cr;
    708 {
    709 	int s;
    710 
    711 	s = splimp();				/* ??? */
    712 	if (--cr->cr_ref == 0)
    713 		FREE((caddr_t)cr, M_CRED);
    714 	(void) splx(s);
    715 }
    716 
    717 /*
    718  * Copy cred structure to a new one and free the old one.
    719  */
    720 struct ucred *
    721 crcopy(cr)
    722 	struct ucred *cr;
    723 {
    724 	struct ucred *newcr;
    725 
    726 	if (cr->cr_ref == 1)
    727 		return (cr);
    728 	newcr = crget();
    729 	*newcr = *cr;
    730 	crfree(cr);
    731 	newcr->cr_ref = 1;
    732 	return (newcr);
    733 }
    734 
    735 /*
    736  * Dup cred struct to a new held one.
    737  */
    738 struct ucred *
    739 crdup(cr)
    740 	struct ucred *cr;
    741 {
    742 	struct ucred *newcr;
    743 
    744 	newcr = crget();
    745 	*newcr = *cr;
    746 	newcr->cr_ref = 1;
    747 	return (newcr);
    748 }
    749 
    750 /*
    751  * Get login name, if available.
    752  */
    753 /* ARGSUSED */
    754 int
    755 sys___getlogin(l, v, retval)
    756 	struct lwp *l;
    757 	void *v;
    758 	register_t *retval;
    759 {
    760 	struct sys___getlogin_args /* {
    761 		syscallarg(char *) namebuf;
    762 		syscallarg(size_t) namelen;
    763 	} */ *uap = v;
    764 	struct proc *p = l->l_proc;
    765 
    766 	if (SCARG(uap, namelen) > sizeof(p->p_pgrp->pg_session->s_login))
    767 		SCARG(uap, namelen) = sizeof(p->p_pgrp->pg_session->s_login);
    768 	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
    769 	    (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen)));
    770 }
    771 
    772 /*
    773  * Set login name.
    774  */
    775 /* ARGSUSED */
    776 int
    777 sys_setlogin(l, v, retval)
    778 	struct lwp *l;
    779 	void *v;
    780 	register_t *retval;
    781 {
    782 	struct sys_setlogin_args /* {
    783 		syscallarg(const char *) namebuf;
    784 	} */ *uap = v;
    785 	struct proc *p = l->l_proc;
    786 	int error;
    787 
    788 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
    789 		return (error);
    790 	error = copyinstr(SCARG(uap, namebuf), p->p_pgrp->pg_session->s_login,
    791 	    sizeof(p->p_pgrp->pg_session->s_login) - 1, (size_t *)0);
    792 	if (error == ENAMETOOLONG)
    793 		error = EINVAL;
    794 	return (error);
    795 }
    796