[BACK]Return to kern_prot.c CVS log [TXT][DIR] Up to [local] / sys / kern

Annotation of sys/kern/kern_prot.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: kern_prot.c,v 1.30 2007/04/03 08:05:43 art Exp $      */
        !             2: /*     $NetBSD: kern_prot.c,v 1.33 1996/02/09 18:59:42 christos Exp $  */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993
        !             6:  *     The Regents of the University of California.  All rights reserved.
        !             7:  * (c) UNIX System Laboratories, Inc.
        !             8:  * All or some portions of this file are derived from material licensed
        !             9:  * to the University of California by American Telephone and Telegraph
        !            10:  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
        !            11:  * the permission of UNIX System Laboratories, Inc.
        !            12:  *
        !            13:  * Redistribution and use in source and binary forms, with or without
        !            14:  * modification, are permitted provided that the following conditions
        !            15:  * are met:
        !            16:  * 1. Redistributions of source code must retain the above copyright
        !            17:  *    notice, this list of conditions and the following disclaimer.
        !            18:  * 2. Redistributions in binary form must reproduce the above copyright
        !            19:  *    notice, this list of conditions and the following disclaimer in the
        !            20:  *    documentation and/or other materials provided with the distribution.
        !            21:  * 3. Neither the name of the University nor the names of its contributors
        !            22:  *    may be used to endorse or promote products derived from this software
        !            23:  *    without specific prior written permission.
        !            24:  *
        !            25:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            26:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            27:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            28:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            29:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            30:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            31:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            32:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            33:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            34:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            35:  * SUCH DAMAGE.
        !            36:  *
        !            37:  *     @(#)kern_prot.c 8.6 (Berkeley) 1/21/94
        !            38:  */
        !            39:
        !            40: /*
        !            41:  * System calls related to processes and protection
        !            42:  */
        !            43:
        !            44: #include <sys/param.h>
        !            45: #include <sys/acct.h>
        !            46: #include <sys/systm.h>
        !            47: #include <sys/ucred.h>
        !            48: #include <sys/proc.h>
        !            49: #include <sys/timeb.h>
        !            50: #include <sys/times.h>
        !            51: #include <sys/malloc.h>
        !            52: #include <sys/filedesc.h>
        !            53: #include <sys/pool.h>
        !            54:
        !            55: #include <sys/mount.h>
        !            56: #include <sys/syscallargs.h>
        !            57:
        !            58: /* ARGSUSED */
        !            59: int
        !            60: sys_getpid(struct proc *p, void *v, register_t *retval)
        !            61: {
        !            62:
        !            63:        *retval = p->p_p->ps_mainproc->p_pid;
        !            64: #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2) || \
        !            65:     defined(COMPAT_FREEBSD) || defined(COMPAT_BSDOS)
        !            66:        retval[1] = p->p_p->ps_mainproc->p_pptr->p_pid;
        !            67: #endif
        !            68:        return (0);
        !            69: }
        !            70:
        !            71: #ifdef RTHREADS
        !            72: /* ARGSUSED */
        !            73: int
        !            74: sys_getthrid(p, v, retval)
        !            75:        struct proc *p;
        !            76:        void *v;
        !            77:        register_t *retval;
        !            78: {
        !            79:
        !            80:        *retval = p->p_pid;
        !            81:        return (0);
        !            82: }
        !            83: #endif
        !            84:
        !            85: /* ARGSUSED */
        !            86: int
        !            87: sys_getppid(struct proc *p, void *v, register_t *retval)
        !            88: {
        !            89:
        !            90:        *retval = p->p_p->ps_mainproc->p_pptr->p_pid;
        !            91:        return (0);
        !            92: }
        !            93:
        !            94: /* Get process group ID; note that POSIX getpgrp takes no parameter */
        !            95: int
        !            96: sys_getpgrp(struct proc *p, void *v, register_t *retval)
        !            97: {
        !            98:
        !            99:        *retval = p->p_pgrp->pg_id;
        !           100:        return (0);
        !           101: }
        !           102:
        !           103: /*
        !           104:  * SysVR.4 compatible getpgid()
        !           105:  */
        !           106: pid_t
        !           107: sys_getpgid(struct proc *curp, void *v, register_t *retval)
        !           108: {
        !           109:        struct sys_getpgid_args /* {
        !           110:                syscallarg(pid_t) pid;
        !           111:        } */ *uap = v;
        !           112:        struct proc *targp = curp;
        !           113:
        !           114:        if (SCARG(uap, pid) == 0 || SCARG(uap, pid) == curp->p_pid)
        !           115:                goto found;
        !           116:        if ((targp = pfind(SCARG(uap, pid))) == NULL)
        !           117:                return (ESRCH);
        !           118:        if (targp->p_session != curp->p_session)
        !           119:                return (EPERM);
        !           120: found:
        !           121:        *retval = targp->p_pgid;
        !           122:        return (0);
        !           123: }
        !           124:
        !           125: pid_t
        !           126: sys_getsid(struct proc *curp, void *v, register_t *retval)
        !           127: {
        !           128:        struct sys_getsid_args /* {
        !           129:                syscallarg(pid_t) pid;
        !           130:        } */ *uap = v;
        !           131:        struct proc *targp = curp;
        !           132:
        !           133:        if (SCARG(uap, pid) == 0 || SCARG(uap, pid) == curp->p_pid)
        !           134:                goto found;
        !           135:        if ((targp = pfind(SCARG(uap, pid))) == NULL)
        !           136:                return (ESRCH);
        !           137:        if (targp->p_session != curp->p_session)
        !           138:                return (EPERM);
        !           139: found:
        !           140:        /* Skip exiting processes */
        !           141:        if (targp->p_pgrp->pg_session->s_leader == NULL)
        !           142:                return (ESRCH);
        !           143:        *retval = targp->p_pgrp->pg_session->s_leader->p_pid;
        !           144:        return (0);
        !           145: }
        !           146:
        !           147: /* ARGSUSED */
        !           148: int
        !           149: sys_getuid(struct proc *p, void *v, register_t *retval)
        !           150: {
        !           151:
        !           152:        *retval = p->p_cred->p_ruid;
        !           153: #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2) || \
        !           154:     defined(COMPAT_FREEBSD) || defined(COMPAT_BSDOS)
        !           155:        retval[1] = p->p_ucred->cr_uid;
        !           156: #endif
        !           157:        return (0);
        !           158: }
        !           159:
        !           160: /* ARGSUSED */
        !           161: int
        !           162: sys_geteuid(struct proc *p, void *v, register_t *retval)
        !           163: {
        !           164:
        !           165:        *retval = p->p_ucred->cr_uid;
        !           166:        return (0);
        !           167: }
        !           168:
        !           169: /* ARGSUSED */
        !           170: int
        !           171: sys_issetugid(struct proc *p, void *v, register_t *retval)
        !           172: {
        !           173:        if (p->p_flag & P_SUGIDEXEC)
        !           174:                *retval = 1;
        !           175:        else
        !           176:                *retval = 0;
        !           177:        return (0);
        !           178: }
        !           179:
        !           180: /* ARGSUSED */
        !           181: int
        !           182: sys_getgid(struct proc *p, void *v, register_t *retval)
        !           183: {
        !           184:
        !           185:        *retval = p->p_cred->p_rgid;
        !           186: #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_FREEBSD) || defined(COMPAT_BSDOS)
        !           187:        retval[1] = p->p_ucred->cr_gid;
        !           188: #endif
        !           189:        return (0);
        !           190: }
        !           191:
        !           192: /*
        !           193:  * Get effective group ID.  The "egid" is groups[0], and could be obtained
        !           194:  * via getgroups.  This syscall exists because it is somewhat painful to do
        !           195:  * correctly in a library function.
        !           196:  */
        !           197: /* ARGSUSED */
        !           198: int
        !           199: sys_getegid(struct proc *p, void *v, register_t *retval)
        !           200: {
        !           201:
        !           202:        *retval = p->p_ucred->cr_gid;
        !           203:        return (0);
        !           204: }
        !           205:
        !           206: int
        !           207: sys_getgroups(struct proc *p, void *v, register_t *retval)
        !           208: {
        !           209:        struct sys_getgroups_args /* {
        !           210:                syscallarg(int) gidsetsize;
        !           211:                syscallarg(gid_t *) gidset;
        !           212:        } */ *uap = v;
        !           213:        struct pcred *pc = p->p_cred;
        !           214:        u_int ngrp;
        !           215:        int error;
        !           216:
        !           217:        if ((ngrp = SCARG(uap, gidsetsize)) == 0) {
        !           218:                *retval = pc->pc_ucred->cr_ngroups;
        !           219:                return (0);
        !           220:        }
        !           221:        if (ngrp < pc->pc_ucred->cr_ngroups)
        !           222:                return (EINVAL);
        !           223:        ngrp = pc->pc_ucred->cr_ngroups;
        !           224:        error = copyout((caddr_t)pc->pc_ucred->cr_groups,
        !           225:            (caddr_t)SCARG(uap, gidset), ngrp * sizeof(gid_t));
        !           226:        if (error)
        !           227:                return (error);
        !           228:        *retval = ngrp;
        !           229:        return (0);
        !           230: }
        !           231:
        !           232: /* ARGSUSED */
        !           233: int
        !           234: sys_setsid(struct proc *p, void *v, register_t *retval)
        !           235: {
        !           236:
        !           237:        if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) {
        !           238:                return (EPERM);
        !           239:        } else {
        !           240:                (void)enterpgrp(p, p->p_pid, 1);
        !           241:                *retval = p->p_pid;
        !           242:                return (0);
        !           243:        }
        !           244: }
        !           245:
        !           246: /*
        !           247:  * set process group (setpgid/old setpgrp)
        !           248:  *
        !           249:  * caller does setpgid(targpid, targpgid)
        !           250:  *
        !           251:  * pid must be caller or child of caller (ESRCH)
        !           252:  * if a child
        !           253:  *     pid must be in same session (EPERM)
        !           254:  *     pid can't have done an exec (EACCES)
        !           255:  * if pgid != pid
        !           256:  *     there must exist some pid in same session having pgid (EPERM)
        !           257:  * pid must not be session leader (EPERM)
        !           258:  */
        !           259: /* ARGSUSED */
        !           260: int
        !           261: sys_setpgid(struct proc *curp, void *v, register_t *retval)
        !           262: {
        !           263:        struct sys_setpgid_args /* {
        !           264:                syscallarg(pid_t) pid;
        !           265:                syscallarg(int) pgid;
        !           266:        } */ *uap = v;
        !           267:        struct proc *targp;             /* target process */
        !           268:        struct pgrp *pgrp;              /* target pgrp */
        !           269:        pid_t pid;
        !           270:        int pgid;
        !           271:
        !           272:        pid = SCARG(uap, pid);
        !           273:        pgid = SCARG(uap, pgid);
        !           274:
        !           275:        if (pgid < 0)
        !           276:                return (EINVAL);
        !           277:
        !           278:        if (pid != 0 && pid != curp->p_pid) {
        !           279:                if ((targp = pfind(pid)) == 0 || !inferior(targp))
        !           280:                        return (ESRCH);
        !           281:                if (targp->p_session != curp->p_session)
        !           282:                        return (EPERM);
        !           283:                if (targp->p_flag & P_EXEC)
        !           284:                        return (EACCES);
        !           285:        } else
        !           286:                targp = curp;
        !           287:        if (SESS_LEADER(targp))
        !           288:                return (EPERM);
        !           289:        if (pgid == 0)
        !           290:                pgid = targp->p_pid;
        !           291:        else if (pgid != targp->p_pid)
        !           292:                if ((pgrp = pgfind(pgid)) == 0 ||
        !           293:                    pgrp->pg_session != curp->p_session)
        !           294:                        return (EPERM);
        !           295:        return (enterpgrp(targp, pgid, 0));
        !           296: }
        !           297:
        !           298: /* ARGSUSED */
        !           299: int
        !           300: sys_getresuid(struct proc *p, void *v, register_t *retval)
        !           301: {
        !           302:        struct sys_getresuid_args /* {
        !           303:                syscallarg(uid_t *) ruid;
        !           304:                syscallarg(uid_t *) euid;
        !           305:                syscallarg(uid_t *) suid;
        !           306:        } */ *uap = v;
        !           307:        struct pcred *pc = p->p_cred;
        !           308:        uid_t *ruid, *euid, *suid;
        !           309:        int error1 = 0, error2 = 0, error3 = 0;
        !           310:
        !           311:        ruid = SCARG(uap, ruid);
        !           312:        euid = SCARG(uap, euid);
        !           313:        suid = SCARG(uap, suid);
        !           314:
        !           315:        if (ruid != NULL)
        !           316:                error1 = copyout(&pc->p_ruid, ruid, sizeof(*ruid));
        !           317:        if (euid != NULL)
        !           318:                error2 = copyout(&pc->pc_ucred->cr_uid, euid, sizeof(*euid));
        !           319:        if (suid != NULL)
        !           320:                error3 = copyout(&pc->p_svuid, suid, sizeof(*suid));
        !           321:
        !           322:        return (error1 ? error1 : error2 ? error2 : error3);
        !           323: }
        !           324:
        !           325: /* ARGSUSED */
        !           326: int
        !           327: sys_setresuid(struct proc *p, void *v, register_t *retval)
        !           328: {
        !           329:        struct sys_setresuid_args /* {
        !           330:                syscallarg(uid_t) ruid;
        !           331:                syscallarg(uid_t) euid;
        !           332:                syscallarg(uid_t) suid;
        !           333:        } */ *uap = v;
        !           334:        struct pcred *pc = p->p_cred;
        !           335:        uid_t ruid, euid, suid;
        !           336:        int error;
        !           337:
        !           338:        ruid = SCARG(uap, ruid);
        !           339:        euid = SCARG(uap, euid);
        !           340:        suid = SCARG(uap, suid);
        !           341:
        !           342:        if ((ruid == -1 || ruid == pc->p_ruid) &&
        !           343:            (euid == -1 || euid == pc->pc_ucred->cr_uid) &&
        !           344:            (suid == -1 || suid == pc->p_svuid))
        !           345:                return (0);                     /* no change */
        !           346:
        !           347:        /*
        !           348:         * Any of the real, effective, and saved uids may be changed
        !           349:         * to the current value of one of the three (root is not limited).
        !           350:         */
        !           351:        if (ruid != (uid_t)-1 &&
        !           352:            ruid != pc->p_ruid &&
        !           353:            ruid != pc->pc_ucred->cr_uid &&
        !           354:            ruid != pc->p_svuid &&
        !           355:            (error = suser(p, 0)))
        !           356:                return (error);
        !           357:
        !           358:        if (euid != (uid_t)-1 &&
        !           359:            euid != pc->p_ruid &&
        !           360:            euid != pc->pc_ucred->cr_uid &&
        !           361:            euid != pc->p_svuid &&
        !           362:            (error = suser(p, 0)))
        !           363:                return (error);
        !           364:
        !           365:        if (suid != (uid_t)-1 &&
        !           366:            suid != pc->p_ruid &&
        !           367:            suid != pc->pc_ucred->cr_uid &&
        !           368:            suid != pc->p_svuid &&
        !           369:            (error = suser(p, 0)))
        !           370:                return (error);
        !           371:
        !           372:        /*
        !           373:         * Note that unlike the other set*uid() calls, each
        !           374:         * uid type is set independently of the others.
        !           375:         */
        !           376:        if (ruid != (uid_t)-1 && ruid != pc->p_ruid) {
        !           377:                /*
        !           378:                 * Transfer proc count to new user.
        !           379:                 */
        !           380:                (void)chgproccnt(pc->p_ruid, -1);
        !           381:                (void)chgproccnt(ruid, 1);
        !           382:                pc->p_ruid = ruid;
        !           383:        }
        !           384:        if (euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid) {
        !           385:                /*
        !           386:                 * Copy credentials so other references do not see our changes.
        !           387:                 */
        !           388:                pc->pc_ucred = crcopy(pc->pc_ucred);
        !           389:                pc->pc_ucred->cr_uid = euid;
        !           390:        }
        !           391:        if (suid != (uid_t)-1 && suid != pc->p_svuid)
        !           392:                pc->p_svuid = suid;
        !           393:
        !           394:        atomic_setbits_int(&p->p_flag, P_SUGID);
        !           395:        return (0);
        !           396: }
        !           397:
        !           398: /* ARGSUSED */
        !           399: int
        !           400: sys_getresgid(struct proc *p, void *v, register_t *retval)
        !           401: {
        !           402:        struct sys_getresgid_args /* {
        !           403:                syscallarg(gid_t *) rgid;
        !           404:                syscallarg(gid_t *) egid;
        !           405:                syscallarg(gid_t *) sgid;
        !           406:        } */ *uap = v;
        !           407:        struct pcred *pc = p->p_cred;
        !           408:        gid_t *rgid, *egid, *sgid;
        !           409:        int error1 = 0, error2 = 0, error3 = 0;
        !           410:
        !           411:        rgid = SCARG(uap, rgid);
        !           412:        egid = SCARG(uap, egid);
        !           413:        sgid = SCARG(uap, sgid);
        !           414:
        !           415:        if (rgid != NULL)
        !           416:                error1 = copyout(&pc->p_rgid, rgid, sizeof(*rgid));
        !           417:        if (egid != NULL)
        !           418:                error2 = copyout(&pc->pc_ucred->cr_gid, egid, sizeof(*egid));
        !           419:        if (sgid != NULL)
        !           420:                error3 = copyout(&pc->p_svgid, sgid, sizeof(*sgid));
        !           421:
        !           422:        return (error1 ? error1 : error2 ? error2 : error3);
        !           423: }
        !           424:
        !           425: /* ARGSUSED */
        !           426: int
        !           427: sys_setresgid(struct proc *p, void *v, register_t *retval)
        !           428: {
        !           429:        struct sys_setresgid_args /* {
        !           430:                syscallarg(gid_t) rgid;
        !           431:                syscallarg(gid_t) egid;
        !           432:                syscallarg(gid_t) sgid;
        !           433:        } */ *uap = v;
        !           434:        struct pcred *pc = p->p_cred;
        !           435:        gid_t rgid, egid, sgid;
        !           436:        int error;
        !           437:
        !           438:        rgid = SCARG(uap, rgid);
        !           439:        egid = SCARG(uap, egid);
        !           440:        sgid = SCARG(uap, sgid);
        !           441:
        !           442:        if ((rgid == -1 || rgid == pc->p_rgid) &&
        !           443:            (egid == -1 || egid == pc->pc_ucred->cr_gid) &&
        !           444:            (sgid == -1 || sgid == pc->p_svgid))
        !           445:                return (0);                     /* no change */
        !           446:
        !           447:        /*
        !           448:         * Any of the real, effective, and saved gids may be changed
        !           449:         * to the current value of one of the three (root is not limited).
        !           450:         */
        !           451:        if (rgid != (gid_t)-1 &&
        !           452:            rgid != pc->p_rgid &&
        !           453:            rgid != pc->pc_ucred->cr_gid &&
        !           454:            rgid != pc->p_svgid &&
        !           455:            (error = suser(p, 0)))
        !           456:                return (error);
        !           457:
        !           458:        if (egid != (gid_t)-1 &&
        !           459:            egid != pc->p_rgid &&
        !           460:            egid != pc->pc_ucred->cr_gid &&
        !           461:            egid != pc->p_svgid &&
        !           462:            (error = suser(p, 0)))
        !           463:                return (error);
        !           464:
        !           465:        if (sgid != (gid_t)-1 &&
        !           466:            sgid != pc->p_rgid &&
        !           467:            sgid != pc->pc_ucred->cr_gid &&
        !           468:            sgid != pc->p_svgid &&
        !           469:            (error = suser(p, 0)))
        !           470:                return (error);
        !           471:
        !           472:        /*
        !           473:         * Note that unlike the other set*gid() calls, each
        !           474:         * gid type is set independently of the others.
        !           475:         */
        !           476:        if (rgid != (gid_t)-1)
        !           477:                pc->p_rgid = rgid;
        !           478:        if (egid != (gid_t)-1) {
        !           479:                /*
        !           480:                 * Copy credentials so other references do not see our changes.
        !           481:                 */
        !           482:                pc->pc_ucred = crcopy(pc->pc_ucred);
        !           483:                pc->pc_ucred->cr_gid = egid;
        !           484:        }
        !           485:        if (sgid != (gid_t)-1)
        !           486:                pc->p_svgid = sgid;
        !           487:
        !           488:        atomic_setbits_int(&p->p_flag, P_SUGID);
        !           489:        return (0);
        !           490: }
        !           491:
        !           492: /* ARGSUSED */
        !           493: int
        !           494: sys_setregid(struct proc *p, void *v, register_t *retval)
        !           495: {
        !           496:        struct sys_setregid_args /* {
        !           497:                syscallarg(gid_t) rgid;
        !           498:                syscallarg(gid_t) egid;
        !           499:        } */ *uap = v;
        !           500:        struct pcred *pc = p->p_cred;
        !           501:        struct sys_setresgid_args sresgidargs;
        !           502:        gid_t rgid, egid;
        !           503:
        !           504:        rgid = SCARG(&sresgidargs, rgid) = SCARG(uap, rgid);
        !           505:        egid = SCARG(&sresgidargs, egid) = SCARG(uap, egid);
        !           506:
        !           507:        /*
        !           508:         * The saved gid presents a bit of a dilemma, as it did not
        !           509:         * exist when setregid(2) was conceived.  We only set the saved
        !           510:         * gid when the real gid is specified and either its value would
        !           511:         * change, or where the saved and effective gids are different.
        !           512:         */
        !           513:        if (rgid != (gid_t)-1 && (rgid != pc->p_rgid ||
        !           514:            pc->p_svgid != (egid != (gid_t)-1 ? egid : pc->pc_ucred->cr_gid)))
        !           515:                SCARG(&sresgidargs, sgid) = rgid;
        !           516:        else
        !           517:                SCARG(&sresgidargs, sgid) = (gid_t)-1;
        !           518:
        !           519:        return (sys_setresgid(p, &sresgidargs, retval));
        !           520: }
        !           521:
        !           522: /* ARGSUSED */
        !           523: int
        !           524: sys_setreuid(struct proc *p, void *v, register_t *retval)
        !           525: {
        !           526:        struct sys_setreuid_args /* {
        !           527:                syscallarg(uid_t) ruid;
        !           528:                syscallarg(uid_t) euid;
        !           529:        } */ *uap = v;
        !           530:        struct pcred *pc = p->p_cred;
        !           531:        struct sys_setresuid_args sresuidargs;
        !           532:        uid_t ruid, euid;
        !           533:
        !           534:        ruid = SCARG(&sresuidargs, ruid) = SCARG(uap, ruid);
        !           535:        euid = SCARG(&sresuidargs, euid) = SCARG(uap, euid);
        !           536:
        !           537:        /*
        !           538:         * The saved uid presents a bit of a dilemma, as it did not
        !           539:         * exist when setreuid(2) was conceived.  We only set the saved
        !           540:         * uid when the real uid is specified and either its value would
        !           541:         * change, or where the saved and effective uids are different.
        !           542:         */
        !           543:        if (ruid != (uid_t)-1 && (ruid != pc->p_ruid ||
        !           544:            pc->p_svuid != (euid != (uid_t)-1 ? euid : pc->pc_ucred->cr_uid)))
        !           545:                SCARG(&sresuidargs, suid) = ruid;
        !           546:        else
        !           547:                SCARG(&sresuidargs, suid) = (uid_t)-1;
        !           548:
        !           549:        return (sys_setresuid(p, &sresuidargs, retval));
        !           550: }
        !           551:
        !           552: /* ARGSUSED */
        !           553: int
        !           554: sys_setuid(struct proc *p, void *v, register_t *retval)
        !           555: {
        !           556:        struct sys_setuid_args /* {
        !           557:                syscallarg(uid_t) uid;
        !           558:        } */ *uap = v;
        !           559:        struct pcred *pc = p->p_cred;
        !           560:        uid_t uid;
        !           561:        int error;
        !           562:
        !           563:        uid = SCARG(uap, uid);
        !           564:
        !           565:        if (pc->pc_ucred->cr_uid == uid &&
        !           566:            pc->p_ruid == uid &&
        !           567:            pc->p_svuid == uid)
        !           568:                return (0);
        !           569:
        !           570:        if (uid != pc->p_ruid &&
        !           571:            uid != pc->p_svuid &&
        !           572:            uid != pc->pc_ucred->cr_uid &&
        !           573:            (error = suser(p, 0)))
        !           574:                return (error);
        !           575:
        !           576:        /*
        !           577:         * Everything's okay, do it.
        !           578:         */
        !           579:        if (uid == pc->pc_ucred->cr_uid ||
        !           580:            suser(p, 0) == 0) {
        !           581:                /*
        !           582:                 * Transfer proc count to new user.
        !           583:                 */
        !           584:                if (uid != pc->p_ruid) {
        !           585:                        (void)chgproccnt(pc->p_ruid, -1);
        !           586:                        (void)chgproccnt(uid, 1);
        !           587:                }
        !           588:                pc->p_ruid = uid;
        !           589:                pc->p_svuid = uid;
        !           590:        }
        !           591:
        !           592:        /*
        !           593:         * Copy credentials so other references do not see our changes.
        !           594:         */
        !           595:        pc->pc_ucred = crcopy(pc->pc_ucred);
        !           596:        pc->pc_ucred->cr_uid = uid;
        !           597:        atomic_setbits_int(&p->p_flag, P_SUGID);
        !           598:        return (0);
        !           599: }
        !           600:
        !           601: /* ARGSUSED */
        !           602: int
        !           603: sys_seteuid(struct proc *p, void *v, register_t *retval)
        !           604: {
        !           605:        struct sys_seteuid_args /* {
        !           606:                syscallarg(uid_t) euid;
        !           607:        } */ *uap = v;
        !           608:        struct pcred *pc = p->p_cred;
        !           609:        uid_t euid;
        !           610:        int error;
        !           611:
        !           612:        euid = SCARG(uap, euid);
        !           613:
        !           614:        if (pc->pc_ucred->cr_uid == euid)
        !           615:                return (0);
        !           616:
        !           617:        if (euid != pc->p_ruid && euid != pc->p_svuid &&
        !           618:            (error = suser(p, 0)))
        !           619:                return (error);
        !           620:
        !           621:        /*
        !           622:         * Copy credentials so other references do not see our changes.
        !           623:         */
        !           624:        pc->pc_ucred = crcopy(pc->pc_ucred);
        !           625:        pc->pc_ucred->cr_uid = euid;
        !           626:        atomic_setbits_int(&p->p_flag, P_SUGID);
        !           627:        return (0);
        !           628: }
        !           629:
        !           630: /* ARGSUSED */
        !           631: int
        !           632: sys_setgid(struct proc *p, void *v, register_t *retval)
        !           633: {
        !           634:        struct sys_setgid_args /* {
        !           635:                syscallarg(gid_t) gid;
        !           636:        } */ *uap = v;
        !           637:        struct pcred *pc = p->p_cred;
        !           638:        gid_t gid;
        !           639:        int error;
        !           640:
        !           641:        gid = SCARG(uap, gid);
        !           642:
        !           643:        if (pc->pc_ucred->cr_gid == gid &&
        !           644:            pc->p_rgid == gid &&
        !           645:            pc->p_svgid == gid)
        !           646:                return (0);
        !           647:
        !           648:        if (gid != pc->p_rgid &&
        !           649:            gid != pc->p_svgid &&
        !           650:            gid != pc->pc_ucred->cr_gid &&
        !           651:            (error = suser(p, 0)))
        !           652:                return (error);
        !           653:
        !           654:        if (gid == pc->pc_ucred->cr_gid ||
        !           655:            suser(p, 0) == 0) {
        !           656:                pc->p_rgid = gid;
        !           657:                pc->p_svgid = gid;
        !           658:        }
        !           659:
        !           660:        /*
        !           661:         * Copy credentials so other references do not see our changes.
        !           662:         */
        !           663:        pc->pc_ucred = crcopy(pc->pc_ucred);
        !           664:        pc->pc_ucred->cr_gid = gid;
        !           665:        atomic_setbits_int(&p->p_flag, P_SUGID);
        !           666:        return (0);
        !           667: }
        !           668:
        !           669: /* ARGSUSED */
        !           670: int
        !           671: sys_setegid(struct proc *p, void *v, register_t *retval)
        !           672: {
        !           673:        struct sys_setegid_args /* {
        !           674:                syscallarg(gid_t) egid;
        !           675:        } */ *uap = v;
        !           676:        struct pcred *pc = p->p_cred;
        !           677:        gid_t egid;
        !           678:        int error;
        !           679:
        !           680:        egid = SCARG(uap, egid);
        !           681:
        !           682:        if (pc->pc_ucred->cr_gid == egid)
        !           683:                return (0);
        !           684:
        !           685:        if (egid != pc->p_rgid && egid != pc->p_svgid &&
        !           686:            (error = suser(p, 0)))
        !           687:                return (error);
        !           688:
        !           689:        /*
        !           690:         * Copy credentials so other references do not see our changes.
        !           691:         */
        !           692:        pc->pc_ucred = crcopy(pc->pc_ucred);
        !           693:        pc->pc_ucred->cr_gid = egid;
        !           694:        atomic_setbits_int(&p->p_flag, P_SUGID);
        !           695:        return (0);
        !           696: }
        !           697:
        !           698: /* ARGSUSED */
        !           699: int
        !           700: sys_setgroups(struct proc *p, void *v, register_t *retval)
        !           701: {
        !           702:        struct sys_setgroups_args /* {
        !           703:                syscallarg(int) gidsetsize;
        !           704:                syscallarg(const gid_t *) gidset;
        !           705:        } */ *uap = v;
        !           706:        struct pcred *pc = p->p_cred;
        !           707:        u_int ngrp;
        !           708:        int error;
        !           709:
        !           710:        if ((error = suser(p, 0)) != 0)
        !           711:                return (error);
        !           712:        ngrp = SCARG(uap, gidsetsize);
        !           713:        if (ngrp > NGROUPS)
        !           714:                return (EINVAL);
        !           715:        pc->pc_ucred = crcopy(pc->pc_ucred);
        !           716:        error = copyin((caddr_t)SCARG(uap, gidset),
        !           717:            (caddr_t)pc->pc_ucred->cr_groups, ngrp * sizeof(gid_t));
        !           718:        if (error)
        !           719:                return (error);
        !           720:        pc->pc_ucred->cr_ngroups = ngrp;
        !           721:        atomic_setbits_int(&p->p_flag, P_SUGID);
        !           722:        return (0);
        !           723: }
        !           724:
        !           725: /*
        !           726:  * Check if gid is a member of the group set.
        !           727:  */
        !           728: int
        !           729: groupmember(gid_t gid, struct ucred *cred)
        !           730: {
        !           731:        gid_t *gp;
        !           732:        gid_t *egp;
        !           733:
        !           734:        egp = &(cred->cr_groups[cred->cr_ngroups]);
        !           735:        for (gp = cred->cr_groups; gp < egp; gp++)
        !           736:                if (*gp == gid)
        !           737:                        return (1);
        !           738:        return (0);
        !           739: }
        !           740:
        !           741: /*
        !           742:  * Test whether this process has special user powers.
        !           743:  * Returns 0 or error.
        !           744:  */
        !           745: int
        !           746: suser(struct proc *p, u_int flags)
        !           747: {
        !           748:        struct ucred *cred = p->p_ucred;
        !           749:
        !           750:        if (cred->cr_uid == 0) {
        !           751:                if (!(flags & SUSER_NOACCT))
        !           752:                        p->p_acflag |= ASU;
        !           753:                return (0);
        !           754:        }
        !           755:        return (EPERM);
        !           756: }
        !           757:
        !           758: /*
        !           759:  * replacement for old suser, for callers who don't have a process
        !           760:  */
        !           761: int
        !           762: suser_ucred(struct ucred *cred)
        !           763: {
        !           764:        if (cred->cr_uid == 0)
        !           765:                return (0);
        !           766:        return (EPERM);
        !           767: }
        !           768:
        !           769: /*
        !           770:  * Allocate a zeroed cred structure.
        !           771:  */
        !           772: struct ucred *
        !           773: crget(void)
        !           774: {
        !           775:        struct ucred *cr;
        !           776:
        !           777:        cr = pool_get(&ucred_pool, PR_WAITOK);
        !           778:        bzero((caddr_t)cr, sizeof(*cr));
        !           779:        cr->cr_ref = 1;
        !           780:        return (cr);
        !           781: }
        !           782:
        !           783: /*
        !           784:  * Free a cred structure.
        !           785:  * Throws away space when ref count gets to 0.
        !           786:  */
        !           787: void
        !           788: crfree(struct ucred *cr)
        !           789: {
        !           790:
        !           791:        if (--cr->cr_ref == 0)
        !           792:                pool_put(&ucred_pool, cr);
        !           793: }
        !           794:
        !           795: /*
        !           796:  * Copy cred structure to a new one and free the old one.
        !           797:  */
        !           798: struct ucred *
        !           799: crcopy(struct ucred *cr)
        !           800: {
        !           801:        struct ucred *newcr;
        !           802:
        !           803:        if (cr->cr_ref == 1)
        !           804:                return (cr);
        !           805:        newcr = crget();
        !           806:        *newcr = *cr;
        !           807:        crfree(cr);
        !           808:        newcr->cr_ref = 1;
        !           809:        return (newcr);
        !           810: }
        !           811:
        !           812: /*
        !           813:  * Dup cred struct to a new held one.
        !           814:  */
        !           815: struct ucred *
        !           816: crdup(struct ucred *cr)
        !           817: {
        !           818:        struct ucred *newcr;
        !           819:
        !           820:        newcr = crget();
        !           821:        *newcr = *cr;
        !           822:        newcr->cr_ref = 1;
        !           823:        return (newcr);
        !           824: }
        !           825:
        !           826: /*
        !           827:  * Get login name, if available.
        !           828:  */
        !           829: /* ARGSUSED */
        !           830: int
        !           831: sys_getlogin(struct proc *p, void *v, register_t *retval)
        !           832: {
        !           833:        struct sys_getlogin_args /* {
        !           834:                syscallarg(char *) namebuf;
        !           835:                syscallarg(u_int) namelen;
        !           836:        } */ *uap = v;
        !           837:
        !           838:        if (SCARG(uap, namelen) > sizeof (p->p_pgrp->pg_session->s_login))
        !           839:                SCARG(uap, namelen) = sizeof (p->p_pgrp->pg_session->s_login);
        !           840:        return (copyout((caddr_t) p->p_pgrp->pg_session->s_login,
        !           841:            (caddr_t) SCARG(uap, namebuf), SCARG(uap, namelen)));
        !           842: }
        !           843:
        !           844: /*
        !           845:  * Set login name.
        !           846:  */
        !           847: /* ARGSUSED */
        !           848: int
        !           849: sys_setlogin(struct proc *p, void *v, register_t *retval)
        !           850: {
        !           851:        struct sys_setlogin_args /* {
        !           852:                syscallarg(const char *) namebuf;
        !           853:        } */ *uap = v;
        !           854:        int error;
        !           855:
        !           856:        if ((error = suser(p, 0)) != 0)
        !           857:                return (error);
        !           858:        error = copyinstr((caddr_t) SCARG(uap, namebuf),
        !           859:            (caddr_t) p->p_pgrp->pg_session->s_login,
        !           860:            sizeof (p->p_pgrp->pg_session->s_login), (size_t *)0);
        !           861:        if (error == ENAMETOOLONG)
        !           862:                error = EINVAL;
        !           863:        return (error);
        !           864: }
        !           865:
        !           866: /*
        !           867:  * Check if a process is allowed to raise its privileges.
        !           868:  */
        !           869: int
        !           870: proc_cansugid(struct proc *p)
        !           871: {
        !           872:        /* ptrace(2)d processes shouldn't. */
        !           873:        if ((p->p_flag & P_TRACED) != 0)
        !           874:                return (0);
        !           875:
        !           876:        /* proceses with shared filedescriptors shouldn't. */
        !           877:        if (p->p_fd->fd_refcnt > 1)
        !           878:                return (0);
        !           879:
        !           880:        /* Allow. */
        !           881:        return (1);
        !           882: }

CVSweb