Index: usr.bin/id/id.1 =================================================================== --- usr.bin/id/id.1 (revision 219137) +++ usr.bin/id/id.1 (working copy) @@ -31,7 +31,7 @@ .\" @(#)id.1 8.1 (Berkeley) 6/6/93 .\" $FreeBSD$ .\" -.Dd September 26, 2006 +.Dd March 5, 2011 .Dt ID 1 .Os .Sh NAME @@ -51,6 +51,8 @@ .Fl P .Op Ar user .Nm +.Fl c +.Nm .Fl g Op Fl nr .Op Ar user .Nm @@ -89,6 +91,8 @@ Display the id as a password file entry. Ignored for compatibility with other .Nm implementations. +.It Fl c +Display current login class. .It Fl g Display the effective group ID as a number. .It Fl n Index: usr.bin/id/id.c =================================================================== --- usr.bin/id/id.c (revision 219137) +++ usr.bin/id/id.c (working copy) @@ -74,11 +74,13 @@ main(int argc, char *argv[]) struct group *gr; struct passwd *pw; int Gflag, Mflag, Pflag, ch, gflag, id, nflag, pflag, rflag, uflag; - int Aflag; + int Aflag, cflag; + int error; const char *myname; + char loginclass[MAXLOGNAME]; Gflag = Mflag = Pflag = gflag = nflag = pflag = rflag = uflag = 0; - Aflag = 0; + Aflag = cflag = 0; myname = strrchr(argv[0], '/'); myname = (myname != NULL) ? myname + 1 : argv[0]; @@ -92,7 +94,7 @@ main(int argc, char *argv[]) } while ((ch = getopt(argc, argv, - (isgroups || iswhoami) ? "" : "APGMagnpru")) != -1) + (isgroups || iswhoami) ? "" : "APGMacgnpru")) != -1) switch(ch) { #ifdef USE_BSM_AUDIT case 'A': @@ -110,6 +112,9 @@ main(int argc, char *argv[]) break; case 'a': break; + case 'c': + cflag = 1; + break; case 'g': gflag = 1; break; @@ -158,6 +163,14 @@ main(int argc, char *argv[]) } #endif + if (cflag) { + error = getloginclass(0, loginclass, sizeof(loginclass)); + if (error != 0) + err(1, "loginclass"); + (void)printf("%s\n", loginclass); + exit(0); + } + if (gflag) { id = pw ? pw->pw_gid : rflag ? getgid() : getegid(); if (nflag && (gr = getgrgid(id))) @@ -467,7 +480,7 @@ usage(void) else if (iswhoami) (void)fprintf(stderr, "usage: whoami\n"); else - (void)fprintf(stderr, "%s\n%s%s\n%s\n%s\n%s\n%s\n%s\n", + (void)fprintf(stderr, "%s\n%s%s\n%s\n%s\n%s\n%s\n%s\n%s\n", "usage: id [user]", #ifdef USE_BSM_AUDIT " id -A\n", @@ -477,6 +490,7 @@ usage(void) " id -G [-n] [user]", " id -M", " id -P [user]", + " id -c", " id -g [-nr] [user]", " id -p [user]", " id -u [-nr] [user]"); Index: include/unistd.h =================================================================== --- include/unistd.h (revision 219137) +++ include/unistd.h (working copy) @@ -500,6 +500,7 @@ int feature_present(const char *); char *fflagstostr(u_long); int getdomainname(char *, int); int getgrouplist(const char *, gid_t, gid_t *, int *); +int getloginclass(pid_t, char *, size_t); mode_t getmode(const void *, mode_t); int getosreldate(void); int getpeereid(int, uid_t *, gid_t *); @@ -560,6 +561,7 @@ int setkey(const char *); #define _SETKEY_DECLARED #endif int setlogin(const char *); +int setloginclass(const char *); void *setmode(const char *); void setproctitle(const char *_fmt, ...) __printf0like(1, 2); int setresgid(gid_t, gid_t, gid_t); Index: lib/libutil/login_cap.h =================================================================== --- lib/libutil/login_cap.h (revision 219137) +++ lib/libutil/login_cap.h (working copy) @@ -49,7 +49,8 @@ #define LOGIN_SETENV 0x0080 /* set user environment */ #define LOGIN_SETMAC 0x0100 /* set user default MAC label */ #define LOGIN_SETCPUMASK 0x0200 /* set user cpumask */ -#define LOGIN_SETALL 0x03ff /* set everything */ +#define LOGIN_SETLOGINCLASS 0x0400 /* set login class in the kernel */ +#define LOGIN_SETALL 0x07ff /* set everything */ #define BI_AUTH "authorize" /* accepted authentication */ #define BI_REJECT "reject" /* rejected authentication */ Index: lib/libutil/login_class.c =================================================================== --- lib/libutil/login_class.c (revision 219137) +++ lib/libutil/login_class.c (working copy) @@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -425,6 +426,7 @@ setusercontext(login_cap_t *lc, const struct passw quad_t p; mode_t mymask; login_cap_t *llc = NULL; + struct sigaction sa, prevsa; struct rtprio rtp; int error; @@ -512,6 +514,27 @@ setusercontext(login_cap_t *lc, const struct passw return (-1); } + /* Inform the kernel about current login class */ + if (lc != NULL && lc->lc_class != NULL && (flags & LOGIN_SETLOGINCLASS)) { + /* + * XXX: This is a workaround to fail gracefully in case the kernel + * does not support setloginclass(2). + */ + bzero(&sa, sizeof(sa)); + sa.sa_handler = SIG_IGN; + sigfillset(&sa.sa_mask); + sigaction(SIGSYS, &sa, &prevsa); + error = setloginclass(lc->lc_class); + sigaction(SIGSYS, &prevsa, NULL); + if (error != 0) { + syslog(LOG_ERR, "setloginclass(%s): %m", lc->lc_class); +#ifdef notyet + login_close(llc); + return (-1); +#endif + } + } + mymask = (flags & LOGIN_SETUMASK) ? umask(LOGIN_DEFUMASK) : 0; mymask = setlogincontext(lc, pwd, mymask, flags); login_close(llc); Index: lib/libc/sys/Symbol.map =================================================================== --- lib/libc/sys/Symbol.map (revision 219137) +++ lib/libc/sys/Symbol.map (working copy) @@ -342,6 +342,7 @@ FBSD_1.1 { fexecve; fstatat; futimesat; + getloginclass; jail_get; jail_set; jail_remove; @@ -355,6 +356,7 @@ FBSD_1.1 { readlinkat; renameat; setfib; + setloginclass; shmctl; symlinkat; unlinkat; Index: bin/ps/ps.1 =================================================================== --- bin/ps/ps.1 (revision 219137) +++ bin/ps/ps.1 (working copy) @@ -29,7 +29,7 @@ .\" @(#)ps.1 8.3 (Berkeley) 4/18/94 .\" $FreeBSD$ .\" -.Dd July 24, 2010 +.Dd March 5, 2011 .Dt PS 1 .Os .Sh NAME @@ -280,6 +280,8 @@ be very young) it is possible for the sum of all fields to exceed 100%. .It Cm %mem The percentage of real memory used by this process. +.It Cm class +Login class associated with the process. .It Cm flags The flags associated with the process as in the include file @@ -475,6 +477,8 @@ accounting flag (alias .Cm acflg ) .It Cm args command and arguments +.It Cm class +login class .It Cm comm command .It Cm command Index: bin/ps/keyword.c =================================================================== --- bin/ps/keyword.c (revision 219137) +++ bin/ps/keyword.c (working copy) @@ -79,6 +79,8 @@ static VAR var[] = { CHAR, NULL, 0}, {"blocked", "", "sigmask", 0, NULL, NULL, 0, 0, CHAR, NULL, 0}, {"caught", "", "sigcatch", 0, NULL, NULL, 0, 0, CHAR, NULL, 0}, + {"class", "CLASS", NULL, LJUST|DSIZ, loginclass, s_loginclass, + SHRT_MAX, 0, CHAR, NULL, 0}, {"comm", "COMMAND", NULL, LJUST|DSIZ, ucomm, s_comm, COMMLEN + OCOMMLEN + 1, 0, CHAR, NULL, 0}, {"command", "COMMAND", NULL, COMM|LJUST|USER, command, NULL, 16, 0, Index: bin/ps/extern.h =================================================================== --- bin/ps/extern.h (revision 219137) +++ bin/ps/extern.h (working copy) @@ -55,6 +55,7 @@ const char *fmt_argv(char **, char *, size_t); double getpcpu(const KINFO *); void kvar(KINFO *, VARENT *); void label(KINFO *, VARENT *); +void loginclass(KINFO *, VARENT *); void logname(KINFO *, VARENT *); void longtname(KINFO *, VARENT *); void lstarted(KINFO *, VARENT *); @@ -74,6 +75,7 @@ void runame(KINFO *, VARENT *); void rvar(KINFO *, VARENT *); int s_comm(KINFO *); int s_label(KINFO *); +int s_loginclass(KINFO *); int s_rgroupname(KINFO *); int s_runame(KINFO *); int s_uname(KINFO *); Index: bin/ps/print.c =================================================================== --- bin/ps/print.c (revision 219137) +++ bin/ps/print.c (working copy) @@ -862,6 +862,25 @@ out: return; } +void +loginclass(KINFO *k, VARENT *ve) +{ + char buf[MAXLOGNAME]; + int error; + VAR *v; + + v = ve->var; + if (k->ki_p->ki_flag & P_SYSTEM) { + (void)printf("%-*s", v->width, " -"); + return; + } + error = getloginclass(k->ki_p->ki_pid, buf, sizeof(buf)); + if (error == 0) + (void)printf("%-*s", v->width, buf); + else + (void)printf("%-*s", v->width, " -"); +} + int s_comm(KINFO *k) { @@ -895,3 +914,17 @@ s_label(KINFO *k) mac_free(proclabel); return (size); } + +int +s_loginclass(KINFO *k) +{ + char buf[MAXLOGNAME]; + int error; + + if (k->ki_p->ki_flag & P_SYSTEM) + return (3); /* strlen (" -") */ + error = getloginclass(k->ki_p->ki_pid, buf, sizeof(buf)); + if (error != 0) + return (0); + return (strlen(buf)); +} Index: sys/conf/files =================================================================== --- sys/conf/files (revision 219137) +++ sys/conf/files (working copy) @@ -2186,6 +2186,7 @@ kern/kern_linker.c standard kern/kern_lock.c standard kern/kern_lockf.c standard kern/kern_lockstat.c optional kdtrace_hooks +kern/kern_loginclass.c standard kern/kern_malloc.c standard kern/kern_mbuf.c standard kern/kern_mib.c standard Index: sys/kern/kern_loginclass.c =================================================================== --- sys/kern/kern_loginclass.c (revision 0) +++ sys/kern/kern_loginclass.c (revision 0) @@ -0,0 +1,231 @@ +/*- + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Edward Tomasz Napierala under sponsorship + * from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Processes may set login class name using setloginclass(2). This + * is usually done through call to setusercontext(3), by programs + * such as login(1), based on information from master.passwd(5). Kernel + * uses this information to enforce per-class resource limits. Current + * login class can be determined using id(1). Login class is inherited + * from the parent process during fork(2). If not set, it defaults + * to "default". + * + * Code in this file implements setloginclass(2) and getloginclass(2) + * system calls, and maintains class name storage and retrieval. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static MALLOC_DEFINE(M_LOGINCLASS, "loginclass", "loginclass structures"); + +LIST_HEAD(, loginclass) loginclasses; + +/* + * Lock protecting loginclasses list. + */ +static struct mtx loginclasses_lock; + +static void lc_init(void); +SYSINIT(loginclass, SI_SUB_CPU, SI_ORDER_FIRST, lc_init, NULL); + +void +loginclass_hold(struct loginclass *lc) +{ + + refcount_acquire(&lc->lc_refcount); +} + +void +loginclass_free(struct loginclass *lc) +{ + int old; + + old = lc->lc_refcount; + if (old > 1 && atomic_cmpset_int(&lc->lc_refcount, old, old - 1)) + return; + + mtx_lock(&loginclasses_lock); + if (refcount_release(&lc->lc_refcount)) { + LIST_REMOVE(lc, lc_next); + mtx_unlock(&loginclasses_lock); + free(lc, M_LOGINCLASS); + + return; + } + mtx_unlock(&loginclasses_lock); +} + +/* + * Return loginclass structure with a corresponding name. Not + * performance critical, as it's used mainly by setloginclass(2), + * which happens once per login session. Caller has to use + * loginclass_free() on the returned value when it's no longer + * needed. + */ +struct loginclass * +loginclass_find(const char *name) +{ + struct loginclass *lc, *newlc; + + if (name[0] == '\0' || strlen(name) >= MAXLOGNAME) + return (NULL); + + newlc = malloc(sizeof(*newlc), M_LOGINCLASS, M_ZERO | M_WAITOK); + + mtx_lock(&loginclasses_lock); + LIST_FOREACH(lc, &loginclasses, lc_next) { + if (strcmp(name, lc->lc_name) != 0) + continue; + + /* Found loginclass with a matching name? */ + loginclass_hold(lc); + mtx_unlock(&loginclasses_lock); + free(newlc, M_LOGINCLASS); + return (lc); + } + + /* Add new loginclass. */ + strcpy(newlc->lc_name, name); + refcount_init(&newlc->lc_refcount, 1); + LIST_INSERT_HEAD(&loginclasses, newlc, lc_next); + mtx_unlock(&loginclasses_lock); + + return (newlc); +} + +/* + * Get login class name. + */ +#ifndef _SYS_SYSPROTO_H_ +struct getloginclass_args { + char *namebuf; + size_t namelen; +}; +#endif +/* ARGSUSED */ +int +getloginclass(struct thread *td, struct getloginclass_args *uap) +{ + int error = 0; + size_t lcnamelen; + struct proc *p; + struct loginclass *lc; + + if (uap->pid == 0) { + p = td->td_proc; + PROC_LOCK(p); + } else { + p = pfind(uap->pid); + if (p == NULL) + return (ESRCH); + error = p_cansee(td, p); + if (error != 0) { + PROC_UNLOCK(p); + return (error); + } + } + lc = p->p_ucred->cr_loginclass; + loginclass_hold(lc); + PROC_UNLOCK(p); + + lcnamelen = strlen(lc->lc_name) + 1; + if (lcnamelen > uap->namelen) + error = ERANGE; + if (error == 0) + error = copyout(lc->lc_name, uap->namebuf, lcnamelen); + loginclass_free(lc); + return (error); +} + +/* + * Set login class name. + */ +#ifndef _SYS_SYSPROTO_H_ +struct setloginclass_args { + const char *namebuf; +}; +#endif +/* ARGSUSED */ +int +setloginclass(struct thread *td, struct setloginclass_args *uap) +{ + struct proc *p = td->td_proc; + int error; + char lcname[MAXLOGNAME]; + struct loginclass *newlc; + struct ucred *newcred, *oldcred; + + error = priv_check(td, PRIV_PROC_SETLOGINCLASS); + if (error != 0) + return (error); + error = copyinstr(uap->namebuf, lcname, sizeof(lcname), NULL); + if (error != 0) + return (error); + + newlc = loginclass_find(lcname); + if (newlc == NULL) + return (EINVAL); + newcred = crget(); + + PROC_LOCK(p); + oldcred = crcopysafe(p, newcred); + newcred->cr_loginclass = newlc; + p->p_ucred = newcred; + PROC_UNLOCK(p); + + loginclass_free(oldcred->cr_loginclass); + crfree(oldcred); + + return (0); +} + +static void +lc_init(void) +{ + + mtx_init(&loginclasses_lock, "loginclasses lock", NULL, MTX_DEF); +} Property changes on: sys/kern/kern_loginclass.c ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + FreeBSD=%H Added: svn:eol-style + native Index: sys/kern/init_main.c =================================================================== --- sys/kern/init_main.c (revision 219137) +++ sys/kern/init_main.c (working copy) @@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -484,6 +485,7 @@ proc0_init(void *dummy __unused) p->p_ucred->cr_uidinfo = uifind(0); p->p_ucred->cr_ruidinfo = uifind(0); p->p_ucred->cr_prison = &prison0; + p->p_ucred->cr_loginclass = loginclass_find("default"); #ifdef AUDIT audit_cred_kproc0(p->p_ucred); #endif Index: sys/kern/kern_prot.c =================================================================== --- sys/kern/kern_prot.c (revision 219137) +++ sys/kern/kern_prot.c (working copy) @@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -1842,6 +1843,8 @@ crfree(struct ucred *cr) */ if (cr->cr_prison != NULL) prison_free(cr->cr_prison); + if (cr->cr_loginclass != NULL) + loginclass_free(cr->cr_loginclass); #ifdef AUDIT audit_cred_destroy(cr); #endif @@ -1878,6 +1881,7 @@ crcopy(struct ucred *dest, struct ucred *src) uihold(dest->cr_uidinfo); uihold(dest->cr_ruidinfo); prison_hold(dest->cr_prison); + loginclass_hold(dest->cr_loginclass); #ifdef AUDIT audit_cred_copy(src, dest); #endif Index: sys/kern/syscalls.master =================================================================== --- sys/kern/syscalls.master (revision 219137) +++ sys/kern/syscalls.master (working copy) @@ -926,5 +926,8 @@ fd_set *ou, fd_set *ex, \ const struct timespec *ts, \ const sigset_t *sm); } +523 AUE_NULL STD { int getloginclass(pid_t pid, char *namebuf, \ + size_t namelen); } +524 AUE_NULL STD { int setloginclass(const char *namebuf); } ; Please copy any additions and changes to the following compatability tables: ; sys/compat/freebsd32/syscalls.master Index: sys/compat/freebsd32/syscalls.master =================================================================== --- sys/compat/freebsd32/syscalls.master (revision 219137) +++ sys/compat/freebsd32/syscalls.master (working copy) @@ -962,3 +962,6 @@ fd_set *ou, fd_set *ex, \ const struct timespec32 *ts, \ const sigset_t *sm); } +523 AUE_NULL NOPROTO { int getloginclass(pid_t pid, char *namebuf, \ + size_t namelen); } +524 AUE_NULL NOPROTO { int setloginclass(const char *namebuf); } Index: sys/sys/loginclass.h =================================================================== --- sys/sys/loginclass.h (revision 0) +++ sys/sys/loginclass.h (revision 0) @@ -0,0 +1,49 @@ +/*- + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Edward Tomasz Napierala under sponsorship + * from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _SYS_LOGINCLASS_H_ +#define _SYS_LOGINCLASS_H_ + +/* + * Exactly one of these structures exists per login class. + */ +struct loginclass { + LIST_ENTRY(loginclass) lc_next; + char lc_name[MAXLOGNAME]; + u_int lc_refcount; +}; + +void loginclass_hold(struct loginclass *lc); +void loginclass_free(struct loginclass *lc); +struct loginclass *loginclass_find(const char *name); + +#endif /* !_SYS_LOGINCLASS_H_ */ + Property changes on: sys/sys/loginclass.h ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + FreeBSD=%H Added: svn:eol-style + native Index: sys/sys/ucred.h =================================================================== --- sys/sys/ucred.h (revision 219137) +++ sys/sys/ucred.h (working copy) @@ -35,6 +35,8 @@ #include +struct loginclass; + /* * Credentials. * @@ -54,7 +56,7 @@ struct ucred { struct uidinfo *cr_uidinfo; /* per euid resource consumption */ struct uidinfo *cr_ruidinfo; /* per ruid resource consumption */ struct prison *cr_prison; /* jail(2) */ - void *cr_pspare; /* general use */ + struct loginclass *cr_loginclass; /* login class */ u_int cr_flags; /* credential flags */ void *cr_pspare2[2]; /* general use 2 */ #define cr_endcopy cr_label Index: sys/sys/priv.h =================================================================== --- sys/sys/priv.h (revision 219137) +++ sys/sys/priv.h (working copy) @@ -156,6 +156,7 @@ #define PRIV_PROC_LIMIT 160 /* Exceed user process limit. */ #define PRIV_PROC_SETLOGIN 161 /* Can call setlogin. */ #define PRIV_PROC_SETRLIMIT 162 /* Can raise resources limits. */ +#define PRIV_PROC_SETLOGINCLASS 163 /* Can call setloginclass(2). */ /* System V IPC privileges. */