123372Smckusick /* 237578Smckusick * Copyright (c) 1982, 1986, 1989 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*40667Skarels * @(#)kern_prot.c 7.8 (Berkeley) 03/31/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" 2717092Sbloom #include "user.h" 2817092Sbloom #include "proc.h" 2917092Sbloom #include "timeb.h" 3017092Sbloom #include "times.h" 3117092Sbloom #include "reboot.h" 3237578Smckusick #include "mount.h" 3317092Sbloom #include "buf.h" 3437578Smckusick #include "../ufs/quota.h" 3537578Smckusick #include "malloc.h" 367420Sroot 3737579Smckusick #include "machine/reg.h" 3837579Smckusick 397498Sroot getpid() 407498Sroot { 417498Sroot 427498Sroot u.u_r.r_val1 = u.u_procp->p_pid; 437498Sroot u.u_r.r_val2 = u.u_procp->p_ppid; 447498Sroot } 457498Sroot 467498Sroot getpgrp() 477498Sroot { 487498Sroot register struct a { 497498Sroot int pid; 507498Sroot } *uap = (struct a *)u.u_ap; 517498Sroot register struct proc *p; 527498Sroot 537498Sroot if (uap->pid == 0) 5437579Smckusick p = u.u_procp; 5537579Smckusick else if ((p = pfind(uap->pid)) == 0) { 567498Sroot u.u_error = ESRCH; 577498Sroot return; 587498Sroot } 5937579Smckusick u.u_r.r_val1 = p->p_pgrp->pg_id; 607498Sroot } 617498Sroot 627420Sroot getuid() 637420Sroot { 647420Sroot 65*40667Skarels u.u_r.r_val1 = u.u_procp->p_ruid; 66*40667Skarels u.u_r.r_val2 = u.u_cred->cr_uid; 677420Sroot } 687420Sroot 697498Sroot getgid() 707498Sroot { 717498Sroot 72*40667Skarels u.u_r.r_val1 = u.u_procp->p_rgid; 73*40667Skarels u.u_r.r_val2 = u.u_cred->cr_groups[0]; 747498Sroot } 757498Sroot 767866Sroot getgroups() 777498Sroot { 787498Sroot register struct a { 798624Sroot u_int gidsetsize; 807498Sroot int *gidset; 817498Sroot } *uap = (struct a *)u.u_ap; 8218362Skarels register gid_t *gp; 8318362Skarels register int *lp; 8418362Skarels int groups[NGROUPS]; 857498Sroot 8637578Smckusick if (uap->gidsetsize == 0) { 87*40667Skarels u.u_r.r_val1 = u.u_cred->cr_ngroups; 8837578Smckusick return; 8937578Smckusick } 90*40667Skarels if (uap->gidsetsize < u.u_cred->cr_ngroups) { 917866Sroot u.u_error = EINVAL; 927866Sroot return; 937866Sroot } 94*40667Skarels uap->gidsetsize = u.u_cred->cr_ngroups; 95*40667Skarels gp = u.u_cred->cr_groups; 9637578Smckusick for (lp = groups; lp < &groups[uap->gidsetsize]; ) 9718362Skarels *lp++ = *gp++; 9818362Skarels u.u_error = copyout((caddr_t)groups, (caddr_t)uap->gidset, 9918362Skarels uap->gidsetsize * sizeof (groups[0])); 1009997Ssam if (u.u_error) 1017498Sroot return; 1027866Sroot u.u_r.r_val1 = uap->gidsetsize; 1037498Sroot } 1047498Sroot 10537579Smckusick setsid() 10637579Smckusick { 10737579Smckusick register struct proc *p = u.u_procp; 10837579Smckusick 10937579Smckusick if ((p->p_pgid == p->p_pid) || pgfind(p->p_pid)) 11037579Smckusick u.u_error = EPERM; 11137579Smckusick else { 11237579Smckusick pgmv(p, p->p_pid, 1); 11337579Smckusick u.u_r.r_val1 = p->p_pid; 11437579Smckusick } 11537579Smckusick return; 11637579Smckusick } 11737579Smckusick 11837579Smckusick /* 11937579Smckusick * set process group 12037579Smckusick * 121*40667Skarels * caller does setpgrp(pid, pgid) 122*40667Skarels * 123*40667Skarels * pid must be caller or child of caller (ESRCH) 124*40667Skarels * if a child 125*40667Skarels * pid must be in same session (EPERM) 126*40667Skarels * pid can't have done an exec (EACCES) 127*40667Skarels * if pgid != pid 128*40667Skarels * there must exist some pid in same session having pgid (EPERM) 129*40667Skarels * pid must not be session leader (EPERM) 13037579Smckusick */ 1317498Sroot setpgrp() 1327498Sroot { 1337498Sroot register struct a { 1347498Sroot int pid; 13537579Smckusick int pgid; 1367498Sroot } *uap = (struct a *)u.u_ap; 13737579Smckusick register struct proc *p; 13837579Smckusick register struct pgrp *pgrp; 1397498Sroot 1407498Sroot if (uap->pid == 0) 14137579Smckusick p = u.u_procp; 14237579Smckusick else if ((p = pfind(uap->pid)) == 0 || !inferior(p)) { 1437498Sroot u.u_error = ESRCH; 1447498Sroot return; 1457498Sroot } 14637579Smckusick else if (p != u.u_procp) { 14737579Smckusick if (p->p_session != u.u_procp->p_session) { 14837579Smckusick u.u_error = EPERM; 14937579Smckusick return; 15037579Smckusick } 15137579Smckusick if (p->p_flag&SEXEC) { 15237579Smckusick u.u_error = EACCES; 15337579Smckusick return; 15437579Smckusick } 15537579Smckusick } 15637579Smckusick if (SESS_LEADER(p)) { 1577498Sroot u.u_error = EPERM; 1587498Sroot return; 1597498Sroot } 16037579Smckusick if (uap->pgid == 0) 16137579Smckusick uap->pgid = p->p_pid; 16237579Smckusick else if ((uap->pgid != p->p_pid) && 16337579Smckusick (((pgrp = pgfind(uap->pgid)) == 0) || 16437579Smckusick pgrp->pg_mem == NULL || 16537579Smckusick pgrp->pg_session != u.u_procp->p_session)) { 16637579Smckusick u.u_error = EPERM; 16737579Smckusick return; 16837579Smckusick } 16937579Smckusick /* 17037579Smckusick * done checking, now doit 17137579Smckusick */ 17237579Smckusick pgmv(p, uap->pgid, 0); 1737498Sroot } 1747498Sroot 1759160Ssam setreuid() 1767420Sroot { 1779160Ssam struct a { 1789160Ssam int ruid; 1799160Ssam int euid; 1809160Ssam } *uap; 181*40667Skarels register struct proc *p = u.u_procp; 1829160Ssam register int ruid, euid; 1839160Ssam 1849160Ssam uap = (struct a *)u.u_ap; 1859160Ssam ruid = uap->ruid; 1869160Ssam if (ruid == -1) 187*40667Skarels ruid = p->p_ruid; 188*40667Skarels #ifdef COMPAT_43 189*40667Skarels if (ruid != p->p_ruid && ruid != u.u_cred->cr_uid /* XXX */ && 19037553Smckusick (u.u_error = suser(u.u_cred, &u.u_acflag))) 191*40667Skarels #else 192*40667Skarels if (ruid != p->p_ruid && (u.u_error = suser(u.u_cred, &u.u_acflag))) 193*40667Skarels #endif 1949160Ssam return; 1959160Ssam euid = uap->euid; 1969160Ssam if (euid == -1) 197*40667Skarels euid = u.u_cred->cr_uid; 198*40667Skarels if (euid != u.u_cred->cr_uid && euid != p->p_ruid && 199*40667Skarels euid != p->p_svuid && (u.u_error = suser(u.u_cred, &u.u_acflag))) 2009160Ssam return; 2019160Ssam /* 2029160Ssam * Everything's okay, do it. 20337578Smckusick * Copy credentials so other references do not 20437578Smckusick * see our changes. 2059160Ssam */ 2069160Ssam #ifdef QUOTA 2079320Ssam if (u.u_quota->q_uid != ruid) { 2089320Ssam qclean(); 20926354Skarels qstart(getquota((uid_t)ruid, 0, 0)); 2109320Ssam } 2119160Ssam #endif 21237578Smckusick if (u.u_cred->cr_ref > 1) 21337578Smckusick u.u_cred = crcopy(u.u_cred); 214*40667Skarels u.u_cred->cr_uid = euid; 215*40667Skarels p->p_uid = euid; 216*40667Skarels p->p_ruid = ruid; 2179160Ssam } 2189160Ssam 2199160Ssam setregid() 2207420Sroot { 2219160Ssam register struct a { 2229160Ssam int rgid; 2239160Ssam int egid; 2249160Ssam } *uap; 2259160Ssam register int rgid, egid; 226*40667Skarels register struct proc *p = u.u_procp; 2279160Ssam 2289160Ssam uap = (struct a *)u.u_ap; 2299160Ssam rgid = uap->rgid; 2309160Ssam if (rgid == -1) 231*40667Skarels rgid = p->p_rgid; 232*40667Skarels #ifdef COMPAT_43_XXX 233*40667Skarels if (rgid != p->p_rgid && rgid != u.u_cred->cr_groups[0] /* XXX */ && 23437553Smckusick (u.u_error = suser(u.u_cred, &u.u_acflag))) 235*40667Skarels #else 236*40667Skarels if (rgid != p->p_rgid && (u.u_error = suser(u.u_cred, &u.u_acflag))) 237*40667Skarels #endif 2389160Ssam return; 2399160Ssam egid = uap->egid; 2409160Ssam if (egid == -1) 241*40667Skarels egid = u.u_cred->cr_groups[0]; 242*40667Skarels if (egid != u.u_cred->cr_groups[0] && egid != p->p_rgid && 243*40667Skarels egid != p->p_svgid && (u.u_error = suser(u.u_cred, &u.u_acflag))) 2449160Ssam return; 24537578Smckusick if (u.u_cred->cr_ref > 1) 24637578Smckusick u.u_cred = crcopy(u.u_cred); 247*40667Skarels p->p_rgid = rgid; 248*40667Skarels u.u_cred->cr_groups[0] = egid; 2499160Ssam } 2509160Ssam 2517866Sroot setgroups() 2527498Sroot { 2537498Sroot register struct a { 2548624Sroot u_int gidsetsize; 2557498Sroot int *gidset; 2567498Sroot } *uap = (struct a *)u.u_ap; 25718362Skarels register gid_t *gp; 25818362Skarels register int *lp; 25937578Smckusick int ngrp, groups[NGROUPS]; 2607498Sroot 26137553Smckusick if (u.u_error = suser(u.u_cred, &u.u_acflag)) 2627498Sroot return; 263*40667Skarels ngrp = uap->gidsetsize; 264*40667Skarels if (ngrp > NGROUPS) { 2657866Sroot u.u_error = EINVAL; 2667498Sroot return; 2677498Sroot } 26818362Skarels u.u_error = copyin((caddr_t)uap->gidset, (caddr_t)groups, 26918362Skarels uap->gidsetsize * sizeof (groups[0])); 2709997Ssam if (u.u_error) 2717498Sroot return; 272*40667Skarels gp = u.u_cred->cr_groups; 27337578Smckusick for (lp = groups; lp < &groups[uap->gidsetsize]; ) 27418362Skarels *gp++ = *lp++; 275*40667Skarels u.u_cred->cr_ngroups = ngrp; 2767498Sroot } 2777498Sroot 2787498Sroot /* 27937578Smckusick * Check if gid is a member of the group set. 28011810Ssam */ 28137578Smckusick groupmember(gid, cred) 28226275Skarels gid_t gid; 28337578Smckusick register struct ucred *cred; 2847866Sroot { 28518362Skarels register gid_t *gp; 28637578Smckusick gid_t *egp; 2877866Sroot 28837578Smckusick egp = &(cred->cr_groups[cred->cr_ngroups]); 28937578Smckusick for (gp = cred->cr_groups; gp < egp; gp++) 2907866Sroot if (*gp == gid) 29137578Smckusick return (1); 29237578Smckusick return (0); 2937866Sroot } 2947866Sroot 29511810Ssam /* 29637578Smckusick * Test if the current user is the super user. 29711810Ssam */ 29837578Smckusick suser(cred, acflag) 29937578Smckusick struct ucred *cred; 30037578Smckusick short *acflag; 3017866Sroot { 3027866Sroot 30337578Smckusick if (cred->cr_uid == 0) { 30437578Smckusick if (acflag) 30537578Smckusick *acflag |= ASU; 30637578Smckusick return (0); 30718362Skarels } 30837578Smckusick return (EPERM); 3097866Sroot } 31011810Ssam 31111810Ssam /* 31237578Smckusick * Allocate a zeroed cred structure. 31311810Ssam */ 31437578Smckusick struct ucred * 31537578Smckusick crget() 31611810Ssam { 31737578Smckusick register struct ucred *cr; 31811810Ssam 31937578Smckusick MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); 32037578Smckusick bzero((caddr_t)cr, sizeof(*cr)); 32137578Smckusick cr->cr_ref = 1; 32237578Smckusick return(cr); 32311810Ssam } 32437085Skfall 32537085Skfall /* 32637578Smckusick * Free a cred structure. 32737578Smckusick * Throws away space when ref count gets to 0. 32837085Skfall */ 32937578Smckusick crfree(cr) 33037578Smckusick struct ucred *cr; 33137578Smckusick { 33237578Smckusick int s = splimp(); 33337085Skfall 33437578Smckusick if (--cr->cr_ref != 0) { 33537578Smckusick (void) splx(s); 33637578Smckusick return; 33737578Smckusick } 33837578Smckusick FREE((caddr_t)cr, M_CRED); 33937578Smckusick (void) splx(s); 34037578Smckusick } 34137578Smckusick 34237578Smckusick /* 34337578Smckusick * Copy cred structure to a new one and free the old one. 34437578Smckusick */ 34537578Smckusick struct ucred * 34637578Smckusick crcopy(cr) 34737578Smckusick struct ucred *cr; 34837085Skfall { 34937578Smckusick struct ucred *newcr; 35037085Skfall 35137578Smckusick newcr = crget(); 35237578Smckusick *newcr = *cr; 35337578Smckusick crfree(cr); 35437578Smckusick newcr->cr_ref = 1; 35537578Smckusick return(newcr); 35637085Skfall } 35737085Skfall 35837085Skfall /* 35937578Smckusick * Dup cred struct to a new held one. 36037085Skfall */ 36137578Smckusick struct ucred * 36237578Smckusick crdup(cr) 36337578Smckusick struct ucred *cr; 36437085Skfall { 36537578Smckusick struct ucred *newcr; 36637085Skfall 36737578Smckusick newcr = crget(); 36837578Smckusick *newcr = *cr; 36937578Smckusick newcr->cr_ref = 1; 37037578Smckusick return(newcr); 37137085Skfall } 37237579Smckusick 37337579Smckusick /* 374*40667Skarels * Get login name, if available. 37537579Smckusick */ 376*40667Skarels getlogin() 37737579Smckusick { 37837579Smckusick struct a { 37937579Smckusick char *namebuf; 38037579Smckusick u_int namelen; 38137579Smckusick } *uap = (struct a *)u.u_ap; 38237579Smckusick 383*40667Skarels if (uap->namelen > sizeof (u.u_procp->p_logname)) 384*40667Skarels uap->namelen = sizeof (u.u_procp->p_logname); 385*40667Skarels u.u_error = copyout((caddr_t)u.u_procp->p_logname, 386*40667Skarels (caddr_t)uap->namebuf, uap->namelen); 38737579Smckusick } 38837579Smckusick 38937579Smckusick /* 390*40667Skarels * Set login name. 39137579Smckusick */ 392*40667Skarels setlogin() 39337579Smckusick { 39437579Smckusick struct a { 39537579Smckusick char *namebuf; 39637579Smckusick } *uap = (struct a *)u.u_ap; 397*40667Skarels int error; 39837579Smckusick 39937579Smckusick if (u.u_error = suser(u.u_cred, &u.u_acflag)) 40037579Smckusick return; 401*40667Skarels error = copyinstr((caddr_t)uap->namebuf, (caddr_t)u.u_procp->p_logname, 402*40667Skarels sizeof (u.u_procp->p_logname) - 1, (int *) 0); 403*40667Skarels if (error == ENOENT) /* name too long */ 404*40667Skarels error = EINVAL; 405*40667Skarels u.u_error = error; 40637579Smckusick } 407