121288Sdavidn/*- 221288Sdavidn * Copyright (c) 1996 by 321288Sdavidn * Sean Eric Fagan <sef@kithrup.com> 421288Sdavidn * David Nugent <davidn@blaze.net.au> 521288Sdavidn * All rights reserved. 621288Sdavidn * 721288Sdavidn * Redistribution and use in source and binary forms, with or without 821288Sdavidn * modification, is permitted provided that the following conditions 921288Sdavidn * are met: 1021288Sdavidn * 1. Redistributions of source code must retain the above copyright 1121288Sdavidn * notice immediately at the beginning of the file, without modification, 1221288Sdavidn * this list of conditions, and the following disclaimer. 1321288Sdavidn * 2. Redistributions in binary form must reproduce the above copyright 1421288Sdavidn * notice, this list of conditions and the following disclaimer in the 1521288Sdavidn * documentation and/or other materials provided with the distribution. 1621288Sdavidn * 3. This work was done expressly for inclusion into FreeBSD. Other use 1721288Sdavidn * is permitted provided this notation is included. 1821288Sdavidn * 4. Absolutely no warranty of function or purpose is made by the authors. 1921288Sdavidn * 5. Modifications may be freely made to this file providing the above 2021288Sdavidn * conditions are met. 2121288Sdavidn * 2221288Sdavidn * High-level routines relating to use of the user capabilities database 2321288Sdavidn */ 2421288Sdavidn 2584225Sdillon#include <sys/cdefs.h> 2684225Sdillon__FBSDID("$FreeBSD$"); 2784225Sdillon 28180815Sbrooks#include <sys/param.h> 29180815Sbrooks#include <sys/cpuset.h> 30116344Smarkm#include <sys/mac.h> 31184081Sdes#include <sys/resource.h> 32116344Smarkm#include <sys/rtprio.h> 33184081Sdes#include <sys/stat.h> 34184081Sdes#include <sys/time.h> 35184081Sdes 36184081Sdes#include <ctype.h> 37184081Sdes#include <err.h> 38116344Smarkm#include <errno.h> 3921288Sdavidn#include <fcntl.h> 40116344Smarkm#include <login_cap.h> 41116344Smarkm#include <paths.h> 4221288Sdavidn#include <pwd.h> 43219304Strasz#include <signal.h> 44116344Smarkm#include <stdio.h> 45116344Smarkm#include <stdlib.h> 46116344Smarkm#include <string.h> 4721288Sdavidn#include <syslog.h> 48116344Smarkm#include <unistd.h> 4921288Sdavidn 5021288Sdavidn 5121288Sdavidnstatic struct login_res { 5225670Sdavidn const char *what; 5325670Sdavidn rlim_t (*who)(login_cap_t *, const char *, rlim_t, rlim_t); 5425670Sdavidn int why; 5521288Sdavidn} resources[] = { 56181905Sed { "cputime", login_getcaptime, RLIMIT_CPU }, 57181905Sed { "filesize", login_getcapsize, RLIMIT_FSIZE }, 58181905Sed { "datasize", login_getcapsize, RLIMIT_DATA }, 59181905Sed { "stacksize", login_getcapsize, RLIMIT_STACK }, 60181905Sed { "memoryuse", login_getcapsize, RLIMIT_RSS }, 61181905Sed { "memorylocked", login_getcapsize, RLIMIT_MEMLOCK }, 62181905Sed { "maxproc", login_getcapnum, RLIMIT_NPROC }, 63181905Sed { "openfiles", login_getcapnum, RLIMIT_NOFILE }, 64181905Sed { "coredumpsize", login_getcapsize, RLIMIT_CORE }, 65181905Sed { "sbsize", login_getcapsize, RLIMIT_SBSIZE }, 66181905Sed { "vmemoryuse", login_getcapsize, RLIMIT_VMEM }, 67181905Sed { "pseudoterminals", login_getcapnum, RLIMIT_NPTS }, 68194767Skib { "swapuse", login_getcapsize, RLIMIT_SWAP }, 69181905Sed { NULL, 0, 0 } 7021288Sdavidn}; 7121288Sdavidn 7221288Sdavidn 7321288Sdavidnvoid 7421288Sdavidnsetclassresources(login_cap_t *lc) 7521288Sdavidn{ 7625670Sdavidn struct login_res *lr; 7721288Sdavidn 7825670Sdavidn if (lc == NULL) 7925670Sdavidn return; 8021402Sdavidn 8125670Sdavidn for (lr = resources; lr->what != NULL; ++lr) { 8225670Sdavidn struct rlimit rlim; 8321288Sdavidn 8425670Sdavidn /* 8525670Sdavidn * The login.conf file can have <limit>, <limit>-max, and 8625670Sdavidn * <limit>-cur entries. 8725670Sdavidn * What we do is get the current current- and maximum- limits. 8825670Sdavidn * Then, we try to get an entry for <limit> from the capability, 8925670Sdavidn * using the current and max limits we just got as the 9025670Sdavidn * default/error values. 9125670Sdavidn * *Then*, we try looking for <limit>-cur and <limit>-max, 9225670Sdavidn * again using the appropriate values as the default/error 9325670Sdavidn * conditions. 9425670Sdavidn */ 9521288Sdavidn 9625670Sdavidn if (getrlimit(lr->why, &rlim) != 0) 9725670Sdavidn syslog(LOG_ERR, "getting %s resource limit: %m", lr->what); 9825670Sdavidn else { 99184081Sdes char name_cur[40]; 10025670Sdavidn char name_max[40]; 10125670Sdavidn rlim_t rcur = rlim.rlim_cur; 10225670Sdavidn rlim_t rmax = rlim.rlim_max; 10321288Sdavidn 10425670Sdavidn sprintf(name_cur, "%s-cur", lr->what); 10525670Sdavidn sprintf(name_max, "%s-max", lr->what); 10621288Sdavidn 10725670Sdavidn rcur = (*lr->who)(lc, lr->what, rcur, rcur); 10825670Sdavidn rmax = (*lr->who)(lc, lr->what, rmax, rmax); 10925670Sdavidn rlim.rlim_cur = (*lr->who)(lc, name_cur, rcur, rcur); 11025670Sdavidn rlim.rlim_max = (*lr->who)(lc, name_max, rmax, rmax); 111184081Sdes 11225670Sdavidn if (setrlimit(lr->why, &rlim) == -1) 11325670Sdavidn syslog(LOG_WARNING, "set class '%s' resource limit %s: %m", lc->lc_class, lr->what); 11425670Sdavidn } 11525670Sdavidn } 11621288Sdavidn} 11721288Sdavidn 11825670Sdavidn 11925670Sdavidn 12021288Sdavidnstatic struct login_vars { 12125670Sdavidn const char *tag; 12225670Sdavidn const char *var; 12325670Sdavidn const char *def; 12498977Sache int overwrite; 12521288Sdavidn} pathvars[] = { 12698977Sache { "path", "PATH", NULL, 1}, 12798977Sache { "cdpath", "CDPATH", NULL, 1}, 12898977Sache { "manpath", "MANPATH", NULL, 1}, 12998977Sache { NULL, NULL, NULL, 0} 13021288Sdavidn}, envars[] = { 13198977Sache { "lang", "LANG", NULL, 1}, 13298977Sache { "charset", "MM_CHARSET", NULL, 1}, 13398977Sache { "timezone", "TZ", NULL, 1}, 13498977Sache { "term", "TERM", NULL, 0}, 13598977Sache { NULL, NULL, NULL, 0} 13621288Sdavidn}; 13721288Sdavidn 13821288Sdavidnstatic char * 13994202Srusubstvar(const char * var, const struct passwd * pwd, int hlen, int pch, int nlen) 14021288Sdavidn{ 14125670Sdavidn char *np = NULL; 14221288Sdavidn 14325670Sdavidn if (var != NULL) { 14425670Sdavidn int tildes = 0; 14525670Sdavidn int dollas = 0; 14625670Sdavidn char *p; 147184633Sdes const char *q; 14821288Sdavidn 14925670Sdavidn if (pwd != NULL) { 150184633Sdes for (q = var; *q != '\0'; ++q) { 151184633Sdes tildes += (*q == '~'); 152184633Sdes dollas += (*q == '$'); 153184633Sdes } 15425670Sdavidn } 15521288Sdavidn 15625670Sdavidn np = malloc(strlen(var) + (dollas * nlen) 15725670Sdavidn - dollas + (tildes * (pch+hlen)) 15825670Sdavidn - tildes + 1); 15921288Sdavidn 16025670Sdavidn if (np != NULL) { 16125670Sdavidn p = strcpy(np, var); 16221288Sdavidn 16325670Sdavidn if (pwd != NULL) { 16425670Sdavidn /* 16525670Sdavidn * This loop does user username and homedir substitutions 16625670Sdavidn * for unescaped $ (username) and ~ (homedir) 16725670Sdavidn */ 16825670Sdavidn while (*(p += strcspn(p, "~$")) != '\0') { 16925670Sdavidn int l = strlen(p); 17021288Sdavidn 17147118Sache if (p > np && *(p-1) == '\\') /* Escaped: */ 17225670Sdavidn memmove(p - 1, p, l + 1); /* Slide-out the backslash */ 17325670Sdavidn else if (*p == '~') { 17425670Sdavidn int v = pch && *(p+1) != '/'; /* Avoid double // */ 17525670Sdavidn memmove(p + hlen + v, p + 1, l); /* Subst homedir */ 17625670Sdavidn memmove(p, pwd->pw_dir, hlen); 17725670Sdavidn if (v) 17825670Sdavidn p[hlen] = '/'; 17925670Sdavidn p += hlen + v; 18025670Sdavidn } 18125670Sdavidn else /* if (*p == '$') */ { 18225670Sdavidn memmove(p + nlen, p + 1, l); /* Subst username */ 18325670Sdavidn memmove(p, pwd->pw_name, nlen); 18425670Sdavidn p += nlen; 18525670Sdavidn } 18625670Sdavidn } 18725670Sdavidn } 18821288Sdavidn } 18921288Sdavidn } 19025670Sdavidn 191184082Sdes return (np); 19221288Sdavidn} 19321288Sdavidn 19421288Sdavidn 19521288Sdavidnvoid 19621288Sdavidnsetclassenvironment(login_cap_t *lc, const struct passwd * pwd, int paths) 19721288Sdavidn{ 19825670Sdavidn struct login_vars *vars = paths ? pathvars : envars; 19925670Sdavidn int hlen = pwd ? strlen(pwd->pw_dir) : 0; 20025670Sdavidn int nlen = pwd ? strlen(pwd->pw_name) : 0; 20125670Sdavidn char pch = 0; 20221288Sdavidn 20325670Sdavidn if (hlen && pwd->pw_dir[hlen-1] != '/') 20425670Sdavidn ++pch; 20521288Sdavidn 20625670Sdavidn while (vars->tag != NULL) { 20794202Sru const char * var = paths ? login_getpath(lc, vars->tag, NULL) 20894202Sru : login_getcapstr(lc, vars->tag, NULL, NULL); 20921288Sdavidn 21025670Sdavidn char * np = substvar(var, pwd, hlen, pch, nlen); 21121288Sdavidn 21225670Sdavidn if (np != NULL) { 21398977Sache setenv(vars->var, np, vars->overwrite); 21425670Sdavidn free(np); 21525670Sdavidn } else if (vars->def != NULL) { 21625670Sdavidn setenv(vars->var, vars->def, 0); 21725670Sdavidn } 21825670Sdavidn ++vars; 21921288Sdavidn } 22021288Sdavidn 22125670Sdavidn /* 22225670Sdavidn * If we're not processing paths, then see if there is a setenv list by 22325670Sdavidn * which the admin and/or user may set an arbitrary set of env vars. 22425670Sdavidn */ 22525670Sdavidn if (!paths) { 226121193Smarkm const char **set_env = login_getcaplist(lc, "setenv", ","); 22721402Sdavidn 22825670Sdavidn if (set_env != NULL) { 22925670Sdavidn while (*set_env != NULL) { 23025670Sdavidn char *p = strchr(*set_env, '='); 23121402Sdavidn 23225670Sdavidn if (p != NULL) { /* Discard invalid entries */ 23325670Sdavidn char *np; 23425670Sdavidn 23525670Sdavidn *p++ = '\0'; 23625670Sdavidn if ((np = substvar(p, pwd, hlen, pch, nlen)) != NULL) { 23725670Sdavidn setenv(*set_env, np, 1); 23825670Sdavidn free(np); 23925670Sdavidn } 24025670Sdavidn } 24125670Sdavidn ++set_env; 24225670Sdavidn } 24321288Sdavidn } 24421288Sdavidn } 24521288Sdavidn} 24621288Sdavidn 24721288Sdavidn 248180815Sbrooksstatic int 249180815Sbrookslist2cpuset(const char *list, cpuset_t *mask) 250180815Sbrooks{ 251180815Sbrooks enum { NONE, NUM, DASH } state; 252180815Sbrooks int lastnum; 253180815Sbrooks int curnum; 254180815Sbrooks const char *l; 255180815Sbrooks 256180815Sbrooks state = NONE; 257180815Sbrooks curnum = lastnum = 0; 258180815Sbrooks for (l = list; *l != '\0';) { 259180815Sbrooks if (isdigit(*l)) { 260180815Sbrooks curnum = atoi(l); 261180815Sbrooks if (curnum > CPU_SETSIZE) 262180815Sbrooks errx(EXIT_FAILURE, 263180815Sbrooks "Only %d cpus supported", CPU_SETSIZE); 264180815Sbrooks while (isdigit(*l)) 265180815Sbrooks l++; 266180815Sbrooks switch (state) { 267180815Sbrooks case NONE: 268180815Sbrooks lastnum = curnum; 269180815Sbrooks state = NUM; 270180815Sbrooks break; 271180815Sbrooks case DASH: 272180815Sbrooks for (; lastnum <= curnum; lastnum++) 273180815Sbrooks CPU_SET(lastnum, mask); 274180815Sbrooks state = NONE; 275180815Sbrooks break; 276180815Sbrooks case NUM: 277180815Sbrooks default: 278180815Sbrooks return (0); 279180815Sbrooks } 280180815Sbrooks continue; 281180815Sbrooks } 282180815Sbrooks switch (*l) { 283180815Sbrooks case ',': 284180815Sbrooks switch (state) { 285180815Sbrooks case NONE: 286180815Sbrooks break; 287180815Sbrooks case NUM: 288180815Sbrooks CPU_SET(curnum, mask); 289180815Sbrooks state = NONE; 290180815Sbrooks break; 291180815Sbrooks case DASH: 292180815Sbrooks return (0); 293180815Sbrooks break; 294180815Sbrooks } 295180815Sbrooks break; 296180815Sbrooks case '-': 297180815Sbrooks if (state != NUM) 298180815Sbrooks return (0); 299180815Sbrooks state = DASH; 300180815Sbrooks break; 301180815Sbrooks default: 302180815Sbrooks return (0); 303180815Sbrooks } 304180815Sbrooks l++; 305180815Sbrooks } 306180815Sbrooks switch (state) { 307180815Sbrooks case NONE: 308180815Sbrooks break; 309180815Sbrooks case NUM: 310180815Sbrooks CPU_SET(curnum, mask); 311180815Sbrooks break; 312180815Sbrooks case DASH: 313180815Sbrooks return (0); 314180815Sbrooks } 315184082Sdes return (1); 316180815Sbrooks} 317180815Sbrooks 318180815Sbrooks 319180815Sbrooksvoid 320180815Sbrookssetclasscpumask(login_cap_t *lc) 321180815Sbrooks{ 322180815Sbrooks const char *maskstr; 323180815Sbrooks cpuset_t maskset; 324180815Sbrooks cpusetid_t setid; 325180815Sbrooks 326180815Sbrooks maskstr = login_getcapstr(lc, "cpumask", NULL, NULL); 327180815Sbrooks CPU_ZERO(&maskset); 328180815Sbrooks if (maskstr == NULL) 329180815Sbrooks return; 330180815Sbrooks if (strcasecmp("default", maskstr) == 0) 331180815Sbrooks return; 332180815Sbrooks if (!list2cpuset(maskstr, &maskset)) { 333180815Sbrooks syslog(LOG_WARNING, 334180815Sbrooks "list2cpuset(%s) invalid mask specification", maskstr); 335180815Sbrooks return; 336180815Sbrooks } 337180815Sbrooks 338180815Sbrooks if (cpuset(&setid) != 0) { 339180815Sbrooks syslog(LOG_ERR, "cpuset(): %s", strerror(errno)); 340180815Sbrooks return; 341180815Sbrooks } 342180815Sbrooks 343180815Sbrooks if (cpuset_setaffinity(CPU_LEVEL_CPUSET, CPU_WHICH_PID, -1, 344180815Sbrooks sizeof(maskset), &maskset) != 0) 345180815Sbrooks syslog(LOG_ERR, "cpuset_setaffinity(%s): %s", maskstr, 346180815Sbrooks strerror(errno)); 347180815Sbrooks} 348180815Sbrooks 349180815Sbrooks 35021288Sdavidn/* 35121288Sdavidn * setclasscontext() 35221288Sdavidn * 35321288Sdavidn * For the login class <class>, set various class context values 35421288Sdavidn * (limits, mainly) to the values for that class. Which values are 35521288Sdavidn * set are controlled by <flags> -- see <login_class.h> for the 35621288Sdavidn * possible values. 35721288Sdavidn * 35821288Sdavidn * setclasscontext() can only set resources, priority, and umask. 35921288Sdavidn */ 36021288Sdavidn 36121288Sdavidnint 36221288Sdavidnsetclasscontext(const char *classname, unsigned int flags) 36321288Sdavidn{ 36425670Sdavidn int rc; 36525670Sdavidn login_cap_t *lc; 36625670Sdavidn 36725670Sdavidn lc = login_getclassbyname(classname, NULL); 36825670Sdavidn 36925670Sdavidn flags &= LOGIN_SETRESOURCES | LOGIN_SETPRIORITY | 37025670Sdavidn LOGIN_SETUMASK | LOGIN_SETPATH; 37125670Sdavidn 37225670Sdavidn rc = lc ? setusercontext(lc, NULL, 0, flags) : -1; 37325670Sdavidn login_close(lc); 374184082Sdes return (rc); 37521288Sdavidn} 37621288Sdavidn 37721288Sdavidn 37825670Sdavidn 37921288Sdavidn/* 380169189Syar * Private function which takes care of processing 38125670Sdavidn */ 38225670Sdavidn 38325670Sdavidnstatic mode_t 38425670Sdavidnsetlogincontext(login_cap_t *lc, const struct passwd *pwd, 38525670Sdavidn mode_t mymask, unsigned long flags) 38625670Sdavidn{ 38725670Sdavidn if (lc) { 38825670Sdavidn /* Set resources */ 38925670Sdavidn if (flags & LOGIN_SETRESOURCES) 39025670Sdavidn setclassresources(lc); 39125670Sdavidn /* See if there's a umask override */ 39225670Sdavidn if (flags & LOGIN_SETUMASK) 39325670Sdavidn mymask = (mode_t)login_getcapnum(lc, "umask", mymask, mymask); 39425670Sdavidn /* Set paths */ 39525670Sdavidn if (flags & LOGIN_SETPATH) 39625670Sdavidn setclassenvironment(lc, pwd, 1); 39725670Sdavidn /* Set environment */ 39825670Sdavidn if (flags & LOGIN_SETENV) 39925670Sdavidn setclassenvironment(lc, pwd, 0); 400180815Sbrooks /* Set cpu affinity */ 401180815Sbrooks if (flags & LOGIN_SETCPUMASK) 402180815Sbrooks setclasscpumask(lc); 40325670Sdavidn } 404184082Sdes return (mymask); 40525670Sdavidn} 40625670Sdavidn 40725670Sdavidn 40825670Sdavidn 40925670Sdavidn/* 41021288Sdavidn * setusercontext() 41121288Sdavidn * 41221288Sdavidn * Given a login class <lc> and a user in <pwd>, with a uid <uid>, 41321288Sdavidn * set the context as in setclasscontext(). <flags> controls which 41421288Sdavidn * values are set. 41521288Sdavidn * 41621288Sdavidn * The difference between setclasscontext() and setusercontext() is 41721288Sdavidn * that the former sets things up for an already-existing process, 41821288Sdavidn * while the latter sets things up from a root context. Such as might 41921288Sdavidn * be called from login(1). 42021288Sdavidn * 42121288Sdavidn */ 42221288Sdavidn 42321288Sdavidnint 42421288Sdavidnsetusercontext(login_cap_t *lc, const struct passwd *pwd, uid_t uid, unsigned int flags) 42521288Sdavidn{ 42625670Sdavidn quad_t p; 42725670Sdavidn mode_t mymask; 42825670Sdavidn login_cap_t *llc = NULL; 429219304Strasz struct sigaction sa, prevsa; 43036351Ssteve struct rtprio rtp; 431105757Srwatson int error; 43221288Sdavidn 43325670Sdavidn if (lc == NULL) { 43425670Sdavidn if (pwd != NULL && (lc = login_getpwclass(pwd)) != NULL) 43525670Sdavidn llc = lc; /* free this when we're done */ 43625670Sdavidn } 43721288Sdavidn 43825670Sdavidn if (flags & LOGIN_SETPATH) 43925670Sdavidn pathvars[0].def = uid ? _PATH_DEFPATH : _PATH_STDPATH; 44021288Sdavidn 44125670Sdavidn /* we need a passwd entry to set these */ 44225670Sdavidn if (pwd == NULL) 443106831Srwatson flags &= ~(LOGIN_SETGROUP | LOGIN_SETLOGIN | LOGIN_SETMAC); 44421288Sdavidn 44525670Sdavidn /* Set the process priority */ 44625670Sdavidn if (flags & LOGIN_SETPRIORITY) { 44725670Sdavidn p = login_getcapnum(lc, "priority", LOGIN_DEFPRI, LOGIN_DEFPRI); 44821288Sdavidn 449169189Syar if (p > PRIO_MAX) { 45036351Ssteve rtp.type = RTP_PRIO_IDLE; 45136351Ssteve rtp.prio = p - PRIO_MAX - 1; 45236351Ssteve p = (rtp.prio > RTP_PRIO_MAX) ? 31 : p; 453169189Syar if (rtprio(RTP_SET, 0, &rtp)) 45436351Ssteve syslog(LOG_WARNING, "rtprio '%s' (%s): %m", 455231306Seadler pwd ? pwd->pw_name : "-", 456231306Seadler lc ? lc->lc_class : LOGIN_DEFCLASS); 457169189Syar } else if (p < PRIO_MIN) { 45836351Ssteve rtp.type = RTP_PRIO_REALTIME; 45936351Ssteve rtp.prio = abs(p - PRIO_MIN + RTP_PRIO_MAX); 46036351Ssteve p = (rtp.prio > RTP_PRIO_MAX) ? 1 : p; 461169189Syar if (rtprio(RTP_SET, 0, &rtp)) 46236351Ssteve syslog(LOG_WARNING, "rtprio '%s' (%s): %m", 463231306Seadler pwd ? pwd->pw_name : "-", 464231306Seadler lc ? lc->lc_class : LOGIN_DEFCLASS); 46536351Ssteve } else { 46636351Ssteve if (setpriority(PRIO_PROCESS, 0, (int)p) != 0) 46736351Ssteve syslog(LOG_WARNING, "setpriority '%s' (%s): %m", 468231306Seadler pwd ? pwd->pw_name : "-", 469231306Seadler lc ? lc->lc_class : LOGIN_DEFCLASS); 47036351Ssteve } 47125670Sdavidn } 47221288Sdavidn 47325670Sdavidn /* Setup the user's group permissions */ 47425670Sdavidn if (flags & LOGIN_SETGROUP) { 47525670Sdavidn if (setgid(pwd->pw_gid) != 0) { 47637947Sache syslog(LOG_ERR, "setgid(%lu): %m", (u_long)pwd->pw_gid); 47725670Sdavidn login_close(llc); 478184082Sdes return (-1); 47925670Sdavidn } 48025670Sdavidn if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) { 48137947Sache syslog(LOG_ERR, "initgroups(%s,%lu): %m", pwd->pw_name, 48237947Sache (u_long)pwd->pw_gid); 48325670Sdavidn login_close(llc); 484184082Sdes return (-1); 48525670Sdavidn } 48625670Sdavidn } 48721288Sdavidn 488105757Srwatson /* Set up the user's MAC label. */ 489105757Srwatson if ((flags & LOGIN_SETMAC) && mac_is_present(NULL) == 1) { 490105757Srwatson const char *label_string; 491105757Srwatson mac_t label; 492105757Srwatson 493105757Srwatson label_string = login_getcapstr(lc, "label", NULL, NULL); 494105757Srwatson if (label_string != NULL) { 495105757Srwatson if (mac_from_text(&label, label_string) == -1) { 496105757Srwatson syslog(LOG_ERR, "mac_from_text('%s') for %s: %m", 497105757Srwatson pwd->pw_name, label_string); 498184082Sdes return (-1); 499105757Srwatson } 500105757Srwatson if (mac_set_proc(label) == -1) 501105757Srwatson error = errno; 502105757Srwatson else 503105757Srwatson error = 0; 504105757Srwatson mac_free(label); 505105757Srwatson if (error != 0) { 506105757Srwatson syslog(LOG_ERR, "mac_set_proc('%s') for %s: %s", 507105757Srwatson label_string, pwd->pw_name, strerror(error)); 508184082Sdes return (-1); 509105757Srwatson } 510105757Srwatson } 511105757Srwatson } 512105757Srwatson 51325670Sdavidn /* Set the sessions login */ 51425670Sdavidn if ((flags & LOGIN_SETLOGIN) && setlogin(pwd->pw_name) != 0) { 51525670Sdavidn syslog(LOG_ERR, "setlogin(%s): %m", pwd->pw_name); 51625670Sdavidn login_close(llc); 517184082Sdes return (-1); 51825670Sdavidn } 51921288Sdavidn 520219304Strasz /* Inform the kernel about current login class */ 521219304Strasz if (lc != NULL && lc->lc_class != NULL && (flags & LOGIN_SETLOGINCLASS)) { 522219304Strasz /* 523219304Strasz * XXX: This is a workaround to fail gracefully in case the kernel 524219304Strasz * does not support setloginclass(2). 525219304Strasz */ 526219304Strasz bzero(&sa, sizeof(sa)); 527219304Strasz sa.sa_handler = SIG_IGN; 528219304Strasz sigfillset(&sa.sa_mask); 529219304Strasz sigaction(SIGSYS, &sa, &prevsa); 530219304Strasz error = setloginclass(lc->lc_class); 531219304Strasz sigaction(SIGSYS, &prevsa, NULL); 532219304Strasz if (error != 0) { 533219304Strasz syslog(LOG_ERR, "setloginclass(%s): %m", lc->lc_class); 534219304Strasz#ifdef notyet 535219304Strasz login_close(llc); 536219304Strasz return (-1); 537219304Strasz#endif 538219304Strasz } 539219304Strasz } 540219304Strasz 54125670Sdavidn mymask = (flags & LOGIN_SETUMASK) ? umask(LOGIN_DEFUMASK) : 0; 54225670Sdavidn mymask = setlogincontext(lc, pwd, mymask, flags); 54325670Sdavidn login_close(llc); 54421288Sdavidn 54525670Sdavidn /* This needs to be done after anything that needs root privs */ 54625670Sdavidn if ((flags & LOGIN_SETUSER) && setuid(uid) != 0) { 54737947Sache syslog(LOG_ERR, "setuid(%lu): %m", (u_long)uid); 548184082Sdes return (-1); /* Paranoia again */ 54921288Sdavidn } 55021288Sdavidn 55125670Sdavidn /* 55225670Sdavidn * Now, we repeat some of the above for the user's private entries 55325670Sdavidn */ 554211393Sdes if (getuid() == uid && (lc = login_getuserclass(pwd)) != NULL) { 55525670Sdavidn mymask = setlogincontext(lc, pwd, mymask, flags); 55625670Sdavidn login_close(lc); 55725670Sdavidn } 55821288Sdavidn 55925670Sdavidn /* Finally, set any umask we've found */ 56025670Sdavidn if (flags & LOGIN_SETUMASK) 56125670Sdavidn umask(mymask); 56221288Sdavidn 563184082Sdes return (0); 56421288Sdavidn} 565