source: server/common/patches/httpd-suexec-scripts.patch @ 838

Last change on this file since 838 was 823, checked in by geofft, 16 years ago
Add suexec support for things in a trusted directory, so we can make a trusted svn, etc. wrapper and su to the target user to use their permissions. This commit is being made with svnserve being invoked by such a trusted wrapper. Let's see if it works.
File size: 8.3 KB
RevLine 
[1]1# scripts.mit.edu httpd suexec patch
[823]2# Copyright (C) 2006, 2007, 2008  Jeff Arnold <jbarnold@mit.edu>,
3#                                 Joe Presbrey <presbrey@mit.edu>,
4#                                 Anders Kaseorg <andersk@mit.edu>,
5#                                 Geoffrey Thomas <geofft@mit.edu>
[1]6#
7# This program is free software; you can redistribute it and/or
8# modify it under the terms of the GNU General Public License
9# as published by the Free Software Foundation; either version 2
10# of the License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, write to the Free Software
19# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
20#
21# See /COPYRIGHT in this repository for more information.
22#
[103]23--- httpd-2.2.2/support/Makefile.in.old 2005-07-06 19:15:34.000000000 -0400
24+++ httpd-2.2.2/support/Makefile.in     2007-01-20 17:12:51.000000000 -0500
25@@ -60,7 +60,7 @@
26
27 suexec_OBJECTS = suexec.lo
28 suexec: $(suexec_OBJECTS)
29-       $(LINK) $(suexec_OBJECTS)
30+       $(LINK) -lselinux $(suexec_OBJECTS)
31
32 htcacheclean_OBJECTS = htcacheclean.lo
33 htcacheclean: $(htcacheclean_OBJECTS)
[823]34--- httpd-2.2.2/configure.in.old        2007-07-17 10:48:25.000000000 -0400
35+++ httpd-2.2.2/configure.in    2008-08-29 08:15:41.000000000 -0400
36@@ -559,6 +559,10 @@
37 APACHE_HELP_STRING(--with-suexec-userdir,User subdirectory),[
38   AC_DEFINE_UNQUOTED(AP_USERDIR_SUFFIX, "$withval", [User subdirectory] ) ] )
39 
40+AC_ARG_WITH(suexec-trusteddir,
41+APACHE_HELP_STRING(--with-suexec-trusteddir,Trusted SuExec directory),[
42+  AC_DEFINE_UNQUOTED(AP_TRUSTED_DIRECTORY, "$withval", [Trusted SuExec directory] ) ] )
43+
44 AC_ARG_WITH(suexec-docroot,
45 APACHE_HELP_STRING(--with-suexec-docroot,SuExec root directory),[
46   AC_DEFINE_UNQUOTED(AP_DOC_ROOT, "$withval", [SuExec root directory] ) ] )
[1]47--- httpd-2.2.2/support/suexec.c.old    2006-04-21 21:53:06.000000000 -0400
[315]48+++ httpd-2.2.2/support/suexec.c        2007-05-22 10:32:04.000000000 -0400
[298]49@@ -30,6 +30,8 @@
50  *
51  */
52 
53+#define STATIC_CAT_PATH "/usr/local/bin/static-cat"
54+
55 #include "apr.h"
56 #include "ap_config.h"
57 #include "suexec.h"
58@@ -46,6 +48,7 @@
[103]59 #include <stdio.h>
60 #include <stdarg.h>
61 #include <stdlib.h>
62+#include <selinux/selinux.h>
63 
64 #ifdef HAVE_PWD_H
65 #include <pwd.h>
[405]66@@ -95,6 +98,7 @@
[1]67 {
68     /* variable name starts with */
69     "HTTP_",
70+    "HTTPS_",
71     "SSL_",
72 
73     /* variable name is */
[405]74@@ -140,6 +144,7 @@
[1]75     "UNIQUE_ID=",
76     "USER_NAME=",
77     "TZ=",
78+    "PHPRC=",
79     NULL
80 };
81 
[823]82@@ -245,9 +250,58 @@
[298]83     environ = cleanenv;
84 }
85 
86+static const char *static_extensions[] = {
87+    "html",
88+    "css",
89+    "gif",
90+    "jpg",
91+    "png",
92+    "htm",
93+    "jpeg",
94+    "js",
95+    "ico",
96+    "xml",
97+    "xsl",
98+    "tiff",
99+    "tif",
100+    "tgz",
101+    "tar",
102+    "jar",
103+    "zip",
104+    "pdf",
105+    "ps",
106+    "doc",
107+    "xls",
108+    "ppt",
109+    "swf",
110+    "mp3",
111+    "mov",
112+    "wmv",
113+    "mpg",
114+    "mpeg",
115+    "avi",
116+    "il",
117+    "JPG",
[315]118+    "xhtml",
[618]119+    "svg",
[298]120+    NULL
121+};
122+
123+static int is_static_extension(const char *file)
124+{
125+    const char *extension = strrchr(file, '.');
126+    const char **p;
127+    if (extension == NULL) return 0;
128+    for (p = static_extensions; *p; ++p) {
129+        if (strcmp(extension + 1, *p) == 0) return 1;
130+    }
131+    return 0;
132+}
133+
134 int main(int argc, char *argv[])
135 {
136     int userdir = 0;        /* ~userdir flag             */
[823]137+    int trusteddir = 0;     /* TRUSTED_DIRECTORY flag    */
138     uid_t uid;              /* user information          */
139     gid_t gid;              /* target group placeholder  */
140     char *target_uname;     /* target user name          */
141@@ -350,6 +404,20 @@
142 #endif /*_OSD_POSIX*/
143 
144     /*
145+     * First check if this is an absolute path to the directory
146+     * of trusted executables. These are supposed to be security
147+     * audited to check parameters and validity on their own...
148+     */
149+    if (strstr(cmd, AP_TRUSTED_DIRECTORY) == cmd) {
150+        if (strstr(cmd, "/../") != NULL) {
151+            log_err("invalid command (%s)\n", cmd);
152+            exit(104);
153+        }
154+        trusteddir = 1;
155+        goto TRUSTED_DIRECTORY;
156+    }
157+
158+    /*
159      * Check for a leading '/' (absolute path) in the command to be executed,
160      * or attempts to back up out of the current directory,
161      * to protect against attacks.  If any are
162@@ -371,6 +439,7 @@
163         userdir = 1;
164     }
165 
166+TRUSTED_DIRECTORY:
167     /*
168      * Error out if the target username is invalid.
169      */
170@@ -450,7 +519,7 @@
[103]171      * Error out if attempt is made to execute as root or as
172      * a UID less than AP_UID_MIN.  Tsk tsk.
173      */
174-    if ((uid == 0) || (uid < AP_UID_MIN)) {
175+    if ((uid == 0) || (uid < AP_UID_MIN && uid != 102)) {
176         log_err("cannot run as forbidden uid (%d/%s)\n", uid, cmd);
177         exit(107);
178     }
[823]179@@ -482,6 +551,19 @@
[103]180         log_err("failed to setuid (%ld: %s)\n", uid, cmd);
181         exit(110);
182     }
[406]183+    if (is_selinux_enabled()) {
184+        if (uid == 102) {
185+            if (setexeccon("system_u:system_r:signup_t:s0") == -1) {
186+                log_err("failed to setexeccon (%ld: %s) to signup_t\n", uid, cmd);
187+                exit(201);
188+            }
189+        } else {
190+            if (setexeccon("user_u:user_r:user_t:s0") == -1) {
191+                log_err("failed to setexeccon (%ld: %s) to user_t\n", uid, cmd);
192+                exit(202);
193+            }
[405]194+        }
[103]195+    }
196 
197     /*
198      * Get the current working directory, as well as the proper
[823]199@@ -504,6 +586,21 @@
200             log_err("cannot get docroot information (%s)\n", target_homedir);
201             exit(112);
[1]202         }
[823]203+        size_t expected_len = strlen(target_homedir)+1+strlen(AP_USERDIR_SUFFIX)+1;
204+        char *expected = malloc(expected_len);
205+        snprintf(expected, expected_len, "%s/%s", target_homedir, AP_USERDIR_SUFFIX);
206+        if (strncmp(cwd, expected, expected_len-1) != 0) {
207+            log_err("error: file's directory not a subdirectory of user's home directory (%s, %s)\n", cwd, expected);
208+            exit(114);
209+        }
210+    }
211+    else if (trusteddir) {
212+        if (((chdir(AP_TRUSTED_DIRECTORY)) != 0) ||
213+            ((getcwd(dwd, AP_MAXPATH)) == NULL) |
214+            ((chdir(cwd)) != 0)) {
215+            log_err("cannot get docroot information (%s)\n", AP_TRUSTED_DIRECTORY);
216+            exit(112);
217+        }
[1]218     }
[823]219     else {
220         if (((chdir(AP_DOC_ROOT)) != 0) ||
221@@ -530,15 +627,17 @@
[1]222     /*
223      * Error out if cwd is writable by others.
224      */
225+#if 0
226     if ((dir_info.st_mode & S_IWOTH) || (dir_info.st_mode & S_IWGRP)) {
227         log_err("directory is writable by others: (%s)\n", cwd);
228         exit(116);
229     }
230+#endif
231 
232     /*
233      * Error out if we cannot stat the program.
234      */
235-    if (((lstat(cmd, &prg_info)) != 0) || (S_ISLNK(prg_info.st_mode))) {
236+    if (((lstat(cmd, &prg_info)) != 0) /*|| (S_ISLNK(prg_info.st_mode))*/) {
237         log_err("cannot stat program: (%s)\n", cmd);
238         exit(117);
239     }
[823]240@@ -546,10 +645,12 @@
[1]241     /*
242      * Error out if the program is writable by others.
243      */
244+#if 0
245     if ((prg_info.st_mode & S_IWOTH) || (prg_info.st_mode & S_IWGRP)) {
246         log_err("file is writable by others: (%s/%s)\n", cwd, cmd);
247         exit(118);
248     }
249+#endif
250 
251     /*
252      * Error out if the file is setuid or setgid.
[823]253@@ -563,6 +664,7 @@
[1]254      * Error out if the target name/group is different from
255      * the name/group of the cwd or the program.
256      */
257+#if 0
258     if ((uid != dir_info.st_uid) ||
259         (gid != dir_info.st_gid) ||
260         (uid != prg_info.st_uid) ||
[823]261@@ -574,6 +676,7 @@
[1]262                 prg_info.st_uid, prg_info.st_gid);
263         exit(120);
264     }
265+#endif
266     /*
267      * Error out if the program is not executable for the user.
268      * Otherwise, she won't find any error in the logs except for
[823]269@@ -606,6 +709,13 @@
270       exit(122);
[298]271     }
272 
273+    if (is_static_extension(cmd)) {
274+        argv[2] = STATIC_CAT_PATH;
275+        execv(STATIC_CAT_PATH, &argv[2]);
276+       log_err("(%d)%s: static_cat exec failed (%s)\n", errno, strerror(errno), argv[2]);
277+       exit(255);
278+    }
279+
280     /*
281      * Execute the command, replacing our image with its own.
282      */
Note: See TracBrowser for help on using the repository browser.