KaiGai Kohei wrote:
> Stefan Fritsch wrote:
>> On Thursday 09 April 2009, Graham Dumpleton wrote:
>>> Only you would know that. But then, I could be pointing you at the
>>> wrong MPM. There is from memory another by another name developed
>>> outside of ASF which intends to do the same think. The way it is
>>> implemented is probably going to be different and may be the one I
>>> am actually thinking of. I can't remember the name of it right now.
>> Maybe you mean MPM itk, which can change to different users for 
>> different vhosts?
>>
>> http://mpm-itk.sesse.net/
> 
> Thanks for your information.
> 
> It is designed on the prefork. It makes a child process for each
> connection to call ap_process_connection() in separated context,
> and the parent waits for the completion of this.
> In addition, it assigns configured uid/gid on the header_parser hook,
> then contents handlers are invoked.
> 
> It seems to me that we can share its basic idea and design.
> The mpm-itk also has separatable two functionalities:
>  1. it makes a process for each connection.
>  2. it assigns privileges on a process.
> 
> I believe we are now on the right direction.

At first, I planed to implement a new mpm from the scratch, but I
reconsidered it may be a burden for the reviewers, so the attached
patch is implemented as an enhancement of the latest prefork.
(I guess it is a preferable manner.)

The first attached patch adds a new "security" mpm which enables to
launch a new process for each connections, and gives a chance to assign
appropriate privileges for external modules. The newly spawned process
is always one-time purpose, because SELinux does not allow to revert
its privileges.

The second patch is an implementation of the mod_selinux module which
assigns the working process a security context based on authentication
process at the fixups hook, prior to invocations of contents handler.

  Step to apply the patches:
  % svn co http://svn.apache.org/repos/asf/httpd/httpd/trunk httpd-devel
  % cd httpd-devel
  % mkdir -p server/mpm/security
  % cp -f server/mpm/prefork/prefork.c server/mpm/security
  % cp -f server/mpm/prefork/mpm_default.h server/mpm/security
  % cat ~/apache-httpd-security-mpm.1.patch | patch -p1
  % cat ~/apache-httpd-mod_selinux.1.patch | patch -p1

  (*) The attached patch contains only differences from the prefork.

I would like to push this kind of features to the upstreamed httpd
eventually. If you have any suggestion, please feel free to comment.

Thanks,
-- 
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>
Index: httpd-devel/server/mpm/MPM.NAMING
===================================================================
--- httpd-devel/server/mpm/MPM.NAMING	(revision 763518)
+++ httpd-devel/server/mpm/MPM.NAMING	(working copy)
@@ -9,3 +9,5 @@
   worker ........ Multi Process model with threads.  One acceptor thread,
                   multiple worker threads.
   netware ....... Multi-threaded MPM for Netware
+  security ...... Forks a one-time process for each request. External module
+                  can assign appropriate privileges prior to handlers.
Index: httpd-devel/server/mpm/config.m4
===================================================================
--- httpd-devel/server/mpm/config.m4	(revision 763518)
+++ httpd-devel/server/mpm/config.m4	(working copy)
@@ -1,7 +1,7 @@
 AC_MSG_CHECKING(which MPM to use)
 AC_ARG_WITH(mpm,
 APACHE_HELP_STRING(--with-mpm=MPM,Choose the process model for Apache to use.
-                          MPM={simple|event|worker|prefork|winnt}
+                          MPM={simple|event|worker|prefork|winnt|security}
                           Specify "shared" instead of an MPM name to load MPMs dynamically.
 ),[
   APACHE_MPM=$withval
Index: httpd-devel/server/mpm/security/Makefile.in
===================================================================
--- httpd-devel/server/mpm/security/Makefile.in	(revision 0)
+++ httpd-devel/server/mpm/security/Makefile.in	(revision 0)
@@ -0,0 +1,5 @@
+
+LTLIBRARY_NAME    = libsecurity.la
+LTLIBRARY_SOURCES = security.c
+
+include $(top_srcdir)/build/ltlib.mk
Index: httpd-devel/server/mpm/security/config.m4
===================================================================
--- httpd-devel/server/mpm/security/config.m4	(revision 0)
+++ httpd-devel/server/mpm/security/config.m4	(revision 0)
@@ -0,0 +1,3 @@
+if test "$MPM_NAME" = "security" ; then
+    APACHE_FAST_OUTPUT(server/mpm/$MPM_NAME/Makefile)
+fi
--- httpd-devel/server/mpm/security/prefork.c	2009-04-13 09:14:47.000000000 +0900
+++ httpd-devel/server/mpm/security/security.c	2009-04-13 15:17:12.000000000 +0900
@@ -94,15 +94,15 @@
 static int mpm_state = AP_MPMQ_STARTING;
 static ap_pod_t *pod;
 
-/* data retained by prefork across load/unload of the module
+/* data retained by security across load/unload of the module
  * allocated on first call to pre-config hook; located on
  * subsequent calls to pre-config hook
  */
-typedef struct prefork_retained_data {
+typedef struct security_retained_data {
     int first_server_limit;
     int module_loads;
-} prefork_retained_data;
-static prefork_retained_data *retained;
+} security_retained_data;
+static security_retained_data *retained;
 
 #define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
 
@@ -131,6 +131,7 @@
 
 static pid_t ap_my_pid; /* it seems silly to call getpid all the time */
 static pid_t parent_pid;
+static volatile pid_t worker_pid = 0;
 static int my_child_num;
 static ap_generation_t volatile my_generation=0;
 
@@ -242,7 +243,7 @@
 #define SAFE_ACCEPT(stmt) do {stmt;} while(0)
 #endif
 
-static int prefork_query(int query_code, int *result, apr_status_t *rv)
+static int security_query(int query_code, int *result, apr_status_t *rv)
 {
     *rv = APR_SUCCESS;
     switch(query_code){
@@ -295,15 +296,15 @@
     return OK;
 }
 
-static apr_status_t prefork_note_child_killed(int childnum)
+static apr_status_t security_note_child_killed(int childnum)
 {
     ap_scoreboard_image->parent[childnum].pid = 0;
     return APR_SUCCESS;
 }
 
-static const char *prefork_get_name(void)
+static const char *security_get_name(void)
 {
-    return "prefork";
+    return "security";
 }
 
 /*****************************************************************
@@ -312,6 +313,8 @@
 
 static void just_die(int sig)
 {
+    if (worker_pid > 0)
+	kill(worker_pid, sig);
     clean_child_exit(0);
 }
 
@@ -444,10 +447,6 @@
 
 static void child_main(int child_num_arg)
 {
-#if APR_HAS_THREADS
-    apr_thread_t *thd = NULL;
-    apr_os_thread_t osthd;
-#endif
     apr_pool_t *ptrans;
     apr_allocator_t *allocator;
     apr_status_t status;
@@ -477,11 +476,6 @@
     apr_allocator_owner_set(allocator, pchild);
     apr_pool_tag(pchild, "pchild");
 
-#if APR_HAS_THREADS
-    osthd = apr_os_thread_current();
-    apr_os_thread_put(&thd, &osthd, pchild);
-#endif
-    
     apr_pool_create(&ptrans, pchild);
     apr_pool_tag(ptrans, "transaction");
 
@@ -650,9 +644,49 @@
 
         current_conn = ap_run_create_connection(ptrans, ap_server_conf, csd, my_child_num, sbh, bucket_alloc);
         if (current_conn) {
+	    int status;
+
+	    worker_pid = fork();
+	    if (worker_pid < 0) {
+		ap_log_error(APLOG_MARK, APLOG_ERR, errno, ap_server_conf,
+			     "unable to fork a worker process");
+		ap_lingering_close(current_conn);
+	    } else if (worker_pid == 0) {
 #if APR_HAS_THREADS
-            current_conn->current_thread = thd;
+		apr_thread_t *thd = NULL;
+		apr_os_thread_t osthd;
+
+		osthd = apr_os_thread_current();
+		apr_os_thread_put(&thd, &osthd, pchild);
+		current_conn->current_thread = thd;
 #endif
+		/* no need to hold server sockets */
+		ap_close_listeners();
+
+		getcon_raw(&context);
+
+		ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
+			     "fork a worker process (%s)", context);
+
+		ap_process_connection(current_conn, csd);
+		ap_lingering_close(current_conn);
+
+		exit(0);
+	    } else {
+		/* no need to hold client socket */
+		ap_lingering_close(current_conn);
+
+		/* wait for completion of worker process */
+		while (waitpid(worker_pid, &status, 0) < 0 && errno == EINTR);
+
+		if (WIFSIGNALED(status) || WEXITSTATUS(status)) {
+		    ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf,
+				 "worker process exit abnormally");
+		    die_now = 1;
+		}
+		worker_pid = 0;
+	    }
+
             ap_process_connection(current_conn, csd);
             ap_lingering_close(current_conn);
         }
@@ -895,7 +929,7 @@
  * Executive routines.
  */
 
-static int prefork_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
+static int security_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
 {
     int index;
     int remaining_children_to_start;
@@ -1229,7 +1263,7 @@
 /* This really should be a post_config hook, but the error log is already
  * redirected by that point, so we need to do this in the open_logs phase.
  */
-static int prefork_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
+static int security_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
 {
     int startup = 0;
     int level_flags = 0;
@@ -1259,11 +1293,11 @@
     return OK;
 }
 
-static int prefork_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp)
+static int security_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp)
 {
     int no_detach, debug, foreground;
     apr_status_t rv;
-    const char *userdata_key = "mpm_prefork_module";
+    const char *userdata_key = "mpm_security_module";
 
     mpm_state = AP_MPMQ_STARTING;
 
@@ -1319,7 +1353,7 @@
     return OK;
 }
 
-static int prefork_check_config(apr_pool_t *p, apr_pool_t *plog,
+static int security_check_config(apr_pool_t *p, apr_pool_t *plog,
                                 apr_pool_t *ptemp, server_rec *s)
 {
     int startup = 0;
@@ -1405,7 +1439,7 @@
         ap_daemons_limit = 1;
     }
 
-    /* ap_daemons_to_start > ap_daemons_limit checked in prefork_run() */
+    /* ap_daemons_to_start > ap_daemons_limit checked in security_run() */
     if (ap_daemons_to_start < 0) {
         if (startup) {
             ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL,
@@ -1436,12 +1470,12 @@
         ap_daemons_min_free = 1;
     }
 
-    /* ap_daemons_max_free < ap_daemons_min_free + 1 checked in prefork_run() */
+    /* ap_daemons_max_free < ap_daemons_min_free + 1 checked in security_run() */
 
     return OK;
 }
 
-static void prefork_hooks(apr_pool_t *p)
+static void security_hooks(apr_pool_t *p)
 {
     /* Our open_logs hook function must run before the core's, or stderr
      * will be redirected to a file, and the messages won't print to the
@@ -1449,16 +1483,16 @@
      */
     static const char *const aszSucc[] = {"core.c", NULL};
 
-    ap_hook_open_logs(prefork_open_logs, NULL, aszSucc, APR_HOOK_REALLY_FIRST);
+    ap_hook_open_logs(security_open_logs, NULL, aszSucc, APR_HOOK_REALLY_FIRST);
     /* we need to set the MPM state before other pre-config hooks use MPM query
      * to retrieve it, so register as REALLY_FIRST
      */
-    ap_hook_pre_config(prefork_pre_config, NULL, NULL, APR_HOOK_REALLY_FIRST);
-    ap_hook_check_config(prefork_check_config, NULL, NULL, APR_HOOK_MIDDLE);
-    ap_hook_mpm(prefork_run, NULL, NULL, APR_HOOK_MIDDLE);
-    ap_hook_mpm_query(prefork_query, NULL, NULL, APR_HOOK_MIDDLE);
-    ap_hook_mpm_note_child_killed(prefork_note_child_killed, NULL, NULL, APR_HOOK_MIDDLE);
-    ap_hook_mpm_get_name(prefork_get_name, NULL, NULL, APR_HOOK_MIDDLE);
+    ap_hook_pre_config(security_pre_config, NULL, NULL, APR_HOOK_REALLY_FIRST);
+    ap_hook_check_config(security_check_config, NULL, NULL, APR_HOOK_MIDDLE);
+    ap_hook_mpm(security_run, NULL, NULL, APR_HOOK_MIDDLE);
+    ap_hook_mpm_query(security_query, NULL, NULL, APR_HOOK_MIDDLE);
+    ap_hook_mpm_note_child_killed(security_note_child_killed, NULL, NULL, APR_HOOK_MIDDLE);
+    ap_hook_mpm_get_name(security_get_name, NULL, NULL, APR_HOOK_MIDDLE);
 }
 
 static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy, const char *arg)
@@ -1516,7 +1550,7 @@
     return NULL;
 }
 
-static const command_rec prefork_cmds[] = {
+static const command_rec security_cmds[] = {
 LISTEN_COMMANDS,
 AP_INIT_TAKE1("StartServers", set_daemons_to_start, NULL, RSRC_CONF,
               "Number of child processes launched at server startup"),
@@ -1532,13 +1566,13 @@
 { NULL }
 };
 
-module AP_MODULE_DECLARE_DATA mpm_prefork_module = {
+module AP_MODULE_DECLARE_DATA mpm_security_module = {
     MPM20_MODULE_STUFF,
     NULL,                       /* hook to run before apache parses args */
     NULL,                       /* create per-directory config structure */
     NULL,                       /* merge per-directory config structures */
     NULL,                       /* create per-server config structure */
     NULL,                       /* merge per-server config structures */
-    prefork_cmds,               /* command apr_table_t */
-    prefork_hooks,              /* register hooks */
+    security_cmds,              /* command apr_table_t */
+    security_hooks,             /* register hooks */
 };
Index: httpd-devel/modules/arch/unix/mod_selinux.c
===================================================================
--- httpd-devel/modules/arch/unix/mod_selinux.c	(revision 0)
+++ httpd-devel/modules/arch/unix/mod_selinux.c	(revision 0)
@@ -0,0 +1,306 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "apr_strings.h"
+#include "apr_thread_proc.h"
+
+#include "httpd.h"
+#include "http_request.h"
+#include "http_config.h"
+#include "http_log.h"
+#include <stdio.h>
+#include <string.h>
+#include <selinux/selinux.h>
+#include <selinux/context.h>
+
+typedef struct
+{
+    char *dirname;
+    char *config_file;
+    char *default_domain;
+} selinux_config;
+
+module AP_MODULE_DECLARE_DATA selinux_module;
+
+static char *
+selinux_lookup_entry(request_rec *r, const char *filename)
+{
+    const char *white_space = " \t\r\n";
+    ap_configfile_t *filp;
+    char buffer[MAX_STRING_LEN];
+    apr_status_t status;
+    char *ident, *entry, *mask, *pos;
+    apr_ipsubnet_t *ipsub;
+    int negative, lineno = 0;
+
+    status = ap_pcfg_openfile(&filp, r->pool, filename);
+    if (status != APR_SUCCESS) {
+        ap_log_rerror(APLOG_MARK, LOG_WARNING, status, r,
+                      "Unable to open: %s", filename);
+        return NULL;
+    }
+
+    while (ap_cfg_getline(buffer, sizeof(buffer), filp) == 0) {
+        negative = 0;
+        lineno++;
+
+        /* skip empty line */
+        pos = strchr(buffer, '#');
+        if (pos)
+            *pos = '\0';
+
+        ident = strtok_r(buffer, white_space, &pos);
+        if (!ident)
+            continue;
+
+        /* if the line begins with '!', it means negative. */
+        if (*ident == '!') {
+            ident++;
+            negative = 1;
+        }
+
+        /* fetch domain and range */
+        entry = strtok_r(NULL, white_space, &pos);
+        if (!entry || strtok_r(NULL, white_space, &pos)) {
+            ap_log_rerror(APLOG_MARK, LOG_WARNING, 0, r,
+                          "syntax error at %s:%d", filename, lineno);
+            continue;
+        }
+
+        /* ident is network address? or username? */
+        mask = strchr(ident, '/');
+        if (mask)
+            *mask++ = '\0';
+
+        if (apr_ipsubnet_create(&ipsub, ident, mask, r->pool) == APR_SUCCESS) {
+            if (apr_ipsubnet_test(ipsub, r->connection->remote_addr)) {
+                if (!negative)
+                    goto found;
+            } else if (negative)
+                goto found;
+        }
+        else if (r->user) {
+            if (mask)
+                *--mask = '/';  /* fixup assumption of network address */
+            if (strcmp(r->user, ident) == 0) {
+                if (!negative)
+                    goto found;
+            } else if (negative)
+                goto found;
+        }
+    }
+    /* not found */
+    ap_cfg_closefile(filp);
+    return NULL;
+
+found:
+    ap_cfg_closefile(filp);
+    return apr_pstrdup(r->pool, entry);
+}
+
+static int selinux_post_read_request(request_rec *r)
+{
+    selinux_config *sconf
+        = ap_get_module_config(r->per_dir_config,
+                               &selinux_module);
+    /*
+     * If mod_selinux is available on the given request,
+     * it does not allow to cache the contents to keep
+     * consistency of access controls.
+     */
+    if (sconf && is_selinux_enabled() == 1)
+        r->no_cache = 1;
+
+    return DECLINED;
+}
+
+static int selinux_fixups(request_rec *r)
+{
+    selinux_config *sconf;
+    security_context_t old_context;
+    security_context_t new_context;
+    security_context_t tmp_context;
+    char *entry = NULL;
+
+    sconf = ap_get_module_config(r->per_dir_config,
+                                 &selinux_module);
+    if (!sconf)
+        return DECLINED;
+
+    if (is_selinux_enabled() < 1)
+        return DECLINED;
+
+    /*
+     * Is there any matched entry or default domain
+     * configured? If not, this module does not anything.
+     */
+    if (sconf->config_file)
+        entry = selinux_lookup_entry(r, sconf->config_file);
+    if (!entry)
+        entry = apr_pstrdup(r->pool, sconf->default_domain);
+    if (!entry)
+        return DECLINED;  /* no matched and default domain */
+
+    /*
+     * Get the current security context
+     */
+    if (getcon_raw(&tmp_context) < 0) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, errno, r->server,
+                     "SELinux: getcon_raw() failed");
+        return HTTP_INTERNAL_SERVER_ERROR;
+    }
+    old_context = apr_pstrdup(r->pool, tmp_context);
+    freecon(tmp_context);
+
+    /*
+     * Compute a new security context
+     */
+    if (!strcasecmp(entry, "auth-module")) {
+        new_context = (security_context_t )apr_table_get(r->notes,
+                                                         "auth-security-context");
+        if (!new_context) {
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r,
+                          "No SELinux aware authentication module");
+            return HTTP_INTERNAL_SERVER_ERROR;
+        }
+    } else {
+        context_t context;
+        char *domain = entry;
+        char *range = NULL;
+
+        range = strchr(domain, ':');
+        if (range)
+            *range++ = '\0';
+
+        context = context_new(old_context);
+        if (!context) {
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r,
+                          "context_new('%s') failed", old_context);
+            return HTTP_INTERNAL_SERVER_ERROR;
+        }
+        if (domain && strcmp(domain, "*") != 0)
+            context_type_set(context, domain);
+        if (range  && strcmp(range, "*") != 0)
+            context_range_set(context, range);
+
+        tmp_context = context_str(context);
+        if (!tmp_context) {
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r,
+                          "context_str() failed");
+            context_free(context);
+            return HTTP_INTERNAL_SERVER_ERROR;
+        }
+        new_context = apr_pstrdup(r->pool, tmp_context);
+        freecon(tmp_context);
+    }
+
+    if (strcmp(old_context, new_context) == 0) {
+        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+                      "no need to set security context: %s "
+                      "(uri=%s dir=%s user=%s remote=%s)",
+                      old_context,
+                      r->uri, sconf->dirname, r->user,
+                      r->connection->remote_ip);
+        return DECLINED;
+    }
+
+    if (setcon_raw(new_context) < 0) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r,
+                      "setcon_raw('%s') failed", new_context);
+        return HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+                  "set security context: %s -> %s "
+                  "(uri=%s dir=%s user=%s remote=%s)",
+                  old_context, new_context,
+                  r->uri, sconf->dirname, r->user,
+                  r->connection->remote_ip);
+    return DECLINED;
+}
+
+static void *
+selinux_create_dir_config(apr_pool_t *p, char *dirname)
+{
+    selinux_config *sconf
+        = apr_palloc(p, sizeof(selinux_config));
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL,
+                 "SELinux: create dir config at: %s", dirname);
+
+    sconf->dirname = apr_pstrdup(p, dirname);
+    sconf->config_file = NULL;
+    sconf->default_domain = NULL;
+
+    return sconf;
+}
+
+static const char *
+set_config_file(cmd_parms *cmd, void *mconfig, const char *v1)
+{
+    selinux_config *sconf
+        = ap_get_module_config(cmd->context, &selinux_module);
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server,
+                 "selinuxUserMappingFile = %s at %s",
+                 v1, sconf->dirname);
+
+    sconf->config_file = apr_pstrdup(cmd->pool, v1);
+
+    return NULL;
+}
+
+static const char *
+set_default_domain(cmd_parms *cmd, void *mconfig, const char *v1)
+{
+    selinux_config *sconf
+        = ap_get_module_config(cmd->context, &selinux_module);
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server,
+                 "selinuxDefaultDomain = %s at %s",
+                 v1, sconf->dirname);
+
+    sconf->default_domain = apr_pstrdup(cmd->pool, v1);
+
+    return NULL;
+}
+
+static void selinux_register_hooks(apr_pool_t *p)
+{
+    ap_hook_post_read_request(selinux_post_read_request,
+			      NULL, NULL, APR_HOOK_MIDDLE);
+    ap_hook_fixups(selinux_fixups, NULL, NULL, APR_HOOK_MIDDLE);
+}
+
+static const command_rec selinux_cmds[] = {
+    AP_INIT_TAKE1("selinuxConfigFile",
+                  set_config_file, NULL, OR_OPTIONS,
+                  "SELinux user/domain mapping file"),
+    AP_INIT_TAKE1("selinuxDefaultDomain",
+                  set_default_domain, NULL, OR_OPTIONS,
+                  "SELinux default security context"),
+    {NULL},
+};
+
+module AP_MODULE_DECLARE_DATA selinux_module =
+{
+    STANDARD20_MODULE_STUFF,
+    selinux_create_dir_config,  /* create per-directory config */
+    NULL,                       /* merge per-directory config */
+    NULL,                       /* server config creator */
+    NULL,                       /* server config merger */
+    selinux_cmds,               /* command table */
+    selinux_register_hooks,     /* set up other hooks */
+};
Index: httpd-devel/modules/arch/unix/config5.m4
===================================================================
--- httpd-devel/modules/arch/unix/config5.m4	(revision 763518)
+++ httpd-devel/modules/arch/unix/config5.m4	(working copy)
@@ -3,7 +3,7 @@
 
 if test "$APACHE_MPM" = "simple" -o "$APACHE_MPM" = "worker" \
    -o "$APACHE_MPM" = "event" -o "$APACHE_MPM" = "prefork" \
-   -o "$APACHE_MPM" = "shared"; then
+   -o "$APACHE_MPM" = "shared" -o "$APACHE_MPM" = "security"; then
   unixd_mods_enable=yes
 else
   unixd_mods_enable=no
@@ -18,5 +18,11 @@
   fi
 ])
 
+APACHE_MODULE(selinux, Apache/SELinux plus support, , , no, [
+  AC_CHECK_LIB(selinux, getcon_raw,
+    [APR_ADDTO(MOD_SELINUX_LDADD, [-lselinux])],
+    [AC_MSG_ERROR([libselinux is not installed])]
+  )
+])
 APACHE_MODPATH_FINISH
 

Reply via email to