diff options
Diffstat (limited to 'lib/libutil/login_class.c')
-rw-r--r-- | lib/libutil/login_class.c | 499 |
1 files changed, 255 insertions, 244 deletions
diff --git a/lib/libutil/login_class.c b/lib/libutil/login_class.c index cf6d6d6..73190e9 100644 --- a/lib/libutil/login_class.c +++ b/lib/libutil/login_class.c @@ -21,7 +21,7 @@ * * High-level routines relating to use of the user capabilities database * - * $Id$ + * $Id: login_class.c,v 1.5 1997/02/22 15:08:22 peter Exp $ */ #include <stdio.h> @@ -45,202 +45,197 @@ static struct login_res { - const char * what; - rlim_t (*who)(login_cap_t *, const char *, rlim_t, rlim_t); - int why; + const char *what; + rlim_t (*who)(login_cap_t *, const char *, rlim_t, rlim_t); + int why; } resources[] = { - { "cputime", login_getcaptime, RLIMIT_CPU }, - { "filesize", login_getcapsize, RLIMIT_FSIZE }, - { "datasize", login_getcapsize, RLIMIT_DATA }, - { "stacksize", login_getcapsize, RLIMIT_STACK }, - { "coredumpsize", login_getcapsize, RLIMIT_CORE }, - { "memoryuse", login_getcapsize, RLIMIT_RSS }, - { "memorylocked", login_getcapsize, RLIMIT_MEMLOCK }, - { "maxproc", login_getcapnum, RLIMIT_NPROC }, - { "openfiles", login_getcapnum, RLIMIT_NOFILE }, - { NULL, 0, 0 } + { "cputime", login_getcaptime, RLIMIT_CPU }, + { "filesize", login_getcapsize, RLIMIT_FSIZE }, + { "datasize", login_getcapsize, RLIMIT_DATA }, + { "stacksize", login_getcapsize, RLIMIT_STACK }, + { "memoryuse", login_getcapsize, RLIMIT_RSS }, + { "memorylocked", login_getcapsize, RLIMIT_MEMLOCK }, + { "maxproc", login_getcapnum, RLIMIT_NPROC }, + { "openfiles", login_getcapnum, RLIMIT_NOFILE }, + { "coredumpsize", login_getcapsize, RLIMIT_CORE }, + { NULL, 0, 0 } }; - void setclassresources(login_cap_t *lc) { - struct login_res *lr = resources; - - if (lc == NULL) - return; + struct login_res *lr; - while (lr->what != NULL) { - struct rlimit rlim, - newlim; - char cur[40], - max[40]; - rlim_t rcur, - rmax; + if (lc == NULL) + return; - sprintf(cur, "%s-cur", lr->what); - sprintf(max, "%s-max", lr->what); + for (lr = resources; lr->what != NULL; ++lr) { + struct rlimit rlim; - /* - * The login.conf file can have <limit>, <limit>-max, and - * <limit>-cur entries. - * What we do is get the current current- and maximum- limits. - * Then, we try to get an entry for <limit> from the capability, - * using the current and max limits we just got as the - * default/error values. - * *Then*, we try looking for <limit>-cur and <limit>-max, - * again using the appropriate values as the default/error - * conditions. - */ - - getrlimit(lr->why, &rlim); - rcur = rlim.rlim_cur; - rmax = rlim.rlim_max; + /* + * The login.conf file can have <limit>, <limit>-max, and + * <limit>-cur entries. + * What we do is get the current current- and maximum- limits. + * Then, we try to get an entry for <limit> from the capability, + * using the current and max limits we just got as the + * default/error values. + * *Then*, we try looking for <limit>-cur and <limit>-max, + * again using the appropriate values as the default/error + * conditions. + */ - rcur = (*lr->who)(lc, lr->what, rcur, rcur); - rmax = (*lr->who)(lc, lr->what, rmax, rmax); - newlim.rlim_cur = (*lr->who)(lc, cur, rcur, rcur); - newlim.rlim_max = (*lr->who)(lc, max, rmax, rmax); + if (getrlimit(lr->why, &rlim) != 0) + syslog(LOG_ERR, "getting %s resource limit: %m", lr->what); + else { + char name_cur[40]; + char name_max[40]; + rlim_t rcur = rlim.rlim_cur; + rlim_t rmax = rlim.rlim_max; + + sprintf(name_cur, "%s-cur", lr->what); + sprintf(name_max, "%s-max", lr->what); + + rcur = (*lr->who)(lc, lr->what, rcur, rcur); + rmax = (*lr->who)(lc, lr->what, rmax, rmax); + rlim.rlim_cur = (*lr->who)(lc, name_cur, rcur, rcur); + rlim.rlim_max = (*lr->who)(lc, name_max, rmax, rmax); - if (setrlimit(lr->why, &newlim) == -1) - syslog(LOG_WARNING, "set class '%s' resource limit %s: %m", lc->lc_class, lr->what); - - ++lr; - } + if (setrlimit(lr->why, &rlim) == -1) + syslog(LOG_WARNING, "set class '%s' resource limit %s: %m", lc->lc_class, lr->what); + } + } } + + static struct login_vars { - const char * tag; - const char * var; - const char * def; + const char *tag; + const char *var; + const char *def; } pathvars[] = { - { "path", "PATH", NULL }, - { "manpath", "MANPATH", NULL }, - { NULL, NULL, NULL } + { "path", "PATH", NULL }, + { "cdpath", "CDPATH", NULL }, + { "manpath", "MANPATH", NULL }, + { NULL, NULL, NULL } }, envars[] = { - { "lang", "LANG", NULL }, - { "charset", "MM_CHARSET", NULL }, - { "timezone", "TZ", NULL }, - { "term", "TERM", UNKNOWN }, - { NULL, NULL, NULL } + { "lang", "LANG", NULL }, + { "charset", "MM_CHARSET", NULL }, + { "timezone", "TZ", NULL }, + { "term", "TERM", UNKNOWN }, + { NULL, NULL, NULL } }; static char * substvar(char * var, const struct passwd * pwd, int hlen, int pch, int nlen) { - char * np = NULL; - - if (var != NULL) { - int tildes = 0; - int dollas = 0; - char * p; - - if (pwd != NULL) { - /* - * Count the number of ~'s in var to substitute - */ - p = var; - while ((p = strchr(p, '~')) != NULL) { - ++tildes; - ++p; - } - - /* - * Count the number of $'s in var to substitute - */ - p = var; - while ((p = strchr(p, '$')) != NULL) { - ++dollas; - ++p; - } - } - - np = malloc(strlen(var) + (dollas * nlen) - dollas + (tildes * (pch+hlen)) - tildes + 1); - - if (np != NULL) { - p = strcpy(np, var); + char *np = NULL; + + if (var != NULL) { + int tildes = 0; + int dollas = 0; + char *p; + + if (pwd != NULL) { + /* Count the number of ~'s in var to substitute */ + p = var; + for (p = var; (p = strchr(p, '~')) != NULL; p++) + ++tildes; + /* Count the number of $'s in var to substitute */ + p = var; + for (p = var; (p = strchr(p, '$')) != NULL; p++) + ++dollas; + } - if (pwd != NULL) { - /* - * This loop does user username and homedir substitutions - * for unescaped $ (username) and ~ (homedir) - */ - while (*(p += strcspn(p, "~$")) != '\0') { - int l = strlen(p); - - if (p > var && *(p-1) == '\\') /* Escaped: */ - memmove(p - 1, p, l + 1); /* Slide-out the backslash */ - else if (*p == '~') { - int v = pch && *(p+1) != '/'; /* Avoid double // */ - memmove(p + hlen + v, p + 1, l); /* Subst homedir */ - memmove(p, pwd->pw_dir, hlen); - if (v) - p[hlen] = '/'; - p += hlen + v; - } - else /* if (*p == '$') */ { - memmove(p + nlen, p + 1, l); /* Subst username */ - memmove(p, pwd->pw_name, nlen); - p += nlen; - } + np = malloc(strlen(var) + (dollas * nlen) + - dollas + (tildes * (pch+hlen)) + - tildes + 1); + + if (np != NULL) { + p = strcpy(np, var); + + if (pwd != NULL) { + /* + * This loop does user username and homedir substitutions + * for unescaped $ (username) and ~ (homedir) + */ + while (*(p += strcspn(p, "~$")) != '\0') { + int l = strlen(p); + + if (p > var && *(p-1) == '\\') /* Escaped: */ + memmove(p - 1, p, l + 1); /* Slide-out the backslash */ + else if (*p == '~') { + int v = pch && *(p+1) != '/'; /* Avoid double // */ + memmove(p + hlen + v, p + 1, l); /* Subst homedir */ + memmove(p, pwd->pw_dir, hlen); + if (v) + p[hlen] = '/'; + p += hlen + v; + } + else /* if (*p == '$') */ { + memmove(p + nlen, p + 1, l); /* Subst username */ + memmove(p, pwd->pw_name, nlen); + p += nlen; + } + } + } } - } } - } - return np; + + return np; } void setclassenvironment(login_cap_t *lc, const struct passwd * pwd, int paths) { - struct login_vars * vars = paths ? pathvars : envars; - int hlen = pwd ? strlen(pwd->pw_dir) : 0; - int nlen = pwd ? strlen(pwd->pw_name) : 0; - char pch = 0; + struct login_vars *vars = paths ? pathvars : envars; + int hlen = pwd ? strlen(pwd->pw_dir) : 0; + int nlen = pwd ? strlen(pwd->pw_name) : 0; + char pch = 0; - if (hlen && pwd->pw_dir[hlen-1] != '/') - ++pch; + if (hlen && pwd->pw_dir[hlen-1] != '/') + ++pch; - while (vars->tag != NULL) { - char * var = paths ? login_getpath(lc, vars->tag, NULL) - : login_getcapstr(lc, vars->tag, NULL, NULL); + while (vars->tag != NULL) { + char * var = paths ? login_getpath(lc, vars->tag, NULL) + : login_getcapstr(lc, vars->tag, NULL, NULL); - char * np = substvar(var, pwd, hlen, pch, nlen); + char * np = substvar(var, pwd, hlen, pch, nlen); - if (np != NULL) { - setenv(vars->var, np, 1); - free(np); - } else if (vars->def != NULL) { - setenv(vars->var, vars->def, 0); - } - ++vars; - } - - /* - * If we're not processing paths, then see if there is a setenv list by - * which the admin and/or user may set an arbitrary set of env vars. - */ - if (!paths) { - char ** set_env = login_getcaplist(lc, "setenv", ","); - - if (set_env != NULL) { - while (*set_env != NULL) { - char *p = strchr(*set_env, '='); - if (p != NULL) { /* Discard invalid entries */ - char * np; - - *p++ = '\0'; - if ((np = substvar(p, pwd, hlen, pch, nlen)) != NULL) { - setenv(*set_env, np, 1); + if (np != NULL) { + setenv(vars->var, np, 1); free(np); - } + } else if (vars->def != NULL) { + setenv(vars->var, vars->def, 0); + } + ++vars; + } + + /* + * If we're not processing paths, then see if there is a setenv list by + * which the admin and/or user may set an arbitrary set of env vars. + */ + if (!paths) { + char **set_env = login_getcaplist(lc, "setenv", ","); + + if (set_env != NULL) { + while (*set_env != NULL) { + char *p = strchr(*set_env, '='); + + if (p != NULL) { /* Discard invalid entries */ + char *np; + + *p++ = '\0'; + if ((np = substvar(p, pwd, hlen, pch, nlen)) != NULL) { + setenv(*set_env, np, 1); + free(np); + } + } + ++set_env; + } } - ++set_env; - } } - } } @@ -258,15 +253,48 @@ setclassenvironment(login_cap_t *lc, const struct passwd * pwd, int paths) int setclasscontext(const char *classname, unsigned int flags) { - int rc; - login_cap_t * lc = login_getclassbyname(classname, NULL); - flags &= (LOGIN_SETRESOURCES| LOGIN_SETPRIORITY|LOGIN_SETUMASK); - rc = setusercontext(lc, NULL, 0, flags); - login_close(lc); - return rc; + int rc; + login_cap_t *lc; + + lc = login_getclassbyname(classname, NULL); + + flags &= LOGIN_SETRESOURCES | LOGIN_SETPRIORITY | + LOGIN_SETUMASK | LOGIN_SETPATH; + + rc = lc ? setusercontext(lc, NULL, 0, flags) : -1; + login_close(lc); + return rc; +} + + + +/* + * Private functionw which takes care of processing + */ + +static mode_t +setlogincontext(login_cap_t *lc, const struct passwd *pwd, + mode_t mymask, unsigned long flags) +{ + if (lc) { + /* Set resources */ + if (flags & LOGIN_SETRESOURCES) + setclassresources(lc); + /* See if there's a umask override */ + if (flags & LOGIN_SETUMASK) + mymask = (mode_t)login_getcapnum(lc, "umask", mymask, mymask); + /* Set paths */ + if (flags & LOGIN_SETPATH) + setclassenvironment(lc, pwd, 1); + /* Set environment */ + if (flags & LOGIN_SETENV) + setclassenvironment(lc, pwd, 0); + } + return mymask; } + /* * setusercontext() * @@ -284,93 +312,76 @@ setclasscontext(const char *classname, unsigned int flags) int setusercontext(login_cap_t *lc, const struct passwd *pwd, uid_t uid, unsigned int flags) { - int i; - login_cap_t * llc = NULL; - - if (lc == NULL) - { - if (pwd != NULL && (lc = login_getclass(pwd)) != NULL) - llc = lc; /* free this when we're done */ - } - - if (flags & LOGIN_SETPATH) - pathvars[0].def = uid ? _PATH_DEFPATH : _PATH_STDPATH; - - /* - * Set the process priority - */ - if (flags & LOGIN_SETPRIORITY) { - int pri = (int)login_getcapnum(lc, "priority", LOGIN_DEFPRI, LOGIN_DEFPRI); - pri = (pri < PRIO_MIN) ? PRIO_MIN : (pri > PRIO_MAX) ? PRIO_MAX : pri; - if (setpriority(PRIO_PROCESS, 0, pri) != 0) - syslog(LOG_WARNING, "setpriority '%s': %m", pwd->pw_name); - } - - /* - * Set resources - */ - if (flags & LOGIN_SETRESOURCES) - setclassresources(lc); - - /* - * Set the sessions login - */ - if ((flags & LOGIN_SETLOGIN) && setlogin(pwd->pw_name) != 0) { - syslog(LOG_ERR, "setlogin '%s': %m", pwd->pw_name); - login_close(llc); - return -1; - } - - /* - * Setup the user's group permissions - */ - if (flags & LOGIN_SETGROUP) { - if (setgid(pwd->pw_gid) != 0) - syslog(LOG_WARNING, "setgid %ld: %m", (long)pwd->pw_gid); - if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) - syslog(LOG_WARNING, "initgroups '%s': %m", pwd->pw_name); - } - - /* - * FreeBSD extension: here we (might) loop and do this twice. - * First, for the class we have been given, and next for - * any user overrides in ~/.login.conf the user's home directory. - */ - if (flags & LOGIN_SETUMASK) - umask(LOGIN_DEFUMASK); /* Set default umask up front */ - - i = 0; - while (i < 2 && lc != NULL) { - - if (flags & LOGIN_SETUMASK) { - rlim_t tmp = login_getcapnum(lc, "umask", RLIM_INFINITY, RLIM_INFINITY); - if (tmp != RLIM_INFINITY) - umask((mode_t)tmp); + quad_t p; + mode_t mymask; + login_cap_t *llc = NULL; + + if (lc == NULL) { + if (pwd != NULL && (lc = login_getpwclass(pwd)) != NULL) + llc = lc; /* free this when we're done */ } if (flags & LOGIN_SETPATH) - setclassenvironment(lc, pwd, 1); + pathvars[0].def = uid ? _PATH_DEFPATH : _PATH_STDPATH; - if (flags & LOGIN_SETENV) - setclassenvironment(lc, pwd, 0); + /* we need a passwd entry to set these */ + if (pwd == NULL) + flags &= ~(LOGIN_SETGROUP | LOGIN_SETLOGIN); - if (i++ == 0) /* Play it again, Sam */ - lc = (pwd == NULL) ? NULL : login_getuserclass(pwd); - } + /* Set the process priority */ + if (flags & LOGIN_SETPRIORITY) { + p = login_getcapnum(lc, "priority", LOGIN_DEFPRI, LOGIN_DEFPRI); - login_close(lc); /* User's private 'me' class */ - login_close(llc); /* Class we opened */ + p = (p < PRIO_MIN || p > PRIO_MAX) ? LOGIN_DEFPRI : p; + if (setpriority(PRIO_PROCESS, 0, (int)p) != 0) + syslog(LOG_WARNING, "setpriority '%s' (%s): %m", + pwd->pw_name, lc ? lc->lc_class : LOGIN_DEFCLASS); + } - /* - * This needs to be done after all of the above. - * Do it last so we avoid getting killed and dropping core - */ - if ((flags & LOGIN_SETUSER) && setuid(uid) != 0) { - syslog(LOG_ERR, "setuid %ld: %m", uid); + /* Setup the user's group permissions */ + if (flags & LOGIN_SETGROUP) { + if (setgid(pwd->pw_gid) != 0) { + syslog(LOG_ERR, "setgid(%ld): %m", (long)pwd->pw_gid); + login_close(llc); + return -1; + } + if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) { + syslog(LOG_ERR, "initgroups(%s,%ld): %m", pwd->pw_name, + pwd->pw_gid); + login_close(llc); + return -1; + } + } + + /* Set the sessions login */ + if ((flags & LOGIN_SETLOGIN) && setlogin(pwd->pw_name) != 0) { + syslog(LOG_ERR, "setlogin(%s): %m", pwd->pw_name); + login_close(llc); + return -1; + } + + mymask = (flags & LOGIN_SETUMASK) ? umask(LOGIN_DEFUMASK) : 0; + mymask = setlogincontext(lc, pwd, mymask, flags); login_close(llc); - return -1; /* Paranoia again */ - } - return 0; + /* This needs to be done after anything that needs root privs */ + if ((flags & LOGIN_SETUSER) && setuid(uid) != 0) { + syslog(LOG_ERR, "setuid(%ld): %m", uid); + return -1; /* Paranoia again */ + } + + /* + * Now, we repeat some of the above for the user's private entries + */ + if ((lc = login_getuserclass(pwd)) != NULL) { + mymask = setlogincontext(lc, pwd, mymask, flags); + login_close(lc); + } + + /* Finally, set any umask we've found */ + if (flags & LOGIN_SETUMASK) + umask(mymask); + + return 0; } |