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