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: stable/11/sys/kern/kern_loginclass.c 335536 2018-06-22 09:18:38Z avg $ 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: stable/11/sys/kern/kern_loginclass.c 335536 2018-06-22 09:18:38Z avg $"); 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/types.h> 55219304Strasz#include <sys/priv.h> 56219304Strasz#include <sys/proc.h> 57219304Strasz#include <sys/queue.h> 58220137Strasz#include <sys/racct.h> 59335536Savg#include <sys/rctl.h> 60219304Strasz#include <sys/refcount.h> 61273763Smjg#include <sys/rwlock.h> 62219304Strasz#include <sys/sysproto.h> 63219304Strasz#include <sys/systm.h> 64219304Strasz 65219304Straszstatic MALLOC_DEFINE(M_LOGINCLASS, "loginclass", "loginclass structures"); 66219304Strasz 67219304StraszLIST_HEAD(, loginclass) loginclasses; 68219304Strasz 69219304Strasz/* 70219304Strasz * Lock protecting loginclasses list. 71219304Strasz */ 72273763Smjgstatic struct rwlock loginclasses_lock; 73273763SmjgRW_SYSINIT(loginclasses_init, &loginclasses_lock, "loginclasses lock"); 74219304Strasz 75219304Straszvoid 76219304Straszloginclass_hold(struct loginclass *lc) 77219304Strasz{ 78219304Strasz 79219304Strasz refcount_acquire(&lc->lc_refcount); 80219304Strasz} 81219304Strasz 82219304Straszvoid 83219304Straszloginclass_free(struct loginclass *lc) 84219304Strasz{ 85219304Strasz int old; 86219304Strasz 87219304Strasz old = lc->lc_refcount; 88219304Strasz if (old > 1 && atomic_cmpset_int(&lc->lc_refcount, old, old - 1)) 89219304Strasz return; 90219304Strasz 91273763Smjg rw_wlock(&loginclasses_lock); 92273763Smjg if (!refcount_release(&lc->lc_refcount)) { 93273763Smjg rw_wunlock(&loginclasses_lock); 94219304Strasz return; 95219304Strasz } 96273763Smjg 97273763Smjg racct_destroy(&lc->lc_racct); 98273763Smjg LIST_REMOVE(lc, lc_next); 99273763Smjg rw_wunlock(&loginclasses_lock); 100273763Smjg 101273763Smjg free(lc, M_LOGINCLASS); 102219304Strasz} 103219304Strasz 104219304Strasz/* 105273763Smjg * Look up a loginclass struct for the parameter name. 106273763Smjg * loginclasses_lock must be locked. 107273763Smjg * Increase refcount on loginclass struct returned. 108273763Smjg */ 109273763Smjgstatic struct loginclass * 110273763Smjgloginclass_lookup(const char *name) 111273763Smjg{ 112273763Smjg struct loginclass *lc; 113273763Smjg 114273763Smjg rw_assert(&loginclasses_lock, RA_LOCKED); 115273763Smjg LIST_FOREACH(lc, &loginclasses, lc_next) 116273763Smjg if (strcmp(name, lc->lc_name) == 0) { 117273763Smjg loginclass_hold(lc); 118273763Smjg break; 119273763Smjg } 120273763Smjg 121273763Smjg return (lc); 122273763Smjg} 123273763Smjg 124273763Smjg/* 125219304Strasz * Return loginclass structure with a corresponding name. Not 126219304Strasz * performance critical, as it's used mainly by setloginclass(2), 127219304Strasz * which happens once per login session. Caller has to use 128219304Strasz * loginclass_free() on the returned value when it's no longer 129219304Strasz * needed. 130219304Strasz */ 131219304Straszstruct loginclass * 132219304Straszloginclass_find(const char *name) 133219304Strasz{ 134273763Smjg struct loginclass *lc, *new_lc; 135219304Strasz 136219304Strasz if (name[0] == '\0' || strlen(name) >= MAXLOGNAME) 137219304Strasz return (NULL); 138219304Strasz 139273763Smjg rw_rlock(&loginclasses_lock); 140273763Smjg lc = loginclass_lookup(name); 141273763Smjg rw_runlock(&loginclasses_lock); 142273763Smjg if (lc != NULL) 143273763Smjg return (lc); 144219304Strasz 145273763Smjg new_lc = malloc(sizeof(*new_lc), M_LOGINCLASS, M_ZERO | M_WAITOK); 146273763Smjg racct_create(&new_lc->lc_racct); 147273763Smjg refcount_init(&new_lc->lc_refcount, 1); 148273763Smjg strcpy(new_lc->lc_name, name); 149219304Strasz 150273763Smjg rw_wlock(&loginclasses_lock); 151273763Smjg /* 152273763Smjg * There's a chance someone created our loginclass while we 153273763Smjg * were in malloc and not holding the lock, so we have to 154273763Smjg * make sure we don't insert a duplicate loginclass. 155273763Smjg */ 156273763Smjg if ((lc = loginclass_lookup(name)) == NULL) { 157273763Smjg LIST_INSERT_HEAD(&loginclasses, new_lc, lc_next); 158273763Smjg rw_wunlock(&loginclasses_lock); 159273763Smjg lc = new_lc; 160273763Smjg } else { 161273763Smjg rw_wunlock(&loginclasses_lock); 162273763Smjg racct_destroy(&new_lc->lc_racct); 163273763Smjg free(new_lc, M_LOGINCLASS); 164219304Strasz } 165219304Strasz 166273763Smjg return (lc); 167219304Strasz} 168219304Strasz 169219304Strasz/* 170219304Strasz * Get login class name. 171219304Strasz */ 172219304Strasz#ifndef _SYS_SYSPROTO_H_ 173219304Straszstruct getloginclass_args { 174219304Strasz char *namebuf; 175219304Strasz size_t namelen; 176219304Strasz}; 177219304Strasz#endif 178219304Strasz/* ARGSUSED */ 179219304Straszint 180225617Skmacysys_getloginclass(struct thread *td, struct getloginclass_args *uap) 181219304Strasz{ 182273764Smjg struct loginclass *lc; 183219304Strasz size_t lcnamelen; 184219304Strasz 185273764Smjg lc = td->td_ucred->cr_loginclass; 186219304Strasz lcnamelen = strlen(lc->lc_name) + 1; 187219304Strasz if (lcnamelen > uap->namelen) 188273764Smjg return (ERANGE); 189273764Smjg return (copyout(lc->lc_name, uap->namebuf, lcnamelen)); 190219304Strasz} 191219304Strasz 192219304Strasz/* 193219304Strasz * Set login class name. 194219304Strasz */ 195219304Strasz#ifndef _SYS_SYSPROTO_H_ 196219304Straszstruct setloginclass_args { 197219304Strasz const char *namebuf; 198219304Strasz}; 199219304Strasz#endif 200219304Strasz/* ARGSUSED */ 201219304Straszint 202225617Skmacysys_setloginclass(struct thread *td, struct setloginclass_args *uap) 203219304Strasz{ 204219304Strasz struct proc *p = td->td_proc; 205219304Strasz int error; 206219304Strasz char lcname[MAXLOGNAME]; 207219304Strasz struct loginclass *newlc; 208219304Strasz struct ucred *newcred, *oldcred; 209219304Strasz 210219304Strasz error = priv_check(td, PRIV_PROC_SETLOGINCLASS); 211219304Strasz if (error != 0) 212219304Strasz return (error); 213219304Strasz error = copyinstr(uap->namebuf, lcname, sizeof(lcname), NULL); 214219304Strasz if (error != 0) 215219304Strasz return (error); 216219304Strasz 217219304Strasz newlc = loginclass_find(lcname); 218219304Strasz if (newlc == NULL) 219219304Strasz return (EINVAL); 220219304Strasz newcred = crget(); 221219304Strasz 222219304Strasz PROC_LOCK(p); 223219304Strasz oldcred = crcopysafe(p, newcred); 224219304Strasz newcred->cr_loginclass = newlc; 225280130Smjg proc_set_cred(p, newcred); 226220137Strasz#ifdef RACCT 227220137Strasz racct_proc_ucred_changed(p, oldcred, newcred); 228335536Savg crhold(newcred); 229220137Strasz#endif 230335536Savg PROC_UNLOCK(p); 231335536Savg#ifdef RCTL 232335536Savg rctl_proc_ucred_changed(p, newcred); 233335536Savg crfree(newcred); 234335536Savg#endif 235219304Strasz loginclass_free(oldcred->cr_loginclass); 236219304Strasz crfree(oldcred); 237219304Strasz 238219304Strasz return (0); 239219304Strasz} 240219304Strasz 241220137Straszvoid 242220137Straszloginclass_racct_foreach(void (*callback)(struct racct *racct, 243290857Strasz void *arg2, void *arg3), void (*pre)(void), void (*post)(void), 244290857Strasz void *arg2, void *arg3) 245220137Strasz{ 246220137Strasz struct loginclass *lc; 247220137Strasz 248273763Smjg rw_rlock(&loginclasses_lock); 249290857Strasz if (pre != NULL) 250290857Strasz (pre)(); 251220137Strasz LIST_FOREACH(lc, &loginclasses, lc_next) 252220137Strasz (callback)(lc->lc_racct, arg2, arg3); 253290857Strasz if (post != NULL) 254290857Strasz (post)(); 255273763Smjg rw_runlock(&loginclasses_lock); 256220137Strasz} 257