123372Smckusick /* 2*43393Skarels * Copyright (c) 1982, 1986, 1989, 1990 Regents of the University of California. 337578Smckusick * All rights reserved. 423372Smckusick * 537578Smckusick * Redistribution and use in source and binary forms are permitted 637578Smckusick * provided that the above copyright notice and this paragraph are 737578Smckusick * duplicated in all such forms and that any documentation, 837578Smckusick * advertising materials, and other materials related to such 937578Smckusick * distribution and use acknowledge that the software was developed 1037578Smckusick * by the University of California, Berkeley. The name of the 1137578Smckusick * University may not be used to endorse or promote products derived 1237578Smckusick * from this software without specific prior written permission. 1337578Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1437578Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1537578Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1637578Smckusick * 17*43393Skarels * @(#)kern_prot.c 7.11 (Berkeley) 06/21/90 1823372Smckusick */ 197420Sroot 207420Sroot /* 217498Sroot * System calls related to processes and protection 227420Sroot */ 237420Sroot 2417092Sbloom #include "param.h" 2537578Smckusick #include "acct.h" 2617092Sbloom #include "systm.h" 27*43393Skarels #include "syscontext.h" 2817092Sbloom #include "proc.h" 2917092Sbloom #include "timeb.h" 3017092Sbloom #include "times.h" 3137578Smckusick #include "malloc.h" 327420Sroot 33*43393Skarels /* ARGSUSED */ 34*43393Skarels getpid(p, uap, retval) 35*43393Skarels struct proc *p; 36*43393Skarels void *uap; 37*43393Skarels int *retval; 38*43393Skarels { 3937579Smckusick 40*43393Skarels *retval = p->p_pid; 41*43393Skarels #ifdef COMPAT_43 42*43393Skarels retval[1] = p->p_ppid; 43*43393Skarels #endif 44*43393Skarels RETURN (0); 45*43393Skarels } 46*43393Skarels 47*43393Skarels /* ARGSUSED */ 48*43393Skarels getppid(p, uap, retval) 49*43393Skarels struct proc *p; 50*43393Skarels void *uap; 51*43393Skarels int *retval; 527498Sroot { 537498Sroot 54*43393Skarels *retval = p->p_ppid; 55*43393Skarels RETURN (0); 567498Sroot } 577498Sroot 58*43393Skarels getpgrp(p, uap, retval) 59*43393Skarels struct proc *p; 60*43393Skarels struct args { 61*43393Skarels int pid; 62*43393Skarels } *uap; 63*43393Skarels int *retval; 647498Sroot { 657498Sroot 66*43393Skarels if (uap->pid != 0 && (p = pfind(uap->pid)) == 0) 67*43393Skarels RETURN (ESRCH); 68*43393Skarels *retval = p->p_pgrp->pg_id; 69*43393Skarels RETURN (0); 707498Sroot } 717498Sroot 72*43393Skarels /* ARGSUSED */ 73*43393Skarels getuid(p, uap, retval) 74*43393Skarels struct proc *p; 75*43393Skarels void *uap; 76*43393Skarels int *retval; 777420Sroot { 787420Sroot 79*43393Skarels *retval = p->p_ruid; 80*43393Skarels #ifdef COMPAT_43 81*43393Skarels retval[1] = u.u_cred->cr_uid; 82*43393Skarels #endif 83*43393Skarels RETURN (0); 847420Sroot } 857420Sroot 86*43393Skarels /* ARGSUSED */ 87*43393Skarels geteuid(p, uap, retval) 88*43393Skarels struct proc *p; 89*43393Skarels void *uap; 90*43393Skarels int *retval; 917498Sroot { 927498Sroot 93*43393Skarels *retval = u.u_cred->cr_uid; 94*43393Skarels RETURN (0); 957498Sroot } 967498Sroot 97*43393Skarels /* ARGSUSED */ 98*43393Skarels getgid(p, uap, retval) 99*43393Skarels struct proc *p; 100*43393Skarels void *uap; 101*43393Skarels int *retval; 1027498Sroot { 103*43393Skarels 104*43393Skarels *retval = p->p_rgid; 105*43393Skarels #ifdef COMPAT_43 106*43393Skarels retval[1] = u.u_cred->cr_groups[0]; 107*43393Skarels #endif 108*43393Skarels RETURN (0); 109*43393Skarels } 110*43393Skarels 111*43393Skarels /* 112*43393Skarels * Get effective group ID. 113*43393Skarels * The "egid" is groups[0], and thus could be obtained via getgroups; 114*43393Skarels * this is somewhat painful to do correctly in a library function, 115*43393Skarels * this the existence of this syscall. 116*43393Skarels */ 117*43393Skarels /* ARGSUSED */ 118*43393Skarels getegid(p, uap, retval) 119*43393Skarels struct proc *p; 120*43393Skarels void *uap; 121*43393Skarels int *retval; 122*43393Skarels { 123*43393Skarels 124*43393Skarels *retval = u.u_cred->cr_groups[0]; 125*43393Skarels RETURN (0); 126*43393Skarels } 127*43393Skarels 128*43393Skarels getgroups(p, uap, retval) 129*43393Skarels struct proc *p; 130*43393Skarels register struct arg { 1318624Sroot u_int gidsetsize; 132*43393Skarels int *gidset; /* XXX not yet POSIX */ 133*43393Skarels } *uap; 134*43393Skarels int *retval; 135*43393Skarels { 13618362Skarels register gid_t *gp; 13718362Skarels register int *lp; 13818362Skarels int groups[NGROUPS]; 139*43393Skarels int error; 1407498Sroot 14137578Smckusick if (uap->gidsetsize == 0) { 142*43393Skarels *retval = u.u_cred->cr_ngroups; 143*43393Skarels RETURN (0); 14437578Smckusick } 145*43393Skarels if (uap->gidsetsize < u.u_cred->cr_ngroups) 146*43393Skarels RETURN (EINVAL); 14740667Skarels uap->gidsetsize = u.u_cred->cr_ngroups; 14840667Skarels gp = u.u_cred->cr_groups; 14937578Smckusick for (lp = groups; lp < &groups[uap->gidsetsize]; ) 15018362Skarels *lp++ = *gp++; 151*43393Skarels if (error = copyout((caddr_t)groups, (caddr_t)uap->gidset, 152*43393Skarels uap->gidsetsize * sizeof (groups[0]))) 153*43393Skarels RETURN (error); 154*43393Skarels *retval = uap->gidsetsize; 155*43393Skarels RETURN (0); 1567498Sroot } 1577498Sroot 158*43393Skarels /* ARGSUSED */ 159*43393Skarels setsid(p, uap, retval) 160*43393Skarels struct proc *p; 161*43393Skarels void *uap; 162*43393Skarels int *retval; 16337579Smckusick { 16437579Smckusick 165*43393Skarels if (p->p_pgid == p->p_pid || pgfind(p->p_pid)) { 166*43393Skarels RETURN (EPERM); 167*43393Skarels } else { 16837579Smckusick pgmv(p, p->p_pid, 1); 169*43393Skarels *retval = p->p_pid; 170*43393Skarels RETURN (0); 17137579Smckusick } 17237579Smckusick } 17337579Smckusick 17437579Smckusick /* 175*43393Skarels * set process group (setpgrp/setpgid) 17637579Smckusick * 17740667Skarels * caller does setpgrp(pid, pgid) 17840667Skarels * 17940667Skarels * pid must be caller or child of caller (ESRCH) 18040667Skarels * if a child 18140667Skarels * pid must be in same session (EPERM) 18240667Skarels * pid can't have done an exec (EACCES) 18340667Skarels * if pgid != pid 18440667Skarels * there must exist some pid in same session having pgid (EPERM) 18540667Skarels * pid must not be session leader (EPERM) 18637579Smckusick */ 187*43393Skarels /* ARGSUSED */ 188*43393Skarels setpgrp(cp, uap, retval) 189*43393Skarels struct proc *cp; 190*43393Skarels register struct args { 1917498Sroot int pid; 19237579Smckusick int pgid; 193*43393Skarels } *uap; 194*43393Skarels int *retval; 195*43393Skarels { 19637579Smckusick register struct proc *p; 19737579Smckusick register struct pgrp *pgrp; 1987498Sroot 199*43393Skarels if (uap->pid != 0) { 200*43393Skarels if ((p = pfind(uap->pid)) == 0 || !inferior(p)) 201*43393Skarels RETURN (ESRCH); 202*43393Skarels if (p->p_session != cp->p_session) 203*43393Skarels RETURN (EPERM); 204*43393Skarels if (p->p_flag&SEXEC) 205*43393Skarels RETURN (EACCES); 206*43393Skarels } else 207*43393Skarels p = cp; 208*43393Skarels if (SESS_LEADER(p)) 209*43393Skarels RETURN (EPERM); 21037579Smckusick if (uap->pgid == 0) 21137579Smckusick uap->pgid = p->p_pid; 21237579Smckusick else if ((uap->pgid != p->p_pid) && 21337579Smckusick (((pgrp = pgfind(uap->pgid)) == 0) || 21437579Smckusick pgrp->pg_mem == NULL || 215*43393Skarels pgrp->pg_session != u.u_procp->p_session)) 216*43393Skarels RETURN (EPERM); 21737579Smckusick /* 218*43393Skarels * done checking, now do it 21937579Smckusick */ 22037579Smckusick pgmv(p, uap->pgid, 0); 221*43393Skarels RETURN (0); 2227498Sroot } 2237498Sroot 224*43393Skarels /* ARGSUSED */ 225*43393Skarels setuid(p, uap, retval) 226*43393Skarels register struct proc *p; 227*43393Skarels struct args { 228*43393Skarels int uid; 229*43393Skarels } *uap; 230*43393Skarels int *retval; 2317420Sroot { 232*43393Skarels register uid_t uid; 233*43393Skarels int error; 234*43393Skarels 235*43393Skarels uid = uap->uid; 236*43393Skarels if (uid != p->p_ruid && (error = suser(u.u_cred, &u.u_acflag))) 237*43393Skarels RETURN (error); 238*43393Skarels /* 239*43393Skarels * Everything's okay, do it. 240*43393Skarels * Copy credentials so other references do not 241*43393Skarels * see our changes. 242*43393Skarels */ 243*43393Skarels if (u.u_cred->cr_ref > 1) 244*43393Skarels u.u_cred = crcopy(u.u_cred); 245*43393Skarels u.u_cred->cr_uid = uid; 246*43393Skarels p->p_uid = uid; 247*43393Skarels p->p_ruid = uid; 248*43393Skarels p->p_svuid = uid; 249*43393Skarels RETURN (0); 250*43393Skarels } 251*43393Skarels 252*43393Skarels /* ARGSUSED */ 253*43393Skarels seteuid(p, uap, retval) 254*43393Skarels register struct proc *p; 255*43393Skarels struct args { 256*43393Skarels int euid; 257*43393Skarels } *uap; 258*43393Skarels int *retval; 259*43393Skarels { 260*43393Skarels register uid_t euid; 261*43393Skarels int error; 262*43393Skarels 263*43393Skarels euid = uap->euid; 264*43393Skarels if (euid != p->p_ruid && euid != p->p_svuid && 265*43393Skarels (error = suser(u.u_cred, &u.u_acflag))) 266*43393Skarels RETURN (error); 267*43393Skarels /* 268*43393Skarels * Everything's okay, do it. 269*43393Skarels * Copy credentials so other references do not 270*43393Skarels * see our changes. 271*43393Skarels */ 272*43393Skarels if (u.u_cred->cr_ref > 1) 273*43393Skarels u.u_cred = crcopy(u.u_cred); 274*43393Skarels u.u_cred->cr_uid = euid; 275*43393Skarels p->p_uid = euid; 276*43393Skarels RETURN (0); 277*43393Skarels } 278*43393Skarels 279*43393Skarels /* ARGSUSED */ 280*43393Skarels setgid(p, uap, retval) 281*43393Skarels struct proc *p; 282*43393Skarels struct args { 283*43393Skarels int gid; 284*43393Skarels } *uap; 285*43393Skarels int *retval; 286*43393Skarels { 287*43393Skarels register gid_t gid; 288*43393Skarels int error; 289*43393Skarels 290*43393Skarels gid = uap->gid; 291*43393Skarels if (gid != p->p_rgid && (error = suser(u.u_cred, &u.u_acflag))) 292*43393Skarels RETURN (error); 293*43393Skarels if (u.u_cred->cr_ref > 1) 294*43393Skarels u.u_cred = crcopy(u.u_cred); 295*43393Skarels p->p_rgid = gid; 296*43393Skarels u.u_cred->cr_groups[0] = gid; 297*43393Skarels p->p_svgid = gid; /* ??? */ 298*43393Skarels RETURN (0); 299*43393Skarels } 300*43393Skarels 301*43393Skarels /* ARGSUSED */ 302*43393Skarels setegid(p, uap, retval) 303*43393Skarels struct proc *p; 304*43393Skarels struct args { 305*43393Skarels int egid; 306*43393Skarels } *uap; 307*43393Skarels int *retval; 308*43393Skarels { 309*43393Skarels register gid_t egid; 310*43393Skarels int error; 311*43393Skarels 312*43393Skarels egid = uap->egid; 313*43393Skarels if (egid != p->p_rgid && egid != p->p_svgid && 314*43393Skarels (error = suser(u.u_cred, &u.u_acflag))) 315*43393Skarels RETURN (error); 316*43393Skarels if (u.u_cred->cr_ref > 1) 317*43393Skarels u.u_cred = crcopy(u.u_cred); 318*43393Skarels u.u_cred->cr_groups[0] = egid; 319*43393Skarels RETURN (0); 320*43393Skarels } 321*43393Skarels 322*43393Skarels #ifdef COMPAT_43 323*43393Skarels /* ARGSUSED */ 324*43393Skarels osetreuid(p, uap, retval) 325*43393Skarels register struct proc *p; 326*43393Skarels struct args { 3279160Ssam int ruid; 3289160Ssam int euid; 3299160Ssam } *uap; 330*43393Skarels int *retval; 331*43393Skarels { 332*43393Skarels register uid_t ruid, euid; 333*43393Skarels int error; 3349160Ssam 335*43393Skarels if (uap->ruid == -1) 33640667Skarels ruid = p->p_ruid; 337*43393Skarels else 338*43393Skarels ruid = uap->ruid; 339*43393Skarels /* 340*43393Skarels * Allow setting real uid to previous effective, 341*43393Skarels * for swapping real and effective. 342*43393Skarels * This should be: 343*43393Skarels * if (ruid != p->p_ruid && (error = suser(u.u_cred, &u.u_acflag))) 344*43393Skarels */ 34540667Skarels if (ruid != p->p_ruid && ruid != u.u_cred->cr_uid /* XXX */ && 346*43393Skarels (error = suser(u.u_cred, &u.u_acflag))) 347*43393Skarels RETURN (error); 348*43393Skarels if (uap->euid == -1) 34940667Skarels euid = u.u_cred->cr_uid; 350*43393Skarels else 351*43393Skarels euid = uap->euid; 35240667Skarels if (euid != u.u_cred->cr_uid && euid != p->p_ruid && 353*43393Skarels euid != p->p_svuid && (error = suser(u.u_cred, &u.u_acflag))) 354*43393Skarels RETURN (error); 3559160Ssam /* 3569160Ssam * Everything's okay, do it. 35737578Smckusick * Copy credentials so other references do not 35837578Smckusick * see our changes. 3599160Ssam */ 36037578Smckusick if (u.u_cred->cr_ref > 1) 36137578Smckusick u.u_cred = crcopy(u.u_cred); 36240667Skarels u.u_cred->cr_uid = euid; 36340667Skarels p->p_uid = euid; 36440667Skarels p->p_ruid = ruid; 365*43393Skarels RETURN (0); 3669160Ssam } 3679160Ssam 368*43393Skarels /* ARGSUSED */ 369*43393Skarels osetregid(p, uap, retval) 370*43393Skarels struct proc *p; 371*43393Skarels struct args { 3729160Ssam int rgid; 3739160Ssam int egid; 3749160Ssam } *uap; 375*43393Skarels int *retval; 376*43393Skarels { 377*43393Skarels register gid_t rgid, egid; 378*43393Skarels int error; 3799160Ssam 380*43393Skarels if (uap->rgid == -1) 38140667Skarels rgid = p->p_rgid; 382*43393Skarels else 383*43393Skarels rgid = uap->rgid; 384*43393Skarels /* 385*43393Skarels * Allow setting real gid to previous effective, 386*43393Skarels * for swapping real and effective. This didn't really work 387*43393Skarels * correctly in 4.[23], but is preserved so old stuff doesn't fail. 388*43393Skarels * This should be: 389*43393Skarels * if (rgid != p->p_rgid && (error = suser(u.u_cred, &u.u_acflag))) 390*43393Skarels */ 39140667Skarels if (rgid != p->p_rgid && rgid != u.u_cred->cr_groups[0] /* XXX */ && 392*43393Skarels (error = suser(u.u_cred, &u.u_acflag))) 393*43393Skarels RETURN (error); 394*43393Skarels if (uap->egid == -1) 39540667Skarels egid = u.u_cred->cr_groups[0]; 396*43393Skarels else 397*43393Skarels egid = uap->egid; 39840667Skarels if (egid != u.u_cred->cr_groups[0] && egid != p->p_rgid && 399*43393Skarels egid != p->p_svgid && (error = suser(u.u_cred, &u.u_acflag))) 400*43393Skarels RETURN (error); 40137578Smckusick if (u.u_cred->cr_ref > 1) 40237578Smckusick u.u_cred = crcopy(u.u_cred); 40340667Skarels p->p_rgid = rgid; 40440667Skarels u.u_cred->cr_groups[0] = egid; 405*43393Skarels RETURN (0); 4069160Ssam } 407*43393Skarels #endif 4089160Ssam 409*43393Skarels /* ARGSUSED */ 410*43393Skarels setgroups(p, uap, retval) 411*43393Skarels struct proc *p; 412*43393Skarels struct args { 4138624Sroot u_int gidsetsize; 4147498Sroot int *gidset; 415*43393Skarels } *uap; 416*43393Skarels int *retval; 417*43393Skarels { 41818362Skarels register gid_t *gp; 41918362Skarels register int *lp; 420*43393Skarels int error, ngrp, groups[NGROUPS]; 4217498Sroot 422*43393Skarels if (error = suser(u.u_cred, &u.u_acflag)) 423*43393Skarels RETURN (error); 42440667Skarels ngrp = uap->gidsetsize; 425*43393Skarels if (ngrp > NGROUPS) 426*43393Skarels RETURN (EINVAL); 427*43393Skarels error = copyin((caddr_t)uap->gidset, (caddr_t)groups, 42818362Skarels uap->gidsetsize * sizeof (groups[0])); 429*43393Skarels if (error) 430*43393Skarels RETURN (error); 43140667Skarels gp = u.u_cred->cr_groups; 43237578Smckusick for (lp = groups; lp < &groups[uap->gidsetsize]; ) 43318362Skarels *gp++ = *lp++; 43440667Skarels u.u_cred->cr_ngroups = ngrp; 435*43393Skarels RETURN (0); 4367498Sroot } 4377498Sroot 4387498Sroot /* 43937578Smckusick * Check if gid is a member of the group set. 44011810Ssam */ 44137578Smckusick groupmember(gid, cred) 44226275Skarels gid_t gid; 44337578Smckusick register struct ucred *cred; 4447866Sroot { 44518362Skarels register gid_t *gp; 44637578Smckusick gid_t *egp; 4477866Sroot 44837578Smckusick egp = &(cred->cr_groups[cred->cr_ngroups]); 44937578Smckusick for (gp = cred->cr_groups; gp < egp; gp++) 4507866Sroot if (*gp == gid) 45137578Smckusick return (1); 45237578Smckusick return (0); 4537866Sroot } 4547866Sroot 45511810Ssam /* 45637578Smckusick * Test if the current user is the super user. 45711810Ssam */ 45837578Smckusick suser(cred, acflag) 45937578Smckusick struct ucred *cred; 46037578Smckusick short *acflag; 4617866Sroot { 4627866Sroot 46337578Smckusick if (cred->cr_uid == 0) { 46437578Smckusick if (acflag) 46537578Smckusick *acflag |= ASU; 46637578Smckusick return (0); 46718362Skarels } 46837578Smckusick return (EPERM); 4697866Sroot } 47011810Ssam 47111810Ssam /* 47237578Smckusick * Allocate a zeroed cred structure. 47311810Ssam */ 47437578Smckusick struct ucred * 47537578Smckusick crget() 47611810Ssam { 47737578Smckusick register struct ucred *cr; 47811810Ssam 47937578Smckusick MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 48037578Smckusick bzero((caddr_t)cr, sizeof(*cr)); 48137578Smckusick cr->cr_ref = 1; 482*43393Skarels return (cr); 48311810Ssam } 48437085Skfall 48537085Skfall /* 48637578Smckusick * Free a cred structure. 48737578Smckusick * Throws away space when ref count gets to 0. 48837085Skfall */ 48937578Smckusick crfree(cr) 49037578Smckusick struct ucred *cr; 49137578Smckusick { 492*43393Skarels int s = splimp(); 49337085Skfall 49437578Smckusick if (--cr->cr_ref != 0) { 49537578Smckusick (void) splx(s); 49637578Smckusick return; 49737578Smckusick } 49837578Smckusick FREE((caddr_t)cr, M_CRED); 49937578Smckusick (void) splx(s); 50037578Smckusick } 50137578Smckusick 50237578Smckusick /* 50337578Smckusick * Copy cred structure to a new one and free the old one. 50437578Smckusick */ 50537578Smckusick struct ucred * 50637578Smckusick crcopy(cr) 50737578Smckusick struct ucred *cr; 50837085Skfall { 50937578Smckusick struct ucred *newcr; 51037085Skfall 51137578Smckusick newcr = crget(); 51237578Smckusick *newcr = *cr; 51337578Smckusick crfree(cr); 51437578Smckusick newcr->cr_ref = 1; 515*43393Skarels return (newcr); 51637085Skfall } 51737085Skfall 51837085Skfall /* 51937578Smckusick * Dup cred struct to a new held one. 52037085Skfall */ 52137578Smckusick struct ucred * 52237578Smckusick crdup(cr) 52337578Smckusick struct ucred *cr; 52437085Skfall { 52537578Smckusick struct ucred *newcr; 52637085Skfall 52737578Smckusick newcr = crget(); 52837578Smckusick *newcr = *cr; 52937578Smckusick newcr->cr_ref = 1; 530*43393Skarels return (newcr); 53137085Skfall } 53237579Smckusick 53337579Smckusick /* 53440667Skarels * Get login name, if available. 53537579Smckusick */ 536*43393Skarels /* ARGSUSED */ 537*43393Skarels getlogin(p, uap, retval) 538*43393Skarels struct proc *p; 539*43393Skarels struct args { 54037579Smckusick char *namebuf; 54137579Smckusick u_int namelen; 542*43393Skarels } *uap; 543*43393Skarels int *retval; 544*43393Skarels { 54537579Smckusick 546*43393Skarels if (uap->namelen > sizeof (p->p_logname)) 547*43393Skarels uap->namelen = sizeof (p->p_logname); 548*43393Skarels RETURN (copyout((caddr_t)p->p_logname, (caddr_t)uap->namebuf, 549*43393Skarels uap->namelen)); 55037579Smckusick } 55137579Smckusick 55237579Smckusick /* 55340667Skarels * Set login name. 55437579Smckusick */ 555*43393Skarels /* ARGSUSED */ 556*43393Skarels setlogin(p, uap, retval) 557*43393Skarels struct proc *p; 558*43393Skarels struct args { 559*43393Skarels char *namebuf; 560*43393Skarels } *uap; 561*43393Skarels int *retval; 56237579Smckusick { 56340667Skarels int error; 56437579Smckusick 565*43393Skarels if (error = suser(u.u_cred, &u.u_acflag)) 566*43393Skarels RETURN (error); 567*43393Skarels error = copyinstr((caddr_t)uap->namebuf, (caddr_t)p->p_logname, 568*43393Skarels sizeof (p->p_logname) - 1, (int *) 0); 56940667Skarels if (error == ENOENT) /* name too long */ 57040667Skarels error = EINVAL; 571*43393Skarels RETURN (error); 57237579Smckusick } 573