11eaf0ac3Slogwang /*-
21eaf0ac3Slogwang * Copyright (c) 1996 by
31eaf0ac3Slogwang * Sean Eric Fagan <[email protected]>
41eaf0ac3Slogwang * David Nugent <[email protected]>
51eaf0ac3Slogwang * All rights reserved.
61eaf0ac3Slogwang *
71eaf0ac3Slogwang * Redistribution and use in source and binary forms, with or without
81eaf0ac3Slogwang * modification, is permitted provided that the following conditions
91eaf0ac3Slogwang * are met:
101eaf0ac3Slogwang * 1. Redistributions of source code must retain the above copyright
111eaf0ac3Slogwang * notice immediately at the beginning of the file, without modification,
121eaf0ac3Slogwang * this list of conditions, and the following disclaimer.
131eaf0ac3Slogwang * 2. Redistributions in binary form must reproduce the above copyright
141eaf0ac3Slogwang * notice, this list of conditions and the following disclaimer in the
151eaf0ac3Slogwang * documentation and/or other materials provided with the distribution.
161eaf0ac3Slogwang * 3. This work was done expressly for inclusion into FreeBSD. Other use
171eaf0ac3Slogwang * is permitted provided this notation is included.
181eaf0ac3Slogwang * 4. Absolutely no warranty of function or purpose is made by the authors.
191eaf0ac3Slogwang * 5. Modifications may be freely made to this file providing the above
201eaf0ac3Slogwang * conditions are met.
211eaf0ac3Slogwang *
221eaf0ac3Slogwang * High-level routines relating to use of the user capabilities database
231eaf0ac3Slogwang */
241eaf0ac3Slogwang
251eaf0ac3Slogwang #include <sys/cdefs.h>
261eaf0ac3Slogwang __FBSDID("$FreeBSD$");
271eaf0ac3Slogwang
281eaf0ac3Slogwang #include <sys/param.h>
291eaf0ac3Slogwang #include <sys/cpuset.h>
301eaf0ac3Slogwang #include <sys/mac.h>
311eaf0ac3Slogwang #include <sys/resource.h>
321eaf0ac3Slogwang #include <sys/rtprio.h>
331eaf0ac3Slogwang #include <sys/stat.h>
341eaf0ac3Slogwang #include <sys/time.h>
351eaf0ac3Slogwang
361eaf0ac3Slogwang #include <ctype.h>
371eaf0ac3Slogwang #include <err.h>
381eaf0ac3Slogwang #include <errno.h>
391eaf0ac3Slogwang #include <fcntl.h>
401eaf0ac3Slogwang #include <login_cap.h>
411eaf0ac3Slogwang #include <paths.h>
421eaf0ac3Slogwang #include <pwd.h>
431eaf0ac3Slogwang #include <stdio.h>
441eaf0ac3Slogwang #include <stdlib.h>
451eaf0ac3Slogwang #include <string.h>
461eaf0ac3Slogwang #include <syslog.h>
471eaf0ac3Slogwang #include <unistd.h>
481eaf0ac3Slogwang
491eaf0ac3Slogwang
501eaf0ac3Slogwang static struct login_res {
511eaf0ac3Slogwang const char *what;
521eaf0ac3Slogwang rlim_t (*who)(login_cap_t *, const char *, rlim_t, rlim_t);
531eaf0ac3Slogwang int why;
541eaf0ac3Slogwang } resources[] = {
551eaf0ac3Slogwang { "cputime", login_getcaptime, RLIMIT_CPU },
561eaf0ac3Slogwang { "filesize", login_getcapsize, RLIMIT_FSIZE },
571eaf0ac3Slogwang { "datasize", login_getcapsize, RLIMIT_DATA },
581eaf0ac3Slogwang { "stacksize", login_getcapsize, RLIMIT_STACK },
591eaf0ac3Slogwang { "memoryuse", login_getcapsize, RLIMIT_RSS },
601eaf0ac3Slogwang { "memorylocked", login_getcapsize, RLIMIT_MEMLOCK },
611eaf0ac3Slogwang { "maxproc", login_getcapnum, RLIMIT_NPROC },
621eaf0ac3Slogwang { "openfiles", login_getcapnum, RLIMIT_NOFILE },
631eaf0ac3Slogwang { "coredumpsize", login_getcapsize, RLIMIT_CORE },
641eaf0ac3Slogwang { "sbsize", login_getcapsize, RLIMIT_SBSIZE },
651eaf0ac3Slogwang { "vmemoryuse", login_getcapsize, RLIMIT_VMEM },
661eaf0ac3Slogwang { "pseudoterminals", login_getcapnum, RLIMIT_NPTS },
671eaf0ac3Slogwang { "swapuse", login_getcapsize, RLIMIT_SWAP },
681eaf0ac3Slogwang { "kqueues", login_getcapsize, RLIMIT_KQUEUES },
691eaf0ac3Slogwang { "umtxp", login_getcapnum, RLIMIT_UMTXP },
701eaf0ac3Slogwang { NULL, 0, 0 }
711eaf0ac3Slogwang };
721eaf0ac3Slogwang
731eaf0ac3Slogwang
741eaf0ac3Slogwang void
setclassresources(login_cap_t * lc)751eaf0ac3Slogwang setclassresources(login_cap_t *lc)
761eaf0ac3Slogwang {
771eaf0ac3Slogwang struct login_res *lr;
781eaf0ac3Slogwang
791eaf0ac3Slogwang if (lc == NULL)
801eaf0ac3Slogwang return;
811eaf0ac3Slogwang
821eaf0ac3Slogwang for (lr = resources; lr->what != NULL; ++lr) {
831eaf0ac3Slogwang struct rlimit rlim;
841eaf0ac3Slogwang
851eaf0ac3Slogwang /*
861eaf0ac3Slogwang * The login.conf file can have <limit>, <limit>-max, and
871eaf0ac3Slogwang * <limit>-cur entries.
881eaf0ac3Slogwang * What we do is get the current current- and maximum- limits.
891eaf0ac3Slogwang * Then, we try to get an entry for <limit> from the capability,
901eaf0ac3Slogwang * using the current and max limits we just got as the
911eaf0ac3Slogwang * default/error values.
921eaf0ac3Slogwang * *Then*, we try looking for <limit>-cur and <limit>-max,
931eaf0ac3Slogwang * again using the appropriate values as the default/error
941eaf0ac3Slogwang * conditions.
951eaf0ac3Slogwang */
961eaf0ac3Slogwang
971eaf0ac3Slogwang if (getrlimit(lr->why, &rlim) != 0)
981eaf0ac3Slogwang syslog(LOG_ERR, "getting %s resource limit: %m", lr->what);
991eaf0ac3Slogwang else {
1001eaf0ac3Slogwang char name_cur[40];
1011eaf0ac3Slogwang char name_max[40];
1021eaf0ac3Slogwang rlim_t rcur = rlim.rlim_cur;
1031eaf0ac3Slogwang rlim_t rmax = rlim.rlim_max;
1041eaf0ac3Slogwang
1051eaf0ac3Slogwang sprintf(name_cur, "%s-cur", lr->what);
1061eaf0ac3Slogwang sprintf(name_max, "%s-max", lr->what);
1071eaf0ac3Slogwang
1081eaf0ac3Slogwang rcur = (*lr->who)(lc, lr->what, rcur, rcur);
1091eaf0ac3Slogwang rmax = (*lr->who)(lc, lr->what, rmax, rmax);
1101eaf0ac3Slogwang rlim.rlim_cur = (*lr->who)(lc, name_cur, rcur, rcur);
1111eaf0ac3Slogwang rlim.rlim_max = (*lr->who)(lc, name_max, rmax, rmax);
1121eaf0ac3Slogwang
1131eaf0ac3Slogwang if (setrlimit(lr->why, &rlim) == -1)
1141eaf0ac3Slogwang syslog(LOG_WARNING, "set class '%s' resource limit %s: %m", lc->lc_class, lr->what);
1151eaf0ac3Slogwang }
1161eaf0ac3Slogwang }
1171eaf0ac3Slogwang }
1181eaf0ac3Slogwang
1191eaf0ac3Slogwang
1201eaf0ac3Slogwang
1211eaf0ac3Slogwang static struct login_vars {
1221eaf0ac3Slogwang const char *tag;
1231eaf0ac3Slogwang const char *var;
1241eaf0ac3Slogwang const char *def;
1251eaf0ac3Slogwang int overwrite;
1261eaf0ac3Slogwang } pathvars[] = {
1271eaf0ac3Slogwang { "path", "PATH", NULL, 1},
1281eaf0ac3Slogwang { "cdpath", "CDPATH", NULL, 1},
1291eaf0ac3Slogwang { "manpath", "MANPATH", NULL, 1},
1301eaf0ac3Slogwang { NULL, NULL, NULL, 0}
1311eaf0ac3Slogwang }, envars[] = {
1321eaf0ac3Slogwang { "lang", "LANG", NULL, 1},
1331eaf0ac3Slogwang { "charset", "MM_CHARSET", NULL, 1},
134*22ce4affSfengbojiang { "mail", "MAIL", NULL, 1},
1351eaf0ac3Slogwang { "timezone", "TZ", NULL, 1},
1361eaf0ac3Slogwang { "term", "TERM", NULL, 0},
1371eaf0ac3Slogwang { NULL, NULL, NULL, 0}
1381eaf0ac3Slogwang };
1391eaf0ac3Slogwang
1401eaf0ac3Slogwang static char *
substvar(const char * var,const struct passwd * pwd,int hlen,int pch,int nlen)1411eaf0ac3Slogwang substvar(const char * var, const struct passwd * pwd, int hlen, int pch, int nlen)
1421eaf0ac3Slogwang {
1431eaf0ac3Slogwang char *np = NULL;
1441eaf0ac3Slogwang
1451eaf0ac3Slogwang if (var != NULL) {
1461eaf0ac3Slogwang int tildes = 0;
1471eaf0ac3Slogwang int dollas = 0;
1481eaf0ac3Slogwang char *p;
1491eaf0ac3Slogwang const char *q;
1501eaf0ac3Slogwang
1511eaf0ac3Slogwang if (pwd != NULL) {
1521eaf0ac3Slogwang for (q = var; *q != '\0'; ++q) {
1531eaf0ac3Slogwang tildes += (*q == '~');
1541eaf0ac3Slogwang dollas += (*q == '$');
1551eaf0ac3Slogwang }
1561eaf0ac3Slogwang }
1571eaf0ac3Slogwang
1581eaf0ac3Slogwang np = malloc(strlen(var) + (dollas * nlen)
1591eaf0ac3Slogwang - dollas + (tildes * (pch+hlen))
1601eaf0ac3Slogwang - tildes + 1);
1611eaf0ac3Slogwang
1621eaf0ac3Slogwang if (np != NULL) {
1631eaf0ac3Slogwang p = strcpy(np, var);
1641eaf0ac3Slogwang
1651eaf0ac3Slogwang if (pwd != NULL) {
1661eaf0ac3Slogwang /*
1671eaf0ac3Slogwang * This loop does user username and homedir substitutions
1681eaf0ac3Slogwang * for unescaped $ (username) and ~ (homedir)
1691eaf0ac3Slogwang */
1701eaf0ac3Slogwang while (*(p += strcspn(p, "~$")) != '\0') {
1711eaf0ac3Slogwang int l = strlen(p);
1721eaf0ac3Slogwang
1731eaf0ac3Slogwang if (p > np && *(p-1) == '\\') /* Escaped: */
1741eaf0ac3Slogwang memmove(p - 1, p, l + 1); /* Slide-out the backslash */
1751eaf0ac3Slogwang else if (*p == '~') {
1761eaf0ac3Slogwang int v = pch && *(p+1) != '/'; /* Avoid double // */
1771eaf0ac3Slogwang memmove(p + hlen + v, p + 1, l); /* Subst homedir */
1781eaf0ac3Slogwang memmove(p, pwd->pw_dir, hlen);
1791eaf0ac3Slogwang if (v)
1801eaf0ac3Slogwang p[hlen] = '/';
1811eaf0ac3Slogwang p += hlen + v;
1821eaf0ac3Slogwang }
1831eaf0ac3Slogwang else /* if (*p == '$') */ {
1841eaf0ac3Slogwang memmove(p + nlen, p + 1, l); /* Subst username */
1851eaf0ac3Slogwang memmove(p, pwd->pw_name, nlen);
1861eaf0ac3Slogwang p += nlen;
1871eaf0ac3Slogwang }
1881eaf0ac3Slogwang }
1891eaf0ac3Slogwang }
1901eaf0ac3Slogwang }
1911eaf0ac3Slogwang }
1921eaf0ac3Slogwang
1931eaf0ac3Slogwang return (np);
1941eaf0ac3Slogwang }
1951eaf0ac3Slogwang
1961eaf0ac3Slogwang
1971eaf0ac3Slogwang void
setclassenvironment(login_cap_t * lc,const struct passwd * pwd,int paths)1981eaf0ac3Slogwang setclassenvironment(login_cap_t *lc, const struct passwd * pwd, int paths)
1991eaf0ac3Slogwang {
2001eaf0ac3Slogwang struct login_vars *vars = paths ? pathvars : envars;
2011eaf0ac3Slogwang int hlen = pwd ? strlen(pwd->pw_dir) : 0;
2021eaf0ac3Slogwang int nlen = pwd ? strlen(pwd->pw_name) : 0;
2031eaf0ac3Slogwang char pch = 0;
2041eaf0ac3Slogwang
2051eaf0ac3Slogwang if (hlen && pwd->pw_dir[hlen-1] != '/')
2061eaf0ac3Slogwang ++pch;
2071eaf0ac3Slogwang
2081eaf0ac3Slogwang while (vars->tag != NULL) {
2091eaf0ac3Slogwang const char * var = paths ? login_getpath(lc, vars->tag, NULL)
2101eaf0ac3Slogwang : login_getcapstr(lc, vars->tag, NULL, NULL);
2111eaf0ac3Slogwang
2121eaf0ac3Slogwang char * np = substvar(var, pwd, hlen, pch, nlen);
2131eaf0ac3Slogwang
2141eaf0ac3Slogwang if (np != NULL) {
2151eaf0ac3Slogwang setenv(vars->var, np, vars->overwrite);
2161eaf0ac3Slogwang free(np);
2171eaf0ac3Slogwang } else if (vars->def != NULL) {
2181eaf0ac3Slogwang setenv(vars->var, vars->def, 0);
2191eaf0ac3Slogwang }
2201eaf0ac3Slogwang ++vars;
2211eaf0ac3Slogwang }
2221eaf0ac3Slogwang
2231eaf0ac3Slogwang /*
2241eaf0ac3Slogwang * If we're not processing paths, then see if there is a setenv list by
2251eaf0ac3Slogwang * which the admin and/or user may set an arbitrary set of env vars.
2261eaf0ac3Slogwang */
2271eaf0ac3Slogwang if (!paths) {
2281eaf0ac3Slogwang const char **set_env = login_getcaplist(lc, "setenv", ",");
2291eaf0ac3Slogwang
2301eaf0ac3Slogwang if (set_env != NULL) {
2311eaf0ac3Slogwang while (*set_env != NULL) {
2321eaf0ac3Slogwang char *p = strchr(*set_env, '=');
2331eaf0ac3Slogwang
2341eaf0ac3Slogwang if (p != NULL) { /* Discard invalid entries */
2351eaf0ac3Slogwang char *np;
2361eaf0ac3Slogwang
2371eaf0ac3Slogwang *p++ = '\0';
2381eaf0ac3Slogwang if ((np = substvar(p, pwd, hlen, pch, nlen)) != NULL) {
2391eaf0ac3Slogwang setenv(*set_env, np, 1);
2401eaf0ac3Slogwang free(np);
2411eaf0ac3Slogwang }
2421eaf0ac3Slogwang }
2431eaf0ac3Slogwang ++set_env;
2441eaf0ac3Slogwang }
2451eaf0ac3Slogwang }
2461eaf0ac3Slogwang }
2471eaf0ac3Slogwang }
2481eaf0ac3Slogwang
2491eaf0ac3Slogwang
2501eaf0ac3Slogwang static int
list2cpuset(const char * list,cpuset_t * mask)2511eaf0ac3Slogwang list2cpuset(const char *list, cpuset_t *mask)
2521eaf0ac3Slogwang {
2531eaf0ac3Slogwang enum { NONE, NUM, DASH } state;
2541eaf0ac3Slogwang int lastnum;
2551eaf0ac3Slogwang int curnum;
2561eaf0ac3Slogwang const char *l;
2571eaf0ac3Slogwang
2581eaf0ac3Slogwang state = NONE;
2591eaf0ac3Slogwang curnum = lastnum = 0;
2601eaf0ac3Slogwang for (l = list; *l != '\0';) {
2611eaf0ac3Slogwang if (isdigit(*l)) {
2621eaf0ac3Slogwang curnum = atoi(l);
2631eaf0ac3Slogwang if (curnum > CPU_SETSIZE)
2641eaf0ac3Slogwang errx(EXIT_FAILURE,
2651eaf0ac3Slogwang "Only %d cpus supported", CPU_SETSIZE);
2661eaf0ac3Slogwang while (isdigit(*l))
2671eaf0ac3Slogwang l++;
2681eaf0ac3Slogwang switch (state) {
2691eaf0ac3Slogwang case NONE:
2701eaf0ac3Slogwang lastnum = curnum;
2711eaf0ac3Slogwang state = NUM;
2721eaf0ac3Slogwang break;
2731eaf0ac3Slogwang case DASH:
2741eaf0ac3Slogwang for (; lastnum <= curnum; lastnum++)
2751eaf0ac3Slogwang CPU_SET(lastnum, mask);
2761eaf0ac3Slogwang state = NONE;
2771eaf0ac3Slogwang break;
2781eaf0ac3Slogwang case NUM:
2791eaf0ac3Slogwang default:
2801eaf0ac3Slogwang return (0);
2811eaf0ac3Slogwang }
2821eaf0ac3Slogwang continue;
2831eaf0ac3Slogwang }
2841eaf0ac3Slogwang switch (*l) {
2851eaf0ac3Slogwang case ',':
2861eaf0ac3Slogwang switch (state) {
2871eaf0ac3Slogwang case NONE:
2881eaf0ac3Slogwang break;
2891eaf0ac3Slogwang case NUM:
2901eaf0ac3Slogwang CPU_SET(curnum, mask);
2911eaf0ac3Slogwang state = NONE;
2921eaf0ac3Slogwang break;
2931eaf0ac3Slogwang case DASH:
2941eaf0ac3Slogwang return (0);
2951eaf0ac3Slogwang break;
2961eaf0ac3Slogwang }
2971eaf0ac3Slogwang break;
2981eaf0ac3Slogwang case '-':
2991eaf0ac3Slogwang if (state != NUM)
3001eaf0ac3Slogwang return (0);
3011eaf0ac3Slogwang state = DASH;
3021eaf0ac3Slogwang break;
3031eaf0ac3Slogwang default:
3041eaf0ac3Slogwang return (0);
3051eaf0ac3Slogwang }
3061eaf0ac3Slogwang l++;
3071eaf0ac3Slogwang }
3081eaf0ac3Slogwang switch (state) {
3091eaf0ac3Slogwang case NONE:
3101eaf0ac3Slogwang break;
3111eaf0ac3Slogwang case NUM:
3121eaf0ac3Slogwang CPU_SET(curnum, mask);
3131eaf0ac3Slogwang break;
3141eaf0ac3Slogwang case DASH:
3151eaf0ac3Slogwang return (0);
3161eaf0ac3Slogwang }
3171eaf0ac3Slogwang return (1);
3181eaf0ac3Slogwang }
3191eaf0ac3Slogwang
3201eaf0ac3Slogwang
3211eaf0ac3Slogwang void
setclasscpumask(login_cap_t * lc)3221eaf0ac3Slogwang setclasscpumask(login_cap_t *lc)
3231eaf0ac3Slogwang {
3241eaf0ac3Slogwang const char *maskstr;
3251eaf0ac3Slogwang cpuset_t maskset;
3261eaf0ac3Slogwang cpusetid_t setid;
3271eaf0ac3Slogwang
3281eaf0ac3Slogwang maskstr = login_getcapstr(lc, "cpumask", NULL, NULL);
3291eaf0ac3Slogwang CPU_ZERO(&maskset);
3301eaf0ac3Slogwang if (maskstr == NULL)
3311eaf0ac3Slogwang return;
3321eaf0ac3Slogwang if (strcasecmp("default", maskstr) == 0)
3331eaf0ac3Slogwang return;
3341eaf0ac3Slogwang if (!list2cpuset(maskstr, &maskset)) {
3351eaf0ac3Slogwang syslog(LOG_WARNING,
3361eaf0ac3Slogwang "list2cpuset(%s) invalid mask specification", maskstr);
3371eaf0ac3Slogwang return;
3381eaf0ac3Slogwang }
3391eaf0ac3Slogwang
3401eaf0ac3Slogwang if (cpuset(&setid) != 0) {
3411eaf0ac3Slogwang syslog(LOG_ERR, "cpuset(): %s", strerror(errno));
3421eaf0ac3Slogwang return;
3431eaf0ac3Slogwang }
3441eaf0ac3Slogwang
3451eaf0ac3Slogwang if (cpuset_setaffinity(CPU_LEVEL_CPUSET, CPU_WHICH_PID, -1,
3461eaf0ac3Slogwang sizeof(maskset), &maskset) != 0)
3471eaf0ac3Slogwang syslog(LOG_ERR, "cpuset_setaffinity(%s): %s", maskstr,
3481eaf0ac3Slogwang strerror(errno));
3491eaf0ac3Slogwang }
3501eaf0ac3Slogwang
3511eaf0ac3Slogwang
3521eaf0ac3Slogwang /*
3531eaf0ac3Slogwang * setclasscontext()
3541eaf0ac3Slogwang *
3551eaf0ac3Slogwang * For the login class <class>, set various class context values
3561eaf0ac3Slogwang * (limits, mainly) to the values for that class. Which values are
3571eaf0ac3Slogwang * set are controlled by <flags> -- see <login_class.h> for the
3581eaf0ac3Slogwang * possible values.
3591eaf0ac3Slogwang *
3601eaf0ac3Slogwang * setclasscontext() can only set resources, priority, and umask.
3611eaf0ac3Slogwang */
3621eaf0ac3Slogwang
3631eaf0ac3Slogwang int
setclasscontext(const char * classname,unsigned int flags)3641eaf0ac3Slogwang setclasscontext(const char *classname, unsigned int flags)
3651eaf0ac3Slogwang {
3661eaf0ac3Slogwang int rc;
3671eaf0ac3Slogwang login_cap_t *lc;
3681eaf0ac3Slogwang
3691eaf0ac3Slogwang lc = login_getclassbyname(classname, NULL);
3701eaf0ac3Slogwang
3711eaf0ac3Slogwang flags &= LOGIN_SETRESOURCES | LOGIN_SETPRIORITY |
3721eaf0ac3Slogwang LOGIN_SETUMASK | LOGIN_SETPATH;
3731eaf0ac3Slogwang
3741eaf0ac3Slogwang rc = lc ? setusercontext(lc, NULL, 0, flags) : -1;
3751eaf0ac3Slogwang login_close(lc);
3761eaf0ac3Slogwang return (rc);
3771eaf0ac3Slogwang }
3781eaf0ac3Slogwang
3791eaf0ac3Slogwang
3801eaf0ac3Slogwang
3811eaf0ac3Slogwang /*
3821eaf0ac3Slogwang * Private function which takes care of processing
3831eaf0ac3Slogwang */
3841eaf0ac3Slogwang
3851eaf0ac3Slogwang static mode_t
setlogincontext(login_cap_t * lc,const struct passwd * pwd,mode_t mymask,unsigned long flags)3861eaf0ac3Slogwang setlogincontext(login_cap_t *lc, const struct passwd *pwd,
3871eaf0ac3Slogwang mode_t mymask, unsigned long flags)
3881eaf0ac3Slogwang {
3891eaf0ac3Slogwang if (lc) {
3901eaf0ac3Slogwang /* Set resources */
3911eaf0ac3Slogwang if (flags & LOGIN_SETRESOURCES)
3921eaf0ac3Slogwang setclassresources(lc);
3931eaf0ac3Slogwang /* See if there's a umask override */
3941eaf0ac3Slogwang if (flags & LOGIN_SETUMASK)
3951eaf0ac3Slogwang mymask = (mode_t)login_getcapnum(lc, "umask", mymask, mymask);
3961eaf0ac3Slogwang /* Set paths */
3971eaf0ac3Slogwang if (flags & LOGIN_SETPATH)
3981eaf0ac3Slogwang setclassenvironment(lc, pwd, 1);
3991eaf0ac3Slogwang /* Set environment */
4001eaf0ac3Slogwang if (flags & LOGIN_SETENV)
4011eaf0ac3Slogwang setclassenvironment(lc, pwd, 0);
4021eaf0ac3Slogwang /* Set cpu affinity */
4031eaf0ac3Slogwang if (flags & LOGIN_SETCPUMASK)
4041eaf0ac3Slogwang setclasscpumask(lc);
4051eaf0ac3Slogwang }
4061eaf0ac3Slogwang return (mymask);
4071eaf0ac3Slogwang }
4081eaf0ac3Slogwang
4091eaf0ac3Slogwang
4101eaf0ac3Slogwang
4111eaf0ac3Slogwang /*
4121eaf0ac3Slogwang * setusercontext()
4131eaf0ac3Slogwang *
4141eaf0ac3Slogwang * Given a login class <lc> and a user in <pwd>, with a uid <uid>,
4151eaf0ac3Slogwang * set the context as in setclasscontext(). <flags> controls which
4161eaf0ac3Slogwang * values are set.
4171eaf0ac3Slogwang *
4181eaf0ac3Slogwang * The difference between setclasscontext() and setusercontext() is
4191eaf0ac3Slogwang * that the former sets things up for an already-existing process,
4201eaf0ac3Slogwang * while the latter sets things up from a root context. Such as might
4211eaf0ac3Slogwang * be called from login(1).
4221eaf0ac3Slogwang *
4231eaf0ac3Slogwang */
4241eaf0ac3Slogwang
4251eaf0ac3Slogwang int
setusercontext(login_cap_t * lc,const struct passwd * pwd,uid_t uid,unsigned int flags)4261eaf0ac3Slogwang setusercontext(login_cap_t *lc, const struct passwd *pwd, uid_t uid, unsigned int flags)
4271eaf0ac3Slogwang {
4281eaf0ac3Slogwang rlim_t p;
4291eaf0ac3Slogwang mode_t mymask;
4301eaf0ac3Slogwang login_cap_t *llc = NULL;
4311eaf0ac3Slogwang struct rtprio rtp;
4321eaf0ac3Slogwang int error;
4331eaf0ac3Slogwang
4341eaf0ac3Slogwang if (lc == NULL) {
4351eaf0ac3Slogwang if (pwd != NULL && (lc = login_getpwclass(pwd)) != NULL)
4361eaf0ac3Slogwang llc = lc; /* free this when we're done */
4371eaf0ac3Slogwang }
4381eaf0ac3Slogwang
4391eaf0ac3Slogwang if (flags & LOGIN_SETPATH)
4401eaf0ac3Slogwang pathvars[0].def = uid ? _PATH_DEFPATH : _PATH_STDPATH;
4411eaf0ac3Slogwang
4421eaf0ac3Slogwang /* we need a passwd entry to set these */
4431eaf0ac3Slogwang if (pwd == NULL)
4441eaf0ac3Slogwang flags &= ~(LOGIN_SETGROUP | LOGIN_SETLOGIN | LOGIN_SETMAC);
4451eaf0ac3Slogwang
4461eaf0ac3Slogwang /* Set the process priority */
4471eaf0ac3Slogwang if (flags & LOGIN_SETPRIORITY) {
4481eaf0ac3Slogwang p = login_getcapnum(lc, "priority", LOGIN_DEFPRI, LOGIN_DEFPRI);
4491eaf0ac3Slogwang
4501eaf0ac3Slogwang if (p > PRIO_MAX) {
4511eaf0ac3Slogwang rtp.type = RTP_PRIO_IDLE;
4521eaf0ac3Slogwang p -= PRIO_MAX + 1;
4531eaf0ac3Slogwang rtp.prio = p > RTP_PRIO_MAX ? RTP_PRIO_MAX : p;
4541eaf0ac3Slogwang if (rtprio(RTP_SET, 0, &rtp))
4551eaf0ac3Slogwang syslog(LOG_WARNING, "rtprio '%s' (%s): %m",
4561eaf0ac3Slogwang pwd ? pwd->pw_name : "-",
4571eaf0ac3Slogwang lc ? lc->lc_class : LOGIN_DEFCLASS);
4581eaf0ac3Slogwang } else if (p < PRIO_MIN) {
4591eaf0ac3Slogwang rtp.type = RTP_PRIO_REALTIME;
4601eaf0ac3Slogwang p -= PRIO_MIN - RTP_PRIO_MAX;
4611eaf0ac3Slogwang rtp.prio = p < RTP_PRIO_MIN ? RTP_PRIO_MIN : p;
4621eaf0ac3Slogwang if (rtprio(RTP_SET, 0, &rtp))
4631eaf0ac3Slogwang syslog(LOG_WARNING, "rtprio '%s' (%s): %m",
4641eaf0ac3Slogwang pwd ? pwd->pw_name : "-",
4651eaf0ac3Slogwang lc ? lc->lc_class : LOGIN_DEFCLASS);
4661eaf0ac3Slogwang } else {
4671eaf0ac3Slogwang if (setpriority(PRIO_PROCESS, 0, (int)p) != 0)
4681eaf0ac3Slogwang syslog(LOG_WARNING, "setpriority '%s' (%s): %m",
4691eaf0ac3Slogwang pwd ? pwd->pw_name : "-",
4701eaf0ac3Slogwang lc ? lc->lc_class : LOGIN_DEFCLASS);
4711eaf0ac3Slogwang }
4721eaf0ac3Slogwang }
4731eaf0ac3Slogwang
4741eaf0ac3Slogwang /* Setup the user's group permissions */
4751eaf0ac3Slogwang if (flags & LOGIN_SETGROUP) {
4761eaf0ac3Slogwang if (setgid(pwd->pw_gid) != 0) {
4771eaf0ac3Slogwang syslog(LOG_ERR, "setgid(%lu): %m", (u_long)pwd->pw_gid);
4781eaf0ac3Slogwang login_close(llc);
4791eaf0ac3Slogwang return (-1);
4801eaf0ac3Slogwang }
4811eaf0ac3Slogwang if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) {
4821eaf0ac3Slogwang syslog(LOG_ERR, "initgroups(%s,%lu): %m", pwd->pw_name,
4831eaf0ac3Slogwang (u_long)pwd->pw_gid);
4841eaf0ac3Slogwang login_close(llc);
4851eaf0ac3Slogwang return (-1);
4861eaf0ac3Slogwang }
4871eaf0ac3Slogwang }
4881eaf0ac3Slogwang
4891eaf0ac3Slogwang /* Set up the user's MAC label. */
4901eaf0ac3Slogwang if ((flags & LOGIN_SETMAC) && mac_is_present(NULL) == 1) {
4911eaf0ac3Slogwang const char *label_string;
4921eaf0ac3Slogwang mac_t label;
4931eaf0ac3Slogwang
4941eaf0ac3Slogwang label_string = login_getcapstr(lc, "label", NULL, NULL);
4951eaf0ac3Slogwang if (label_string != NULL) {
4961eaf0ac3Slogwang if (mac_from_text(&label, label_string) == -1) {
4971eaf0ac3Slogwang syslog(LOG_ERR, "mac_from_text('%s') for %s: %m",
4981eaf0ac3Slogwang pwd->pw_name, label_string);
4991eaf0ac3Slogwang return (-1);
5001eaf0ac3Slogwang }
5011eaf0ac3Slogwang if (mac_set_proc(label) == -1)
5021eaf0ac3Slogwang error = errno;
5031eaf0ac3Slogwang else
5041eaf0ac3Slogwang error = 0;
5051eaf0ac3Slogwang mac_free(label);
5061eaf0ac3Slogwang if (error != 0) {
5071eaf0ac3Slogwang syslog(LOG_ERR, "mac_set_proc('%s') for %s: %s",
5081eaf0ac3Slogwang label_string, pwd->pw_name, strerror(error));
5091eaf0ac3Slogwang return (-1);
5101eaf0ac3Slogwang }
5111eaf0ac3Slogwang }
5121eaf0ac3Slogwang }
5131eaf0ac3Slogwang
5141eaf0ac3Slogwang /* Set the sessions login */
5151eaf0ac3Slogwang if ((flags & LOGIN_SETLOGIN) && setlogin(pwd->pw_name) != 0) {
5161eaf0ac3Slogwang syslog(LOG_ERR, "setlogin(%s): %m", pwd->pw_name);
5171eaf0ac3Slogwang login_close(llc);
5181eaf0ac3Slogwang return (-1);
5191eaf0ac3Slogwang }
5201eaf0ac3Slogwang
5211eaf0ac3Slogwang /* Inform the kernel about current login class */
5221eaf0ac3Slogwang if (lc != NULL && lc->lc_class != NULL && (flags & LOGIN_SETLOGINCLASS)) {
5231eaf0ac3Slogwang error = setloginclass(lc->lc_class);
5241eaf0ac3Slogwang if (error != 0) {
5251eaf0ac3Slogwang syslog(LOG_ERR, "setloginclass(%s): %m", lc->lc_class);
5261eaf0ac3Slogwang #ifdef notyet
5271eaf0ac3Slogwang login_close(llc);
5281eaf0ac3Slogwang return (-1);
5291eaf0ac3Slogwang #endif
5301eaf0ac3Slogwang }
5311eaf0ac3Slogwang }
5321eaf0ac3Slogwang
5331eaf0ac3Slogwang mymask = (flags & LOGIN_SETUMASK) ? umask(LOGIN_DEFUMASK) : 0;
5341eaf0ac3Slogwang mymask = setlogincontext(lc, pwd, mymask, flags);
5351eaf0ac3Slogwang login_close(llc);
5361eaf0ac3Slogwang
5371eaf0ac3Slogwang /* This needs to be done after anything that needs root privs */
5381eaf0ac3Slogwang if ((flags & LOGIN_SETUSER) && setuid(uid) != 0) {
5391eaf0ac3Slogwang syslog(LOG_ERR, "setuid(%lu): %m", (u_long)uid);
5401eaf0ac3Slogwang return (-1); /* Paranoia again */
5411eaf0ac3Slogwang }
5421eaf0ac3Slogwang
5431eaf0ac3Slogwang /*
5441eaf0ac3Slogwang * Now, we repeat some of the above for the user's private entries
5451eaf0ac3Slogwang */
5461eaf0ac3Slogwang if (getuid() == uid && (lc = login_getuserclass(pwd)) != NULL) {
5471eaf0ac3Slogwang mymask = setlogincontext(lc, pwd, mymask, flags);
5481eaf0ac3Slogwang login_close(lc);
5491eaf0ac3Slogwang }
5501eaf0ac3Slogwang
5511eaf0ac3Slogwang /* Finally, set any umask we've found */
5521eaf0ac3Slogwang if (flags & LOGIN_SETUMASK)
5531eaf0ac3Slogwang umask(mymask);
5541eaf0ac3Slogwang
5551eaf0ac3Slogwang return (0);
5561eaf0ac3Slogwang }
557