summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Wu <lekensteyn@gmail.com>2013-04-13 11:35:26 +0200
committerPeter Wu <lekensteyn@gmail.com>2013-04-13 14:44:30 +0200
commit3a94c23aed0f687940a0442d318359699e00015e (patch)
tree347584873b4c4d04e117bbd970413fa1aad71460
parent333ff9951b169f6a093608497b8b97f304365017 (diff)
downloadfcgiwrap-3a94c23aed0f687940a0442d318359699e00015e.tar.xz
fcgiwrap-3a94c23aed0f687940a0442d318359699e00015e.zip
Add `-p path` option to restrict scripts
If the purpose of fcgiwrap is to wrap cgit, then I want to be sure that no other program can be executed under the privileges of the fcgiwrap user. When the option `-p path` is given, only the programs specified by `path` are allowed to execute (multiple occurrences of `-p` are merged to form a list of allowed programs). Note that this value will be matched literally, no attempt is done to canonicalize the path. This also implies that glob patterns or directories will never match.
-rw-r--r--fcgiwrap.c29
1 files changed, 27 insertions, 2 deletions
diff --git a/fcgiwrap.c b/fcgiwrap.c
index 81c5062..e86ff9d 100644
--- a/fcgiwrap.c
+++ b/fcgiwrap.c
@@ -58,6 +58,8 @@
extern char **environ;
static char * const * inherited_environ;
+static const char **allowed_programs;
+static size_t allowed_programs_count;
static const char * blacklisted_env_vars[] = {
"AUTH_TYPE",
@@ -485,6 +487,19 @@ static void inherit_environment(void)
}
}
+static bool is_allowed_program(const char *program) {
+ size_t i;
+ if (!allowed_programs_count)
+ return true;
+
+ for (i = 0; i < allowed_programs_count; i++) {
+ if (!strcmp(allowed_programs[i], program))
+ return true;
+ }
+
+ return false;
+}
+
static void cgi_error(const char *message, const char *reason, const char *filename)
{
printf("Status: %s\r\nContent-Type: text/plain\r\n\r\n%s\r\n",
@@ -541,6 +556,9 @@ static void handle_fcgi_request(void)
if (!filename)
cgi_error("403 Forbidden", "Cannot get script name, are DOCUMENT_ROOT and SCRIPT_NAME (or SCRIPT_FILENAME) set and is the script executable?", NULL);
+ if (!is_allowed_program(filename))
+ cgi_error("403 Forbidden", "The given script is not allowed to execute", filename);
+
last_slash = strrchr(filename, '/');
if (!last_slash)
cgi_error("403 Forbidden", "Script name must be a fully qualified path", filename);
@@ -760,7 +778,7 @@ int main(int argc, char **argv)
char *socket_url = NULL;
int c;
- while ((c = getopt(argc, argv, "c:hfs:")) != -1) {
+ while ((c = getopt(argc, argv, "c:hfs:p:")) != -1) {
switch (c) {
case 'f':
stderr_to_fastcgi++;
@@ -773,6 +791,7 @@ int main(int argc, char **argv)
" -c <number>\t\tNumber of processes to prefork\n"
" -s <socket_url>\tSocket to bind to (say -s help for help)\n"
" -h\t\t\tShow this help message and exit\n"
+ " -p <path>\t\tRestrict execution to this script. (repeated options will be merged)\n"
"\nReport bugs to Grzegorz Nosek <"PACKAGE_BUGREPORT">.\n"
PACKAGE_NAME" home page: <http://nginx.localdomain.pl/wiki/FcgiWrap>\n",
argv[0]
@@ -784,8 +803,14 @@ int main(int argc, char **argv)
case 's':
socket_url = strdup(optarg);
break;
+ case 'p':
+ allowed_programs = realloc(allowed_programs, (allowed_programs_count + 1) * sizeof (char *));
+ if (!allowed_programs)
+ abort();
+ allowed_programs[allowed_programs_count++] = strdup(optarg);
+ break;
case '?':
- if (optopt == 'c' || optopt == 's')
+ if (optopt == 'c' || optopt == 's' || optopt == 'p')
fprintf(stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint(optopt))
fprintf(stderr, "Unknown option `-%c'.\n", optopt);