aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Bühler <stbuehler@web.de>2008-07-21 17:23:09 +0200
committerStefan Bühler <stbuehler@web.de>2008-07-21 17:23:09 +0200
commitd8a5d7d3846d4395e7864bc6958459fa2c77e2d0 (patch)
treebe3b892da339f2125c0a362fa20e4fd21ed3b6fe
parent48ee447c5d10707497f2f6f27e4633d4547c7056 (diff)
downloadspawn-fcgi2-d8a5d7d3846d4395e7864bc6958459fa2c77e2d0.tar.gz
spawn-fcgi2-d8a5d7d3846d4395e7864bc6958459fa2c77e2d0.zip
Add limits support via /etc/security/limits.conf (without pam)
-rw-r--r--CMakeLists.txt20
-rw-r--r--pam_limits.c486
-rw-r--r--spawn-fcgi.c23
-rw-r--r--wscript22
4 files changed, 543 insertions, 8 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b7f9a01..d9541bc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -5,7 +5,7 @@ MACRO(ADD_TARGET_PROPERTIES _target _name _properties)
LIST(REMOVE_AT _properties 0)
LIST(REMOVE_AT _properties 0)
GET_TARGET_PROPERTY(_old_properties ${_target} ${_name})
- MESSAGE("adding property to ${_target} ${_name}: ${_properties}")
+ #MESSAGE("adding property to ${_target} ${_name}: ${_properties}")
IF(NOT _old_properties)
# in case it's NOTFOUND
SET(_old_properties)
@@ -17,24 +17,36 @@ PROJECT(spawn-fcgi)
SET(PACKAGE_VERSION 1.0)
EXEC_PROGRAM(date ARGS "'+%b %d %Y %H:%M:%S UTC'" OUTPUT_VARIABLE PACKAGE_BUILD_DATE)
-INCLUDE(FindPkgConfig)
+OPTION(USE_LIMITS "Enable /etc/security/limits.conf support" ON)
+# GLIB 2
+INCLUDE(FindPkgConfig)
pkg_check_modules (GLIB2 REQUIRED glib-2.0)
-
SET(GLIB_INCLUDES ${GLIB2_INCLUDE_DIRS} ${GLIB2_INCLUDE_DIRS}/glib-2.0/ ${GLIB2_INCLUDE_DIRS}/glib-2.0/include/)
INCLUDE_DIRECTORIES(${GLIB_INCLUDES})
-add_executable(spawn-fcgi spawn-fcgi.c)
+SET(MAIN_SOURCE spawn-fcgi.c)
+
+IF(USE_LIMITS)
+SET(MAIN_SOURCE ${MAIN_SOURCE} pam_limits.c)
+ADD_DEFINITIONS(-DUSE_LIMITS)
+ENDIF(USE_LIMITS)
+
+add_executable(spawn-fcgi ${MAIN_SOURCE})
ADD_TARGET_PROPERTIES(spawn-fcgi COMPILE_FLAGS "-std=gnu99 -Wall -g -Wshadow -W -pedantic -fPIC -D_GNU_SOURCE")
+
+# GLIB 2
ADD_TARGET_PROPERTIES(spawn-fcgi LINK_FLAGS "${GLIB2_LDFLAGS}")
ADD_TARGET_PROPERTIES(spawn-fcgi COMPILE_FLAGS "${GLIB2_CFLAGS_OTHER}")
+
ADD_DEFINITIONS(
-DPACKAGE_NAME="\\"${CMAKE_PROJECT_NAME}\\""
-DPACKAGE_VERSION="\\"${PACKAGE_VERSION}\\""
-DPACKAGE_BUILD_DATE="\\"${PACKAGE_BUILD_DATE}\\""
)
+
INSTALL(TARGETS spawn-fcgi DESTINATION bin)
diff --git a/pam_limits.c b/pam_limits.c
new file mode 100644
index 0000000..880de31
--- /dev/null
+++ b/pam_limits.c
@@ -0,0 +1,486 @@
+/*
+ * pam_limits - impose resource limits when opening a user session
+ *
+ * 1.6 - modified for PLD (added process priority settings)
+ * by Marcin Korzonek <mkorz@shadow.eu.org>
+ * 1.5 - Elliot Lee's "max system logins patch"
+ * 1.4 - addressed bug in configuration file parser
+ * 1.3 - modified the configuration file format
+ * 1.2 - added 'debug' and 'conf=' arguments
+ * 1.1 - added @group support
+ * 1.0 - initial release - Linux ONLY
+ *
+ * See end for Copyright information
+ */
+
+#if !defined(linux) && !defined(__linux)
+#error THIS CODE IS KNOWN TO WORK ONLY ON LINUX !!!
+#endif
+
+#include <glib.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/resource.h>
+#include <limits.h>
+
+#include <utmp.h>
+#ifndef UT_USER /* some systems have ut_name instead of ut_user */
+#define UT_USER ut_user
+#endif
+
+#include <grp.h>
+#include <pwd.h>
+
+/* Module defines */
+#ifndef LIMITS_FILE
+#define LIMITS_FILE "/etc/security/limits.conf"
+#endif
+
+#define LINE_LENGTH 1024
+
+#define LIMITS_DEF_USER 0 /* limit was set by an user entry */
+#define LIMITS_DEF_GROUP 1 /* limit was set by a group entry */
+#define LIMITS_DEF_ALLGROUP 2 /* limit was set by a group entry */
+#define LIMITS_DEF_ALL 3 /* limit was set by an default entry */
+#define LIMITS_DEF_DEFAULT 4 /* limit was set by an default entry */
+#define LIMITS_DEF_NONE 5 /* this limit was not set yet */
+
+struct user_limits_struct {
+ int supported;
+ int src_soft;
+ int src_hard;
+ struct rlimit limit;
+};
+
+/* internal data */
+struct pam_limit_s {
+ int priority; /* the priority to run user process with */
+ struct user_limits_struct limits[RLIM_NLIMITS];
+ struct passwd *pwd;
+};
+
+#define LIMIT_PRI RLIM_NLIMITS+1
+
+#define LIMIT_SOFT 1
+#define LIMIT_HARD 2
+
+#define LIMITED_OK 0 /* limit setting appeared to work */
+#define LIMIT_ERR 1 /* error setting a limit */
+#define LOGIN_ERR 2 /* too many logins err */
+
+typedef enum {
+ LIMHANDLE_OK = 0,
+ LIMHANDLE_ERROR = -1,
+ LIMHANDLE_IGNORE = 1
+} limhandle_t;
+
+static limhandle_t init_limits(struct pam_limit_s *pl) {
+ int i, r;
+
+ for(i = 0; i < RLIM_NLIMITS; i++) {
+ errno = 0;
+ r = getrlimit(i, &pl->limits[i].limit);
+ if (r == -1) {
+ pl->limits[i].supported = 0;
+ if (errno != EINVAL) {
+ g_printerr("Couldn't getrlimit: %s\n", g_strerror(errno));
+ return LIMHANDLE_ERROR;
+ }
+ } else {
+ pl->limits[i].supported = 1;
+ pl->limits[i].src_soft = LIMITS_DEF_NONE;
+ pl->limits[i].src_hard = LIMITS_DEF_NONE;
+ }
+ }
+
+ errno = 0;
+ pl->priority = getpriority (PRIO_PROCESS, 0);
+ if (pl->priority == -1 && errno != 0) {
+ g_printerr("Couldn't getpriority: %s\n", g_strerror(errno));
+ return LIMHANDLE_ERROR;
+ }
+
+ return LIMHANDLE_OK;
+}
+
+static void
+process_limit (int source, const char *lim_type,
+ const char *lim_item, const char *lim_value,
+ struct pam_limit_s *pl) {
+ int limit_item;
+ int limit_type = 0;
+ int int_value = 0;
+ rlim_t rlimit_value = 0;
+ char *endptr;
+ const char *value_orig = lim_value;
+
+/*
+ if (ctrl & PAM_DEBUG_ARG)
+ pam_syslog(pamh, LOG_DEBUG, "%s: processing %s %s %s for %s",
+ __FUNCTION__, lim_type, lim_item, lim_value,
+ limits_def_names[source]);*/
+
+ if (strcmp(lim_item, "cpu") == 0) {
+ limit_item = RLIMIT_CPU;
+ } else if (strcmp(lim_item, "fsize") == 0) {
+ limit_item = RLIMIT_FSIZE;
+ } else if (strcmp(lim_item, "data") == 0) {
+ limit_item = RLIMIT_DATA;
+ } else if (strcmp(lim_item, "stack") == 0) {
+ limit_item = RLIMIT_STACK;
+ } else if (strcmp(lim_item, "core") == 0) {
+ limit_item = RLIMIT_CORE;
+ } else if (strcmp(lim_item, "rss") == 0) {
+ limit_item = RLIMIT_RSS;
+ } else if (strcmp(lim_item, "nproc") == 0) {
+ limit_item = RLIMIT_NPROC;
+ } else if (strcmp(lim_item, "nofile") == 0) {
+ limit_item = RLIMIT_NOFILE;
+ } else if (strcmp(lim_item, "memlock") == 0) {
+ limit_item = RLIMIT_MEMLOCK;
+ } else if (strcmp(lim_item, "as") == 0) {
+ limit_item = RLIMIT_AS;
+#ifdef RLIMIT_LOCKS
+ } else if (strcmp(lim_item, "locks") == 0) {
+ limit_item = RLIMIT_LOCKS;
+#endif
+#ifdef RLIMIT_SIGPENDING
+ } else if (strcmp(lim_item, "sigpending") == 0) {
+ limit_item = RLIMIT_SIGPENDING;
+#endif
+#ifdef RLIMIT_MSGQUEUE
+ } else if (strcmp(lim_item, "msgqueue") == 0) {
+ limit_item = RLIMIT_MSGQUEUE;
+#endif
+#ifdef RLIMIT_NICE
+ } else if (strcmp(lim_item, "nice") == 0) {
+ limit_item = RLIMIT_NICE;
+#endif
+#ifdef RLIMIT_RTPRIO
+ } else if (strcmp(lim_item, "rtprio") == 0) {
+ limit_item = RLIMIT_RTPRIO;
+#endif
+ } else if (strcmp(lim_item, "priority") == 0) {
+ limit_item = LIMIT_PRI;
+ } else {
+ g_printerr("unknown limit item '%s'\n", lim_item);
+ return;
+ }
+
+ if (strcmp(lim_type,"soft")==0) {
+ limit_type=LIMIT_SOFT;
+ } else if (strcmp(lim_type, "hard")==0) {
+ limit_type=LIMIT_HARD;
+ } else if (strcmp(lim_type,"-")==0) {
+ limit_type=LIMIT_SOFT | LIMIT_HARD;
+ } else {
+ g_printerr("unknown limit type '%s'\n", lim_type);
+ return;
+ }
+ if (limit_item != LIMIT_PRI
+#ifdef RLIMIT_NICE
+ && limit_item != RLIMIT_NICE
+#endif
+ && (strcmp(lim_value, "-1") == 0
+ || strcmp(lim_value, "-") == 0 || strcmp(lim_value, "unlimited") == 0
+ || strcmp(lim_value, "infinity") == 0)) {
+ int_value = -1;
+ rlimit_value = RLIM_INFINITY;
+ } else if (limit_item == LIMIT_PRI
+#ifdef RLIMIT_NICE
+ || limit_item == RLIMIT_NICE
+#endif
+ ) {
+ long temp;
+ temp = strtol (lim_value, &endptr, 10);
+ temp = temp < INT_MAX ? temp : INT_MAX;
+ int_value = temp > INT_MIN ? temp : INT_MIN;
+ if (int_value == 0 && value_orig == endptr) {
+ g_printerr("wrong limit value '%s' for limit type '%s'\n",
+ lim_value, lim_type);
+ return;
+ }
+ } else {
+#ifdef __USE_FILE_OFFSET64
+ rlimit_value = strtoull (lim_value, &endptr, 10);
+#else
+ rlimit_value = strtoul (lim_value, &endptr, 10);
+#endif
+ if (rlimit_value == 0 && value_orig == endptr) {
+ g_printerr("wrong limit value '%s' for limit type '%s'",
+ lim_value, lim_type);
+ return;
+ }
+ }
+
+ switch(limit_item) {
+ case RLIMIT_CPU:
+ if (rlimit_value != RLIM_INFINITY)
+ rlimit_value *= 60;
+ break;
+ case RLIMIT_FSIZE:
+ case RLIMIT_DATA:
+ case RLIMIT_STACK:
+ case RLIMIT_CORE:
+ case RLIMIT_RSS:
+ case RLIMIT_MEMLOCK:
+ case RLIMIT_AS:
+ if (rlimit_value != RLIM_INFINITY)
+ rlimit_value *= 1024;
+ break;
+#ifdef RLIMIT_NICE
+ case RLIMIT_NICE:
+ if (int_value > 19)
+ int_value = 19;
+ rlimit_value = 19 - int_value;
+ break;
+#endif
+ }
+
+ if (limit_item != LIMIT_PRI) {
+ if (limit_type & LIMIT_SOFT) {
+ if (pl->limits[limit_item].src_soft < source) {
+ return;
+ } else {
+ pl->limits[limit_item].limit.rlim_cur = rlimit_value;
+ pl->limits[limit_item].src_soft = source;
+ }
+ }
+ if (limit_type & LIMIT_HARD) {
+ if (pl->limits[limit_item].src_hard < source) {
+ return;
+ } else {
+ pl->limits[limit_item].limit.rlim_max = rlimit_value;
+ pl->limits[limit_item].src_hard = source;
+ }
+ }
+ } else {
+ /* recent kernels support negative priority limits (=raise priority) */
+
+ if (limit_item == LIMIT_PRI) {
+ pl->priority = int_value;
+ }
+ }
+ return;
+}
+
+static gboolean pam_modutil_user_in_group_nam_nam(struct passwd *pwd, const char *group) {
+ struct group *grp;
+ grp = getgrnam(group);
+ size_t i;
+
+ if (pwd == NULL || grp == NULL) return FALSE;
+ if (pwd->pw_gid == grp->gr_gid) return TRUE;
+
+ for (i = 0; (grp->gr_mem != NULL) && (grp->gr_mem[i] != NULL); i++) {
+ if (strcmp(pwd->pw_name, grp->gr_mem[i]) == 0) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static int parse_config_file(const char *conf_file, struct passwd *pwd, struct pam_limit_s *pl) {
+ FILE *fil;
+ char buf[LINE_LENGTH];
+
+ fil = fopen(conf_file, "r");
+ if (fil == NULL) {
+ g_printerr("cannot read settings from '%s': %s", conf_file, g_strerror(errno));
+ return -1;
+ }
+
+ /* init things */
+ memset(buf, 0, sizeof(buf));
+ /* start the show */
+ while (fgets(buf, LINE_LENGTH, fil) != NULL) {
+ char domain[LINE_LENGTH];
+ char ltype[LINE_LENGTH];
+ char item[LINE_LENGTH];
+ char value[LINE_LENGTH];
+ int i;
+ size_t j;
+ char *tptr;
+
+ tptr = buf;
+ /* skip the leading white space */
+ while (*tptr && isspace(*tptr))
+ tptr++;
+ strncpy(buf, tptr, sizeof(buf)-1);
+ buf[sizeof(buf)-1] = '\0';
+
+ /* Rip off the comments */
+ tptr = strchr(buf,'#');
+ if (tptr)
+ *tptr = '\0';
+ /* Rip off the newline char */
+ tptr = strchr(buf,'\n');
+ if (tptr)
+ *tptr = '\0';
+ /* Anything left ? */
+ if (!strlen(buf)) {
+ memset(buf, 0, sizeof(buf));
+ continue;
+ }
+
+ memset(domain, 0, sizeof(domain));
+ memset(ltype, 0, sizeof(ltype));
+ memset(item, 0, sizeof(item));
+ memset(value, 0, sizeof(value));
+
+ i = sscanf(buf,"%s%s%s%s", domain, ltype, item, value);
+/*
+ D(("scanned line[%d]: domain[%s], ltype[%s], item[%s], value[%s]",
+ i, domain, ltype, item, value));
+*/
+
+ for(j=0; j < strlen(ltype); j++)
+ ltype[j]=tolower(ltype[j]);
+ for(j=0; j < strlen(item); j++)
+ item[j]=tolower(item[j]);
+ for(j=0; j < strlen(value); j++)
+ value[j]=tolower(value[j]);
+
+ if (i == 4) { /* a complete line */
+ if (strcmp(pwd->pw_name, domain) == 0) /* this user have a limit */
+ process_limit(LIMITS_DEF_USER, ltype, item, value, pl);
+ else if (domain[0]=='@') {
+ if (pam_modutil_user_in_group_nam_nam(pwd, domain+1))
+ process_limit(LIMITS_DEF_GROUP, ltype, item, value, pl);
+ } else if (domain[0]=='%') {
+ if (strcmp(domain,"%") == 0)
+ process_limit(LIMITS_DEF_ALL, ltype, item, value, pl);
+ else if (pam_modutil_user_in_group_nam_nam(pwd, domain+1)) {
+ process_limit(LIMITS_DEF_ALLGROUP, ltype, item, value, pl);
+ }
+ } else if (strcmp(domain, "*") == 0) {
+ process_limit(LIMITS_DEF_DEFAULT, ltype, item, value, pl);
+ }
+ } else if (i == 2 && ltype[0] == '-') { /* Probably a no-limit line */
+ if (strcmp(pwd->pw_name, domain) == 0) {
+ fclose(fil);
+ return LIMHANDLE_IGNORE;
+ } else if (domain[0] == '@' && pam_modutil_user_in_group_nam_nam(pwd, domain+1)) {
+ fclose(fil);
+ return LIMHANDLE_IGNORE;
+ }
+ } else {
+ g_printerr("invalid line '%s' - skipped\n", buf);
+ }
+ }
+ fclose(fil);
+ return LIMHANDLE_OK;
+}
+
+static int setup_limits(struct pam_limit_s *pl) {
+ int i;
+ int status;
+ int retval = LIMHANDLE_OK;
+
+ for (i=0, status=LIMITED_OK; i<RLIM_NLIMITS; i++) {
+ if (!pl->limits[i].supported) {
+ /* skip it if its not known to the system */
+ continue;
+ }
+ if (pl->limits[i].src_soft == LIMITS_DEF_NONE &&
+ pl->limits[i].src_hard == LIMITS_DEF_NONE) {
+ /* skip it if its not initialized */
+ continue;
+ }
+ if (pl->limits[i].limit.rlim_cur > pl->limits[i].limit.rlim_max)
+ pl->limits[i].limit.rlim_cur = pl->limits[i].limit.rlim_max;
+ status |= setrlimit(i, &pl->limits[i].limit);
+ }
+
+ if (status) {
+ retval = LIMHANDLE_ERROR;
+ }
+
+ status = setpriority(PRIO_PROCESS, 0, pl->priority);
+ if (status != 0) {
+ retval = LIMHANDLE_ERROR;
+ }
+
+ return retval;
+}
+
+/* now the session stuff */
+int pam_set_limits(const char *conf_file, const char *username) {
+ int retval;
+ struct pam_limit_s pl;
+ struct passwd *pwd;
+
+ pwd = getpwnam(username);
+ if (NULL == pwd) return LIMHANDLE_ERROR;
+
+ if (!conf_file) conf_file = LIMITS_FILE;
+ memset(&pl, 0, sizeof(pl));
+
+ retval = init_limits(&pl);
+ if (retval != LIMHANDLE_OK) {
+ g_printerr("cannot initialize\n");
+ return retval;
+ }
+
+ retval = parse_config_file(conf_file, pwd, &pl);
+ if (retval == LIMHANDLE_IGNORE) {
+ return LIMHANDLE_OK;
+ }
+ if (retval != LIMHANDLE_OK) {
+ g_printerr("error parsing the configuration file\n");
+ return retval;
+ }
+
+ retval = setup_limits(&pl);
+ if (retval != LIMHANDLE_OK) {
+ return retval;
+ }
+
+ return LIMHANDLE_OK;
+}
+
+/*
+ * Copyright (c) Cristian Gafton, 1996-1997, <gafton@redhat.com>
+ * All rights reserved.
+ *
+ * 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, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 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.
+ */
diff --git a/spawn-fcgi.c b/spawn-fcgi.c
index 1897da4..9e59a6e 100644
--- a/spawn-fcgi.c
+++ b/spawn-fcgi.c
@@ -28,6 +28,9 @@
# define __attribute__(x) /*NOTHING*/
#endif
+#ifdef USE_LIMITS
+int pam_set_limits(const char *conf_file, const char *username);
+#endif
/*
spawn-fcgi - spawns fastcgi processes
@@ -79,6 +82,10 @@ typedef struct {
gboolean show_version;
gboolean keep_fds, close_fds; /* keep/close STDOUT/STDERR */
+#ifdef USE_LIMITS
+ gboolean use_limits;
+#endif
+
gchar *chroot;
gchar *uid, *gid;
gchar *socketuid, *socketgid;
@@ -110,6 +117,10 @@ static options opts = {
FALSE,
FALSE, FALSE,
+#ifdef USE_LIMITS
+ FALSE,
+#endif
+
NULL,
NULL, NULL,
NULL, NULL,
@@ -310,6 +321,13 @@ int drop_priv() {
return -1;
}
+#ifdef USE_LIMITS
+ if (opts.use_limits && data.username) {
+ if (0 != pam_set_limits(NULL, data.username)) {
+ }
+ }
+#endif
+
/* do the change before we do the chroot() */
if (data.gid != (gid_t) -1) {
if (0 != setgid(data.gid)) {
@@ -455,11 +473,14 @@ static const GOptionEntry entries[] = {
{ "pid", 'P', 0, G_OPTION_ARG_FILENAME, &opts.pid_file, "Name of PID-file for spawned process", "path" },
{ "no-daemon", 'n', 0, G_OPTION_ARG_NONE, &opts.no_fork, "Don't fork (for daemontools)", NULL },
{ "keep-fds", 0, 0, G_OPTION_ARG_NONE, &opts.keep_fds, "Keep stdout/stderr open (default for --no-daemon)", NULL },
- { "close-fds", 0, 0, G_OPTION_ARG_NONE, &opts.close_fds, "Close stdout/stderr (default it not --no-daemon)", NULL },
+ { "close-fds", 0, 0, G_OPTION_ARG_NONE, &opts.close_fds, "Close stdout/stderr (default if not --no-daemon)", NULL },
{ "version", 'v', 0, G_OPTION_ARG_NONE, &opts.show_version, "Show version", NULL },
{ "chroot", 'c', 0, G_OPTION_ARG_FILENAME, &opts.chroot, "(root only) chroot to directory", "dir" },
{ "uid", 'u', 0, G_OPTION_ARG_STRING, &opts.uid, "(root only) change to user-id", "user" },
{ "gid", 'g', 0, G_OPTION_ARG_STRING, &opts.gid, "(root only) change to group-id", "group" },
+#ifdef USE_LIMITS
+ { "limits", 'l', 0, G_OPTION_ARG_NONE, &opts.use_limits, "Set limits using /etc/security/limits.conf", NULL },
+#endif
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &opts.args, "<fcgiapp> [fcgi app arguments]", NULL },
{ NULL, 0, 0, 0, NULL, NULL, NULL }
};
diff --git a/wscript b/wscript
index 5d143f0..2ca50b0 100644
--- a/wscript
+++ b/wscript
@@ -14,6 +14,8 @@ blddir = 'build'
def set_options(opt):
opt.tool_options('compiler_cc')
+ opt.add_option('--without-limits', action='store_false', help='without /etc/security/limits.conf support', dest = 'limits', default = True)
+
def tolist(x):
if type(x) is types.ListType:
@@ -36,6 +38,10 @@ def configure(conf):
conf.check_tool('compiler_cc')
+ if opts.limits:
+ conf.define("USE_LIMITS", 1)
+ conf.env['USE_LIMITS'] = opts.limits
+
conf.define("PACKAGE_NAME", APPNAME)
conf.define("PACKAGE_VERSION", VERSION)
conf.define("PACKAGE_BUILD_DATE", strftime("%b %d %Y %H:%M:%S UTC", gmtime()));
@@ -54,12 +60,22 @@ def configure(conf):
conf.write_config_header('config.h')
+main_source = '''
+ spawn-fcgi.c
+'''
+
+limits_source = '''
+ pam_limits.c
+'''
+
def build(bld):
+ env = bld.env
+
spawnfcgi = bld.new_task_gen('cc', 'program')
spawnfcgi.name = 'spawn-fcgi'
- spawnfcgi.source = '''
- spawn-fcgi.c
- '''
+ spawnfcgi.source = main_source
+ if env['USE_LIMITS']:
+ spawnfcgi.source += limits_source
spawnfcgi.target = 'spawn-fcgi'
spawnfcgi.uselib += 'glib spawnfcgi'
spawnfcgi.includes = '.'