[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[patch] OpenBSD -CURRENT Bug: httpd restarts fail in chroot from etag-state



I believe this patch solves the problem.  The essence
is: use an absolute path to the etag-state if we're
already chrooted; make sure the owner of the etag-state
file is root.www and make it the file group readable
so that we can read it (but not write it) after chrooting;
make some more informative error messages.

Tested on my system by running httpd with no arguments,
then doing a kill -HUP on the httpd parent process.
Confirmed that the httpd process succesfully restarts itself
(logging no errors) and correctly reads the etag-state file,
and that the generated etags (from a HEAD request) are
the same before and after the restart.

Comments/corrections?

Index: src/main/http_protocol.c
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/src/main/http_protocol.c,v
retrieving revision 1.18
diff -u -r1.18 http_protocol.c
--- src/main/http_protocol.c	2003/02/17 03:14:33	1.18
+++ src/main/http_protocol.c	2003/02/20 23:08:17
@@ -3189,6 +3189,8 @@
  */
 static AP_SHA1_CTX baseCtx;
 
+#define S_ETAG_MODE (S_IRUSR | S_IWUSR | S_IRGRP)
+
 API_EXPORT(void) ap_init_etag(pool *pconf)
 {
     struct stat st;
@@ -3199,11 +3201,19 @@
 
     ap_SHA1Init(&baseCtx);
 
-    filename = ap_server_root_relative(pconf, "logs/etag-state");
-    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, NULL,
-      "Initializing etag from %s", filename);
+    if (ap_server_is_chrooted()) {
+        filename = "/logs/etag-state";
+        ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, NULL,
+          "Initializing etag from %s (chrooted)", filename);
+        fd = open(filename, O_RDONLY|O_NOFOLLOW, S_ETAG_MODE);
+    } else {
+        filename = ap_server_root_relative(pconf, "logs/etag-state");
+        ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, NULL,
+          "Initializing etag from %s (not yet chrooted)", filename);
+        fd = open(filename, O_CREAT|O_RDWR|O_NOFOLLOW, S_ETAG_MODE);
+    }
 
-    if ((fd = open(filename, O_CREAT|O_RDWR|O_NOFOLLOW, 0600)) == -1) {
+    if (fd == -1) {
         ap_log_error(APLOG_MARK, APLOG_CRIT, NULL,
           "could not open %s", filename);
         exit(-1);
@@ -3215,7 +3225,44 @@
         exit(-1);
     }
 
+    if ((st.st_mode & ALLPERMS) != S_ETAG_MODE) {
+        /* if wrong permissions and already chrooted, nothing we can do */
+        if (ap_server_is_chrooted()) {
+            ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_CRIT, NULL,
+              "%s has wrong permissions: %o", filename, st.st_mode);
+            exit(-1);
+        }
+
+        if (fchmod(fd, S_ETAG_MODE) == -1) {
+            ap_log_error(APLOG_MARK, APLOG_CRIT, NULL,
+              "could not set correct permissions of %s", filename);
+            exit(-1);
+        }
+    }
+
+    if (st.st_gid != ap_group_id) {
+        /* if wrong ownership and already chrooted, nothing we can do */
+        if (ap_server_is_chrooted()) {
+            ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_CRIT, NULL,
+              "%s has wrong group ownership", filename);
+            exit(-1);
+        }
+
+        if (fchown(fd, -1, ap_group_id) == -1) {
+            ap_log_error(APLOG_MARK, APLOG_CRIT, NULL,
+              "could not set correct group ownership of %s", filename);
+            exit(-1);
+        }
+    }
+
     if (st.st_size != sizeof(rnd)*4) {
+        /* if wrong size and we're already chrooted, nothing we can do */
+        if (ap_server_is_chrooted()) {
+            ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_CRIT, NULL,
+              "%s is the wrong size (%qd bytes)", filename, st.st_size);
+            exit(-1);
+        }
+
         if (st.st_size > 0) {
             ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, NULL,
               "truncating %s from %qd bytes to 0", filename, st.st_size);