1c19800e8SDoug Rabson /* 2*ae771770SStanislav Sedov * Copyright (c) 2005 Kungliga Tekniska Högskolan 3c19800e8SDoug Rabson * (Royal Institute of Technology, Stockholm, Sweden). 4c19800e8SDoug Rabson * All rights reserved. 5c19800e8SDoug Rabson * 6c19800e8SDoug Rabson * Redistribution and use in source and binary forms, with or without 7c19800e8SDoug Rabson * modification, are permitted provided that the following conditions 8c19800e8SDoug Rabson * are met: 9c19800e8SDoug Rabson * 10c19800e8SDoug Rabson * 1. Redistributions of source code must retain the above copyright 11c19800e8SDoug Rabson * notice, this list of conditions and the following disclaimer. 12c19800e8SDoug Rabson * 13c19800e8SDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright 14c19800e8SDoug Rabson * notice, this list of conditions and the following disclaimer in the 15c19800e8SDoug Rabson * documentation and/or other materials provided with the distribution. 16c19800e8SDoug Rabson * 17c19800e8SDoug Rabson * 3. Neither the name of the Institute nor the names of its contributors 18c19800e8SDoug Rabson * may be used to endorse or promote products derived from this software 19c19800e8SDoug Rabson * without specific prior written permission. 20c19800e8SDoug Rabson * 21c19800e8SDoug Rabson * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22c19800e8SDoug Rabson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23c19800e8SDoug Rabson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24c19800e8SDoug Rabson * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25c19800e8SDoug Rabson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26c19800e8SDoug Rabson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27c19800e8SDoug Rabson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28c19800e8SDoug Rabson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29c19800e8SDoug Rabson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30c19800e8SDoug Rabson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31c19800e8SDoug Rabson * SUCH DAMAGE. 32c19800e8SDoug Rabson */ 33c19800e8SDoug Rabson 34c19800e8SDoug Rabson #include "login_locl.h" 35c19800e8SDoug Rabson 36*ae771770SStanislav Sedov RCSID("$Id$"); 37c19800e8SDoug Rabson 38c19800e8SDoug Rabson #include <errno.h> 39c19800e8SDoug Rabson #include <limits.h> 40c19800e8SDoug Rabson #ifdef HAVE_SYS_RESOURCE_H 41c19800e8SDoug Rabson #include <sys/resource.h> 42c19800e8SDoug Rabson #endif 43c19800e8SDoug Rabson 44c19800e8SDoug Rabson struct limit { 45c19800e8SDoug Rabson const char *name; 46c19800e8SDoug Rabson int resource; 47c19800e8SDoug Rabson int scale; 48c19800e8SDoug Rabson int has_limit; 49c19800e8SDoug Rabson struct rlimit limit; 50c19800e8SDoug Rabson } limits[] = { 51c19800e8SDoug Rabson #define LIM(X, S) { #X, RLIMIT_##X, S, 0 } 52c19800e8SDoug Rabson LIM(CORE, 1024), 53c19800e8SDoug Rabson LIM(CPU, 60), 54c19800e8SDoug Rabson LIM(DATA, 1024), 55c19800e8SDoug Rabson LIM(FSIZE, 1024), 56c19800e8SDoug Rabson #ifdef RLIMIT_MEMLOCK 57c19800e8SDoug Rabson LIM(MEMLOCK, 1024), 58c19800e8SDoug Rabson #endif 59c19800e8SDoug Rabson LIM(NOFILE, 1), 60c19800e8SDoug Rabson #ifdef RLIMIT_NPROC 61c19800e8SDoug Rabson LIM(NPROC, 1), 62c19800e8SDoug Rabson #endif 63c19800e8SDoug Rabson #ifdef RLIMIT_RSS 64c19800e8SDoug Rabson LIM(RSS, 1024), 65c19800e8SDoug Rabson #endif 66c19800e8SDoug Rabson LIM(STACK, 1024), 67c19800e8SDoug Rabson 68c19800e8SDoug Rabson #ifdef RLIMIT_AS 69c19800e8SDoug Rabson LIM(AS, 1024), 70c19800e8SDoug Rabson #endif 71c19800e8SDoug Rabson #ifdef RLIMIT_LOCKS 72c19800e8SDoug Rabson LIM(LOCKS, 1), 73c19800e8SDoug Rabson #endif 74c19800e8SDoug Rabson /* 75c19800e8SDoug Rabson maxlogins 76c19800e8SDoug Rabson priority 77c19800e8SDoug Rabson */ 78c19800e8SDoug Rabson { NULL, 0 } 79c19800e8SDoug Rabson }; 80c19800e8SDoug Rabson 81c19800e8SDoug Rabson static struct limit * 82c19800e8SDoug Rabson find_limit(const char *name) 83c19800e8SDoug Rabson { 84c19800e8SDoug Rabson struct limit *l; 85c19800e8SDoug Rabson for(l = limits; l->name != NULL; l++) 86c19800e8SDoug Rabson if(strcasecmp(name, l->name) == 0) 87c19800e8SDoug Rabson return l; 88c19800e8SDoug Rabson return NULL; 89c19800e8SDoug Rabson } 90c19800e8SDoug Rabson 91c19800e8SDoug Rabson /* this function reads limits.conf files similar to pam_limits 92c19800e8SDoug Rabson unimplemented features include: 93c19800e8SDoug Rabson % maxlogins 94c19800e8SDoug Rabson "-" no limits, 95c19800e8SDoug Rabson priorities etc that are not set via setrlimit 96c19800e8SDoug Rabson XXX uses static storage, and clobbers getgr* 97c19800e8SDoug Rabson */ 98c19800e8SDoug Rabson 99c19800e8SDoug Rabson int 100c19800e8SDoug Rabson read_limits_conf(const char *file, const struct passwd *pwd) 101c19800e8SDoug Rabson { 102c19800e8SDoug Rabson FILE *f; 103c19800e8SDoug Rabson char *args[4]; 104c19800e8SDoug Rabson int lineno = 0; 105c19800e8SDoug Rabson char buf[1024]; 106c19800e8SDoug Rabson struct limit *l; 107c19800e8SDoug Rabson rlim_t value; 108c19800e8SDoug Rabson 109c19800e8SDoug Rabson f = fopen(file, "r"); 110c19800e8SDoug Rabson if(f == NULL) { 111c19800e8SDoug Rabson if(errno != ENOENT && errno != ENOTDIR) 112c19800e8SDoug Rabson syslog(LOG_ERR, "%s: %m", file); 113c19800e8SDoug Rabson return -1; 114c19800e8SDoug Rabson } 115c19800e8SDoug Rabson 116c19800e8SDoug Rabson while(fgets(buf, sizeof(buf), f) != NULL) { 117c19800e8SDoug Rabson char *last = NULL; 118c19800e8SDoug Rabson char *end = NULL; 119c19800e8SDoug Rabson int level; 120c19800e8SDoug Rabson 121c19800e8SDoug Rabson lineno++; 122c19800e8SDoug Rabson 123c19800e8SDoug Rabson if(buf[0] == '\0') { 124c19800e8SDoug Rabson syslog(LOG_ERR, "%s: line %d: NUL character", file, lineno); 125c19800e8SDoug Rabson continue; 126c19800e8SDoug Rabson } 127c19800e8SDoug Rabson if(buf[strlen(buf) - 1] != '\n') { 128c19800e8SDoug Rabson /* file did not end with a newline, figure out if we're at 129c19800e8SDoug Rabson the EOF, or if our buffer was too small */ 130c19800e8SDoug Rabson int eof = 1; 131c19800e8SDoug Rabson int c; 132c19800e8SDoug Rabson while((c = fgetc(f)) != EOF) { 133c19800e8SDoug Rabson eof = 0; 134c19800e8SDoug Rabson if(c == '\n') 135c19800e8SDoug Rabson break; 136c19800e8SDoug Rabson } 137c19800e8SDoug Rabson if(!eof) { 138c19800e8SDoug Rabson syslog(LOG_ERR, "%s: line %d: line too long", file, lineno); 139c19800e8SDoug Rabson continue; 140c19800e8SDoug Rabson } 141c19800e8SDoug Rabson } 142c19800e8SDoug Rabson buf[strcspn(buf, "#\r\n")] = '\0'; 143c19800e8SDoug Rabson if((args[0] = strtok_r(buf, " \t", &last)) == NULL || 144c19800e8SDoug Rabson (args[1] = strtok_r(NULL, " \t", &last)) == NULL || 145c19800e8SDoug Rabson (args[2] = strtok_r(NULL, " \t", &last)) == NULL || 146c19800e8SDoug Rabson (args[3] = strtok_r(NULL, " \t", &last)) == NULL) { 147c19800e8SDoug Rabson if(args[0] != NULL) /* this would include comment lines */ 148c19800e8SDoug Rabson syslog(LOG_ERR, "%s: line %d: malformed line", file, lineno); 149c19800e8SDoug Rabson continue; 150c19800e8SDoug Rabson } 151c19800e8SDoug Rabson 152c19800e8SDoug Rabson l = find_limit(args[2]); 153c19800e8SDoug Rabson if(l == NULL) { 154c19800e8SDoug Rabson syslog(LOG_ERR, "%s: line %d: unknown limit %s", file, lineno, args[2]); 155c19800e8SDoug Rabson continue; 156c19800e8SDoug Rabson } 157c19800e8SDoug Rabson if(strcmp(args[3], "-") == 0) { 158c19800e8SDoug Rabson value = RLIM_INFINITY; 159c19800e8SDoug Rabson } else { 160c19800e8SDoug Rabson errno = 0; 161c19800e8SDoug Rabson value = strtol(args[3], &end, 10); 162c19800e8SDoug Rabson if(*end != '\0') { 163c19800e8SDoug Rabson syslog(LOG_ERR, "%s: line %d: bad value %s", file, lineno, args[3]); 164c19800e8SDoug Rabson continue; 165c19800e8SDoug Rabson } 166c19800e8SDoug Rabson if((value == LONG_MIN || value == LONG_MAX) && errno == ERANGE) { 167c19800e8SDoug Rabson syslog(LOG_ERR, "%s: line %d: bad value %s", file, lineno, args[3]); 168c19800e8SDoug Rabson continue; 169c19800e8SDoug Rabson } 170c19800e8SDoug Rabson if(value * l->scale < value) 171c19800e8SDoug Rabson value = RLIM_INFINITY; 172c19800e8SDoug Rabson else 173c19800e8SDoug Rabson value *= l->scale; 174c19800e8SDoug Rabson } 175c19800e8SDoug Rabson level = 0; 176c19800e8SDoug Rabson /* XXX unclear: if you set group hard and user soft limit, 177c19800e8SDoug Rabson should the hard limit still apply? this code doesn't. */ 178c19800e8SDoug Rabson if(strcmp(args[0], pwd->pw_name) == 0) 179c19800e8SDoug Rabson level = 3; 180c19800e8SDoug Rabson if(*args[0] == '@') { 181c19800e8SDoug Rabson struct group *gr; 182c19800e8SDoug Rabson gr = getgrnam(args[0] + 1); 183c19800e8SDoug Rabson if(gr != NULL && gr->gr_gid == pwd->pw_gid) 184c19800e8SDoug Rabson level = 2; 185c19800e8SDoug Rabson } 186c19800e8SDoug Rabson if(strcmp(args[0], "*") == 0) 187c19800e8SDoug Rabson level = 1; 188c19800e8SDoug Rabson if(level == 0 || level < l->has_limit) /* not for us */ 189c19800e8SDoug Rabson continue; 190c19800e8SDoug Rabson if(l->has_limit < level) { 191c19800e8SDoug Rabson if(getrlimit(l->resource, &l->limit) < 0) 192c19800e8SDoug Rabson continue; 193c19800e8SDoug Rabson l->has_limit = level; 194c19800e8SDoug Rabson } 195c19800e8SDoug Rabson 196c19800e8SDoug Rabson /* XXX unclear: if you soft to more than default hard, should 197c19800e8SDoug Rabson we set hard to soft? this code doesn't. */ 198c19800e8SDoug Rabson if(strcasecmp(args[1], "soft") == 0 || strcmp(args[1], "-") == 0) 199c19800e8SDoug Rabson l->limit.rlim_cur = value; 200c19800e8SDoug Rabson if(strcasecmp(args[1], "hard") == 0 || strcmp(args[1], "-") == 0) 201c19800e8SDoug Rabson l->limit.rlim_max = value; 202c19800e8SDoug Rabson } 203c19800e8SDoug Rabson fclose(f); 204c19800e8SDoug Rabson for(l = limits; l->name != NULL; l++) { 205c19800e8SDoug Rabson if(l->has_limit) { 206c19800e8SDoug Rabson if(l->limit.rlim_cur > l->limit.rlim_max) 207c19800e8SDoug Rabson l->limit.rlim_cur = l->limit.rlim_max; 208c19800e8SDoug Rabson if(setrlimit(l->resource, &l->limit) != 0) 209c19800e8SDoug Rabson syslog(LOG_ERR, "setrlimit RLIM_%s failed: %m", l->name); 210c19800e8SDoug Rabson } 211c19800e8SDoug Rabson l->has_limit = 0; 212c19800e8SDoug Rabson } 213c19800e8SDoug Rabson return 0; 214c19800e8SDoug Rabson } 215