Home | History | Annotate | Line # | Download | only in kern
kern_prot.c revision 1.81
      1 /*	$NetBSD: kern_prot.c,v 1.81 2004/04/17 15:15:29 christos 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. Neither the name of the University nor the names of its contributors
     21  *    may be used to endorse or promote products derived from this software
     22  *    without specific prior written permission.
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34  * SUCH DAMAGE.
     35  *
     36  *	@(#)kern_prot.c	8.9 (Berkeley) 2/14/95
     37  */
     38 
     39 /*
     40  * System calls related to processes and protection
     41  */
     42 
     43 #include <sys/cdefs.h>
     44 __KERNEL_RCSID(0, "$NetBSD: kern_prot.c,v 1.81 2004/04/17 15:15:29 christos Exp $");
     45 
     46 #include "opt_compat_43.h"
     47 
     48 #include <sys/param.h>
     49 #include <sys/acct.h>
     50 #include <sys/systm.h>
     51 #include <sys/ucred.h>
     52 #include <sys/proc.h>
     53 #include <sys/timeb.h>
     54 #include <sys/times.h>
     55 #include <sys/malloc.h>
     56 #include <sys/syslog.h>
     57 #include <sys/resourcevar.h>
     58 
     59 #include <sys/mount.h>
     60 #include <sys/sa.h>
     61 #include <sys/syscallargs.h>
     62 
     63 MALLOC_DEFINE(M_CRED, "cred", "credentials");
     64 
     65 int	sys_getpid(struct lwp *, void *, register_t *);
     66 int	sys_getpid_with_ppid(struct lwp *, void *, register_t *);
     67 int	sys_getuid(struct lwp *, void *, register_t *);
     68 int	sys_getuid_with_euid(struct lwp *, void *, register_t *);
     69 int	sys_getgid(struct lwp *, void *, register_t *);
     70 int	sys_getgid_with_egid(struct lwp *, void *, register_t *);
     71 
     72 /* ARGSUSED */
     73 int
     74 sys_getpid(struct lwp *l, void *v, 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(struct lwp *l, void *v, register_t *retval)
     85 {
     86 	struct proc *p = l->l_proc;
     87 
     88 	retval[0] = p->p_pid;
     89 	retval[1] = p->p_pptr->p_pid;
     90 	return (0);
     91 }
     92 
     93 /* ARGSUSED */
     94 int
     95 sys_getppid(struct lwp *l, void *v, register_t *retval)
     96 {
     97 	struct proc *p = l->l_proc;
     98 
     99 	*retval = p->p_pptr->p_pid;
    100 	return (0);
    101 }
    102 
    103 /* Get process group ID; note that POSIX getpgrp takes no parameter */
    104 int
    105 sys_getpgrp(struct lwp *l, void *v, register_t *retval)
    106 {
    107 	struct proc *p = l->l_proc;
    108 
    109 	*retval = p->p_pgrp->pg_id;
    110 	return (0);
    111 }
    112 
    113 /*
    114  * Return the process group ID of the session leader (session ID)
    115  * for the specified process.
    116  */
    117 int
    118 sys_getsid(struct lwp *l, void *v, register_t *retval)
    119 {
    120 	struct sys_getsid_args /* {
    121 		syscalldarg(pid_t) pid;
    122 	} */ *uap = v;
    123 	struct proc *p = l->l_proc;
    124 
    125 	if (SCARG(uap, pid) == 0)
    126 		goto found;
    127 	if ((p = pfind(SCARG(uap, pid))) == 0)
    128 		return (ESRCH);
    129 found:
    130 	*retval = p->p_session->s_sid;
    131 	return (0);
    132 }
    133 
    134 int
    135 sys_getpgid(struct lwp *l, void *v, register_t *retval)
    136 {
    137 	struct sys_getpgid_args /* {
    138 		syscallarg(pid_t) pid;
    139 	} */ *uap = v;
    140 	struct proc *p = l->l_proc;
    141 
    142 	if (SCARG(uap, pid) == 0)
    143 		goto found;
    144 	if ((p = pfind(SCARG(uap, pid))) == 0)
    145 		return (ESRCH);
    146 found:
    147 	*retval = p->p_pgid;
    148 	return (0);
    149 }
    150 
    151 /* ARGSUSED */
    152 int
    153 sys_getuid(struct lwp *l, void *v, register_t *retval)
    154 {
    155 	struct proc *p = l->l_proc;
    156 
    157 	*retval = p->p_cred->p_ruid;
    158 	return (0);
    159 }
    160 
    161 /* ARGSUSED */
    162 int
    163 sys_getuid_with_euid(struct lwp *l, void *v, register_t *retval)
    164 {
    165 	struct proc *p = l->l_proc;
    166 
    167 	retval[0] = p->p_cred->p_ruid;
    168 	retval[1] = p->p_ucred->cr_uid;
    169 	return (0);
    170 }
    171 
    172 /* ARGSUSED */
    173 int
    174 sys_geteuid(struct lwp *l, void *v, register_t *retval)
    175 {
    176 	struct proc *p = l->l_proc;
    177 
    178 	*retval = p->p_ucred->cr_uid;
    179 	return (0);
    180 }
    181 
    182 /* ARGSUSED */
    183 int
    184 sys_getgid(struct lwp *l, void *v, register_t *retval)
    185 {
    186 	struct proc *p = l->l_proc;
    187 
    188 	*retval = p->p_cred->p_rgid;
    189 	return (0);
    190 }
    191 
    192 /* ARGSUSED */
    193 int
    194 sys_getgid_with_egid(struct lwp *l, void *v, register_t *retval)
    195 {
    196 	struct proc *p = l->l_proc;
    197 
    198 	retval[0] = p->p_cred->p_rgid;
    199 	retval[1] = p->p_ucred->cr_gid;
    200 	return (0);
    201 }
    202 
    203 /*
    204  * Get effective group ID.  The "egid" is groups[0], and could be obtained
    205  * via getgroups.  This syscall exists because it is somewhat painful to do
    206  * correctly in a library function.
    207  */
    208 /* ARGSUSED */
    209 int
    210 sys_getegid(struct lwp *l, void *v, register_t *retval)
    211 {
    212 	struct proc *p = l->l_proc;
    213 
    214 	*retval = p->p_ucred->cr_gid;
    215 	return (0);
    216 }
    217 
    218 int
    219 sys_getgroups(struct lwp *l, void *v, register_t *retval)
    220 {
    221 	struct sys_getgroups_args /* {
    222 		syscallarg(int) gidsetsize;
    223 		syscallarg(gid_t *) gidset;
    224 	} */ *uap = v;
    225 	struct proc *p = l->l_proc;
    226 	struct pcred *pc = p->p_cred;
    227 	u_int ngrp;
    228 	int error;
    229 
    230 	if (SCARG(uap, gidsetsize) == 0) {
    231 		*retval = pc->pc_ucred->cr_ngroups;
    232 		return (0);
    233 	} else if (SCARG(uap, gidsetsize) < 0)
    234 		return (EINVAL);
    235 	ngrp = SCARG(uap, gidsetsize);
    236 	if (ngrp < pc->pc_ucred->cr_ngroups)
    237 		return (EINVAL);
    238 	ngrp = pc->pc_ucred->cr_ngroups;
    239 	error = copyout((caddr_t)pc->pc_ucred->cr_groups,
    240 	    (caddr_t)SCARG(uap, gidset), ngrp * sizeof(gid_t));
    241 	if (error)
    242 		return (error);
    243 	*retval = ngrp;
    244 	return (0);
    245 }
    246 
    247 /* ARGSUSED */
    248 int
    249 sys_setsid(struct lwp *l, void *v, register_t *retval)
    250 {
    251 	struct proc *p = l->l_proc;
    252 
    253 	if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
    254 		return (EPERM);
    255 	} else {
    256 		(void)enterpgrp(p, p->p_pid, 1);
    257 		*retval = p->p_pid;
    258 		return (0);
    259 	}
    260 }
    261 
    262 /*
    263  * set process group (setpgid/old setpgrp)
    264  *
    265  * caller does setpgid(targpid, targpgid)
    266  *
    267  * pgid must be in valid range (EINVAL)
    268  * pid must be caller or child of caller (ESRCH)
    269  * if a child
    270  *	pid must be in same session (EPERM)
    271  *	pid can't have done an exec (EACCES)
    272  * if pgid != pid
    273  * 	there must exist some pid in same session having pgid (EPERM)
    274  * pid must not be session leader (EPERM)
    275  *
    276  * Permission checks now in enterpgrp()
    277  */
    278 /* ARGSUSED */
    279 int
    280 sys_setpgid(struct lwp *l, void *v, register_t *retval)
    281 {
    282 	struct sys_setpgid_args /* {
    283 		syscallarg(int) pid;
    284 		syscallarg(int) pgid;
    285 	} */ *uap = v;
    286 	struct proc *curp = l->l_proc;
    287 	struct proc *targp;			/* target process */
    288 
    289 	if (SCARG(uap, pgid) < 0)
    290 		return EINVAL;
    291 
    292 	/* XXX MP - there is a horrid race here with targp exiting! */
    293 	if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != curp->p_pid) {
    294 		targp = pfind(SCARG(uap, pid));
    295 		if (targp == NULL)
    296 			return ESRCH;
    297 	} else
    298 		targp = curp;
    299 
    300 	if (SCARG(uap, pgid) == 0)
    301 		SCARG(uap, pgid) = targp->p_pid;
    302 	return enterpgrp(targp, SCARG(uap, pgid), 0);
    303 }
    304 
    305 /*
    306  * Set real, effective and saved uids to the requested values.
    307  * non-root callers can only ever change uids to values that match
    308  * one of the processes current uid values.
    309  * This is further restricted by the flags argument.
    310  */
    311 
    312 int
    313 do_setresuid(struct lwp *l, uid_t r, uid_t e, uid_t sv, u_int flags)
    314 {
    315 	int error;
    316 	struct proc *p = l->l_proc;
    317 	struct pcred *pcred = p->p_cred;
    318 	struct ucred *cred = pcred->pc_ucred;
    319 
    320 	/* Superuser can do anything it wants to.... */
    321 	error = suser(cred, &p->p_acflag);
    322 	if (error) {
    323 		/* Otherwise check new value is one of the allowed
    324 		   existing values. */
    325 		if (r != -1 && !((flags & ID_R_EQ_R) && r == pcred->p_ruid)
    326 			    && !((flags & ID_R_EQ_E) && r == cred->cr_uid)
    327 			    && !((flags & ID_R_EQ_S) && r == pcred->p_svuid))
    328 			return error;
    329 		if (e != -1 && !((flags & ID_E_EQ_R) && e == pcred->p_ruid)
    330 			    && !((flags & ID_E_EQ_E) && e == cred->cr_uid)
    331 			    && !((flags & ID_E_EQ_S) && e == pcred->p_svuid))
    332 			return error;
    333 		if (sv != -1 && !((flags & ID_S_EQ_R) && sv == pcred->p_ruid)
    334 			    && !((flags & ID_S_EQ_E) && sv == cred->cr_uid)
    335 			    && !((flags & ID_S_EQ_S) && sv == pcred->p_svuid))
    336 			return error;
    337 	}
    338 
    339 	/* If nothing has changed, short circuit the request */
    340 	if ((r == -1 || r == pcred->p_ruid)
    341 	    && (e == -1 || e == cred->cr_uid)
    342 	    && (sv == -1 || sv == pcred->p_svuid))
    343 		/* nothing to do */
    344 		return 0;
    345 
    346 	/* The pcred structure is not actually shared... */
    347 	if (r != -1 && r != pcred->p_ruid) {
    348 		/* Update count of processes for this user */
    349 		(void)chgproccnt(pcred->p_ruid, -1);
    350 		(void)chgproccnt(r, 1);
    351 		pcred->p_ruid = r;
    352 	}
    353 	if (sv != -1)
    354 		pcred->p_svuid = sv;
    355 	if (e != -1 && e != cred->cr_uid) {
    356 		/* Update a clone of the current credentials */
    357 		pcred->pc_ucred = cred = crcopy(cred);
    358 		cred->cr_uid = e;
    359 	}
    360 
    361 	/* Mark process as having changed credentials, stops tracing etc */
    362 	p_sugid(p);
    363 	return 0;
    364 }
    365 
    366 /*
    367  * Set real, effective and saved gids to the requested values.
    368  * non-root callers can only ever change gids to values that match
    369  * one of the processes current gid values.
    370  * This is further restricted by the flags argument.
    371  */
    372 
    373 int
    374 do_setresgid(struct lwp *l, gid_t r, gid_t e, gid_t sv, u_int flags)
    375 {
    376 	int error;
    377 	struct proc *p = l->l_proc;
    378 	struct pcred *pcred = p->p_cred;
    379 	struct ucred *cred = pcred->pc_ucred;
    380 
    381 	/* Superuser can do anything it wants to.... */
    382 	error = suser(cred, &p->p_acflag);
    383 	if (error) {
    384 		/* Otherwise check new value is one of the allowed
    385 		   existing values. */
    386 		if (r != -1 && !((flags & ID_R_EQ_R) && r == pcred->p_rgid)
    387 			    && !((flags & ID_R_EQ_E) && r == cred->cr_gid)
    388 			    && !((flags & ID_R_EQ_S) && r == pcred->p_svgid))
    389 			return error;
    390 		if (e != -1 && !((flags & ID_E_EQ_R) && e == pcred->p_rgid)
    391 			    && !((flags & ID_E_EQ_E) && e == cred->cr_gid)
    392 			    && !((flags & ID_E_EQ_S) && e == pcred->p_svgid))
    393 			return error;
    394 		if (sv != -1 && !((flags & ID_S_EQ_R) && sv == pcred->p_rgid)
    395 			    && !((flags & ID_S_EQ_E) && sv == cred->cr_gid)
    396 			    && !((flags & ID_S_EQ_S) && sv == pcred->p_svgid))
    397 			return error;
    398 	}
    399 
    400 	/* If nothing has changed, short circuit the request */
    401 	if ((r == -1 || r == pcred->p_rgid)
    402 	    && (e == -1 || e == cred->cr_gid)
    403 	    && (sv == -1 || sv == pcred->p_svgid))
    404 		/* nothing to do */
    405 		return 0;
    406 
    407 	/* The pcred structure is not actually shared... */
    408 	if (r != -1)
    409 		pcred->p_rgid = r;
    410 	if (sv != -1)
    411 		pcred->p_svgid = sv;
    412 	if (e != -1 && e != cred->cr_gid) {
    413 		/* Update a clone of the current credentials */
    414 		pcred->pc_ucred = cred = crcopy(cred);
    415 		cred->cr_gid = e;
    416 	}
    417 
    418 	/* Mark process as having changed credentials, stops tracing etc */
    419 	p_sugid(p);
    420 	return 0;
    421 }
    422 
    423 /* ARGSUSED */
    424 int
    425 sys_setuid(struct lwp *l, void *v, register_t *retval)
    426 {
    427 	struct sys_setuid_args /* {
    428 		syscallarg(uid_t) uid;
    429 	} */ *uap = v;
    430 	uid_t uid = SCARG(uap, uid);
    431 
    432 	return do_setresuid(l, uid, uid, uid,
    433 			    ID_R_EQ_R | ID_E_EQ_R | ID_S_EQ_R);
    434 }
    435 
    436 /* ARGSUSED */
    437 int
    438 sys_seteuid(struct lwp *l, void *v, register_t *retval)
    439 {
    440 	struct sys_seteuid_args /* {
    441 		syscallarg(uid_t) euid;
    442 	} */ *uap = v;
    443 
    444 	return do_setresuid(l, -1, SCARG(uap, euid), -1, ID_E_EQ_R | ID_E_EQ_S);
    445 }
    446 
    447 int
    448 sys_setreuid(struct lwp *l, void *v, register_t *retval)
    449 {
    450 	struct sys_setreuid_args /* {
    451 		syscallarg(uid_t) ruid;
    452 		syscallarg(uid_t) euid;
    453 	} */ *uap = v;
    454 	struct proc *p = l->l_proc;
    455 	uid_t ruid, euid, svuid;
    456 
    457 	ruid = SCARG(uap, ruid);
    458 	euid = SCARG(uap, euid);
    459 	if (ruid == -1)
    460 		ruid = p->p_cred->p_ruid;
    461 	if (euid == -1)
    462 		euid = p->p_ucred->cr_uid;
    463 	/* Saved uid is set to the new euid if the ruid changed */
    464 	svuid = (ruid == p->p_cred->p_ruid) ? -1 : euid;
    465 
    466 	return do_setresuid(l, ruid, euid, svuid,
    467 			    ID_R_EQ_R | ID_R_EQ_E |
    468 			    ID_E_EQ_R | ID_E_EQ_E | ID_E_EQ_S |
    469 			    ID_S_EQ_R | ID_S_EQ_E | ID_S_EQ_S);
    470 }
    471 
    472 /* ARGSUSED */
    473 int
    474 sys_setgid(struct lwp *l, void *v, register_t *retval)
    475 {
    476 	struct sys_setgid_args /* {
    477 		syscallarg(gid_t) gid;
    478 	} */ *uap = v;
    479 	gid_t gid = SCARG(uap, gid);
    480 
    481 	return do_setresgid(l, gid, gid, gid,
    482 			    ID_R_EQ_R | ID_E_EQ_R | ID_S_EQ_R);
    483 }
    484 
    485 /* ARGSUSED */
    486 int
    487 sys_setegid(struct lwp *l, void *v, register_t *retval)
    488 {
    489 	struct sys_setegid_args /* {
    490 		syscallarg(gid_t) egid;
    491 	} */ *uap = v;
    492 
    493 	return do_setresgid(l, -1, SCARG(uap, egid), -1, ID_E_EQ_R | ID_E_EQ_S);
    494 }
    495 
    496 int
    497 sys_setregid(struct lwp *l, void *v, register_t *retval)
    498 {
    499 	struct sys_setregid_args /* {
    500 		syscallarg(gid_t) rgid;
    501 		syscallarg(gid_t) egid;
    502 	} */ *uap = v;
    503 	struct proc *p = l->l_proc;
    504 	gid_t rgid, egid, svgid;
    505 
    506 	rgid = SCARG(uap, rgid);
    507 	egid = SCARG(uap, egid);
    508 	if (rgid == -1)
    509 		rgid = p->p_cred->p_rgid;
    510 	if (egid == -1)
    511 		egid = p->p_ucred->cr_gid;
    512 	/* Saved gid is set to the new egid if the rgid changed */
    513 	svgid = rgid == p->p_cred->p_rgid ? -1 : egid;
    514 
    515 	return do_setresgid(l, rgid, egid, svgid,
    516 			ID_R_EQ_R | ID_R_EQ_E |
    517 			ID_E_EQ_R | ID_E_EQ_E | ID_E_EQ_S |
    518 			ID_S_EQ_R | ID_S_EQ_E | ID_S_EQ_S);
    519 }
    520 
    521 int
    522 sys_issetugid(struct lwp *l, void *v, register_t *retval)
    523 {
    524 	struct proc *p = l->l_proc;
    525 
    526 	/*
    527 	 * Note: OpenBSD sets a P_SUGIDEXEC flag set at execve() time,
    528 	 * we use P_SUGID because we consider changing the owners as
    529 	 * "tainting" as well.
    530 	 * This is significant for procs that start as root and "become"
    531 	 * a user without an exec - programs cannot know *everything*
    532 	 * that libc *might* have put in their data segment.
    533 	 */
    534 	*retval = (p->p_flag & P_SUGID) != 0;
    535 	return (0);
    536 }
    537 
    538 /* ARGSUSED */
    539 int
    540 sys_setgroups(struct lwp *l, void *v, register_t *retval)
    541 {
    542 	struct sys_setgroups_args /* {
    543 		syscallarg(int) gidsetsize;
    544 		syscallarg(const gid_t *) gidset;
    545 	} */ *uap = v;
    546 	struct proc *p = l->l_proc;
    547 	struct pcred *pc = p->p_cred;
    548 	int ngrp;
    549 	int error;
    550 	gid_t grp[NGROUPS];
    551 	size_t grsize;
    552 
    553 	if ((error = suser(pc->pc_ucred, &p->p_acflag)) != 0)
    554 		return (error);
    555 
    556 	ngrp = SCARG(uap, gidsetsize);
    557 	if ((u_int)ngrp > NGROUPS)
    558 		return (EINVAL);
    559 
    560 	grsize = ngrp * sizeof(gid_t);
    561 	error = copyin(SCARG(uap, gidset), grp, grsize);
    562 	if (error)
    563 		return (error);
    564 	/*
    565 	 * Check if this is a no-op.
    566 	 */
    567 	if (pc->pc_ucred->cr_ngroups == (u_int) ngrp &&
    568 	    memcmp(grp, pc->pc_ucred->cr_groups, grsize) == 0)
    569 		return (0);
    570 
    571 	pc->pc_ucred = crcopy(pc->pc_ucred);
    572 	(void)memcpy(pc->pc_ucred->cr_groups, grp, grsize);
    573 	pc->pc_ucred->cr_ngroups = ngrp;
    574 	p_sugid(p);
    575 	return (0);
    576 }
    577 
    578 /*
    579  * Check if gid is a member of the group set.
    580  */
    581 int
    582 groupmember(gid_t gid, const struct ucred *cred)
    583 {
    584 	const gid_t *gp;
    585 	const gid_t *egp;
    586 
    587 	egp = &(cred->cr_groups[cred->cr_ngroups]);
    588 	for (gp = cred->cr_groups; gp < egp; gp++)
    589 		if (*gp == gid)
    590 			return (1);
    591 	return (0);
    592 }
    593 
    594 /*
    595  * Test whether the specified credentials imply "super-user"
    596  * privilege; if so, and we have accounting info, set the flag
    597  * indicating use of super-powers.
    598  * Returns 0 or error.
    599  */
    600 int
    601 suser(const struct ucred *cred, u_short *acflag)
    602 {
    603 
    604 	if (cred->cr_uid == 0) {
    605 		if (acflag)
    606 			*acflag |= ASU;
    607 		return (0);
    608 	}
    609 	return (EPERM);
    610 }
    611 
    612 /*
    613  * Allocate a zeroed cred structure.
    614  */
    615 struct ucred *
    616 crget(void)
    617 {
    618 	struct ucred *cr;
    619 
    620 	MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK);
    621 	memset((caddr_t)cr, 0, sizeof(*cr));
    622 	cr->cr_ref = 1;
    623 	return (cr);
    624 }
    625 
    626 /*
    627  * Free a cred structure.
    628  * Throws away space when ref count gets to 0.
    629  */
    630 void
    631 crfree(struct ucred *cr)
    632 {
    633 
    634 	if (--cr->cr_ref == 0)
    635 		FREE((caddr_t)cr, M_CRED);
    636 }
    637 
    638 /*
    639  * Compare cred structures and return 0 if they match
    640  */
    641 int
    642 crcmp(const struct ucred *cr1, const struct uucred *cr2)
    643 {
    644 	return cr1->cr_uid != cr2->cr_uid ||
    645 	    cr1->cr_gid != cr2->cr_gid ||
    646 	    cr1->cr_ngroups != (uint32_t)cr2->cr_ngroups ||
    647 	    memcmp(cr1->cr_groups, cr2->cr_groups, cr1->cr_ngroups);
    648 }
    649 
    650 /*
    651  * Copy cred structure to a new one and free the old one.
    652  */
    653 struct ucred *
    654 crcopy(struct ucred *cr)
    655 {
    656 	struct ucred *newcr;
    657 
    658 	if (cr->cr_ref == 1)
    659 		return (cr);
    660 	newcr = crget();
    661 	*newcr = *cr;
    662 	crfree(cr);
    663 	newcr->cr_ref = 1;
    664 	return (newcr);
    665 }
    666 
    667 /*
    668  * Dup cred struct to a new held one.
    669  */
    670 struct ucred *
    671 crdup(const struct ucred *cr)
    672 {
    673 	struct ucred *newcr;
    674 
    675 	newcr = crget();
    676 	*newcr = *cr;
    677 	newcr->cr_ref = 1;
    678 	return (newcr);
    679 }
    680 
    681 /*
    682  * convert from userland credentials to kernel one
    683  */
    684 void
    685 crcvt(struct ucred *uc, const struct uucred *uuc)
    686 {
    687 
    688 	uc->cr_ref = 0;
    689 	uc->cr_uid = uuc->cr_uid;
    690 	uc->cr_gid = uuc->cr_gid;
    691 	uc->cr_ngroups = uuc->cr_ngroups;
    692 	(void)memcpy(uc->cr_groups, uuc->cr_groups, sizeof(uuc->cr_groups));
    693 }
    694 
    695 /*
    696  * Get login name, if available.
    697  */
    698 /* ARGSUSED */
    699 int
    700 sys___getlogin(struct lwp *l, void *v, register_t *retval)
    701 {
    702 	struct sys___getlogin_args /* {
    703 		syscallarg(char *) namebuf;
    704 		syscallarg(size_t) namelen;
    705 	} */ *uap = v;
    706 	struct proc *p = l->l_proc;
    707 
    708 	if (SCARG(uap, namelen) > sizeof(p->p_pgrp->pg_session->s_login))
    709 		SCARG(uap, namelen) = sizeof(p->p_pgrp->pg_session->s_login);
    710 	return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
    711 	    (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen)));
    712 }
    713 
    714 /*
    715  * Set login name.
    716  */
    717 /* ARGSUSED */
    718 int
    719 sys___setlogin(struct lwp *l, void *v, register_t *retval)
    720 {
    721 	struct sys___setlogin_args /* {
    722 		syscallarg(const char *) namebuf;
    723 	} */ *uap = v;
    724 	struct proc *p = l->l_proc;
    725 	struct session *s = p->p_pgrp->pg_session;
    726 	char newname[sizeof s->s_login + 1];
    727 	int error;
    728 
    729 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
    730 		return (error);
    731 	error = copyinstr(SCARG(uap, namebuf), &newname, sizeof newname, NULL);
    732 	if (error != 0)
    733 		return (error == ENAMETOOLONG ? EINVAL : error);
    734 
    735 	if (s->s_flags & S_LOGIN_SET && p->p_pid != s->s_sid &&
    736 	    strncmp(newname, s->s_login, sizeof s->s_login) != 0)
    737 		log(LOG_WARNING, "%s (pid %d) changing logname from "
    738 		    "%.*s to %s\n", p->p_comm, p->p_pid,
    739 		    (int)sizeof s->s_login, s->s_login, newname);
    740 	s->s_flags |= S_LOGIN_SET;
    741 	strncpy(s->s_login, newname, sizeof s->s_login);
    742 	return (0);
    743 }
    744