[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

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