kern_loginclass.c revision 225617
1219304Strasz/*- 2219304Strasz * Copyright (c) 2011 The FreeBSD Foundation 3219304Strasz * All rights reserved. 4219304Strasz * 5219304Strasz * This software was developed by Edward Tomasz Napierala under sponsorship 6219304Strasz * from the FreeBSD Foundation. 7219304Strasz * 8219304Strasz * Redistribution and use in source and binary forms, with or without 9219304Strasz * modification, are permitted provided that the following conditions 10219304Strasz * are met: 11219304Strasz * 1. Redistributions of source code must retain the above copyright 12219304Strasz * notice, this list of conditions and the following disclaimer. 13219304Strasz * 2. Redistributions in binary form must reproduce the above copyright 14219304Strasz * notice, this list of conditions and the following disclaimer in the 15219304Strasz * documentation and/or other materials provided with the distribution. 16219304Strasz * 17219304Strasz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18219304Strasz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19219304Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20219304Strasz * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21219304Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22219304Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23219304Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24219304Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25219304Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26219304Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27219304Strasz * SUCH DAMAGE. 28219304Strasz * 29219304Strasz * $FreeBSD: head/sys/kern/kern_loginclass.c 225617 2011-09-16 13:58:51Z kmacy $ 30219304Strasz */ 31219304Strasz 32219304Strasz/* 33219304Strasz * Processes may set login class name using setloginclass(2). This 34219304Strasz * is usually done through call to setusercontext(3), by programs 35219304Strasz * such as login(1), based on information from master.passwd(5). Kernel 36219304Strasz * uses this information to enforce per-class resource limits. Current 37219304Strasz * login class can be determined using id(1). Login class is inherited 38219304Strasz * from the parent process during fork(2). If not set, it defaults 39219304Strasz * to "default". 40219304Strasz * 41219304Strasz * Code in this file implements setloginclass(2) and getloginclass(2) 42219304Strasz * system calls, and maintains class name storage and retrieval. 43219304Strasz */ 44219304Strasz 45219304Strasz#include <sys/cdefs.h> 46219304Strasz__FBSDID("$FreeBSD: head/sys/kern/kern_loginclass.c 225617 2011-09-16 13:58:51Z kmacy $"); 47219304Strasz 48219304Strasz#include <sys/param.h> 49219304Strasz#include <sys/eventhandler.h> 50219304Strasz#include <sys/kernel.h> 51219304Strasz#include <sys/lock.h> 52219304Strasz#include <sys/loginclass.h> 53219304Strasz#include <sys/malloc.h> 54219304Strasz#include <sys/mutex.h> 55219304Strasz#include <sys/types.h> 56219304Strasz#include <sys/priv.h> 57219304Strasz#include <sys/proc.h> 58219304Strasz#include <sys/queue.h> 59220137Strasz#include <sys/racct.h> 60219304Strasz#include <sys/refcount.h> 61219304Strasz#include <sys/sysproto.h> 62219304Strasz#include <sys/systm.h> 63219304Strasz 64219304Straszstatic MALLOC_DEFINE(M_LOGINCLASS, "loginclass", "loginclass structures"); 65219304Strasz 66219304StraszLIST_HEAD(, loginclass) loginclasses; 67219304Strasz 68219304Strasz/* 69219304Strasz * Lock protecting loginclasses list. 70219304Strasz */ 71219304Straszstatic struct mtx loginclasses_lock; 72219304Strasz 73219304Straszstatic void lc_init(void); 74219304StraszSYSINIT(loginclass, SI_SUB_CPU, SI_ORDER_FIRST, lc_init, NULL); 75219304Strasz 76219304Straszvoid 77219304Straszloginclass_hold(struct loginclass *lc) 78219304Strasz{ 79219304Strasz 80219304Strasz refcount_acquire(&lc->lc_refcount); 81219304Strasz} 82219304Strasz 83219304Straszvoid 84219304Straszloginclass_free(struct loginclass *lc) 85219304Strasz{ 86219304Strasz int old; 87219304Strasz 88219304Strasz old = lc->lc_refcount; 89219304Strasz if (old > 1 && atomic_cmpset_int(&lc->lc_refcount, old, old - 1)) 90219304Strasz return; 91219304Strasz 92219304Strasz mtx_lock(&loginclasses_lock); 93219304Strasz if (refcount_release(&lc->lc_refcount)) { 94220137Strasz racct_destroy(&lc->lc_racct); 95219304Strasz LIST_REMOVE(lc, lc_next); 96219304Strasz mtx_unlock(&loginclasses_lock); 97219304Strasz free(lc, M_LOGINCLASS); 98219304Strasz 99219304Strasz return; 100219304Strasz } 101219304Strasz mtx_unlock(&loginclasses_lock); 102219304Strasz} 103219304Strasz 104219304Strasz/* 105219304Strasz * Return loginclass structure with a corresponding name. Not 106219304Strasz * performance critical, as it's used mainly by setloginclass(2), 107219304Strasz * which happens once per login session. Caller has to use 108219304Strasz * loginclass_free() on the returned value when it's no longer 109219304Strasz * needed. 110219304Strasz */ 111219304Straszstruct loginclass * 112219304Straszloginclass_find(const char *name) 113219304Strasz{ 114219304Strasz struct loginclass *lc, *newlc; 115219304Strasz 116219304Strasz if (name[0] == '\0' || strlen(name) >= MAXLOGNAME) 117219304Strasz return (NULL); 118219304Strasz 119219304Strasz newlc = malloc(sizeof(*newlc), M_LOGINCLASS, M_ZERO | M_WAITOK); 120220137Strasz racct_create(&newlc->lc_racct); 121219304Strasz 122219304Strasz mtx_lock(&loginclasses_lock); 123219304Strasz LIST_FOREACH(lc, &loginclasses, lc_next) { 124219304Strasz if (strcmp(name, lc->lc_name) != 0) 125219304Strasz continue; 126219304Strasz 127219304Strasz /* Found loginclass with a matching name? */ 128219304Strasz loginclass_hold(lc); 129219304Strasz mtx_unlock(&loginclasses_lock); 130220137Strasz racct_destroy(&newlc->lc_racct); 131219304Strasz free(newlc, M_LOGINCLASS); 132219304Strasz return (lc); 133219304Strasz } 134219304Strasz 135219304Strasz /* Add new loginclass. */ 136219304Strasz strcpy(newlc->lc_name, name); 137219304Strasz refcount_init(&newlc->lc_refcount, 1); 138219304Strasz LIST_INSERT_HEAD(&loginclasses, newlc, lc_next); 139219304Strasz mtx_unlock(&loginclasses_lock); 140219304Strasz 141219304Strasz return (newlc); 142219304Strasz} 143219304Strasz 144219304Strasz/* 145219304Strasz * Get login class name. 146219304Strasz */ 147219304Strasz#ifndef _SYS_SYSPROTO_H_ 148219304Straszstruct getloginclass_args { 149219304Strasz char *namebuf; 150219304Strasz size_t namelen; 151219304Strasz}; 152219304Strasz#endif 153219304Strasz/* ARGSUSED */ 154219304Straszint 155225617Skmacysys_getloginclass(struct thread *td, struct getloginclass_args *uap) 156219304Strasz{ 157219304Strasz int error = 0; 158219304Strasz size_t lcnamelen; 159219304Strasz struct proc *p; 160219304Strasz struct loginclass *lc; 161219304Strasz 162219304Strasz p = td->td_proc; 163219304Strasz PROC_LOCK(p); 164219304Strasz lc = p->p_ucred->cr_loginclass; 165219304Strasz loginclass_hold(lc); 166219304Strasz PROC_UNLOCK(p); 167219304Strasz 168219304Strasz lcnamelen = strlen(lc->lc_name) + 1; 169219304Strasz if (lcnamelen > uap->namelen) 170219304Strasz error = ERANGE; 171219304Strasz if (error == 0) 172219304Strasz error = copyout(lc->lc_name, uap->namebuf, lcnamelen); 173219304Strasz loginclass_free(lc); 174219304Strasz return (error); 175219304Strasz} 176219304Strasz 177219304Strasz/* 178219304Strasz * Set login class name. 179219304Strasz */ 180219304Strasz#ifndef _SYS_SYSPROTO_H_ 181219304Straszstruct setloginclass_args { 182219304Strasz const char *namebuf; 183219304Strasz}; 184219304Strasz#endif 185219304Strasz/* ARGSUSED */ 186219304Straszint 187225617Skmacysys_setloginclass(struct thread *td, struct setloginclass_args *uap) 188219304Strasz{ 189219304Strasz struct proc *p = td->td_proc; 190219304Strasz int error; 191219304Strasz char lcname[MAXLOGNAME]; 192219304Strasz struct loginclass *newlc; 193219304Strasz struct ucred *newcred, *oldcred; 194219304Strasz 195219304Strasz error = priv_check(td, PRIV_PROC_SETLOGINCLASS); 196219304Strasz if (error != 0) 197219304Strasz return (error); 198219304Strasz error = copyinstr(uap->namebuf, lcname, sizeof(lcname), NULL); 199219304Strasz if (error != 0) 200219304Strasz return (error); 201219304Strasz 202219304Strasz newlc = loginclass_find(lcname); 203219304Strasz if (newlc == NULL) 204219304Strasz return (EINVAL); 205219304Strasz newcred = crget(); 206219304Strasz 207219304Strasz PROC_LOCK(p); 208219304Strasz oldcred = crcopysafe(p, newcred); 209219304Strasz newcred->cr_loginclass = newlc; 210219304Strasz p->p_ucred = newcred; 211219304Strasz PROC_UNLOCK(p); 212220137Strasz#ifdef RACCT 213220137Strasz racct_proc_ucred_changed(p, oldcred, newcred); 214220137Strasz#endif 215219304Strasz loginclass_free(oldcred->cr_loginclass); 216219304Strasz crfree(oldcred); 217219304Strasz 218219304Strasz return (0); 219219304Strasz} 220219304Strasz 221220137Straszvoid 222220137Straszloginclass_racct_foreach(void (*callback)(struct racct *racct, 223220137Strasz void *arg2, void *arg3), void *arg2, void *arg3) 224220137Strasz{ 225220137Strasz struct loginclass *lc; 226220137Strasz 227220137Strasz mtx_lock(&loginclasses_lock); 228220137Strasz LIST_FOREACH(lc, &loginclasses, lc_next) 229220137Strasz (callback)(lc->lc_racct, arg2, arg3); 230220137Strasz mtx_unlock(&loginclasses_lock); 231220137Strasz} 232220137Strasz 233219304Straszstatic void 234219304Straszlc_init(void) 235219304Strasz{ 236219304Strasz 237219304Strasz mtx_init(&loginclasses_lock, "loginclasses lock", NULL, MTX_DEF); 238219304Strasz} 239