2010-12-20 12:29:10 -08:00
|
|
|
/*
|
2006-04-11 21:52:54 +00:00
|
|
|
* Copyright (c) 2004, 2005, 2006 NOVELL (All rights reserved)
|
|
|
|
*
|
|
|
|
* The mod_apparmor module is licensed under the terms of the GNU
|
|
|
|
* Lesser General Public License, version 2.1. Please see the file
|
|
|
|
* COPYING.LGPL.
|
|
|
|
*
|
|
|
|
* mod_apparmor - (apache 2.0.x)
|
|
|
|
* Author: Steve Beattie <sbeattie@suse.de>
|
|
|
|
*
|
|
|
|
* This currently only implements change_hat functionality, but could be
|
|
|
|
* extended for other stuff we decide to do.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "ap_config.h"
|
|
|
|
#include "httpd.h"
|
|
|
|
#include "http_config.h"
|
|
|
|
#include "http_request.h"
|
|
|
|
#include "http_log.h"
|
2014-01-23 13:38:31 -08:00
|
|
|
#include "http_main.h"
|
2006-04-11 21:52:54 +00:00
|
|
|
#include "http_protocol.h"
|
|
|
|
#include "util_filter.h"
|
|
|
|
#include "apr.h"
|
|
|
|
#include "apr_strings.h"
|
|
|
|
#include "apr_lib.h"
|
|
|
|
|
2014-01-09 11:57:13 -08:00
|
|
|
#include <sys/apparmor.h>
|
2006-04-11 21:52:54 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
/* #define DEBUG */
|
|
|
|
#ifndef __unused
|
|
|
|
#define __unused __attribute__((unused))
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* should the following be configurable? */
|
|
|
|
#define DEFAULT_HAT "HANDLING_UNTRUSTED_INPUT"
|
|
|
|
#define DEFAULT_URI_HAT "DEFAULT_URI"
|
|
|
|
|
2014-01-23 13:38:31 -08:00
|
|
|
/* Compatibility with apache 2.2 */
|
|
|
|
#if AP_SERVER_MAJORVERSION_NUMBER == 2 && AP_SERVER_MINORVERSION_NUMBER < 3
|
2014-01-23 13:40:19 -08:00
|
|
|
#define APLOG_TRACE1 APLOG_DEBUG
|
2014-01-23 13:38:31 -08:00
|
|
|
server_rec *ap_server_conf = NULL;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef APLOG_USE_MODULE
|
|
|
|
APLOG_USE_MODULE(apparmor);
|
|
|
|
#endif
|
2006-04-11 21:52:54 +00:00
|
|
|
module AP_MODULE_DECLARE_DATA apparmor_module;
|
|
|
|
|
2014-01-23 13:43:36 -08:00
|
|
|
static unsigned long magic_token = 0;
|
2006-04-11 21:52:54 +00:00
|
|
|
static int inside_default_hat = 0;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
const char * hat_name;
|
|
|
|
char * path;
|
|
|
|
} immunix_dir_cfg;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
const char * hat_name;
|
|
|
|
int is_initialized;
|
|
|
|
} immunix_srv_cfg;
|
|
|
|
|
|
|
|
/* immunix_init() gets invoked in the post_config stage of apache.
|
|
|
|
* Unfortunately, apache reads its config once when it starts up, then
|
|
|
|
* it re-reads it when goes into its restart loop, where it starts it's
|
|
|
|
* children. This means we cannot call change_hat here, as the modules
|
|
|
|
* memory will be wiped out, and the magic_token will be lost, so apache
|
|
|
|
* wouldn't be able to change_hat back out. */
|
|
|
|
static int
|
|
|
|
immunix_init (apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
|
|
|
|
{
|
|
|
|
apr_file_t * file;
|
|
|
|
apr_size_t size = sizeof (magic_token);
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = apr_file_open (&file, "/dev/urandom", APR_READ, APR_OS_DEFAULT, p);
|
|
|
|
if (!ret) {
|
|
|
|
apr_file_read (file, (void *) &magic_token, &size);
|
|
|
|
apr_file_close (file);
|
|
|
|
} else {
|
2014-01-23 13:38:31 -08:00
|
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, "Failed to open /dev/urandom");
|
2006-04-11 21:52:54 +00:00
|
|
|
}
|
2014-01-23 13:40:19 -08:00
|
|
|
ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, ap_server_conf, "Opened /dev/urandom successfully");
|
2006-04-11 21:52:54 +00:00
|
|
|
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* As each child starts up, we'll change_hat into a default hat, mostly
|
|
|
|
* to protect ourselves from bugs in parsing network input, but before
|
|
|
|
* we change_hat to the uri specific hat. */
|
|
|
|
static void
|
|
|
|
immunix_child_init (apr_pool_t *p, server_rec *s)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2014-01-23 13:40:19 -08:00
|
|
|
ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, ap_server_conf, "init: calling change_hat");
|
2014-01-23 13:43:36 -08:00
|
|
|
ret = aa_change_hat(DEFAULT_HAT, magic_token);
|
2006-04-11 21:52:54 +00:00
|
|
|
if (ret < 0) {
|
2014-01-23 13:43:36 -08:00
|
|
|
aa_change_hat(NULL, magic_token);
|
2014-01-23 13:38:31 -08:00
|
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, "Failed to change_hat to '%s'",
|
2006-04-11 21:52:54 +00:00
|
|
|
DEFAULT_HAT);
|
|
|
|
} else {
|
|
|
|
inside_default_hat = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2014-01-23 13:41:57 -08:00
|
|
|
debug_dump_uri(request_rec *r)
|
2006-04-11 21:52:54 +00:00
|
|
|
{
|
2014-01-23 13:41:57 -08:00
|
|
|
apr_uri_t *uri = &r->parsed_uri;
|
|
|
|
if (uri)
|
|
|
|
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "Dumping uri info "
|
2006-04-11 21:52:54 +00:00
|
|
|
"scheme='%s' host='%s' path='%s' query='%s' fragment='%s'",
|
|
|
|
uri->scheme, uri->hostname, uri->path, uri->query,
|
|
|
|
uri->fragment);
|
|
|
|
else
|
2014-01-23 13:41:57 -08:00
|
|
|
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "Asked to dump NULL uri");
|
2006-04-11 21:52:54 +00:00
|
|
|
|
|
|
|
}
|
2014-01-23 13:41:57 -08:00
|
|
|
|
2006-04-11 21:52:54 +00:00
|
|
|
/*
|
|
|
|
immunix_enter_hat will attempt to change_hat in the following order:
|
|
|
|
(1) to a hatname in a location directive
|
|
|
|
(2) to the uri
|
|
|
|
(3) to a per-server default
|
|
|
|
(4) to DEFAULT_URI
|
|
|
|
(5) back to the parent profile
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
immunix_enter_hat (request_rec *r)
|
|
|
|
{
|
|
|
|
int sd_ret = -1;
|
|
|
|
immunix_dir_cfg * dcfg = (immunix_dir_cfg *)
|
|
|
|
ap_get_module_config (r->per_dir_config, &apparmor_module);
|
|
|
|
immunix_srv_cfg * scfg = (immunix_srv_cfg *)
|
|
|
|
ap_get_module_config (r->server->module_config, &apparmor_module);
|
|
|
|
|
2014-01-23 13:41:57 -08:00
|
|
|
debug_dump_uri(r);
|
2014-01-23 13:40:19 -08:00
|
|
|
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "in immunix_enter_hat (%s) n:0x%lx p:0x%lx main:0x%lx",
|
2006-04-11 21:52:54 +00:00
|
|
|
dcfg->path, (unsigned long) r->next, (unsigned long) r->prev,
|
|
|
|
(unsigned long) r->main);
|
|
|
|
|
|
|
|
/* We only call change_hat for the main request, not subrequests */
|
|
|
|
if (r->main)
|
|
|
|
return OK;
|
|
|
|
|
|
|
|
if (inside_default_hat) {
|
2014-01-23 13:43:36 -08:00
|
|
|
aa_change_hat(NULL, magic_token);
|
2006-04-11 21:52:54 +00:00
|
|
|
inside_default_hat = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dcfg != NULL && dcfg->hat_name != NULL) {
|
2014-01-23 13:38:31 -08:00
|
|
|
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "calling change_hat [dcfg] %s", dcfg->hat_name);
|
2014-01-23 13:43:36 -08:00
|
|
|
sd_ret = aa_change_hat(dcfg->hat_name, magic_token);
|
2006-04-11 21:52:54 +00:00
|
|
|
if (sd_ret < 0) {
|
2014-01-23 13:43:36 -08:00
|
|
|
aa_change_hat(NULL, magic_token);
|
2006-04-11 21:52:54 +00:00
|
|
|
} else {
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-23 13:38:31 -08:00
|
|
|
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "calling change_hat [uri] %s", r->uri);
|
2014-01-23 13:43:36 -08:00
|
|
|
sd_ret = aa_change_hat(r->uri, magic_token);
|
2006-04-11 21:52:54 +00:00
|
|
|
if (sd_ret < 0) {
|
2014-01-23 13:43:36 -08:00
|
|
|
aa_change_hat(NULL, magic_token);
|
2006-04-11 21:52:54 +00:00
|
|
|
} else {
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (scfg != NULL && scfg->hat_name != NULL) {
|
2014-01-23 13:38:31 -08:00
|
|
|
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "calling change_hat [scfg] %s", scfg->hat_name);
|
2014-01-23 13:43:36 -08:00
|
|
|
sd_ret = aa_change_hat(scfg->hat_name, magic_token);
|
2006-04-11 21:52:54 +00:00
|
|
|
if (sd_ret < 0) {
|
2014-01-23 13:43:36 -08:00
|
|
|
aa_change_hat(NULL, magic_token);
|
2006-04-11 21:52:54 +00:00
|
|
|
} else {
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-23 13:38:31 -08:00
|
|
|
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "calling change_hat DEFAULT_URI");
|
2014-01-23 13:43:36 -08:00
|
|
|
sd_ret = aa_change_hat(DEFAULT_URI_HAT, magic_token);
|
|
|
|
if (sd_ret < 0) aa_change_hat(NULL, magic_token);
|
2006-04-11 21:52:54 +00:00
|
|
|
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
immunix_exit_hat (request_rec *r)
|
|
|
|
{
|
|
|
|
int sd_ret;
|
|
|
|
immunix_dir_cfg * dcfg = (immunix_dir_cfg *)
|
|
|
|
ap_get_module_config (r->per_dir_config, &apparmor_module);
|
|
|
|
/* immunix_srv_cfg * scfg = (immunix_srv_cfg *)
|
|
|
|
ap_get_module_config (r->server->module_config, &apparmor_module); */
|
2014-01-23 13:40:19 -08:00
|
|
|
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "exiting change_hat - dir hat %s path %s", dcfg->hat_name, dcfg->path);
|
2014-01-23 13:43:36 -08:00
|
|
|
aa_change_hat(NULL, magic_token);
|
2006-04-11 21:52:54 +00:00
|
|
|
|
2014-01-23 13:43:36 -08:00
|
|
|
sd_ret = aa_change_hat(DEFAULT_HAT, magic_token);
|
2006-04-11 21:52:54 +00:00
|
|
|
if (sd_ret < 0) {
|
2014-01-23 13:43:36 -08:00
|
|
|
aa_change_hat(NULL, magic_token);
|
2014-01-23 13:38:31 -08:00
|
|
|
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Failed to change_hat to '%s'",
|
2006-04-11 21:52:54 +00:00
|
|
|
DEFAULT_HAT);
|
|
|
|
} else {
|
|
|
|
inside_default_hat = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
aa_cmd_ch_path (cmd_parms * cmd, void * mconfig, const char * parm1)
|
|
|
|
{
|
2014-01-23 13:38:31 -08:00
|
|
|
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, "directory config change hat %s",
|
2006-04-11 21:52:54 +00:00
|
|
|
parm1 ? parm1 : "DEFAULT");
|
|
|
|
immunix_dir_cfg * dcfg = mconfig;
|
|
|
|
if (parm1 != NULL) {
|
|
|
|
dcfg->hat_name = parm1;
|
|
|
|
} else {
|
|
|
|
dcfg->hat_name = "DEFAULT";
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int path_warn_once;
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
immunix_cmd_ch_path (cmd_parms * cmd, void * mconfig, const char * parm1)
|
|
|
|
{
|
|
|
|
if (path_warn_once == 0) {
|
2014-01-23 13:38:31 -08:00
|
|
|
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, "ImmHatName is "
|
2006-04-11 21:52:54 +00:00
|
|
|
"deprecated, please use AAHatName instead");
|
|
|
|
path_warn_once = 1;
|
|
|
|
}
|
|
|
|
return aa_cmd_ch_path(cmd, mconfig, parm1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
aa_cmd_ch_srv (cmd_parms * cmd, void * mconfig, const char * parm1)
|
|
|
|
{
|
2014-01-23 13:38:31 -08:00
|
|
|
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, "server config change hat %s",
|
2006-04-11 21:52:54 +00:00
|
|
|
parm1 ? parm1 : "DEFAULT");
|
|
|
|
immunix_srv_cfg * scfg = mconfig;
|
|
|
|
if (parm1 != NULL) {
|
|
|
|
scfg->hat_name = parm1;
|
|
|
|
} else {
|
|
|
|
scfg->hat_name = "DEFAULT";
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int srv_warn_once;
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
immunix_cmd_ch_srv (cmd_parms * cmd, void * mconfig, const char * parm1)
|
|
|
|
{
|
|
|
|
if (srv_warn_once == 0) {
|
2014-01-23 13:38:31 -08:00
|
|
|
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, "ImmDefaultHatName is "
|
2006-04-11 21:52:54 +00:00
|
|
|
"deprecated, please use AADefaultHatName instead");
|
|
|
|
srv_warn_once = 1;
|
|
|
|
}
|
|
|
|
return aa_cmd_ch_srv(cmd, mconfig, parm1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *
|
|
|
|
immunix_create_dir_config (apr_pool_t * p, char * path)
|
|
|
|
{
|
|
|
|
immunix_dir_cfg * newcfg = (immunix_dir_cfg *) apr_pcalloc(p, sizeof(* newcfg));
|
|
|
|
|
2014-01-23 13:40:19 -08:00
|
|
|
ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, ap_server_conf, "in immunix_create_dir (%s)", path ? path : ":no path:");
|
2006-04-11 21:52:54 +00:00
|
|
|
if (newcfg == NULL) {
|
2014-01-23 13:38:31 -08:00
|
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, "immunix_create_dir: couldn't alloc dir config");
|
2006-04-11 21:52:54 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
newcfg->path = apr_pstrdup (p, path ? path : ":no path:");
|
|
|
|
|
|
|
|
return newcfg;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX: Should figure out an appropriate action to take here, if any
|
|
|
|
|
|
|
|
static void *
|
|
|
|
immunix_merge_dir_config (apr_pool_t * p, void * parent, void * child)
|
|
|
|
{
|
|
|
|
immunix_dir_cfg * newcfg = (immunix_dir_cfg *) apr_pcalloc(p, sizeof(* newcfg));
|
|
|
|
|
2014-01-23 13:40:19 -08:00
|
|
|
ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, ap_server_conf, "in immunix_merge_dir ()");
|
2006-04-11 21:52:54 +00:00
|
|
|
if (newcfg == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return newcfg;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void *
|
|
|
|
immunix_create_srv_config (apr_pool_t * p, server_rec * srv)
|
|
|
|
{
|
|
|
|
immunix_srv_cfg * newcfg = (immunix_srv_cfg *) apr_pcalloc(p, sizeof(* newcfg));
|
|
|
|
|
2014-01-23 13:40:19 -08:00
|
|
|
ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, ap_server_conf, "in immunix_create_srv");
|
2006-04-11 21:52:54 +00:00
|
|
|
if (newcfg == NULL) {
|
2014-01-23 13:38:31 -08:00
|
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, "immunix_create_srv: couldn't alloc srv config");
|
2006-04-11 21:52:54 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return newcfg;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static const command_rec immunix_cmds[] = {
|
|
|
|
|
|
|
|
AP_INIT_TAKE1 (
|
|
|
|
"ImmHatName",
|
|
|
|
immunix_cmd_ch_path,
|
|
|
|
NULL,
|
|
|
|
ACCESS_CONF,
|
|
|
|
""
|
|
|
|
),
|
|
|
|
AP_INIT_TAKE1 (
|
|
|
|
"ImmDefaultHatName",
|
|
|
|
immunix_cmd_ch_srv,
|
|
|
|
NULL,
|
|
|
|
RSRC_CONF,
|
|
|
|
""
|
|
|
|
),
|
|
|
|
AP_INIT_TAKE1 (
|
|
|
|
"AAHatName",
|
|
|
|
aa_cmd_ch_path,
|
|
|
|
NULL,
|
|
|
|
ACCESS_CONF,
|
|
|
|
""
|
|
|
|
),
|
|
|
|
AP_INIT_TAKE1 (
|
|
|
|
"AADefaultHatName",
|
|
|
|
aa_cmd_ch_srv,
|
|
|
|
NULL,
|
|
|
|
RSRC_CONF,
|
|
|
|
""
|
|
|
|
),
|
|
|
|
{ NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
register_hooks (apr_pool_t *p)
|
|
|
|
{
|
|
|
|
ap_hook_post_config (immunix_init, NULL, NULL, APR_HOOK_MIDDLE);
|
|
|
|
ap_hook_child_init (immunix_child_init, NULL, NULL, APR_HOOK_MIDDLE);
|
|
|
|
ap_hook_access_checker(immunix_enter_hat, NULL, NULL, APR_HOOK_FIRST);
|
|
|
|
/* ap_hook_post_read_request(immunix_enter_hat, NULL, NULL, APR_HOOK_FIRST); */
|
|
|
|
ap_hook_log_transaction(immunix_exit_hat, NULL, NULL, APR_HOOK_LAST);
|
|
|
|
}
|
|
|
|
|
|
|
|
module AP_MODULE_DECLARE_DATA apparmor_module = {
|
|
|
|
STANDARD20_MODULE_STUFF,
|
|
|
|
immunix_create_dir_config, /* dir config creater */
|
|
|
|
NULL, /* dir merger --- default is to override */
|
|
|
|
/* immunix_merge_dir_config, */ /* dir merger --- default is to override */
|
|
|
|
immunix_create_srv_config, /* server config */
|
|
|
|
NULL, /* merge server config */
|
|
|
|
immunix_cmds, /* command table */
|
|
|
|
register_hooks /* register hooks */
|
|
|
|
};
|