1*2bfc50bcSEdward Tomasz Napierala /*- 2*2bfc50bcSEdward Tomasz Napierala * Copyright (c) 2011 The FreeBSD Foundation 3*2bfc50bcSEdward Tomasz Napierala * All rights reserved. 4*2bfc50bcSEdward Tomasz Napierala * 5*2bfc50bcSEdward Tomasz Napierala * This software was developed by Edward Tomasz Napierala under sponsorship 6*2bfc50bcSEdward Tomasz Napierala * from the FreeBSD Foundation. 7*2bfc50bcSEdward Tomasz Napierala * 8*2bfc50bcSEdward Tomasz Napierala * Redistribution and use in source and binary forms, with or without 9*2bfc50bcSEdward Tomasz Napierala * modification, are permitted provided that the following conditions 10*2bfc50bcSEdward Tomasz Napierala * are met: 11*2bfc50bcSEdward Tomasz Napierala * 1. Redistributions of source code must retain the above copyright 12*2bfc50bcSEdward Tomasz Napierala * notice, this list of conditions and the following disclaimer. 13*2bfc50bcSEdward Tomasz Napierala * 2. Redistributions in binary form must reproduce the above copyright 14*2bfc50bcSEdward Tomasz Napierala * notice, this list of conditions and the following disclaimer in the 15*2bfc50bcSEdward Tomasz Napierala * documentation and/or other materials provided with the distribution. 16*2bfc50bcSEdward Tomasz Napierala * 17*2bfc50bcSEdward Tomasz Napierala * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18*2bfc50bcSEdward Tomasz Napierala * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19*2bfc50bcSEdward Tomasz Napierala * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20*2bfc50bcSEdward Tomasz Napierala * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21*2bfc50bcSEdward Tomasz Napierala * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22*2bfc50bcSEdward Tomasz Napierala * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23*2bfc50bcSEdward Tomasz Napierala * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24*2bfc50bcSEdward Tomasz Napierala * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25*2bfc50bcSEdward Tomasz Napierala * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26*2bfc50bcSEdward Tomasz Napierala * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27*2bfc50bcSEdward Tomasz Napierala * SUCH DAMAGE. 28*2bfc50bcSEdward Tomasz Napierala * 29*2bfc50bcSEdward Tomasz Napierala * $FreeBSD$ 30*2bfc50bcSEdward Tomasz Napierala */ 31*2bfc50bcSEdward Tomasz Napierala 32*2bfc50bcSEdward Tomasz Napierala /* 33*2bfc50bcSEdward Tomasz Napierala * Processes may set login class name using setloginclass(2). This 34*2bfc50bcSEdward Tomasz Napierala * is usually done through call to setusercontext(3), by programs 35*2bfc50bcSEdward Tomasz Napierala * such as login(1), based on information from master.passwd(5). Kernel 36*2bfc50bcSEdward Tomasz Napierala * uses this information to enforce per-class resource limits. Current 37*2bfc50bcSEdward Tomasz Napierala * login class can be determined using id(1). Login class is inherited 38*2bfc50bcSEdward Tomasz Napierala * from the parent process during fork(2). If not set, it defaults 39*2bfc50bcSEdward Tomasz Napierala * to "default". 40*2bfc50bcSEdward Tomasz Napierala * 41*2bfc50bcSEdward Tomasz Napierala * Code in this file implements setloginclass(2) and getloginclass(2) 42*2bfc50bcSEdward Tomasz Napierala * system calls, and maintains class name storage and retrieval. 43*2bfc50bcSEdward Tomasz Napierala */ 44*2bfc50bcSEdward Tomasz Napierala 45*2bfc50bcSEdward Tomasz Napierala #include <sys/cdefs.h> 46*2bfc50bcSEdward Tomasz Napierala __FBSDID("$FreeBSD$"); 47*2bfc50bcSEdward Tomasz Napierala 48*2bfc50bcSEdward Tomasz Napierala #include <sys/param.h> 49*2bfc50bcSEdward Tomasz Napierala #include <sys/eventhandler.h> 50*2bfc50bcSEdward Tomasz Napierala #include <sys/kernel.h> 51*2bfc50bcSEdward Tomasz Napierala #include <sys/lock.h> 52*2bfc50bcSEdward Tomasz Napierala #include <sys/loginclass.h> 53*2bfc50bcSEdward Tomasz Napierala #include <sys/malloc.h> 54*2bfc50bcSEdward Tomasz Napierala #include <sys/mutex.h> 55*2bfc50bcSEdward Tomasz Napierala #include <sys/types.h> 56*2bfc50bcSEdward Tomasz Napierala #include <sys/priv.h> 57*2bfc50bcSEdward Tomasz Napierala #include <sys/proc.h> 58*2bfc50bcSEdward Tomasz Napierala #include <sys/queue.h> 59*2bfc50bcSEdward Tomasz Napierala #include <sys/refcount.h> 60*2bfc50bcSEdward Tomasz Napierala #include <sys/sysproto.h> 61*2bfc50bcSEdward Tomasz Napierala #include <sys/systm.h> 62*2bfc50bcSEdward Tomasz Napierala 63*2bfc50bcSEdward Tomasz Napierala static MALLOC_DEFINE(M_LOGINCLASS, "loginclass", "loginclass structures"); 64*2bfc50bcSEdward Tomasz Napierala 65*2bfc50bcSEdward Tomasz Napierala LIST_HEAD(, loginclass) loginclasses; 66*2bfc50bcSEdward Tomasz Napierala 67*2bfc50bcSEdward Tomasz Napierala /* 68*2bfc50bcSEdward Tomasz Napierala * Lock protecting loginclasses list. 69*2bfc50bcSEdward Tomasz Napierala */ 70*2bfc50bcSEdward Tomasz Napierala static struct mtx loginclasses_lock; 71*2bfc50bcSEdward Tomasz Napierala 72*2bfc50bcSEdward Tomasz Napierala static void lc_init(void); 73*2bfc50bcSEdward Tomasz Napierala SYSINIT(loginclass, SI_SUB_CPU, SI_ORDER_FIRST, lc_init, NULL); 74*2bfc50bcSEdward Tomasz Napierala 75*2bfc50bcSEdward Tomasz Napierala void 76*2bfc50bcSEdward Tomasz Napierala loginclass_hold(struct loginclass *lc) 77*2bfc50bcSEdward Tomasz Napierala { 78*2bfc50bcSEdward Tomasz Napierala 79*2bfc50bcSEdward Tomasz Napierala refcount_acquire(&lc->lc_refcount); 80*2bfc50bcSEdward Tomasz Napierala } 81*2bfc50bcSEdward Tomasz Napierala 82*2bfc50bcSEdward Tomasz Napierala void 83*2bfc50bcSEdward Tomasz Napierala loginclass_free(struct loginclass *lc) 84*2bfc50bcSEdward Tomasz Napierala { 85*2bfc50bcSEdward Tomasz Napierala int old; 86*2bfc50bcSEdward Tomasz Napierala 87*2bfc50bcSEdward Tomasz Napierala old = lc->lc_refcount; 88*2bfc50bcSEdward Tomasz Napierala if (old > 1 && atomic_cmpset_int(&lc->lc_refcount, old, old - 1)) 89*2bfc50bcSEdward Tomasz Napierala return; 90*2bfc50bcSEdward Tomasz Napierala 91*2bfc50bcSEdward Tomasz Napierala mtx_lock(&loginclasses_lock); 92*2bfc50bcSEdward Tomasz Napierala if (refcount_release(&lc->lc_refcount)) { 93*2bfc50bcSEdward Tomasz Napierala LIST_REMOVE(lc, lc_next); 94*2bfc50bcSEdward Tomasz Napierala mtx_unlock(&loginclasses_lock); 95*2bfc50bcSEdward Tomasz Napierala free(lc, M_LOGINCLASS); 96*2bfc50bcSEdward Tomasz Napierala 97*2bfc50bcSEdward Tomasz Napierala return; 98*2bfc50bcSEdward Tomasz Napierala } 99*2bfc50bcSEdward Tomasz Napierala mtx_unlock(&loginclasses_lock); 100*2bfc50bcSEdward Tomasz Napierala } 101*2bfc50bcSEdward Tomasz Napierala 102*2bfc50bcSEdward Tomasz Napierala /* 103*2bfc50bcSEdward Tomasz Napierala * Return loginclass structure with a corresponding name. Not 104*2bfc50bcSEdward Tomasz Napierala * performance critical, as it's used mainly by setloginclass(2), 105*2bfc50bcSEdward Tomasz Napierala * which happens once per login session. Caller has to use 106*2bfc50bcSEdward Tomasz Napierala * loginclass_free() on the returned value when it's no longer 107*2bfc50bcSEdward Tomasz Napierala * needed. 108*2bfc50bcSEdward Tomasz Napierala */ 109*2bfc50bcSEdward Tomasz Napierala struct loginclass * 110*2bfc50bcSEdward Tomasz Napierala loginclass_find(const char *name) 111*2bfc50bcSEdward Tomasz Napierala { 112*2bfc50bcSEdward Tomasz Napierala struct loginclass *lc, *newlc; 113*2bfc50bcSEdward Tomasz Napierala 114*2bfc50bcSEdward Tomasz Napierala if (name[0] == '\0' || strlen(name) >= MAXLOGNAME) 115*2bfc50bcSEdward Tomasz Napierala return (NULL); 116*2bfc50bcSEdward Tomasz Napierala 117*2bfc50bcSEdward Tomasz Napierala newlc = malloc(sizeof(*newlc), M_LOGINCLASS, M_ZERO | M_WAITOK); 118*2bfc50bcSEdward Tomasz Napierala 119*2bfc50bcSEdward Tomasz Napierala mtx_lock(&loginclasses_lock); 120*2bfc50bcSEdward Tomasz Napierala LIST_FOREACH(lc, &loginclasses, lc_next) { 121*2bfc50bcSEdward Tomasz Napierala if (strcmp(name, lc->lc_name) != 0) 122*2bfc50bcSEdward Tomasz Napierala continue; 123*2bfc50bcSEdward Tomasz Napierala 124*2bfc50bcSEdward Tomasz Napierala /* Found loginclass with a matching name? */ 125*2bfc50bcSEdward Tomasz Napierala loginclass_hold(lc); 126*2bfc50bcSEdward Tomasz Napierala mtx_unlock(&loginclasses_lock); 127*2bfc50bcSEdward Tomasz Napierala free(newlc, M_LOGINCLASS); 128*2bfc50bcSEdward Tomasz Napierala return (lc); 129*2bfc50bcSEdward Tomasz Napierala } 130*2bfc50bcSEdward Tomasz Napierala 131*2bfc50bcSEdward Tomasz Napierala /* Add new loginclass. */ 132*2bfc50bcSEdward Tomasz Napierala strcpy(newlc->lc_name, name); 133*2bfc50bcSEdward Tomasz Napierala refcount_init(&newlc->lc_refcount, 1); 134*2bfc50bcSEdward Tomasz Napierala LIST_INSERT_HEAD(&loginclasses, newlc, lc_next); 135*2bfc50bcSEdward Tomasz Napierala mtx_unlock(&loginclasses_lock); 136*2bfc50bcSEdward Tomasz Napierala 137*2bfc50bcSEdward Tomasz Napierala return (newlc); 138*2bfc50bcSEdward Tomasz Napierala } 139*2bfc50bcSEdward Tomasz Napierala 140*2bfc50bcSEdward Tomasz Napierala /* 141*2bfc50bcSEdward Tomasz Napierala * Get login class name. 142*2bfc50bcSEdward Tomasz Napierala */ 143*2bfc50bcSEdward Tomasz Napierala #ifndef _SYS_SYSPROTO_H_ 144*2bfc50bcSEdward Tomasz Napierala struct getloginclass_args { 145*2bfc50bcSEdward Tomasz Napierala char *namebuf; 146*2bfc50bcSEdward Tomasz Napierala size_t namelen; 147*2bfc50bcSEdward Tomasz Napierala }; 148*2bfc50bcSEdward Tomasz Napierala #endif 149*2bfc50bcSEdward Tomasz Napierala /* ARGSUSED */ 150*2bfc50bcSEdward Tomasz Napierala int 151*2bfc50bcSEdward Tomasz Napierala getloginclass(struct thread *td, struct getloginclass_args *uap) 152*2bfc50bcSEdward Tomasz Napierala { 153*2bfc50bcSEdward Tomasz Napierala int error = 0; 154*2bfc50bcSEdward Tomasz Napierala size_t lcnamelen; 155*2bfc50bcSEdward Tomasz Napierala struct proc *p; 156*2bfc50bcSEdward Tomasz Napierala struct loginclass *lc; 157*2bfc50bcSEdward Tomasz Napierala 158*2bfc50bcSEdward Tomasz Napierala p = td->td_proc; 159*2bfc50bcSEdward Tomasz Napierala PROC_LOCK(p); 160*2bfc50bcSEdward Tomasz Napierala lc = p->p_ucred->cr_loginclass; 161*2bfc50bcSEdward Tomasz Napierala loginclass_hold(lc); 162*2bfc50bcSEdward Tomasz Napierala PROC_UNLOCK(p); 163*2bfc50bcSEdward Tomasz Napierala 164*2bfc50bcSEdward Tomasz Napierala lcnamelen = strlen(lc->lc_name) + 1; 165*2bfc50bcSEdward Tomasz Napierala if (lcnamelen > uap->namelen) 166*2bfc50bcSEdward Tomasz Napierala error = ERANGE; 167*2bfc50bcSEdward Tomasz Napierala if (error == 0) 168*2bfc50bcSEdward Tomasz Napierala error = copyout(lc->lc_name, uap->namebuf, lcnamelen); 169*2bfc50bcSEdward Tomasz Napierala loginclass_free(lc); 170*2bfc50bcSEdward Tomasz Napierala return (error); 171*2bfc50bcSEdward Tomasz Napierala } 172*2bfc50bcSEdward Tomasz Napierala 173*2bfc50bcSEdward Tomasz Napierala /* 174*2bfc50bcSEdward Tomasz Napierala * Set login class name. 175*2bfc50bcSEdward Tomasz Napierala */ 176*2bfc50bcSEdward Tomasz Napierala #ifndef _SYS_SYSPROTO_H_ 177*2bfc50bcSEdward Tomasz Napierala struct setloginclass_args { 178*2bfc50bcSEdward Tomasz Napierala const char *namebuf; 179*2bfc50bcSEdward Tomasz Napierala }; 180*2bfc50bcSEdward Tomasz Napierala #endif 181*2bfc50bcSEdward Tomasz Napierala /* ARGSUSED */ 182*2bfc50bcSEdward Tomasz Napierala int 183*2bfc50bcSEdward Tomasz Napierala setloginclass(struct thread *td, struct setloginclass_args *uap) 184*2bfc50bcSEdward Tomasz Napierala { 185*2bfc50bcSEdward Tomasz Napierala struct proc *p = td->td_proc; 186*2bfc50bcSEdward Tomasz Napierala int error; 187*2bfc50bcSEdward Tomasz Napierala char lcname[MAXLOGNAME]; 188*2bfc50bcSEdward Tomasz Napierala struct loginclass *newlc; 189*2bfc50bcSEdward Tomasz Napierala struct ucred *newcred, *oldcred; 190*2bfc50bcSEdward Tomasz Napierala 191*2bfc50bcSEdward Tomasz Napierala error = priv_check(td, PRIV_PROC_SETLOGINCLASS); 192*2bfc50bcSEdward Tomasz Napierala if (error != 0) 193*2bfc50bcSEdward Tomasz Napierala return (error); 194*2bfc50bcSEdward Tomasz Napierala error = copyinstr(uap->namebuf, lcname, sizeof(lcname), NULL); 195*2bfc50bcSEdward Tomasz Napierala if (error != 0) 196*2bfc50bcSEdward Tomasz Napierala return (error); 197*2bfc50bcSEdward Tomasz Napierala 198*2bfc50bcSEdward Tomasz Napierala newlc = loginclass_find(lcname); 199*2bfc50bcSEdward Tomasz Napierala if (newlc == NULL) 200*2bfc50bcSEdward Tomasz Napierala return (EINVAL); 201*2bfc50bcSEdward Tomasz Napierala newcred = crget(); 202*2bfc50bcSEdward Tomasz Napierala 203*2bfc50bcSEdward Tomasz Napierala PROC_LOCK(p); 204*2bfc50bcSEdward Tomasz Napierala oldcred = crcopysafe(p, newcred); 205*2bfc50bcSEdward Tomasz Napierala newcred->cr_loginclass = newlc; 206*2bfc50bcSEdward Tomasz Napierala p->p_ucred = newcred; 207*2bfc50bcSEdward Tomasz Napierala PROC_UNLOCK(p); 208*2bfc50bcSEdward Tomasz Napierala 209*2bfc50bcSEdward Tomasz Napierala loginclass_free(oldcred->cr_loginclass); 210*2bfc50bcSEdward Tomasz Napierala crfree(oldcred); 211*2bfc50bcSEdward Tomasz Napierala 212*2bfc50bcSEdward Tomasz Napierala return (0); 213*2bfc50bcSEdward Tomasz Napierala } 214*2bfc50bcSEdward Tomasz Napierala 215*2bfc50bcSEdward Tomasz Napierala static void 216*2bfc50bcSEdward Tomasz Napierala lc_init(void) 217*2bfc50bcSEdward Tomasz Napierala { 218*2bfc50bcSEdward Tomasz Napierala 219*2bfc50bcSEdward Tomasz Napierala mtx_init(&loginclasses_lock, "loginclasses lock", NULL, MTX_DEF); 220*2bfc50bcSEdward Tomasz Napierala } 221