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