mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-30 13:58:22 +00:00
merge apparmor trunk back into the tree
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
#include "http_config.h"
|
||||
#include "http_request.h"
|
||||
#include "http_log.h"
|
||||
#include "http_main.h"
|
||||
#include "http_protocol.h"
|
||||
#include "util_filter.h"
|
||||
#include "apr.h"
|
||||
@@ -35,9 +36,18 @@
|
||||
#define DEFAULT_HAT "HANDLING_UNTRUSTED_INPUT"
|
||||
#define DEFAULT_URI_HAT "DEFAULT_URI"
|
||||
|
||||
/* Compatibility with apache 2.2 */
|
||||
#if AP_SERVER_MAJORVERSION_NUMBER == 2 && AP_SERVER_MINORVERSION_NUMBER < 3
|
||||
#define APLOG_TRACE1 APLOG_DEBUG
|
||||
server_rec *ap_server_conf = NULL;
|
||||
#endif
|
||||
|
||||
#ifdef APLOG_USE_MODULE
|
||||
APLOG_USE_MODULE(apparmor);
|
||||
#endif
|
||||
module AP_MODULE_DECLARE_DATA apparmor_module;
|
||||
|
||||
static unsigned int magic_token = 0;
|
||||
static unsigned long magic_token = 0;
|
||||
static int inside_default_hat = 0;
|
||||
|
||||
typedef struct {
|
||||
@@ -68,9 +78,10 @@ immunix_init (apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
|
||||
apr_file_read (file, (void *) &magic_token, &size);
|
||||
apr_file_close (file);
|
||||
} else {
|
||||
ap_log_error (APLOG_MARK, APLOG_ERR, 0, NULL, "Failed to open /dev/urandom");
|
||||
ap_log_error(APLOG_MARK, APLOG_ERR, errno, ap_server_conf,
|
||||
"Failed to open /dev/urandom");
|
||||
}
|
||||
ap_log_error (APLOG_MARK, APLOG_DEBUG, 0, NULL, "Opened /dev/urandom successfully");
|
||||
ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, ap_server_conf, "Opened /dev/urandom successfully");
|
||||
|
||||
return OK;
|
||||
}
|
||||
@@ -83,34 +94,30 @@ immunix_child_init (apr_pool_t *p, server_rec *s)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ap_log_error (APLOG_MARK, APLOG_DEBUG, 0, NULL, "init: calling change_hat");
|
||||
ret = change_hat (DEFAULT_HAT, magic_token);
|
||||
ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, ap_server_conf,
|
||||
"init: calling change_hat with '%s'", DEFAULT_HAT);
|
||||
ret = aa_change_hat(DEFAULT_HAT, magic_token);
|
||||
if (ret < 0) {
|
||||
change_hat (NULL, magic_token);
|
||||
ap_log_error (APLOG_MARK, APLOG_ERR, 0, NULL, "Failed to change_hat to '%s'",
|
||||
DEFAULT_HAT);
|
||||
ap_log_error(APLOG_MARK, APLOG_ERR, errno, ap_server_conf,
|
||||
"Failed to change_hat to '%s'", DEFAULT_HAT);
|
||||
} else {
|
||||
inside_default_hat = 1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static void
|
||||
debug_dump_uri (apr_uri_t * uri)
|
||||
debug_dump_uri(request_rec *r)
|
||||
{
|
||||
apr_uri_t *uri = &r->parsed_uri;
|
||||
if (uri)
|
||||
ap_log_error (APLOG_MARK, APLOG_ERR, 0, NULL, "Dumping uri info "
|
||||
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "Dumping uri info "
|
||||
"scheme='%s' host='%s' path='%s' query='%s' fragment='%s'",
|
||||
uri->scheme, uri->hostname, uri->path, uri->query,
|
||||
uri->fragment);
|
||||
else
|
||||
ap_log_error (APLOG_MARK, APLOG_ERR, 0, NULL, "Asked to dump NULL uri");
|
||||
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "Asked to dump NULL uri");
|
||||
|
||||
}
|
||||
#else
|
||||
static void
|
||||
debug_dump_uri (apr_uri_t * __unused uri) { }
|
||||
#endif
|
||||
|
||||
/*
|
||||
immunix_enter_hat will attempt to change_hat in the following order:
|
||||
@@ -128,9 +135,12 @@ immunix_enter_hat (request_rec *r)
|
||||
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);
|
||||
const char *aa_hat_array[5] = { NULL, NULL, NULL, NULL, NULL };
|
||||
int i = 0;
|
||||
char *aa_con, *aa_mode, *aa_hat;
|
||||
|
||||
debug_dump_uri (&r->parsed_uri);
|
||||
ap_log_error (APLOG_MARK, APLOG_DEBUG, 0, NULL, "in immunix_enter_hat (%s) n:0x%lx p:0x%lx main:0x%lx",
|
||||
debug_dump_uri(r);
|
||||
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "in immunix_enter_hat (%s) n:0x%lx p:0x%lx main:0x%lx",
|
||||
dcfg->path, (unsigned long) r->next, (unsigned long) r->prev,
|
||||
(unsigned long) r->main);
|
||||
|
||||
@@ -139,41 +149,79 @@ immunix_enter_hat (request_rec *r)
|
||||
return OK;
|
||||
|
||||
if (inside_default_hat) {
|
||||
change_hat (NULL, magic_token);
|
||||
aa_change_hat(NULL, magic_token);
|
||||
inside_default_hat = 0;
|
||||
}
|
||||
|
||||
if (dcfg != NULL && dcfg->hat_name != NULL) {
|
||||
ap_log_error (APLOG_MARK, APLOG_DEBUG, 0, NULL, "calling change_hat [dcfg] %s", dcfg->hat_name);
|
||||
sd_ret = change_hat (dcfg->hat_name, magic_token);
|
||||
if (sd_ret < 0) {
|
||||
change_hat (NULL, magic_token);
|
||||
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
|
||||
"[dcfg] adding hat '%s' to aa_change_hat vector", dcfg->hat_name);
|
||||
aa_hat_array[i++] = dcfg->hat_name;
|
||||
}
|
||||
|
||||
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
|
||||
"[uri] adding uri '%s' to aa_change_hat vector", r->uri);
|
||||
aa_hat_array[i++] = r->uri;
|
||||
|
||||
if (scfg) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "Dumping scfg info: "
|
||||
"scfg='0x%lx' scfg->hat_name='%s'",
|
||||
(unsigned long) scfg, scfg->hat_name);
|
||||
} else {
|
||||
return OK;
|
||||
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "scfg is null");
|
||||
}
|
||||
if (scfg != NULL) {
|
||||
if (scfg->hat_name != NULL) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
|
||||
"[scfg] adding hat '%s' to aa_change_hat vector", scfg->hat_name);
|
||||
aa_hat_array[i++] = scfg->hat_name;
|
||||
} else {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
|
||||
"[scfg] adding server_name '%s' to aa_change_hat vector",
|
||||
r->server->server_hostname);
|
||||
aa_hat_array[i++] = r->server->server_hostname;
|
||||
}
|
||||
}
|
||||
|
||||
ap_log_error (APLOG_MARK, APLOG_DEBUG, 0, NULL, "calling change_hat [uri] %s", r->uri);
|
||||
sd_ret = change_hat (r->uri, magic_token);
|
||||
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
|
||||
"[default] adding '%s' to aa_change_hat vector", DEFAULT_URI_HAT);
|
||||
aa_hat_array[i++] = DEFAULT_URI_HAT;
|
||||
|
||||
sd_ret = aa_change_hatv(aa_hat_array, magic_token);
|
||||
if (sd_ret < 0) {
|
||||
change_hat (NULL, magic_token);
|
||||
} else {
|
||||
return OK;
|
||||
ap_log_rerror(APLOG_MARK, APLOG_WARNING, errno, r, "aa_change_hatv call failed");
|
||||
}
|
||||
|
||||
if (scfg != NULL && scfg->hat_name != NULL) {
|
||||
ap_log_error (APLOG_MARK, APLOG_DEBUG, 0, NULL, "calling change_hat [scfg] %s", scfg->hat_name);
|
||||
sd_ret = change_hat (scfg->hat_name, magic_token);
|
||||
/* Check to see if a defined AAHatName or AADefaultHatName would
|
||||
* apply, but wasn't the hat we landed up in; report a warning if
|
||||
* that's the case. */
|
||||
sd_ret = aa_getcon(&aa_con, &aa_mode);
|
||||
if (sd_ret < 0) {
|
||||
change_hat (NULL, magic_token);
|
||||
ap_log_rerror(APLOG_MARK, APLOG_WARNING, errno, r, "aa_getcon call failed");
|
||||
} else {
|
||||
return OK;
|
||||
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
|
||||
"AA checks: aa_getcon result is '%s', mode '%s'", aa_con, aa_mode);
|
||||
/* TODO: use libapparmor get hat_name fn here once it is implemented */
|
||||
aa_hat = strstr(aa_con, "//");
|
||||
if (aa_hat != NULL && strcmp(aa_mode, "enforce") == 0) {
|
||||
aa_hat += 2; /* skip "//" */
|
||||
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
|
||||
"AA checks: apache is in hat '%s', mode '%s'", aa_hat, aa_mode);
|
||||
if (dcfg != NULL && dcfg->hat_name != NULL) {
|
||||
if (strcmp(aa_hat, dcfg->hat_name) != 0)
|
||||
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
|
||||
"AAHatName '%s' applies, but does not appear to be a hat in the apache apparmor policy",
|
||||
dcfg->hat_name);
|
||||
} else if (scfg != NULL && scfg->hat_name != NULL) {
|
||||
if (strcmp(aa_hat, scfg->hat_name) != 0 &&
|
||||
strcmp(aa_hat, r->uri) != 0)
|
||||
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
|
||||
"AADefaultHatName '%s' applies, but does not appear to be a hat in the apache apparmor policy",
|
||||
scfg->hat_name);
|
||||
}
|
||||
}
|
||||
|
||||
ap_log_error (APLOG_MARK, APLOG_DEBUG, 0, NULL, "calling change_hat DEFAULT_URI");
|
||||
sd_ret = change_hat (DEFAULT_URI_HAT, magic_token);
|
||||
if (sd_ret < 0) change_hat (NULL, magic_token);
|
||||
free(aa_con);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
@@ -186,14 +234,18 @@ immunix_exit_hat (request_rec *r)
|
||||
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); */
|
||||
ap_log_error (APLOG_MARK, APLOG_DEBUG, 0, NULL, "exiting change_hat - dir hat %s path %s", dcfg->hat_name, dcfg->path);
|
||||
change_hat (NULL, magic_token);
|
||||
ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "exiting change_hat: dir hat %s dir path %s",
|
||||
dcfg->hat_name, dcfg->path);
|
||||
|
||||
sd_ret = change_hat (DEFAULT_HAT, magic_token);
|
||||
/* can convert the following back to aa_change_hat() when the
|
||||
* aa_change_hat() bug addressed in trunk commit 2329 lands in most
|
||||
* system libapparmors */
|
||||
aa_change_hatv(NULL, magic_token);
|
||||
|
||||
sd_ret = aa_change_hat(DEFAULT_HAT, magic_token);
|
||||
if (sd_ret < 0) {
|
||||
change_hat (NULL, magic_token);
|
||||
ap_log_error (APLOG_MARK, APLOG_ERR, 0, NULL, "Failed to change_hat to '%s'",
|
||||
DEFAULT_HAT);
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r,
|
||||
"Failed to change_hat to '%s'", DEFAULT_HAT);
|
||||
} else {
|
||||
inside_default_hat = 1;
|
||||
}
|
||||
@@ -204,7 +256,7 @@ immunix_exit_hat (request_rec *r)
|
||||
static const char *
|
||||
aa_cmd_ch_path (cmd_parms * cmd, void * mconfig, const char * parm1)
|
||||
{
|
||||
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, "config change hat %s",
|
||||
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, "directory config change hat %s",
|
||||
parm1 ? parm1 : "DEFAULT");
|
||||
immunix_dir_cfg * dcfg = mconfig;
|
||||
if (parm1 != NULL) {
|
||||
@@ -221,7 +273,7 @@ static const char *
|
||||
immunix_cmd_ch_path (cmd_parms * cmd, void * mconfig, const char * parm1)
|
||||
{
|
||||
if (path_warn_once == 0) {
|
||||
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, "ImmHatName is "
|
||||
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, "ImmHatName is "
|
||||
"deprecated, please use AAHatName instead");
|
||||
path_warn_once = 1;
|
||||
}
|
||||
@@ -231,9 +283,10 @@ immunix_cmd_ch_path (cmd_parms * cmd, void * mconfig, const char * parm1)
|
||||
static const char *
|
||||
aa_cmd_ch_srv (cmd_parms * cmd, void * mconfig, const char * parm1)
|
||||
{
|
||||
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, "config change hat %s",
|
||||
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, "server config change hat %s",
|
||||
parm1 ? parm1 : "DEFAULT");
|
||||
immunix_srv_cfg * scfg = mconfig;
|
||||
immunix_srv_cfg * scfg = (immunix_srv_cfg *)
|
||||
ap_get_module_config(cmd->server->module_config, &apparmor_module);
|
||||
if (parm1 != NULL) {
|
||||
scfg->hat_name = parm1;
|
||||
} else {
|
||||
@@ -248,7 +301,7 @@ static const char *
|
||||
immunix_cmd_ch_srv (cmd_parms * cmd, void * mconfig, const char * parm1)
|
||||
{
|
||||
if (srv_warn_once == 0) {
|
||||
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, "ImmDefaultHatName is "
|
||||
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, "ImmDefaultHatName is "
|
||||
"deprecated, please use AADefaultHatName instead");
|
||||
srv_warn_once = 1;
|
||||
}
|
||||
@@ -260,9 +313,9 @@ immunix_create_dir_config (apr_pool_t * p, char * path)
|
||||
{
|
||||
immunix_dir_cfg * newcfg = (immunix_dir_cfg *) apr_pcalloc(p, sizeof(* newcfg));
|
||||
|
||||
ap_log_error (APLOG_MARK, APLOG_DEBUG, 0, NULL, "in immunix_create_dir (%s)", path ? path : ":no path:");
|
||||
ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, ap_server_conf, "in immunix_create_dir (%s)", path ? path : ":no path:");
|
||||
if (newcfg == NULL) {
|
||||
ap_log_error (APLOG_MARK, APLOG_ERR, 0, NULL, "immunix_create_dir: couldn't alloc dir config");
|
||||
ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, "immunix_create_dir: couldn't alloc dir config");
|
||||
return NULL;
|
||||
}
|
||||
newcfg->path = apr_pstrdup (p, path ? path : ":no path:");
|
||||
@@ -277,7 +330,7 @@ immunix_merge_dir_config (apr_pool_t * p, void * parent, void * child)
|
||||
{
|
||||
immunix_dir_cfg * newcfg = (immunix_dir_cfg *) apr_pcalloc(p, sizeof(* newcfg));
|
||||
|
||||
ap_log_error (APLOG_MARK, APLOG_DEBUG, 0, NULL, "in immunix_merge_dir ()");
|
||||
ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, ap_server_conf, "in immunix_merge_dir ()");
|
||||
if (newcfg == NULL)
|
||||
return NULL;
|
||||
|
||||
@@ -290,9 +343,9 @@ immunix_create_srv_config (apr_pool_t * p, server_rec * srv)
|
||||
{
|
||||
immunix_srv_cfg * newcfg = (immunix_srv_cfg *) apr_pcalloc(p, sizeof(* newcfg));
|
||||
|
||||
ap_log_error (APLOG_MARK, APLOG_DEBUG, 0, NULL, "in immunix_create_srv");
|
||||
ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, ap_server_conf, "in immunix_create_srv");
|
||||
if (newcfg == NULL) {
|
||||
ap_log_error (APLOG_MARK, APLOG_ERR, 0, NULL, "immunix_create_srv: couldn't alloc srv config");
|
||||
ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, "immunix_create_srv: couldn't alloc srv config");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@@ -41,10 +41,12 @@ apparmor is also functioning.
|
||||
|
||||
Once mod_apparmor is loaded within Apache, all requests to Apache will
|
||||
cause mod_apparmor to attempt to change into a hat named by the URI
|
||||
(e.g. /app/some.cgi). If no such hat is found, it will fall back to
|
||||
(e.g. /app/some.cgi). If no such hat is found, it will first fall
|
||||
back by attempting to change into a hat that matches the ServerName
|
||||
for the server/vhost. If that hat is not found, it will fall back to
|
||||
attempting to use the hat DEFAULT_URI; if that also does not exist,
|
||||
it will fall back to using the global Apache profile. Most static web
|
||||
pages can simply make use of the DEFAULT_URI hat.
|
||||
it will fall back to using the global Apache profile. Most static
|
||||
web pages can simply make use of the DEFAULT_URI hat.
|
||||
|
||||
Additionally, before any requests come in to Apache, mod_apparmor
|
||||
will attempt to change hat into the HANDLING_UNTRUSTED_INPUT hat.
|
||||
@@ -70,13 +72,14 @@ behavior described above.
|
||||
|
||||
=item B<AADefaultHatName>
|
||||
|
||||
AADefaultHatName allows you to specify a default hat to be used for
|
||||
virtual hosts and other Apache server directives, so that you can have
|
||||
different defaults for different virtual hosts. This can be overridden by
|
||||
the AAHatName directive and is checked for only if there isn't a matching
|
||||
AAHatName or hat named by the URI. If the AADefaultHatName hat does not
|
||||
exist, it falls back to the DEFAULT_URI hat if it exists (as described
|
||||
above).
|
||||
AADefaultHatName allows you to specify a default hat to be used
|
||||
for virtual hosts and other Apache server directives, so that you
|
||||
can have different defaults for different virtual hosts. This can
|
||||
be overridden by the AAHatName directive and is checked for only if
|
||||
there isn't a matching AAHatName or hat named by the URI. The default
|
||||
value of AADefaultHatName is the ServerName for the server/vhost
|
||||
configuration. If the AADefaultHatName hat does not exist, it falls
|
||||
back to the DEFAULT_URI hat if it exists (as described above).
|
||||
|
||||
=back
|
||||
|
||||
@@ -98,8 +101,9 @@ applies, otherwise it will
|
||||
|
||||
2. try to aa_change_hat(2) into the URI itself, otherwise it will
|
||||
|
||||
3. try to aa_change_hat(2) into an AADefaultHatName hat if it has been defined
|
||||
for the server/vhost, otherwise it will
|
||||
3. try to aa_change_hat(2) into an AADefaultHatName hat, either the
|
||||
ServerName (the default) or the configuration value specified by the
|
||||
AADefaultHatName directive, for the server/vhost, otherwise it will
|
||||
|
||||
4. try to aa_change_hat(2) into the DEFAULT_URI hat, if it exists, otherwise it
|
||||
will
|
||||
@@ -112,7 +116,8 @@ will
|
||||
|
||||
mod_apparmor() currently only supports apache2, and has only been tested
|
||||
with the prefork MPM configuration -- threaded configurations of Apache
|
||||
may not work correctly.
|
||||
may not work correctly. For Apache 2.4 users, you should enable the mpm_prefork
|
||||
module.
|
||||
|
||||
There are likely other bugs lurking about; if you find any, please report
|
||||
them at L<https://bugs.launchpad.net/apparmor/+filebug>.
|
||||
|
69
deprecated/utils/Makefile
Normal file
69
deprecated/utils/Makefile
Normal file
@@ -0,0 +1,69 @@
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 1999, 2004-2009 NOVELL (All rights reserved)
|
||||
# Copyright (c) 2010-2011, 2014 Canonical Ltd.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Novell, Inc.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
# NOTE: this Makefile has been adjusted from the original to assist in
|
||||
# the installation of the Immunix perl modules, if they're still needed
|
||||
# by users. Because the utilities conflict with their replacments, make
|
||||
# install *will* *not* install them.
|
||||
|
||||
NAME = apparmor-utils
|
||||
all:
|
||||
COMMONDIR=../../common/
|
||||
|
||||
include common/Make.rules
|
||||
|
||||
COMMONDIR_EXISTS=$(strip $(shell [ -d ${COMMONDIR} ] && echo true))
|
||||
ifeq ($(COMMONDIR_EXISTS), true)
|
||||
common/Make.rules: $(COMMONDIR)/Make.rules
|
||||
ln -sf $(COMMONDIR) .
|
||||
endif
|
||||
|
||||
MODDIR = Immunix
|
||||
PERLTOOLS = aa-genprof aa-logprof aa-autodep aa-audit aa-complain aa-enforce \
|
||||
aa-unconfined aa-disable
|
||||
MODULES = ${MODDIR}/AppArmor.pm ${MODDIR}/Repository.pm \
|
||||
${MODDIR}/Config.pm ${MODDIR}/Severity.pm
|
||||
|
||||
all:
|
||||
|
||||
# need some better way of determining this
|
||||
DESTDIR=/
|
||||
BINDIR=${DESTDIR}/usr/sbin
|
||||
CONFDIR=${DESTDIR}/etc/apparmor
|
||||
VENDOR_PERL=$(shell perl -e 'use Config; print $$Config{"vendorlib"};')
|
||||
PERLDIR=${DESTDIR}${VENDOR_PERL}/${MODDIR}
|
||||
|
||||
.PHONY: install
|
||||
install:
|
||||
install -d ${PERLDIR}
|
||||
install -m 644 ${MODULES} ${PERLDIR}
|
||||
|
||||
.PHONY: clean
|
||||
ifndef VERBOSE
|
||||
.SILENT: clean
|
||||
endif
|
||||
clean: _clean
|
||||
rm -f core core.* *.o *.s *.a *~
|
||||
rm -f Make.rules
|
||||
rm -rf staging/ build/
|
||||
|
||||
.PHONY: check
|
||||
.SILENT: check
|
||||
check:
|
||||
for i in ${MODULES} ${PERLTOOLS} ; do \
|
||||
perl -c $$i || exit 1; \
|
||||
done
|
132
deprecated/utils/aa-audit
Executable file
132
deprecated/utils/aa-audit
Executable file
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/perl
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2005 Novell, Inc. All Rights Reserved.
|
||||
# Copyright (c) 2011 Canonical, Ltd.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Novell, Inc.
|
||||
#
|
||||
# To contact Novell about this file by physical or electronic mail,
|
||||
# you may find current contact information at www.novell.com.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
use strict;
|
||||
use FindBin;
|
||||
use Getopt::Long;
|
||||
|
||||
use Immunix::AppArmor;
|
||||
|
||||
use Data::Dumper;
|
||||
|
||||
use Locale::gettext;
|
||||
use POSIX;
|
||||
|
||||
# initialize the local poo
|
||||
setlocale(LC_MESSAGES, "");
|
||||
textdomain("apparmor-utils");
|
||||
|
||||
$UI_Mode = "text";
|
||||
|
||||
# options variables
|
||||
my $help = '';
|
||||
|
||||
GetOptions(
|
||||
'dir|d=s' => \$profiledir,
|
||||
'help|h' => \$help,
|
||||
);
|
||||
|
||||
# tell 'em how to use it...
|
||||
&usage && exit if $help;
|
||||
|
||||
# let's convert it to full path...
|
||||
$profiledir = get_full_path($profiledir);
|
||||
|
||||
unless (-d $profiledir) {
|
||||
UI_Important("Can't find AppArmor profiles in $profiledir.");
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# what are we profiling?
|
||||
my @profiling = @ARGV;
|
||||
|
||||
unless (@profiling) {
|
||||
@profiling = (UI_GetString("Please enter the program to switch to audit mode: ", ""));
|
||||
}
|
||||
|
||||
for my $profiling (@profiling) {
|
||||
|
||||
next unless $profiling;
|
||||
|
||||
my $fqdbin;
|
||||
if (-e $profiling) {
|
||||
$fqdbin = get_full_path($profiling);
|
||||
chomp($fqdbin);
|
||||
} else {
|
||||
if ($profiling !~ /\//) {
|
||||
opendir(DIR,$profiledir);
|
||||
my @tmp_fqdbin = grep ( /$profiling/, readdir(DIR));
|
||||
closedir(DIR);
|
||||
if (scalar @tmp_fqdbin eq 1) {
|
||||
$fqdbin = "$profiledir/$tmp_fqdbin[0]";
|
||||
} else {
|
||||
my $which = which($profiling);
|
||||
if ($which) {
|
||||
$fqdbin = get_full_path($which);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-e $fqdbin) {
|
||||
|
||||
my $filename;
|
||||
if ($fqdbin =~ /^$profiledir\//) {
|
||||
$filename = $fqdbin;
|
||||
} else {
|
||||
$filename = getprofilefilename($fqdbin);
|
||||
}
|
||||
|
||||
# argh, skip directories
|
||||
next unless -f $filename;
|
||||
|
||||
# skip rpm backup files
|
||||
next if isSkippableFile($filename);
|
||||
|
||||
printf(gettext('Setting %s to audit mode.'), $fqdbin);
|
||||
print "\n";
|
||||
setprofileflags($filename, "audit");
|
||||
|
||||
my $cmd_info = qx(cat $filename | $parser -I$profiledir -r 2>&1 1>/dev/null);
|
||||
if ($? != 0) {
|
||||
UI_Info($cmd_info);
|
||||
exit $?;
|
||||
}
|
||||
|
||||
# if check_for_subdomain();
|
||||
} else {
|
||||
if ($profiling =~ /^[^\/]+$/) {
|
||||
UI_Info(sprintf(gettext('Can\'t find %s in the system path list. If the name of the application is correct, please run \'which %s\' as a user with the correct PATH environment set up in order to find the fully-qualified path.'), $profiling, $profiling));
|
||||
exit 1;
|
||||
} else {
|
||||
UI_Info(sprintf(gettext('%s does not exist, please double-check the path.'), $profiling));
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit 0;
|
||||
|
||||
sub usage {
|
||||
UI_Info(sprintf(gettext("usage: \%s [ -d /path/to/profiles ] [ program to switch to audit mode ]"), $0));
|
||||
exit 0;
|
||||
}
|
||||
|
122
deprecated/utils/aa-autodep
Executable file
122
deprecated/utils/aa-autodep
Executable file
@@ -0,0 +1,122 @@
|
||||
#!/usr/bin/perl
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2005 Novell, Inc. All Rights Reserved.
|
||||
# Copyright (c) 2011 Canonical, Ltd.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Novell, Inc.
|
||||
#
|
||||
# To contact Novell about this file by physical or electronic mail,
|
||||
# you may find current contact information at www.novell.com.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
use strict;
|
||||
use FindBin;
|
||||
use Getopt::Long;
|
||||
|
||||
use Immunix::AppArmor;
|
||||
|
||||
use Data::Dumper;
|
||||
|
||||
use Locale::gettext;
|
||||
use POSIX;
|
||||
|
||||
# force $PATH to be sane
|
||||
$ENV{PATH} = "/bin:/sbin:/usr/bin:/usr/sbin";
|
||||
|
||||
# initialize the local poo
|
||||
setlocale(LC_MESSAGES, "");
|
||||
textdomain("apparmor-utils");
|
||||
|
||||
$UI_Mode = "text";
|
||||
|
||||
# options variables
|
||||
my $help = '';
|
||||
my $force = undef;
|
||||
|
||||
GetOptions(
|
||||
'force' => \$force,
|
||||
'dir|d=s' => \$profiledir,
|
||||
'help|h' => \$help,
|
||||
);
|
||||
|
||||
# tell 'em how to use it...
|
||||
&usage && exit if $help;
|
||||
|
||||
my $sd_mountpoint = check_for_subdomain();
|
||||
|
||||
# let's convert it to full path...
|
||||
$profiledir = get_full_path($profiledir);
|
||||
|
||||
unless (-d $profiledir) {
|
||||
UI_Important(sprintf(gettext('Can\'t find AppArmor profiles in %s.'), $profiledir));
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# what are we profiling?
|
||||
my @profiling = @ARGV;
|
||||
|
||||
unless (@profiling) {
|
||||
@profiling = (UI_GetString(gettext("Please enter the program to create a profile for: "), ""));
|
||||
}
|
||||
|
||||
for my $profiling (@profiling) {
|
||||
|
||||
next unless $profiling;
|
||||
|
||||
my $fqdbin;
|
||||
if (-e $profiling) {
|
||||
$fqdbin = get_full_path($profiling);
|
||||
chomp($fqdbin);
|
||||
} else {
|
||||
if ($profiling !~ /\//) {
|
||||
my $which = which($profiling);
|
||||
if ($which) {
|
||||
$fqdbin = get_full_path($which);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# make sure that the app they're requesting to profile is not marked as
|
||||
# not allowed to have it's own profile
|
||||
if ($qualifiers{$fqdbin}) {
|
||||
unless ($qualifiers{$fqdbin} =~ /p/) {
|
||||
UI_Info(sprintf(gettext('%s is currently marked as a program that should not have it\'s own profile. Usually, programs are marked this way if creating a profile for them is likely to break the rest of the system. If you know what you\'re doing and are certain you want to create a profile for this program, edit the corresponding entry in the [qualifiers] section in /etc/apparmor/logprof.conf.'), $fqdbin));
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (-e $fqdbin) {
|
||||
if (-e getprofilefilename($fqdbin) && !$force) {
|
||||
UI_Info(sprintf(gettext('Profile for %s already exists - skipping.'), $fqdbin));
|
||||
} else {
|
||||
autodep($fqdbin);
|
||||
reload($fqdbin) if $sd_mountpoint;
|
||||
}
|
||||
} else {
|
||||
if ($profiling =~ /^[^\/]+$/) {
|
||||
UI_Info(sprintf(gettext('Can\'t find %s in the system path list. If the name of the application is correct, please run \'which %s\' as a user with the correct PATH environment set up in order to find the fully-qualified path.'), $profiling, $profiling));
|
||||
exit 1;
|
||||
} else {
|
||||
UI_Info(sprintf(gettext('%s does not exist, please double-check the path.'), $profiling));
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit 0;
|
||||
|
||||
sub usage {
|
||||
UI_Info("usage: $0 [ --force ] [ -d /path/to/profiles ]");
|
||||
exit 0;
|
||||
}
|
||||
|
131
deprecated/utils/aa-complain
Executable file
131
deprecated/utils/aa-complain
Executable file
@@ -0,0 +1,131 @@
|
||||
#!/usr/bin/perl
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2005 Novell, Inc. All Rights Reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Novell, Inc.
|
||||
#
|
||||
# To contact Novell about this file by physical or electronic mail,
|
||||
# you may find current contact information at www.novell.com.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
use strict;
|
||||
use FindBin;
|
||||
use Getopt::Long;
|
||||
|
||||
use Immunix::AppArmor;
|
||||
|
||||
use Data::Dumper;
|
||||
|
||||
use Locale::gettext;
|
||||
use POSIX;
|
||||
|
||||
# initialize the local poo
|
||||
setlocale(LC_MESSAGES, "");
|
||||
textdomain("apparmor-utils");
|
||||
|
||||
$UI_Mode = "text";
|
||||
|
||||
# options variables
|
||||
my $help = '';
|
||||
|
||||
GetOptions(
|
||||
'dir|d=s' => \$profiledir,
|
||||
'help|h' => \$help,
|
||||
);
|
||||
|
||||
# tell 'em how to use it...
|
||||
&usage && exit if $help;
|
||||
|
||||
# let's convert it to full path...
|
||||
$profiledir = get_full_path($profiledir);
|
||||
|
||||
unless (-d $profiledir) {
|
||||
UI_Important("Can't find AppArmor profiles in $profiledir.");
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# what are we profiling?
|
||||
my @profiling = @ARGV;
|
||||
|
||||
unless (@profiling) {
|
||||
@profiling = (UI_GetString(gettext("Please enter the program to switch to complain mode: "), ""));
|
||||
}
|
||||
|
||||
for my $profiling (@profiling) {
|
||||
|
||||
next unless $profiling;
|
||||
|
||||
my $fqdbin;
|
||||
if (-e $profiling) {
|
||||
$fqdbin = get_full_path($profiling);
|
||||
chomp($fqdbin);
|
||||
} else {
|
||||
if ($profiling !~ /\//) {
|
||||
opendir(DIR,$profiledir);
|
||||
my @tmp_fqdbin = grep ( /$profiling/, readdir(DIR));
|
||||
closedir(DIR);
|
||||
if (scalar @tmp_fqdbin eq 1) {
|
||||
$fqdbin = "$profiledir/$tmp_fqdbin[0]";
|
||||
} else {
|
||||
my $which = which($profiling);
|
||||
if ($which) {
|
||||
$fqdbin = get_full_path($which);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-e $fqdbin) {
|
||||
|
||||
my $filename;
|
||||
if ($fqdbin =~ /^$profiledir\//) {
|
||||
$filename = $fqdbin;
|
||||
} else {
|
||||
$filename = getprofilefilename($fqdbin);
|
||||
}
|
||||
|
||||
# argh, skip directories
|
||||
next unless -f $filename;
|
||||
|
||||
# skip rpm backup files
|
||||
next if isSkippableFile($filename);
|
||||
|
||||
printf(gettext('Setting %s to complain mode.'), $fqdbin);
|
||||
print "\n";
|
||||
setprofileflags($filename, "complain");
|
||||
|
||||
my $cmd_info = qx(cat $filename | $parser -I$profiledir -r 2>&1 1>/dev/null);
|
||||
if ($? != 0) {
|
||||
UI_Info($cmd_info);
|
||||
exit $?;
|
||||
}
|
||||
|
||||
# if check_for_subdomain();
|
||||
} else {
|
||||
if ($profiling =~ /^[^\/]+$/) {
|
||||
UI_Info(sprintf(gettext('Can\'t find %s in the system path list. If the name of the application is correct, please run \'which %s\' as a user with the correct PATH environment set up in order to find the fully-qualified path.'), $profiling, $profiling));
|
||||
exit 1;
|
||||
} else {
|
||||
UI_Info(sprintf(gettext('%s does not exist, please double-check the path.'), $profiling));
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit 0;
|
||||
|
||||
sub usage {
|
||||
UI_Info(sprintf(gettext("usage: \%s [ -d /path/to/profiles ] [ program to switch to complain mode ]"), $0));
|
||||
exit 0;
|
||||
}
|
||||
|
152
deprecated/utils/aa-disable
Executable file
152
deprecated/utils/aa-disable
Executable file
@@ -0,0 +1,152 @@
|
||||
#!/usr/bin/perl
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2005-2010 Novell, Inc. All Rights Reserved.
|
||||
# Copyright (c) 2011 Canonical, Inc. All Rights Reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Canonical, Inc.
|
||||
#
|
||||
# To contact Canonical about this file by physical or electronic mail,
|
||||
# you may find current contact information at www.canonical.com.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
use strict;
|
||||
use FindBin;
|
||||
use Getopt::Long;
|
||||
|
||||
use Immunix::AppArmor;
|
||||
|
||||
use Data::Dumper;
|
||||
|
||||
use Locale::gettext;
|
||||
use POSIX;
|
||||
use File::Basename;
|
||||
|
||||
# initialize the local poo
|
||||
setlocale(LC_MESSAGES, "");
|
||||
textdomain("apparmor-utils");
|
||||
|
||||
$UI_Mode = "text";
|
||||
|
||||
# options variables
|
||||
my $help = '';
|
||||
|
||||
GetOptions(
|
||||
'dir|d=s' => \$profiledir,
|
||||
'help|h' => \$help,
|
||||
);
|
||||
|
||||
# tell 'em how to use it...
|
||||
&usage && exit if $help;
|
||||
|
||||
# let's convert it to full path...
|
||||
$profiledir = get_full_path($profiledir);
|
||||
|
||||
unless (-d $profiledir) {
|
||||
UI_Important("Can't find AppArmor profiles in $profiledir.");
|
||||
exit 1;
|
||||
}
|
||||
|
||||
my $disabledir = "$profiledir/disable";
|
||||
unless (-d $disabledir) {
|
||||
UI_Important("Can't find AppArmor disable directory '$disabledir'.");
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# what are we profiling?
|
||||
my @profiling = @ARGV;
|
||||
|
||||
unless (@profiling) {
|
||||
@profiling = (UI_GetString(gettext("Please enter the program whose profile should be disabled: "), ""));
|
||||
}
|
||||
|
||||
for my $profiling (@profiling) {
|
||||
|
||||
next unless $profiling;
|
||||
|
||||
my $fqdbin;
|
||||
if (-e $profiling) {
|
||||
$fqdbin = get_full_path($profiling);
|
||||
chomp($fqdbin);
|
||||
} else {
|
||||
if ($profiling !~ /\//) {
|
||||
opendir(DIR,$profiledir);
|
||||
my @tmp_fqdbin = grep ( /$profiling/, readdir(DIR));
|
||||
closedir(DIR);
|
||||
if (scalar @tmp_fqdbin eq 1) {
|
||||
$fqdbin = "$profiledir/$tmp_fqdbin[0]";
|
||||
} else {
|
||||
my $which = which($profiling);
|
||||
if ($which) {
|
||||
$fqdbin = get_full_path($which);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-e $fqdbin) {
|
||||
|
||||
my $filename;
|
||||
if ($fqdbin =~ /^$profiledir\//) {
|
||||
$filename = $fqdbin;
|
||||
} else {
|
||||
$filename = getprofilefilename($fqdbin);
|
||||
}
|
||||
|
||||
# argh, skip directories
|
||||
next unless -f $filename;
|
||||
|
||||
# skip package manager backup files
|
||||
next if isSkippableFile($filename);
|
||||
|
||||
my ($bname, $dname, $suffix) = File::Basename::fileparse($filename);
|
||||
if ($bname eq "") {
|
||||
UI_Info(sprintf(gettext('Could not find basename for %s.'), $filename));
|
||||
exit 1;
|
||||
}
|
||||
|
||||
printf(gettext('Disabling %s.'), $fqdbin);
|
||||
print "\n";
|
||||
|
||||
my $link = "$disabledir/$bname";
|
||||
if (! -e $link) {
|
||||
if (symlink($filename, $link) != 1) {
|
||||
UI_Info(sprintf(gettext('Could not create %s symlink.'), $link));
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
|
||||
my $cmd_info = qx(cat $filename | $parser -I$profiledir -R 2>&1 1>/dev/null);
|
||||
if ($? != 0) {
|
||||
UI_Info($cmd_info);
|
||||
exit $?;
|
||||
}
|
||||
|
||||
# if check_for_subdomain();
|
||||
} else {
|
||||
if ($profiling =~ /^[^\/]+$/) {
|
||||
UI_Info(sprintf(gettext('Can\'t find %s in the system path list. If the name of the application is correct, please run \'which %s\' as a user with the correct PATH environment set up in order to find the fully-qualified path.'), $profiling, $profiling));
|
||||
exit 1;
|
||||
} else {
|
||||
UI_Info(sprintf(gettext('%s does not exist, please double-check the path.'), $profiling));
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit 0;
|
||||
|
||||
sub usage {
|
||||
UI_Info(sprintf(gettext("usage: \%s [ -d /path/to/profiles ] [ program to have profile disabled ]"), $0));
|
||||
exit 0;
|
||||
}
|
||||
|
142
deprecated/utils/aa-enforce
Executable file
142
deprecated/utils/aa-enforce
Executable file
@@ -0,0 +1,142 @@
|
||||
#!/usr/bin/perl
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2005 Novell, Inc. All Rights Reserved.
|
||||
# Copyright (c) 2011 Canonical, Ltd.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Novell, Inc.
|
||||
#
|
||||
# To contact Novell about this file by physical or electronic mail,
|
||||
# you may find current contact information at www.novell.com.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
use strict;
|
||||
use FindBin;
|
||||
use Getopt::Long;
|
||||
|
||||
use Immunix::AppArmor;
|
||||
|
||||
use Data::Dumper;
|
||||
|
||||
use Locale::gettext;
|
||||
use POSIX;
|
||||
|
||||
# initialize the local poo
|
||||
setlocale(LC_MESSAGES, "");
|
||||
textdomain("apparmor-utils");
|
||||
|
||||
$UI_Mode = "text";
|
||||
|
||||
# options variables
|
||||
my $help = '';
|
||||
|
||||
GetOptions(
|
||||
'dir|d=s' => \$profiledir,
|
||||
'help|h' => \$help,
|
||||
);
|
||||
|
||||
# tell 'em how to use it...
|
||||
&usage && exit if $help;
|
||||
|
||||
# let's convert it to full path...
|
||||
$profiledir = get_full_path($profiledir);
|
||||
|
||||
unless (-d $profiledir) {
|
||||
UI_Important("Can't find AppArmor profiles in $profiledir.");
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# what are we profiling?
|
||||
my @profiling = @ARGV;
|
||||
|
||||
unless (@profiling) {
|
||||
@profiling = (UI_GetString(gettext("Please enter the program to switch to enforce mode: "), ""));
|
||||
}
|
||||
|
||||
for my $profiling (@profiling) {
|
||||
|
||||
next unless $profiling;
|
||||
|
||||
my $fqdbin;
|
||||
if (-e $profiling) {
|
||||
$fqdbin = get_full_path($profiling);
|
||||
chomp($fqdbin);
|
||||
} else {
|
||||
if ($profiling !~ /\//) {
|
||||
opendir(DIR,$profiledir);
|
||||
my @tmp_fqdbin = grep ( /$profiling/, readdir(DIR));
|
||||
closedir(DIR);
|
||||
if (scalar @tmp_fqdbin eq 1) {
|
||||
$fqdbin = "$profiledir/$tmp_fqdbin[0]";
|
||||
} else {
|
||||
my $which = which($profiling);
|
||||
if ($which) {
|
||||
$fqdbin = get_full_path($which);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-e $fqdbin) {
|
||||
my $filename;
|
||||
if ($fqdbin =~ /^$profiledir\//) {
|
||||
$filename = $fqdbin;
|
||||
} else {
|
||||
$filename = getprofilefilename($fqdbin);
|
||||
}
|
||||
|
||||
# argh, skip directories
|
||||
next unless -f $filename;
|
||||
|
||||
# skip rpm backup files
|
||||
next if isSkippableFile($filename);
|
||||
|
||||
printf(gettext('Setting %s to enforce mode.'), $fqdbin);
|
||||
print "\n";
|
||||
setprofileflags($filename, "");
|
||||
|
||||
# remove symlink in $profiledir/force-complain as well
|
||||
my $complainlink = $filename;
|
||||
$complainlink =~ s/^$profiledir/$profiledir\/force-complain/;
|
||||
-e $complainlink and unlink($complainlink);
|
||||
|
||||
# remove symlink in $profiledir/disable as well
|
||||
my $disablelink = $filename;
|
||||
$disablelink =~ s/^$profiledir/$profiledir\/disable/;
|
||||
-e $disablelink and unlink($disablelink);
|
||||
|
||||
my $cmd_info = qx(cat $filename | $parser -I$profiledir -r 2>&1 1>/dev/null);
|
||||
if ($? != 0) {
|
||||
UI_Info($cmd_info);
|
||||
exit $?;
|
||||
}
|
||||
|
||||
|
||||
# if check_for_subdomain();
|
||||
} else {
|
||||
if ($profiling =~ /^[^\/]+$/) {
|
||||
UI_Info(sprintf(gettext('Can\'t find %s in the system path list. If the name of the application is correct, please run \'which %s\' as a user with the correct PATH environment set up in order to find the fully-qualified path.'), $profiling, $profiling));
|
||||
exit 1;
|
||||
} else {
|
||||
UI_Info(sprintf(gettext('%s does not exist, please double-check the path.'), $profiling));
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit 0;
|
||||
|
||||
sub usage {
|
||||
UI_Info(sprintf(gettext("usage: \%s [ -d /path/to/profiles ] [ program to switch to enforce mode ]"), $0));
|
||||
exit 0;
|
||||
}
|
||||
|
216
deprecated/utils/aa-genprof
Executable file
216
deprecated/utils/aa-genprof
Executable file
@@ -0,0 +1,216 @@
|
||||
#!/usr/bin/perl
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2005 Novell, Inc. All Rights Reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Novell, Inc.
|
||||
#
|
||||
# To contact Novell about this file by physical or electronic mail,
|
||||
# you may find current contact information at www.novell.com.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
use strict;
|
||||
use Getopt::Long;
|
||||
|
||||
use Immunix::AppArmor;
|
||||
|
||||
use Data::Dumper;
|
||||
|
||||
use Locale::gettext;
|
||||
use POSIX;
|
||||
|
||||
sub sysctl_read($) {
|
||||
my $path = shift;
|
||||
my $value = undef;
|
||||
if (open(SYSCTL, "<$path")) {
|
||||
$value = int(<SYSCTL>);
|
||||
}
|
||||
close(SYSCTL);
|
||||
return $value;
|
||||
}
|
||||
|
||||
sub sysctl_write($$) {
|
||||
my $path = shift;
|
||||
my $value = shift;
|
||||
return if (!defined($value));
|
||||
if (open(SYSCTL, ">$path")) {
|
||||
print SYSCTL $value;
|
||||
close(SYSCTl);
|
||||
}
|
||||
}
|
||||
|
||||
# force $PATH to be sane
|
||||
$ENV{PATH} = "/bin:/sbin:/usr/bin:/usr/sbin";
|
||||
|
||||
# initialize the local poo
|
||||
setlocale(LC_MESSAGES, "");
|
||||
textdomain("apparmor-utils");
|
||||
|
||||
# options variables
|
||||
my $help = '';
|
||||
|
||||
GetOptions(
|
||||
'file|f=s' => \$filename,
|
||||
'dir|d=s' => \$profiledir,
|
||||
'help|h' => \$help,
|
||||
);
|
||||
|
||||
# tell 'em how to use it...
|
||||
&usage && exit if $help;
|
||||
|
||||
my $sd_mountpoint = check_for_subdomain();
|
||||
unless ($sd_mountpoint) {
|
||||
fatal_error(gettext("AppArmor does not appear to be started. Please enable AppArmor and try again."));
|
||||
}
|
||||
|
||||
# let's convert it to full path...
|
||||
$profiledir = get_full_path($profiledir);
|
||||
|
||||
unless (-d $profiledir) {
|
||||
fatal_error "Can't find AppArmor profiles in $profiledir.";
|
||||
}
|
||||
|
||||
# what are we profiling?
|
||||
my $profiling = shift;
|
||||
|
||||
unless ($profiling) {
|
||||
$profiling = UI_GetString(gettext("Please enter the program to profile: "), "")
|
||||
|| exit 0;
|
||||
}
|
||||
|
||||
my $fqdbin;
|
||||
if (-e $profiling) {
|
||||
$fqdbin = get_full_path($profiling);
|
||||
chomp($fqdbin);
|
||||
} else {
|
||||
if ($profiling !~ /\//) {
|
||||
my $which = which($profiling);
|
||||
if ($which) {
|
||||
$fqdbin = get_full_path($which);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unless ($fqdbin && -e $fqdbin) {
|
||||
if ($profiling =~ /^[^\/]+$/) {
|
||||
fatal_error(sprintf(gettext('Can\'t find %s in the system path list. If the name of the application is correct, please run \'which %s\' in the other window in order to find the fully-qualified path.'), $profiling, $profiling));
|
||||
} else {
|
||||
fatal_error(sprintf(gettext('%s does not exist, please double-check the path.'), $profiling));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# make sure that the app they're requesting to profile is not marked as
|
||||
# not allowed to have it's own profile
|
||||
check_qualifiers($fqdbin);
|
||||
|
||||
# load all the include files
|
||||
loadincludes();
|
||||
|
||||
my $profilefilename = getprofilefilename($fqdbin);
|
||||
if (-e $profilefilename) {
|
||||
$helpers{$fqdbin} = getprofileflags($profilefilename) || "enforce";
|
||||
} else {
|
||||
autodep($fqdbin);
|
||||
$helpers{$fqdbin} = "enforce";
|
||||
}
|
||||
|
||||
if ($helpers{$fqdbin} eq "enforce") {
|
||||
complain($fqdbin);
|
||||
reload($fqdbin);
|
||||
}
|
||||
|
||||
# When reading from syslog, it is possible to hit the default kernel
|
||||
# printk ratelimit. This will result in audit entries getting skipped,
|
||||
# making profile generation inaccurate. When using genprof, disable
|
||||
# the printk ratelimit, and restore it on exit.
|
||||
my $ratelimit_sysctl = "/proc/sys/kernel/printk_ratelimit";
|
||||
my $ratelimit_saved = sysctl_read($ratelimit_sysctl);
|
||||
END { sysctl_write($ratelimit_sysctl, $ratelimit_saved); }
|
||||
sysctl_write($ratelimit_sysctl, 0);
|
||||
|
||||
UI_Info(gettext("\nBefore you begin, you may wish to check if a\nprofile already exists for the application you\nwish to confine. See the following wiki page for\nmore information:\nhttp://wiki.apparmor.net/index.php/Profiles"));
|
||||
|
||||
UI_Important(gettext("Please start the application to be profiled in \nanother window and exercise its functionality now.\n\nOnce completed, select the \"Scan\" button below in \norder to scan the system logs for AppArmor events. \n\nFor each AppArmor event, you will be given the \nopportunity to choose whether the access should be \nallowed or denied."));
|
||||
|
||||
my $syslog = 1;
|
||||
my $logmark = "";
|
||||
my $done_profiling = 0;
|
||||
|
||||
$syslog = 0 if (-e "/var/log/audit/audit.log");
|
||||
|
||||
while (not $done_profiling) {
|
||||
if ($syslog) {
|
||||
$logmark = `date | md5sum`;
|
||||
chomp $logmark;
|
||||
$logmark = $1 if $logmark =~ /^([0-9a-f]+)/;
|
||||
system("$logger -p kern.warn 'GenProf: $logmark'");
|
||||
} else {
|
||||
$logmark = last_audit_entry_time();
|
||||
}
|
||||
eval {
|
||||
|
||||
my $q = {};
|
||||
$q->{headers} = [ gettext("Profiling"), $fqdbin ];
|
||||
$q->{functions} = [ "CMD_SCAN", "CMD_FINISHED" ];
|
||||
$q->{default} = "CMD_SCAN";
|
||||
|
||||
my ($ans, $arg) = UI_PromptUser($q);
|
||||
|
||||
if ($ans eq "CMD_SCAN") {
|
||||
|
||||
my $lp_ret = do_logprof_pass($logmark);
|
||||
|
||||
$done_profiling = 1 if $lp_ret eq "FINISHED";
|
||||
|
||||
} else {
|
||||
|
||||
$done_profiling = 1;
|
||||
|
||||
}
|
||||
};
|
||||
if ($@) {
|
||||
if ($@ =~ /FINISHING/) {
|
||||
$done_profiling = 1;
|
||||
} else {
|
||||
die $@;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for my $p (sort keys %helpers) {
|
||||
if ($helpers{$p} eq "enforce") {
|
||||
enforce($p);
|
||||
reload($p);
|
||||
}
|
||||
}
|
||||
|
||||
UI_Info(gettext("Reloaded AppArmor profiles in enforce mode."));
|
||||
UI_Info(gettext("\nPlease consider contributing your new profile! See\nthe following wiki page for more information:\nhttp://wiki.apparmor.net/index.php/Profiles\n"));
|
||||
UI_Info(sprintf(gettext('Finished generating profile for %s.'), $fqdbin));
|
||||
exit 0;
|
||||
|
||||
sub usage {
|
||||
UI_Info(sprintf(gettext("usage: \%s [ -d /path/to/profiles ] [ -f /path/to/logfile ] [ program to profile ]"), $0));
|
||||
exit 0;
|
||||
}
|
||||
|
||||
sub last_audit_entry_time {
|
||||
local $_ = `tail -1 /var/log/audit/audit.log`;
|
||||
my $logmark;
|
||||
if (/^*msg\=audit\((\d+\.\d+\:\d+).*\).*$/) {
|
||||
$logmark = $1;
|
||||
} else {
|
||||
$logmark = "";
|
||||
}
|
||||
return $logmark;
|
||||
}
|
72
deprecated/utils/aa-logprof
Executable file
72
deprecated/utils/aa-logprof
Executable file
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/perl
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2005 Novell, Inc. All Rights Reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Novell, Inc.
|
||||
#
|
||||
# To contact Novell about this file by physical or electronic mail,
|
||||
# you may find current contact information at www.novell.com.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
use strict;
|
||||
use Data::Dumper;
|
||||
use Getopt::Long;
|
||||
use Locale::gettext;
|
||||
use POSIX;
|
||||
|
||||
use Immunix::AppArmor;
|
||||
|
||||
# force $PATH to be sane
|
||||
$ENV{PATH} = "/bin:/sbin:/usr/bin:/usr/sbin";
|
||||
|
||||
# initialize the local poo
|
||||
setlocale(LC_MESSAGES, "");
|
||||
textdomain("apparmor-utils");
|
||||
|
||||
setup_yast();
|
||||
|
||||
# options variables
|
||||
my $help = '';
|
||||
my $logmark;
|
||||
|
||||
GetOptions(
|
||||
'file|f=s' => \$filename,
|
||||
'dir|d=s' => \$profiledir,
|
||||
'logmark|m=s' => \$logmark,
|
||||
'help|h' => \$help,
|
||||
);
|
||||
|
||||
# tell 'em how to use it...
|
||||
&usage && exit if $help;
|
||||
|
||||
# let's convert it to full path...
|
||||
$profiledir = get_full_path($profiledir);
|
||||
|
||||
unless (-d $profiledir) {
|
||||
fatal_error "Can't find AppArmor profiles in $profiledir.";
|
||||
}
|
||||
|
||||
# load all the include files
|
||||
loadincludes();
|
||||
|
||||
do_logprof_pass($logmark);
|
||||
|
||||
shutdown_yast();
|
||||
|
||||
exit 0;
|
||||
|
||||
sub usage {
|
||||
UI_Info(sprintf(gettext("usage: \%s [ -d /path/to/profiles ] [ -f /path/to/logfile ] [ -m \"mark in log to start processing after\""), $0));
|
||||
exit 0;
|
||||
}
|
||||
|
113
deprecated/utils/aa-unconfined
Executable file
113
deprecated/utils/aa-unconfined
Executable file
@@ -0,0 +1,113 @@
|
||||
#!/usr/bin/perl -w
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2005 Novell, Inc. All Rights Reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Novell, Inc.
|
||||
#
|
||||
# To contact Novell about this file by physical or electronic mail,
|
||||
# you may find current contact information at www.novell.com.
|
||||
# ----------------------------------------------------------------------
|
||||
#
|
||||
# unconfined -
|
||||
# audit local system for processes listening on network connections
|
||||
# that are not currently running with a profile.
|
||||
|
||||
use strict;
|
||||
use Getopt::Long;
|
||||
|
||||
use Immunix::AppArmor;
|
||||
use Locale::gettext;
|
||||
use POSIX;
|
||||
|
||||
setlocale(LC_MESSAGES, "");
|
||||
textdomain("apparmor-utils");
|
||||
|
||||
# options variables
|
||||
my $paranoid = '';
|
||||
my $help = '';
|
||||
|
||||
GetOptions(
|
||||
'paranoid' => \$paranoid,
|
||||
'help|h' => \$help,
|
||||
);
|
||||
|
||||
# tell 'em how to use it...
|
||||
&usage && exit if $help;
|
||||
|
||||
sub usage {
|
||||
printf(gettext("Usage: %s [ --paranoid ]\n"), $0);
|
||||
exit 0;
|
||||
}
|
||||
|
||||
my $subdomainfs = check_for_subdomain();
|
||||
|
||||
die gettext("AppArmor does not appear to be started. Please enable AppArmor and try again.") . "\n"
|
||||
unless $subdomainfs;
|
||||
|
||||
my @pids;
|
||||
if ($paranoid) {
|
||||
opendir(PROC, "/proc") or die gettext("Can't read /proc\n");
|
||||
@pids = grep { /^\d+$/ } readdir(PROC);
|
||||
closedir(PROC);
|
||||
} else {
|
||||
if (open(NETSTAT, "LANG=C /bin/netstat -nlp |")) {
|
||||
while (<NETSTAT>) {
|
||||
chomp;
|
||||
push @pids, $5
|
||||
if /^(tcp|udp)\s+\d+\s+\d+\s+\S+\:(\d+)\s+\S+\:(\*|\d+)\s+(LISTEN|\s+)\s+(\d+)\/(\S+)/;
|
||||
}
|
||||
close(NETSTAT);
|
||||
}
|
||||
}
|
||||
|
||||
for my $pid (sort { $a <=> $b } @pids) {
|
||||
my $prog = readlink "/proc/$pid/exe" or next;
|
||||
my $attr;
|
||||
if (open(CURRENT, "/proc/$pid/attr/current")) {
|
||||
while (<CURRENT>) {
|
||||
chomp;
|
||||
$attr = $_ if (/^\// || /^null/);
|
||||
}
|
||||
close(CURRENT);
|
||||
}
|
||||
my $cmdline = `cat /proc/$pid/cmdline`;
|
||||
my $pname = (split(/\0/, $cmdline))[0];
|
||||
if ($pname =~ /\// && !($pname eq $prog)) {
|
||||
$pname = "($pname) ";
|
||||
} else {
|
||||
$pname = "";
|
||||
}
|
||||
if (not $attr) {
|
||||
if ($prog =~ m/^(\/usr\/bin\/python|\/usr\/bin\/perl|\/bin\/bash)$/) {
|
||||
|
||||
#my $scriptname = (split(/\0/, `cat /proc/$pid/cmdline`))[1];
|
||||
$cmdline =~ s/\0/ /g;
|
||||
$cmdline =~ s/\s+$//;
|
||||
chomp $cmdline;
|
||||
print "$pid $prog ($cmdline) " . gettext("not confined\n");
|
||||
} else {
|
||||
print "$pid $prog $pname" . gettext("not confined\n");
|
||||
}
|
||||
} else {
|
||||
if ($prog =~ m/^(\/usr\/bin\/python|\/usr\/bin\/perl|\/bin\/bash)$/) {
|
||||
|
||||
#my $scriptname = (split(/\0/, `cat /proc/$pid/cmdline`))[1];
|
||||
$cmdline =~ s/\0/ /g;
|
||||
$cmdline =~ s/\s+$//;
|
||||
chomp $cmdline;
|
||||
print "$pid $prog ($cmdline) " . gettext("confined by") . " '$attr'\n";
|
||||
} else {
|
||||
print "$pid $prog $pname" . gettext("confined by") . " '$attr'\n";
|
||||
}
|
||||
}
|
||||
}
|
@@ -18,8 +18,8 @@ INCLUDES = $(all_includes)
|
||||
# release, then
|
||||
# - set AA_LIB_AGE to 0.
|
||||
#
|
||||
AA_LIB_CURRENT = 1
|
||||
AA_LIB_REVISION = 2
|
||||
AA_LIB_CURRENT = 2
|
||||
AA_LIB_REVISION = 0
|
||||
AA_LIB_AGE = 0
|
||||
|
||||
SUFFIXES = .pc.in .pc
|
||||
|
@@ -355,7 +355,7 @@ int aa_change_hat(const char *subprofile, unsigned long token)
|
||||
int rc = -1;
|
||||
int len = 0;
|
||||
char *buf = NULL;
|
||||
const char *fmt = "changehat %016x^%s";
|
||||
const char *fmt = "changehat %016lx^%s";
|
||||
|
||||
/* both may not be null */
|
||||
if (!(token || subprofile)) {
|
||||
|
@@ -60,7 +60,7 @@ static inline Chars* insert_char_range(Chars* cset, uchar a, uchar b)
|
||||
%lex-param {YYLEX_PARAM}
|
||||
%parse-param {Node **root}
|
||||
%parse-param {const char *text}
|
||||
%name-prefix = "regex_"
|
||||
%name-prefix "regex_"
|
||||
|
||||
%token <c> CHAR
|
||||
%type <c> regex_char cset_char1 cset_char cset_charN
|
||||
|
@@ -177,8 +177,10 @@ static void process_name(const void *nodep, VISIT value, int __unused level)
|
||||
return;
|
||||
/* aliases create alternate names */
|
||||
alt = (struct alt_name *) calloc(1, sizeof(struct alt_name));
|
||||
if (!alt)
|
||||
if (!alt) {
|
||||
free(n);
|
||||
return;
|
||||
}
|
||||
alt->name = n;
|
||||
alt->next = prof->altnames;
|
||||
prof->altnames = alt;
|
||||
|
@@ -133,13 +133,19 @@ void set_base_dir(char *dir)
|
||||
int add_search_dir(const char *dir)
|
||||
{
|
||||
char *t;
|
||||
size_t len;
|
||||
|
||||
if (npath >= MAX_PATH) {
|
||||
PERROR(_("Error: Could not add directory %s to search path.\n"),
|
||||
dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dir || strlen(dir) <= 0)
|
||||
if (!dir)
|
||||
return 1;
|
||||
|
||||
len = strlen(dir);
|
||||
if (len == 0)
|
||||
return 1;
|
||||
|
||||
t = strdup(dir);
|
||||
@@ -149,8 +155,8 @@ int add_search_dir(const char *dir)
|
||||
}
|
||||
|
||||
/*strip trailing /'s */
|
||||
while (t[strlen(t) - 1] == '/')
|
||||
t[strlen(t) - 1] = 0;
|
||||
while (len > 0 && t[--len] == '/')
|
||||
t[len] = '\0';
|
||||
path[npath] = t;
|
||||
npath++;
|
||||
|
||||
|
@@ -273,8 +273,7 @@ LT_EQUAL <=
|
||||
|
||||
<INCLUDE>{
|
||||
(\<([^\> \t\n]+)\>|\"([^\" \t\n]+)\") { /* <filename> */
|
||||
char *filename = strdup(yytext);
|
||||
filename[strlen(filename) - 1] = '\0';
|
||||
char *filename = strndup(yytext, yyleng - 1);
|
||||
include_filename(filename + 1, *filename == '<');
|
||||
free(filename);
|
||||
yy_pop_state();
|
||||
@@ -488,7 +487,12 @@ LT_EQUAL <=
|
||||
}
|
||||
}
|
||||
|
||||
#include/.*\r?\n { PUSH(INCLUDE); }
|
||||
#include/.*\r?\n {
|
||||
/* Don't use push here as we don't want #include echoed out. It needs
|
||||
* to be handled specially
|
||||
*/
|
||||
yy_push_state(INCLUDE);
|
||||
}
|
||||
|
||||
#.*\r?\n { /* normal comment */
|
||||
DUMP_AND_DEBUG("comment(%d): %s\n", current_lineno, yytext);
|
||||
@@ -536,7 +540,6 @@ LT_EQUAL <=
|
||||
{OPEN_PAREN} { PUSH_AND_RETURN(LIST_VAL_MODE, TOK_OPENPAREN); }
|
||||
|
||||
{VARIABLE_NAME} {
|
||||
DUMP_PREPROCESS;
|
||||
int token = get_keyword_token(yytext);
|
||||
int state = INITIAL;
|
||||
|
||||
|
@@ -87,6 +87,8 @@ char *cacheloc = NULL;
|
||||
/* per-profile settings */
|
||||
int force_complain = 0;
|
||||
|
||||
/* Make sure to update BOTH the short and long_options */
|
||||
static const char *short_options = "adf:h::rRVvI:b:BCD:NSm:qQn:XKTWkL:O:po:";
|
||||
struct option long_options[] = {
|
||||
{"add", 0, 0, 'a'},
|
||||
{"binary", 0, 0, 'B'},
|
||||
@@ -570,7 +572,7 @@ static int process_arg(int c, char *optarg)
|
||||
break;
|
||||
default:
|
||||
display_usage(progname);
|
||||
exit(0);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -583,7 +585,7 @@ static int process_args(int argc, char *argv[])
|
||||
int count = 0;
|
||||
option = OPTION_ADD;
|
||||
|
||||
while ((c = getopt_long(argc, argv, "adf:h::rRVvI:b:BCD:NSm:qQn:XKTWkO:po:", long_options, &o)) != -1)
|
||||
while ((c = getopt_long(argc, argv, short_options, long_options, &o)) != -1)
|
||||
{
|
||||
count += process_arg(c, optarg);
|
||||
}
|
||||
@@ -611,6 +613,7 @@ static int process_config_file(const char *name)
|
||||
|
||||
while ((c = getopt_long_file(f, long_options, &optarg, &o)) != -1)
|
||||
process_arg(c, optarg);
|
||||
fclose(f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@@ -174,6 +174,9 @@ static struct keyword_table rlimit_table[] = {
|
||||
#endif
|
||||
#ifdef RLIMIT_RTPRIO
|
||||
{"rtprio", RLIMIT_RTPRIO},
|
||||
#endif
|
||||
#ifdef RLIMIT_RTTIME
|
||||
{"rttime", RLIMIT_RTTIME},
|
||||
#endif
|
||||
/* terminate */
|
||||
{NULL, 0}
|
||||
|
@@ -24,7 +24,10 @@
|
||||
#include <sys/apparmor.h>
|
||||
#define _(s) gettext(s)
|
||||
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
/* #define DEBUG */
|
||||
|
||||
@@ -39,9 +42,11 @@
|
||||
enum error_type {
|
||||
e_no_error,
|
||||
e_parse_error,
|
||||
e_buffer_overflow
|
||||
};
|
||||
|
||||
/* match any char except \000 0 or more times */
|
||||
static const char *default_match_pattern = "[^\\000]*";
|
||||
|
||||
/* Filters out multiple slashes (except if the first two are slashes,
|
||||
* that's a distinct namespace in linux) and trailing slashes.
|
||||
* NOTE: modifies in place the contents of the path argument */
|
||||
@@ -374,11 +379,6 @@ static pattern_t convert_aaregex_to_pcre(const char *aare, int anchor,
|
||||
}
|
||||
/* check error again, as above STORE may have set it */
|
||||
if (error != e_no_error) {
|
||||
if (error == e_buffer_overflow) {
|
||||
PERROR(_("%s: Internal buffer overflow detected, %d characters exceeded\n"),
|
||||
progname, PATH_MAX);
|
||||
}
|
||||
|
||||
PERROR(_("%s: Unable to parse input line '%s'\n"),
|
||||
progname, aare);
|
||||
|
||||
@@ -634,7 +634,7 @@ static int build_list_val_expr(std::string& buffer, struct value_list *list)
|
||||
int pos;
|
||||
|
||||
if (!list) {
|
||||
buffer.append("[^\\000]*");
|
||||
buffer.append(default_match_pattern);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -667,12 +667,18 @@ static int convert_entry(std::string& buffer, char *entry)
|
||||
if (ptype == ePatternInvalid)
|
||||
return FALSE;
|
||||
} else {
|
||||
buffer.append("[^\\000]*");
|
||||
buffer.append(default_match_pattern);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int clear_and_convert_entry(std::string& buffer, char *entry)
|
||||
{
|
||||
buffer.clear();
|
||||
return convert_entry(buffer, entry);
|
||||
}
|
||||
|
||||
static int build_mnt_flags(char *buffer, int size, unsigned int flags,
|
||||
unsigned int inv_flags)
|
||||
{
|
||||
@@ -681,7 +687,7 @@ static int build_mnt_flags(char *buffer, int size, unsigned int flags,
|
||||
|
||||
if (flags == MS_ALL_FLAGS) {
|
||||
/* all flags are optional */
|
||||
len = snprintf(p, size, "[^\\000]*");
|
||||
len = snprintf(p, size, "%s", default_match_pattern);
|
||||
if (len < 0 || len >= size)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
@@ -721,7 +727,7 @@ static int build_mnt_opts(std::string& buffer, struct value_list *opts)
|
||||
int pos;
|
||||
|
||||
if (!opts) {
|
||||
buffer.append("[^\\000]*");
|
||||
buffer.append(default_match_pattern);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -772,12 +778,9 @@ static int process_mnt_entry(aare_ruleset_t *dfarules, struct mnt_entry *entry)
|
||||
vec[0] = mntbuf.c_str();
|
||||
}
|
||||
/* skip device */
|
||||
devbuf.clear();
|
||||
if (!convert_entry(devbuf, NULL))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
vec[1] = default_match_pattern;
|
||||
/* skip type */
|
||||
vec[2] = devbuf.c_str();
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
flags = entry->flags;
|
||||
inv_flags = entry->inv_flags;
|
||||
@@ -823,14 +826,11 @@ static int process_mnt_entry(aare_ruleset_t *dfarules, struct mnt_entry *entry)
|
||||
if (!convert_entry(mntbuf, entry->mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
devbuf.clear();
|
||||
if (!convert_entry(devbuf, entry->device))
|
||||
if (!clear_and_convert_entry(devbuf, entry->device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
typebuf.clear();
|
||||
if (!convert_entry(typebuf, NULL))
|
||||
goto fail;
|
||||
vec[2] = typebuf.c_str();
|
||||
/* skip type */
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
flags = entry->flags;
|
||||
inv_flags = entry->inv_flags;
|
||||
@@ -858,11 +858,8 @@ static int process_mnt_entry(aare_ruleset_t *dfarules, struct mnt_entry *entry)
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
/* skip device and type */
|
||||
devbuf.clear();
|
||||
if (!convert_entry(devbuf, NULL))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
vec[2] = devbuf.c_str();
|
||||
vec[1] = default_match_pattern;
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
flags = entry->flags;
|
||||
inv_flags = entry->inv_flags;
|
||||
@@ -888,15 +885,11 @@ static int process_mnt_entry(aare_ruleset_t *dfarules, struct mnt_entry *entry)
|
||||
if (!convert_entry(mntbuf, entry->mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
devbuf.clear();
|
||||
if (!convert_entry(devbuf, entry->device))
|
||||
if (!clear_and_convert_entry(devbuf, entry->device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
/* skip type */
|
||||
typebuf.clear();
|
||||
if (!convert_entry(typebuf, NULL))
|
||||
goto fail;
|
||||
vec[2] = typebuf.c_str();
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
flags = entry->flags;
|
||||
inv_flags = entry->inv_flags;
|
||||
@@ -923,8 +916,7 @@ static int process_mnt_entry(aare_ruleset_t *dfarules, struct mnt_entry *entry)
|
||||
if (!convert_entry(mntbuf, entry->mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
devbuf.clear();
|
||||
if (!convert_entry(devbuf, entry->device))
|
||||
if (!clear_and_convert_entry(devbuf, entry->device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
typebuf.clear();
|
||||
@@ -985,8 +977,7 @@ static int process_mnt_entry(aare_ruleset_t *dfarules, struct mnt_entry *entry)
|
||||
if (!convert_entry(mntbuf, entry->mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
devbuf.clear();
|
||||
if (!convert_entry(devbuf, entry->device))
|
||||
if (!clear_and_convert_entry(devbuf, entry->device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
if (!aare_add_rule_vec(dfarules, entry->deny, entry->allow,
|
||||
@@ -1015,7 +1006,7 @@ static int process_dbus_entry(aare_ruleset_t *dfarules, struct dbus_entry *entry
|
||||
std::string pathbuf;
|
||||
std::string ifacebuf;
|
||||
std::string memberbuf;
|
||||
char buffer[128];
|
||||
std::ostringstream buffer;
|
||||
const char *vec[6];
|
||||
|
||||
pattern_t ptype;
|
||||
@@ -1024,8 +1015,8 @@ static int process_dbus_entry(aare_ruleset_t *dfarules, struct dbus_entry *entry
|
||||
if (!entry) /* shouldn't happen */
|
||||
return TRUE;
|
||||
|
||||
sprintf(buffer, "\\x%02x", AA_CLASS_DBUS);
|
||||
busbuf.append(buffer);
|
||||
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_DBUS;
|
||||
busbuf.append(buffer.str());
|
||||
|
||||
if (entry->bus) {
|
||||
ptype = convert_aaregex_to_pcre(entry->bus, 0, busbuf, &pos);
|
||||
@@ -1033,7 +1024,7 @@ static int process_dbus_entry(aare_ruleset_t *dfarules, struct dbus_entry *entry
|
||||
goto fail;
|
||||
} else {
|
||||
/* match any char except \000 0 or more times */
|
||||
busbuf.append("[^\\000]*");
|
||||
busbuf.append(default_match_pattern);
|
||||
}
|
||||
vec[0] = busbuf.c_str();
|
||||
|
||||
@@ -1044,7 +1035,7 @@ static int process_dbus_entry(aare_ruleset_t *dfarules, struct dbus_entry *entry
|
||||
vec[1] = namebuf.c_str();
|
||||
} else {
|
||||
/* match any char except \000 0 or more times */
|
||||
vec[1] = "[^\\000]*";
|
||||
vec[1] = default_match_pattern;
|
||||
}
|
||||
|
||||
if (entry->peer_label) {
|
||||
@@ -1055,7 +1046,7 @@ static int process_dbus_entry(aare_ruleset_t *dfarules, struct dbus_entry *entry
|
||||
vec[2] = peer_labelbuf.c_str();
|
||||
} else {
|
||||
/* match any char except \000 0 or more times */
|
||||
vec[2] = "[^\\000]*";
|
||||
vec[2] = default_match_pattern;
|
||||
}
|
||||
|
||||
if (entry->path) {
|
||||
@@ -1065,7 +1056,7 @@ static int process_dbus_entry(aare_ruleset_t *dfarules, struct dbus_entry *entry
|
||||
vec[3] = pathbuf.c_str();
|
||||
} else {
|
||||
/* match any char except \000 0 or more times */
|
||||
vec[3] = "[^\\000]*";
|
||||
vec[3] = default_match_pattern;
|
||||
}
|
||||
|
||||
if (entry->interface) {
|
||||
@@ -1075,7 +1066,7 @@ static int process_dbus_entry(aare_ruleset_t *dfarules, struct dbus_entry *entry
|
||||
vec[4] = ifacebuf.c_str();
|
||||
} else {
|
||||
/* match any char except \000 0 or more times */
|
||||
vec[4] = "[^\\000]*";
|
||||
vec[4] = default_match_pattern;
|
||||
}
|
||||
|
||||
if (entry->member) {
|
||||
@@ -1085,7 +1076,7 @@ static int process_dbus_entry(aare_ruleset_t *dfarules, struct dbus_entry *entry
|
||||
vec[5] = memberbuf.c_str();
|
||||
} else {
|
||||
/* match any char except \000 0 or more times */
|
||||
vec[5] = "[^\\000]*";
|
||||
vec[5] = default_match_pattern;
|
||||
}
|
||||
|
||||
if (entry->mode & AA_DBUS_BIND) {
|
||||
@@ -1252,41 +1243,36 @@ static int test_filter_slashes(void)
|
||||
do { \
|
||||
std::string tbuf; \
|
||||
std::string tbuf2 = "testprefix"; \
|
||||
char *test_string; \
|
||||
char *output_string = NULL; \
|
||||
std::string expected_str2; \
|
||||
pattern_t ptype; \
|
||||
int pos; \
|
||||
\
|
||||
test_string = strdup((input)); \
|
||||
ptype = convert_aaregex_to_pcre(test_string, 0, tbuf, &pos); \
|
||||
ptype = convert_aaregex_to_pcre((input), 0, tbuf, &pos); \
|
||||
asprintf(&output_string, "simple regex conversion for '%s'\texpected = '%s'\tresult = '%s'", \
|
||||
(input), expected_str, tbuf.c_str()); \
|
||||
(input), (expected_str), tbuf.c_str()); \
|
||||
MY_TEST(strcmp(tbuf.c_str(), (expected_str)) == 0, output_string); \
|
||||
MY_TEST(ptype == (expected_type), "simple regex conversion type check for '" input "'"); \
|
||||
free(output_string); \
|
||||
/* ensure convert_aaregex_to_pcre appends only to passed ref string */ \
|
||||
expected_str2 = tbuf2; \
|
||||
expected_str2.append((expected_str)); \
|
||||
ptype = convert_aaregex_to_pcre(test_string, 0, tbuf2, &pos); \
|
||||
ptype = convert_aaregex_to_pcre((input), 0, tbuf2, &pos); \
|
||||
asprintf(&output_string, "simple regex conversion for '%s'\texpected = '%s'\tresult = '%s'", \
|
||||
(input), expected_str2.c_str(), tbuf2.c_str()); \
|
||||
MY_TEST((tbuf2 == expected_str2), output_string); \
|
||||
free(test_string); free(output_string); \
|
||||
free(output_string); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define MY_REGEX_FAIL_TEST(input) \
|
||||
do { \
|
||||
std::string tbuf; \
|
||||
char *test_string; \
|
||||
pattern_t ptype; \
|
||||
int pos; \
|
||||
\
|
||||
test_string = strdup((input)); \
|
||||
ptype = convert_aaregex_to_pcre(test_string, 0, tbuf, &pos); \
|
||||
ptype = convert_aaregex_to_pcre((input), 0, tbuf, &pos); \
|
||||
MY_TEST(ptype == ePatternInvalid, "simple regex conversion invalid type check for '" input "'"); \
|
||||
free(test_string); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
|
@@ -137,11 +137,11 @@ void free_var_string(struct var_string *var)
|
||||
|
||||
static void trim_trailing_slash(std::string& str)
|
||||
{
|
||||
for (std::string::reverse_iterator rit = str.rbegin();
|
||||
rit != str.rend() && *rit == '/'; ++rit) {
|
||||
/* yuck, reverse_iterators are ugly */
|
||||
str.erase(--rit.base());
|
||||
}
|
||||
std::size_t found = str.find_last_not_of('/');
|
||||
if (found != std::string::npos)
|
||||
str.erase(found + 1);
|
||||
else
|
||||
str.clear(); // str is all '/'
|
||||
}
|
||||
|
||||
static void write_replacement(const char separator, const char* value,
|
||||
@@ -177,10 +177,11 @@ static int expand_by_alternations(struct set_value **valuelist,
|
||||
exit(1);
|
||||
}
|
||||
|
||||
free(*name);
|
||||
|
||||
value = get_next_set_value(valuelist);
|
||||
if (!value) {
|
||||
/* only one entry for the variable, so just sub it in */
|
||||
free(*name);
|
||||
if (asprintf(name, "%s%s%s",
|
||||
split_var->prefix ? split_var->prefix : "",
|
||||
first_value,
|
||||
@@ -201,7 +202,6 @@ static int expand_by_alternations(struct set_value **valuelist,
|
||||
write_replacement(',', value, replacement, filter_leading_slash, filter_trailing_slash);
|
||||
}
|
||||
|
||||
free(*name);
|
||||
if (asprintf(name, "%s%s}%s",
|
||||
split_var->prefix ? split_var->prefix : "",
|
||||
replacement.c_str(),
|
||||
|
@@ -754,6 +754,7 @@ rules: rules TOK_SET TOK_RLIMIT TOK_ID TOK_LE TOK_VALUE TOK_END_OF_RULE
|
||||
value = RLIM_INFINITY;
|
||||
} else {
|
||||
const char *seconds = "seconds";
|
||||
const char *milliseconds = "ms";
|
||||
const char *minutes = "minutes";
|
||||
const char *hours = "hours";
|
||||
const char *days = "days";
|
||||
@@ -779,6 +780,22 @@ rules: rules TOK_SET TOK_RLIMIT TOK_ID TOK_LE TOK_VALUE TOK_END_OF_RULE
|
||||
yyerror("RLIMIT '%s' invalid value %s\n", $4, $6);
|
||||
}
|
||||
break;
|
||||
case RLIMIT_RTTIME:
|
||||
/* RTTIME is measured in microseconds */
|
||||
if (!end || $6 == end || tmp < 0)
|
||||
yyerror("RLIMIT '%s' invalid value %s\n", $4, $6);
|
||||
if (*end == '\0') {
|
||||
value = tmp;
|
||||
} else if (strstr(milliseconds, end) == milliseconds) {
|
||||
value = tmp * 1000;
|
||||
} else if (strstr(seconds, end) == seconds) {
|
||||
value = tmp * 1000 * 1000;
|
||||
} else if (strstr(minutes, end) == minutes) {
|
||||
value = tmp * 1000 * 1000 * 60;
|
||||
} else {
|
||||
yyerror("RLIMIT '%s' invalid value %s\n", $4, $6);
|
||||
}
|
||||
break;
|
||||
case RLIMIT_NOFILE:
|
||||
case RLIMIT_NPROC:
|
||||
case RLIMIT_LOCKS:
|
||||
|
7
parser/tst/simple_tests/file/allow/ok_other_1.sd
Normal file
7
parser/tst/simple_tests/file/allow/ok_other_1.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=DESCRIPTION simple allow other flag test
|
||||
#=EXRESULT PASS
|
||||
|
||||
profile test {
|
||||
allow other /tmp/** rw,
|
||||
}
|
7
parser/tst/simple_tests/file/allow/ok_other_2.sd
Normal file
7
parser/tst/simple_tests/file/allow/ok_other_2.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=DESCRIPTION simple audit allow other flag test
|
||||
#=EXRESULT PASS
|
||||
|
||||
profile test {
|
||||
audit allow other /tmp/** rw,
|
||||
}
|
7
parser/tst/simple_tests/file/ok_other_2.sd
Normal file
7
parser/tst/simple_tests/file/ok_other_2.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=DESCRIPTION simple deny other flag test
|
||||
#=EXRESULT PASS
|
||||
|
||||
profile test {
|
||||
deny other /tmp/** rw,
|
||||
}
|
7
parser/tst/simple_tests/file/ok_other_3.sd
Normal file
7
parser/tst/simple_tests/file/ok_other_3.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=DESCRIPTION simple other flag test
|
||||
#=EXRESULT PASS
|
||||
|
||||
profile test {
|
||||
audit other /tmp/** rw,
|
||||
}
|
7
parser/tst/simple_tests/rlimits/ok_rlimit_18.sd
Normal file
7
parser/tst/simple_tests/rlimits/ok_rlimit_18.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=DESCRIPTION simple realtime time rlimit test
|
||||
#=EXRESULT PASS
|
||||
|
||||
profile rlimit {
|
||||
set rlimit rttime <= 60minutes,
|
||||
}
|
@@ -24,23 +24,6 @@ VALGRIND_ERROR_CODE = 151
|
||||
VALGRIND_ARGS = ['--leak-check=full', '--error-exitcode=%d' % (VALGRIND_ERROR_CODE)]
|
||||
|
||||
VALGRIND_SUPPRESSIONS = '''
|
||||
{
|
||||
valgrind-add_search_dir-obsessive-overreads
|
||||
Memcheck:Addr4
|
||||
fun:_Z*add_search_dir*
|
||||
fun:_Z*process_arg*
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
valgrind-yylex-obsessive-overreads
|
||||
Memcheck:Addr4
|
||||
fun:_Z?yylex?
|
||||
fun:_Z*yyparse*
|
||||
fun:_Z*process_profile*
|
||||
fun:main
|
||||
}
|
||||
|
||||
{
|
||||
valgrind-serialize_profile-obsessive-overreads
|
||||
Memcheck:Addr4
|
||||
|
@@ -44,6 +44,7 @@ local:
|
||||
for profile in ${TOPLEVEL_PROFILES}; do \
|
||||
fn=$$(basename $$profile); \
|
||||
echo "# Site-specific additions and overrides for '$$fn'" > ${PROFILES_SOURCE}/local/$$fn; \
|
||||
grep "include\\s\\s*<local/$$fn>" "$$profile" >/dev/null || { echo "$$profile doesn't contain #include <local/$$fn>" ; exit 1; } ; \
|
||||
done; \
|
||||
|
||||
.PHONY: install
|
||||
|
@@ -35,6 +35,7 @@
|
||||
# DRI
|
||||
/usr/lib{,32,64}/dri/** mr,
|
||||
/usr/lib/@{multiarch}/dri/** mr,
|
||||
/usr/lib/fglrx/dri/** mr,
|
||||
/dev/dri/** rw,
|
||||
/etc/drirc r,
|
||||
owner @{HOME}/.drirc r,
|
||||
|
@@ -56,7 +56,7 @@ owner @{HOME}/.pulse-cookie rwk,
|
||||
owner @{HOME}/.pulse/ rw,
|
||||
owner @{HOME}/.pulse/* rwk,
|
||||
owner /{,var/}run/user/*/pulse/ rw,
|
||||
owner /{,var/}run/user/*/pulse/* rwk,
|
||||
owner /{,var/}run/user/*/pulse/{native,pid} rwk,
|
||||
owner @{HOME}/.config/pulse/cookie rwk,
|
||||
owner /tmp/pulse-*/ rw,
|
||||
owner /tmp/pulse-*/* rw,
|
||||
|
@@ -52,3 +52,6 @@
|
||||
|
||||
# poppler CMap tables
|
||||
/usr/share/poppler/cMap/** r,
|
||||
|
||||
# data files for LibThai
|
||||
/usr/share/libthai/thbrk.tri r,
|
||||
|
@@ -21,6 +21,12 @@
|
||||
/etc/passwd r,
|
||||
/etc/protocols r,
|
||||
|
||||
# When using sssd, the passwd and group files are stored in an alternate path
|
||||
# and the nss plugin also needs to talk to a pipe
|
||||
/var/lib/sss/mc/group r,
|
||||
/var/lib/sss/mc/passwd r,
|
||||
/var/lib/sss/pipes/nss rw,
|
||||
|
||||
/etc/resolv.conf r,
|
||||
# on systems using resolvconf, /etc/resolv.conf is a symlink to
|
||||
# /{,var/}run/resolvconf/resolv.conf and a file sometimes referenced in
|
||||
@@ -50,7 +56,7 @@
|
||||
/etc/default/nss r,
|
||||
|
||||
# avahi-daemon is used for mdns4 resolution
|
||||
/{,var/}run/avahi-daemon/socket w,
|
||||
/{,var/}run/avahi-daemon/socket rw,
|
||||
|
||||
# nis
|
||||
#include <abstractions/nis>
|
||||
|
@@ -13,12 +13,12 @@
|
||||
/usr/lib{,32,64}/python2.[4567]/**.{pyc,so} mr,
|
||||
/usr/lib{,32,64}/python2.[4567]/**.{egg,py,pth} r,
|
||||
/usr/lib{,32,64}/python2.[4567]/{site,dist}-packages/ r,
|
||||
/usr/lib{,32,64}/python3.3/lib-dynload/*.so mr,
|
||||
/usr/lib{,32,64}/python3.[234]/lib-dynload/*.so mr,
|
||||
|
||||
/usr/local/lib{,32,64}/python2.[4567]/**.{pyc,so} mr,
|
||||
/usr/local/lib{,32,64}/python2.[4567]/**.{egg,py,pth} r,
|
||||
/usr/local/lib{,32,64}/python2.[4567]/{site,dist}-packages/ r,
|
||||
/usr/local/lib{,32,64}/python3.3/lib-dynload/*.so mr,
|
||||
/usr/local/lib{,32,64}/python3.[234]/lib-dynload/*.so mr,
|
||||
|
||||
# Site-wide configuration
|
||||
/etc/python2.[4567]/** r,
|
||||
|
@@ -55,3 +55,6 @@
|
||||
|
||||
# Virus scanners
|
||||
/usr/bin/clamscan Cx -> sanitized_helper,
|
||||
|
||||
# gxine (LP: #1057642)
|
||||
/var/lib/xine/gxine.desktop r,
|
||||
|
@@ -33,3 +33,9 @@
|
||||
/usr/lib/@{multiarch}/xfce4/exo-1/exo-helper-1 ixr,
|
||||
/etc/xdg/xdg-xubuntu/xfce4/helpers.rc r,
|
||||
/etc/xdg/xfce4/helpers.rc r,
|
||||
|
||||
# unity webapps integration. Could go in its own abstraction
|
||||
owner /run/user/*/dconf/user rw,
|
||||
owner @{HOME}/.local/share/unity-webapps/availableapps*.db rwk,
|
||||
/usr/bin/debconf-communicate Cxr -> sanitized_helper,
|
||||
owner @{HOME}/.config/libaccounts-glib/accounts.db rk,
|
||||
|
@@ -38,6 +38,9 @@ profile sanitized_helper {
|
||||
network inet,
|
||||
network inet6,
|
||||
|
||||
# Allow all DBus communications
|
||||
dbus,
|
||||
|
||||
# Allow exec of anything, but under this profile. Allow transition
|
||||
# to other profiles if they exist.
|
||||
/bin/* Pixr,
|
||||
|
167
profiles/apparmor.d/abstractions/ubuntu-unity7-base
Normal file
167
profiles/apparmor.d/abstractions/ubuntu-unity7-base
Normal file
@@ -0,0 +1,167 @@
|
||||
# vim:syntax=apparmor
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2013-2014 Canonical Ltd.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
#
|
||||
# Rules common to applications running under Unity 7
|
||||
#
|
||||
|
||||
#include <abstractions/gnome>
|
||||
|
||||
# Allow connecting to session bus and where to connect to services
|
||||
dbus (send)
|
||||
bus=session
|
||||
path=/org/freedesktop/DBus
|
||||
interface=org.freedesktop.DBus
|
||||
member=Hello
|
||||
peer=(name=org.freedesktop.DBus),
|
||||
dbus (send)
|
||||
bus=session
|
||||
path=/org/freedesktop/{db,DB}us
|
||||
interface=org.freedesktop.DBus
|
||||
member={Add,Remove}Match
|
||||
peer=(name=org.freedesktop.DBus),
|
||||
# NameHasOwner and GetNameOwner could leak running processes and apps
|
||||
# depending on how services are implemented
|
||||
dbus (send)
|
||||
bus=session
|
||||
path=/org/freedesktop/DBus
|
||||
interface=org.freedesktop.DBus
|
||||
member=GetNameOwner
|
||||
peer=(name=org.freedesktop.DBus),
|
||||
dbus (send)
|
||||
bus=session
|
||||
path=/org/freedesktop/DBus
|
||||
interface=org.freedesktop.DBus
|
||||
member=NameHasOwner
|
||||
peer=(name=org.freedesktop.DBus),
|
||||
|
||||
# Allow starting services on the session bus (actual communications with
|
||||
# the service are mediated elsewhere)
|
||||
dbus (send)
|
||||
bus=session
|
||||
path=/org/freedesktop/DBus
|
||||
interface=org.freedesktop.DBus
|
||||
member=StartServiceByName
|
||||
peer=(name=org.freedesktop.DBus),
|
||||
|
||||
# Allow connecting to system bus and where to connect to services. Put these
|
||||
# here so we don't need to repeat these rules in multiple places (actual
|
||||
# communications with any system services is mediated elsewhere). This does
|
||||
# allow apps to brute-force enumerate system services, but our system
|
||||
# services aren't a secret.
|
||||
/{,var/}run/dbus/system_bus_socket rw,
|
||||
dbus (send)
|
||||
bus=system
|
||||
path=/org/freedesktop/DBus
|
||||
interface=org.freedesktop.DBus
|
||||
member=Hello
|
||||
peer=(name=org.freedesktop.DBus),
|
||||
dbus (send)
|
||||
bus=system
|
||||
path=/org/freedesktop/{db,DB}us
|
||||
interface=org.freedesktop.DBus
|
||||
member={Add,Remove}Match
|
||||
peer=(name=org.freedesktop.DBus),
|
||||
# NameHasOwner and GetNameOwner could leak running processes and apps
|
||||
# depending on how services are implemented
|
||||
dbus (send)
|
||||
bus=system
|
||||
path=/org/freedesktop/DBus
|
||||
interface=org.freedesktop.DBus
|
||||
member=GetNameOwner
|
||||
peer=(name=org.freedesktop.DBus),
|
||||
dbus (send)
|
||||
bus=system
|
||||
path=/org/freedesktop/DBus
|
||||
interface=org.freedesktop.DBus
|
||||
member=NameHasOwner
|
||||
peer=(name=org.freedesktop.DBus),
|
||||
|
||||
#
|
||||
# Access required for connecting to/communication with Unity HUD
|
||||
#
|
||||
dbus (send)
|
||||
bus=session
|
||||
path="/com/canonical/hud",
|
||||
dbus (send)
|
||||
bus=session
|
||||
interface="com.canonical.hud.*",
|
||||
dbus (send)
|
||||
bus=session
|
||||
path="/com/canonical/hud/applications/*",
|
||||
dbus (receive)
|
||||
bus=session
|
||||
path="/com/canonical/hud",
|
||||
dbus (receive)
|
||||
bus=session
|
||||
interface="com.canonical.hud.*",
|
||||
|
||||
#
|
||||
# Allow access for connecting to/communication with the appmenu
|
||||
#
|
||||
# dbusmenu
|
||||
dbus (send)
|
||||
bus=session
|
||||
interface="com.canonical.AppMenu.*",
|
||||
dbus (receive, send)
|
||||
bus=session
|
||||
path=/com/canonical/menu/**,
|
||||
|
||||
# gmenu
|
||||
dbus (receive, send)
|
||||
bus=session
|
||||
interface=org.gtk.Actions,
|
||||
dbus (receive, send)
|
||||
bus=session
|
||||
interface=org.gtk.Menus,
|
||||
|
||||
#
|
||||
# Access required for using freedesktop notifications
|
||||
#
|
||||
dbus (send)
|
||||
bus=session
|
||||
path=/org/freedesktop/Notifications
|
||||
member=GetCapabilities,
|
||||
dbus (send)
|
||||
bus=session
|
||||
path=/org/freedesktop/Notifications
|
||||
member=GetServerInformation,
|
||||
dbus (send)
|
||||
bus=session
|
||||
path=/org/freedesktop/Notifications
|
||||
member=Notify,
|
||||
dbus (receive)
|
||||
bus=session
|
||||
member="Notify"
|
||||
peer=(name="org.freedesktop.DBus"),
|
||||
dbus (receive)
|
||||
bus=session
|
||||
path=/org/freedesktop/Notifications
|
||||
member=NotificationClosed,
|
||||
dbus (send)
|
||||
bus=session
|
||||
path=/org/freedesktop/Notifications
|
||||
member=CloseNotification,
|
||||
|
||||
# accessibility
|
||||
dbus (send)
|
||||
bus=session
|
||||
peer=(name=org.a11y.Bus),
|
||||
dbus (receive)
|
||||
bus=session
|
||||
interface=org.a11y.atspi*,
|
||||
dbus (receive, send)
|
||||
bus=accessibility,
|
||||
|
||||
#
|
||||
# Deny potentially dangerous access
|
||||
#
|
||||
deny dbus bus=session path=/com/canonical/[Uu]nity/[Dd]ebug**,
|
7
profiles/apparmor.d/abstractions/ubuntu-unity7-launcher
Normal file
7
profiles/apparmor.d/abstractions/ubuntu-unity7-launcher
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
# Access required for connecting to/communicating with the Unity Launcher
|
||||
#
|
||||
dbus (send)
|
||||
bus=session
|
||||
interface="com.canonical.Unity.LauncherEntry"
|
||||
member="Update",
|
7
profiles/apparmor.d/abstractions/ubuntu-unity7-messaging
Normal file
7
profiles/apparmor.d/abstractions/ubuntu-unity7-messaging
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
# Access required for connecting to/communicating with the Unity messaging
|
||||
# indicator
|
||||
#
|
||||
dbus (receive, send)
|
||||
bus=session
|
||||
path="/com/canonical/indicator/messages/*",
|
@@ -1,6 +1,7 @@
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2002-2006 Novell/SUSE
|
||||
# Copyright (C) 2014 Canonical Ltd.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
@@ -15,7 +16,9 @@
|
||||
owner @{HOME}/[dD]ownload{,s}/ r,
|
||||
owner @{HOME}/[dD]ownload{,s}/** rwl,
|
||||
owner @{HOME}/[a-zA-Z0-9]* rwl,
|
||||
owner @{HOME}/Desktop/ r,
|
||||
owner @{HOME}/Desktop/* rwl,
|
||||
owner @{HOME}/@{XDG_DESKTOP_DIR}/ r,
|
||||
owner @{HOME}/@{XDG_DESKTOP_DIR}/* rwl,
|
||||
owner @{HOME}/@{XDG_DOWNLOAD_DIR}/ r,
|
||||
owner @{HOME}/@{XDG_DOWNLOAD_DIR}/* rwl,
|
||||
owner "@{HOME}/My Downloads/" r,
|
||||
owner "@{HOME}/My Downloads/**" rwl,
|
||||
|
@@ -1,6 +1,7 @@
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2002-2006 Novell/SUSE
|
||||
# Copyright (C) 2014 Canonical Ltd.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
@@ -10,11 +11,11 @@
|
||||
|
||||
# per-user write directories
|
||||
owner @{HOME}/ r,
|
||||
owner @{HOME}/Desktop/ r,
|
||||
owner @{HOME}/Documents/ r,
|
||||
owner @{HOME}/Public/ r,
|
||||
owner @{HOME}/@{XDG_DESKTOP_DIR}/ r,
|
||||
owner @{HOME}/@{XDG_DOCUMENTS_DIR}/ r,
|
||||
owner @{HOME}/@{XDG_PUBLICSHARE_DIR}/ r,
|
||||
owner @{HOME}/[a-zA-Z0-9]*/ rw,
|
||||
owner @{HOME}/[a-zA-Z0-9]* rwl,
|
||||
owner @{HOME}/Desktop/** rwl,
|
||||
owner @{HOME}/Documents/** rwl,
|
||||
owner @{HOME}/Public/** rwl,
|
||||
owner @{HOME}/@{XDG_DESKTOP_DIR}/** rwl,
|
||||
owner @{HOME}/@{XDG_DOCUMENTS_DIR}/** rwl,
|
||||
owner @{HOME}/@{XDG_PUBLICSHARE_DIR}/** rwl,
|
||||
|
@@ -13,7 +13,9 @@
|
||||
/tmp/.winbindd/pipe rw,
|
||||
/var/{lib,run}/samba/winbindd_privileged/pipe rw,
|
||||
/etc/samba/smb.conf r,
|
||||
/etc/samba/dhcp.conf r,
|
||||
/usr/lib*/samba/valid.dat r,
|
||||
/usr/lib*/samba/upcase.dat r,
|
||||
/usr/lib*/samba/lowcase.dat r,
|
||||
/usr/share/samba/codepages/{lowcase,upcase,valid}.dat r,
|
||||
|
||||
|
20
profiles/apparmor.d/tunables/dovecot
Normal file
20
profiles/apparmor.d/tunables/dovecot
Normal file
@@ -0,0 +1,20 @@
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2013 Christian Boltz
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
# vim:ft=apparmor
|
||||
|
||||
# @{DOVECOT_MAILSTORE} is a space-separated list of all directories
|
||||
# where dovecot is allowed to store and read mails
|
||||
#
|
||||
# The default value is quite broad to avoid breaking existing setups.
|
||||
# Please change @{DOVECOT_MAILSTORE} to (only) contain the directory
|
||||
# you use, and remove everything else.
|
||||
|
||||
@{DOVECOT_MAILSTORE}=@{HOME}/Maildir/ @{HOME}/mail/ @{HOME}/Mail/ /var/vmail/ /var/mail/ /var/spool/mail/
|
||||
|
@@ -1,7 +1,7 @@
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2006-2009 Novell/SUSE
|
||||
# Copyright (C) 2010-2011 Canonical Ltd.
|
||||
# Copyright (C) 2010-2014 Canonical Ltd.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
@@ -17,3 +17,4 @@
|
||||
#include <tunables/proc>
|
||||
#include <tunables/alias>
|
||||
#include <tunables/kernelvars>
|
||||
#include <tunables/xdg-user-dirs>
|
||||
|
24
profiles/apparmor.d/tunables/xdg-user-dirs
Normal file
24
profiles/apparmor.d/tunables/xdg-user-dirs
Normal file
@@ -0,0 +1,24 @@
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2014 Canonical Ltd.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
# Define the common set of XDG user directories (usually defined in
|
||||
# /etc/xdg/user-dirs.defaults)
|
||||
@{XDG_DESKTOP_DIR}="Desktop"
|
||||
@{XDG_DOWNLOAD_DIR}="Downloads"
|
||||
@{XDG_TEMPLATES_DIR}="Templates"
|
||||
@{XDG_PUBLICSHARE_DIR}="Public"
|
||||
@{XDG_DOCUMENTS_DIR}="Documents"
|
||||
@{XDG_MUSIC_DIR}="Music"
|
||||
@{XDG_PICTURES_DIR}="Pictures"
|
||||
@{XDG_VIDEOS_DIR}="Videos"
|
||||
|
||||
# Also, include files in tunables/xdg-user-dirs.d for site-specific adjustments
|
||||
# to the various XDG directories
|
||||
#include <tunables/xdg-user-dirs.d>
|
21
profiles/apparmor.d/tunables/xdg-user-dirs.d/site.local
Normal file
21
profiles/apparmor.d/tunables/xdg-user-dirs.d/site.local
Normal file
@@ -0,0 +1,21 @@
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2014 Canonical Ltd.
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
# The following may be used to add additional entries such as for
|
||||
# translations. See tunables/xdg-user-dirs for details. Eg:
|
||||
#@{XDG_MUSIC_DIR}+="Musique"
|
||||
|
||||
#@{XDG_DESKTOP_DIR}+=""
|
||||
#@{XDG_DOWNLOAD_DIR}+=""
|
||||
#@{XDG_TEMPLATES_DIR}+=""
|
||||
#@{XDG_PUBLICSHARE_DIR}+=""
|
||||
#@{XDG_DOCUMENTS_DIR}+=""
|
||||
#@{XDG_MUSIC_DIR}+=""
|
||||
#@{XDG_PICTURES_DIR}+=""
|
||||
#@{XDG_VIDEOS_DIR}+=""
|
25
profiles/apparmor.d/usr.lib.dovecot.anvil
Normal file
25
profiles/apparmor.d/usr.lib.dovecot.anvil
Normal file
@@ -0,0 +1,25 @@
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2013 Christian Boltz
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
# vim: ft=apparmor
|
||||
|
||||
#include <tunables/global>
|
||||
|
||||
/usr/lib/dovecot/anvil {
|
||||
#include <abstractions/base>
|
||||
|
||||
capability setgid,
|
||||
capability setuid,
|
||||
capability sys_chroot,
|
||||
|
||||
/usr/lib/dovecot/anvil mr,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
#include <local/usr.lib.dovecot.anvil>
|
||||
}
|
42
profiles/apparmor.d/usr.lib.dovecot.auth
Normal file
42
profiles/apparmor.d/usr.lib.dovecot.auth
Normal file
@@ -0,0 +1,42 @@
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2013 Christian Boltz
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
# vim: ft=apparmor
|
||||
|
||||
#include <tunables/global>
|
||||
|
||||
/usr/lib/dovecot/auth {
|
||||
#include <abstractions/authentication>
|
||||
#include <abstractions/base>
|
||||
#include <abstractions/mysql>
|
||||
#include <abstractions/nameservice>
|
||||
|
||||
deny capability block_suspend,
|
||||
|
||||
capability audit_write,
|
||||
capability setgid,
|
||||
capability setuid,
|
||||
|
||||
/etc/my.cnf r,
|
||||
/etc/my.cnf.d/ r,
|
||||
/etc/my.cnf.d/*.cnf r,
|
||||
|
||||
/etc/dovecot/dovecot-database.conf.ext r,
|
||||
/etc/dovecot/dovecot-sql.conf.ext r,
|
||||
/usr/lib/dovecot/auth mr,
|
||||
|
||||
# kerberos replay cache
|
||||
/var/tmp/imap_* rw,
|
||||
/var/tmp/pop_* rw,
|
||||
/var/tmp/sieve_* rw,
|
||||
/var/tmp/smtp_* rw,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
#include <local/usr.lib.dovecot.auth>
|
||||
}
|
32
profiles/apparmor.d/usr.lib.dovecot.config
Normal file
32
profiles/apparmor.d/usr.lib.dovecot.config
Normal file
@@ -0,0 +1,32 @@
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2013 Christian Boltz
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
# vim: ft=apparmor
|
||||
|
||||
#include <tunables/global>
|
||||
|
||||
/usr/lib/dovecot/config {
|
||||
#include <abstractions/base>
|
||||
#include <abstractions/nameservice>
|
||||
#include <abstractions/ssl_keys>
|
||||
|
||||
deny capability block_suspend,
|
||||
|
||||
capability dac_override,
|
||||
capability setgid,
|
||||
|
||||
|
||||
/etc/dovecot/** r,
|
||||
/usr/bin/doveconf rix,
|
||||
/usr/lib/dovecot/config mr,
|
||||
/usr/lib/dovecot/managesieve Px,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
#include <local/usr.lib.dovecot.config>
|
||||
}
|
@@ -1,6 +1,19 @@
|
||||
# Author: Dulmandakh Sukhbaatar <dulmandakh@gmail.com>
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2009 Dulmandakh Sukhbaatar <dulmandakh@gmail.com>
|
||||
# Copyright (C) 2009-2012 Canonical Ltd.
|
||||
# Copyright (C) 2011-2013 Christian Boltz
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
# vim: ft=apparmor
|
||||
|
||||
#include <tunables/global>
|
||||
#include <tunables/dovecot>
|
||||
|
||||
/usr/lib/dovecot/deliver {
|
||||
#include <abstractions/base>
|
||||
#include <abstractions/nameservice>
|
||||
@@ -8,20 +21,16 @@
|
||||
capability setgid,
|
||||
capability setuid,
|
||||
|
||||
@{DOVECOT_MAILSTORE}/ rw,
|
||||
@{DOVECOT_MAILSTORE}/** rwkl,
|
||||
|
||||
# http://www.postfix.org/SASL_README.html#server_dovecot
|
||||
/etc/dovecot/dovecot.conf r,
|
||||
/etc/dovecot/{auth,conf}.d/*.conf r,
|
||||
/etc/dovecot/dovecot-postfix.conf r,
|
||||
/etc/dovecot/dovecot-postfix.conf r, # ???
|
||||
|
||||
@{HOME} r,
|
||||
@{HOME}/Maildir/ rw,
|
||||
@{HOME}/Maildir/** klrw,
|
||||
@{HOME}/mail/ rw,
|
||||
@{HOME}/mail/* klrw,
|
||||
@{HOME}/mail/.imap/** klrw,
|
||||
@{HOME} r, # ???
|
||||
/usr/lib/dovecot/deliver mr,
|
||||
/var/mail/* klrw,
|
||||
/var/spool/mail/* klrw,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
#include <local/usr.lib.dovecot.deliver>
|
||||
|
30
profiles/apparmor.d/usr.lib.dovecot.dict
Normal file
30
profiles/apparmor.d/usr.lib.dovecot.dict
Normal file
@@ -0,0 +1,30 @@
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2013 Christian Boltz
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
# vim: ft=apparmor
|
||||
|
||||
#include <tunables/global>
|
||||
|
||||
/usr/lib/dovecot/dict {
|
||||
#include <abstractions/base>
|
||||
#include <abstractions/mysql>
|
||||
#include <abstractions/nameservice>
|
||||
|
||||
capability setgid,
|
||||
capability setuid,
|
||||
|
||||
network inet stream,
|
||||
|
||||
/etc/dovecot/dovecot-database.conf.ext r,
|
||||
/etc/dovecot/dovecot-dict-sql.conf.ext r,
|
||||
/usr/lib/dovecot/dict mr,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
#include <local/usr.lib.dovecot.dict>
|
||||
}
|
@@ -1,6 +1,17 @@
|
||||
# Author: Kees Cook <kees@ubuntu.com>
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2009-2013 Canonical Ltd.
|
||||
# Copyright (C) 2013 Christian Boltz
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
# vim: ft=apparmor
|
||||
|
||||
#include <tunables/global>
|
||||
|
||||
/usr/lib/dovecot/dovecot-auth {
|
||||
#include <abstractions/authentication>
|
||||
#include <abstractions/base>
|
||||
|
33
profiles/apparmor.d/usr.lib.dovecot.dovecot-lda
Normal file
33
profiles/apparmor.d/usr.lib.dovecot.dovecot-lda
Normal file
@@ -0,0 +1,33 @@
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2013 Christian Boltz
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
# vim: ft=apparmor
|
||||
|
||||
#include <tunables/global>
|
||||
#include <tunables/dovecot>
|
||||
|
||||
/usr/lib/dovecot/dovecot-lda {
|
||||
#include <abstractions/base>
|
||||
#include <abstractions/nameservice>
|
||||
|
||||
capability setgid,
|
||||
capability setuid,
|
||||
|
||||
@{DOVECOT_MAILSTORE}/ rw,
|
||||
@{DOVECOT_MAILSTORE}/** rwkl,
|
||||
|
||||
/etc/dovecot/** r,
|
||||
/proc/*/mounts r,
|
||||
/{var/,}run/dovecot/mounts r,
|
||||
/usr/bin/doveconf mrix,
|
||||
/usr/lib/dovecot/dovecot-lda mrix,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
#include <local/usr.lib.dovecot.dovecot-lda>
|
||||
}
|
@@ -1,6 +1,18 @@
|
||||
# Author: Kees Cook <kees@ubuntu.com>
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2009-2010 Canonical Ltd.
|
||||
# Copyright (C) 2011-2013 Christian Boltz
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
# vim: ft=apparmor
|
||||
|
||||
#include <tunables/global>
|
||||
#include <tunables/dovecot>
|
||||
|
||||
/usr/lib/dovecot/imap {
|
||||
#include <abstractions/base>
|
||||
#include <abstractions/nameservice>
|
||||
@@ -8,18 +20,11 @@
|
||||
capability setgid,
|
||||
capability setuid,
|
||||
|
||||
@{HOME} r,
|
||||
@{HOME}/Maildir/ rw,
|
||||
@{HOME}/Maildir/** klrw,
|
||||
@{HOME}/Mail/ rw,
|
||||
@{HOME}/Mail/* klrw,
|
||||
@{HOME}/Mail/.imap/** klrw,
|
||||
@{HOME}/mail/ rw,
|
||||
@{HOME}/mail/* klrw,
|
||||
@{HOME}/mail/.imap/** klrw,
|
||||
@{DOVECOT_MAILSTORE}/ rw,
|
||||
@{DOVECOT_MAILSTORE}/** rwkl,
|
||||
|
||||
@{HOME} r, # ???
|
||||
/usr/lib/dovecot/imap mr,
|
||||
/var/mail/* klrw,
|
||||
/var/spool/mail/* klrw,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
#include <local/usr.lib.dovecot.imap>
|
||||
|
@@ -1,4 +1,14 @@
|
||||
# Author: Kees Cook <kees@ubuntu.com>
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2009-2011 Canonical Ltd.
|
||||
# Copyright (C) 2013 Christian Boltz
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
# vim: ft=apparmor
|
||||
|
||||
#include <tunables/global>
|
||||
/usr/lib/dovecot/imap-login {
|
||||
|
35
profiles/apparmor.d/usr.lib.dovecot.lmtp
Normal file
35
profiles/apparmor.d/usr.lib.dovecot.lmtp
Normal file
@@ -0,0 +1,35 @@
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2013 Christian Boltz
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
# vim: ft=apparmor
|
||||
|
||||
#include <tunables/global>
|
||||
#include <tunables/dovecot>
|
||||
|
||||
/usr/lib/dovecot/lmtp {
|
||||
#include <abstractions/base>
|
||||
#include <abstractions/nameservice>
|
||||
|
||||
deny capability block_suspend,
|
||||
|
||||
capability dac_override,
|
||||
capability setgid,
|
||||
capability setuid,
|
||||
|
||||
@{DOVECOT_MAILSTORE}/ rw,
|
||||
@{DOVECOT_MAILSTORE}/** rwkl,
|
||||
|
||||
/proc/*/mounts r,
|
||||
/tmp/dovecot.lmtp.* rw,
|
||||
/usr/lib/dovecot/lmtp mr,
|
||||
/{var/,}run/dovecot/mounts r,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
#include <local/usr.lib.dovecot.lmtp>
|
||||
}
|
25
profiles/apparmor.d/usr.lib.dovecot.log
Normal file
25
profiles/apparmor.d/usr.lib.dovecot.log
Normal file
@@ -0,0 +1,25 @@
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2013 Christian Boltz
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
# vim: ft=apparmor
|
||||
|
||||
#include <tunables/global>
|
||||
|
||||
/usr/lib/dovecot/log {
|
||||
#include <abstractions/base>
|
||||
|
||||
deny capability block_suspend,
|
||||
|
||||
capability setgid,
|
||||
|
||||
/usr/lib/dovecot/log mr,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
#include <local/usr.lib.dovecot.log>
|
||||
}
|
23
profiles/apparmor.d/usr.lib.dovecot.managesieve
Normal file
23
profiles/apparmor.d/usr.lib.dovecot.managesieve
Normal file
@@ -0,0 +1,23 @@
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2013 Christian Boltz
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
# vim: ft=apparmor
|
||||
|
||||
#include <tunables/global>
|
||||
|
||||
/usr/lib/dovecot/managesieve {
|
||||
#include <abstractions/base>
|
||||
|
||||
/etc/dovecot/** r,
|
||||
/usr/bin/doveconf rix,
|
||||
/usr/lib/dovecot/managesieve mrix,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
#include <local/usr.lib.dovecot.managesieve>
|
||||
}
|
@@ -1,4 +1,15 @@
|
||||
# Author: Dulmandakh Sukhbaatar <dulmandakh@gmail.com>
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (c) 2009 Dulmandakh Sukhbaatar <dulmandakh@gmail.com>
|
||||
# Copyright (C) 2009-2011 Canonical Ltd.
|
||||
# Copyright (C) 2013 Christian Boltz
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
# vim: ft=apparmor
|
||||
|
||||
#include <tunables/global>
|
||||
/usr/lib/dovecot/managesieve-login {
|
||||
|
@@ -1,6 +1,18 @@
|
||||
# Author: Kees Cook <kees@ubuntu.com>
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2009-2010 Canonical Ltd.
|
||||
# Copyright (C) 2011-2013 Christian Boltz
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
# vim: ft=apparmor
|
||||
|
||||
#include <tunables/global>
|
||||
#include <tunables/dovecot>
|
||||
|
||||
/usr/lib/dovecot/pop3 {
|
||||
#include <abstractions/base>
|
||||
#include <abstractions/nameservice>
|
||||
@@ -8,13 +20,10 @@
|
||||
capability setgid,
|
||||
capability setuid,
|
||||
|
||||
/var/mail/* klrw,
|
||||
/var/spool/mail/* klrw,
|
||||
@{HOME} r,
|
||||
@{HOME}/mail/* klrw,
|
||||
@{HOME}/mail/.imap/** klrw,
|
||||
@{HOME}/Maildir/ rw,
|
||||
@{HOME}/Maildir/** klrw,
|
||||
@{DOVECOT_MAILSTORE}/ rw,
|
||||
@{DOVECOT_MAILSTORE}/** rwkl,
|
||||
|
||||
@{HOME} r, # ???
|
||||
/usr/lib/dovecot/pop3 mr,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
|
@@ -1,6 +1,17 @@
|
||||
# Author: Kees Cook <kees@ubuntu.com>
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2009-2011 Canonical Ltd.
|
||||
# Copyright (C) 2013 Christian Boltz
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
# vim: ft=apparmor
|
||||
|
||||
#include <tunables/global>
|
||||
|
||||
/usr/lib/dovecot/pop3-login {
|
||||
#include <abstractions/base>
|
||||
#include <abstractions/nameservice>
|
||||
|
27
profiles/apparmor.d/usr.lib.dovecot.ssl-params
Normal file
27
profiles/apparmor.d/usr.lib.dovecot.ssl-params
Normal file
@@ -0,0 +1,27 @@
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2013 Christian Boltz
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
# vim: ft=apparmor
|
||||
|
||||
#include <tunables/global>
|
||||
|
||||
/usr/lib/dovecot/ssl-params {
|
||||
#include <abstractions/base>
|
||||
|
||||
deny capability block_suspend,
|
||||
|
||||
capability setgid,
|
||||
|
||||
/usr/lib/dovecot/ssl-params mr,
|
||||
/var/lib/dovecot/ssl-parameters.dat rw,
|
||||
/var/lib/dovecot/ssl-parameters.dat.tmp rwk,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
#include <local/usr.lib.dovecot.ssl-params>
|
||||
}
|
83
profiles/apparmor.d/usr.sbin.apache2
Normal file
83
profiles/apparmor.d/usr.sbin.apache2
Normal file
@@ -0,0 +1,83 @@
|
||||
# Author: Marc Deslauriers <marc.deslauriers@ubuntu.com>
|
||||
|
||||
#include <tunables/global>
|
||||
/usr/sbin/apache2 {
|
||||
|
||||
# This profile is completely permissive.
|
||||
# It is designed to target specific applications using mod_apparmor,
|
||||
# hats, and the apache2.d directory.
|
||||
#
|
||||
# In order to enable this profile, you must:
|
||||
#
|
||||
# 1- Enable it:
|
||||
# sudo aa-enforce /etc/apparmor.d/usr.sbin.apache2
|
||||
#
|
||||
# 2- Load the mpm_prefork and mod_apparmor modules:
|
||||
# sudo a2dismod <other non-prefork mpm>
|
||||
# sudo a2enmod mpm_prefork
|
||||
# sudo a2enmod apparmor
|
||||
# sudo service apache2 restart
|
||||
#
|
||||
# 3- Place an appropriate profile containing the desired hat in the
|
||||
# /etc/apparmor.d/apache2.d directory. Such profiles should probably
|
||||
# include the "apache2-common" abstraction.
|
||||
#
|
||||
# 4- Use the "AADefaultHatName" apache configuration option to specify a
|
||||
# hat to be used for a given apache virtualhost or "AAHatName" for
|
||||
# a given apache directory or location directive.
|
||||
#
|
||||
#
|
||||
# There is an example profile for phpsysinfo included in the
|
||||
# apparmor-profiles package. To try it:
|
||||
#
|
||||
# 1- Install the phpsysinfo and the apparmor-profiles packages:
|
||||
# sudo apt-get install phpsysinfo apparmor-profiles
|
||||
#
|
||||
# 2- Enable the main apache2 profile
|
||||
# sudo aa-enforce /etc/apparmor.d/usr.sbin.apache2
|
||||
#
|
||||
# 3- Configure apache with the following:
|
||||
# <Directory /var/www/phpsysinfo/>
|
||||
# AAHatName phpsysinfo
|
||||
# </Directory>
|
||||
#
|
||||
|
||||
#include <abstractions/base>
|
||||
#include <abstractions/nameservice>
|
||||
|
||||
capability dac_override,
|
||||
capability kill,
|
||||
capability net_bind_service,
|
||||
capability setgid,
|
||||
capability setuid,
|
||||
capability sys_tty_config,
|
||||
|
||||
/ rw,
|
||||
/** mrwlkix,
|
||||
|
||||
|
||||
^DEFAULT_URI {
|
||||
#include <abstractions/base>
|
||||
#include <abstractions/nameservice>
|
||||
|
||||
/ rw,
|
||||
/** mrwlkix,
|
||||
|
||||
}
|
||||
|
||||
^HANDLING_UNTRUSTED_INPUT {
|
||||
#include <abstractions/nameservice>
|
||||
|
||||
/ rw,
|
||||
/** mrwlkix,
|
||||
|
||||
}
|
||||
|
||||
# This directory contains web application
|
||||
# package-specific apparmor files.
|
||||
|
||||
#include <apache2.d>
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
#include <local/usr.sbin.apache2>
|
||||
}
|
@@ -29,6 +29,8 @@
|
||||
/etc/dnsmasq.d/ r,
|
||||
/etc/dnsmasq.d/* r,
|
||||
/etc/ethers r,
|
||||
/etc/NetworkManager/dnsmasq.d/ r,
|
||||
/etc/NetworkManager/dnsmasq.d/* r,
|
||||
|
||||
/usr/sbin/dnsmasq mr,
|
||||
|
||||
@@ -56,6 +58,7 @@
|
||||
/{,var/}run/nm-dns-dnsmasq.conf r,
|
||||
/{,var/}run/sendsigs.omit.d/*dnsmasq.pid w,
|
||||
/{,var/}run/NetworkManager/dnsmasq.conf r,
|
||||
/{,var/}run/NetworkManager/dnsmasq.pid w,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
#include <local/usr.sbin.dnsmasq>
|
||||
|
@@ -1,37 +1,61 @@
|
||||
# Author: Kees Cook <kees@ubuntu.com>
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2009-2013 Canonical Ltd.
|
||||
# Copyright (C) 2011-2013 Christian Boltz
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
# vim: ft=apparmor
|
||||
|
||||
#include <tunables/global>
|
||||
|
||||
/usr/sbin/dovecot {
|
||||
#include <abstractions/authentication>
|
||||
#include <abstractions/base>
|
||||
#include <abstractions/mysql>
|
||||
#include <abstractions/nameservice>
|
||||
#include <abstractions/ssl_certs>
|
||||
#include <abstractions/ssl_keys>
|
||||
|
||||
capability chown,
|
||||
capability dac_override,
|
||||
capability fsetid,
|
||||
capability kill,
|
||||
capability net_bind_service,
|
||||
capability setgid,
|
||||
capability setuid,
|
||||
capability sys_chroot,
|
||||
capability fsetid,
|
||||
|
||||
/etc/dovecot/** r,
|
||||
/etc/mtab r,
|
||||
/etc/lsb-release r,
|
||||
/etc/SuSE-release r,
|
||||
@{PROC}/@{pid}/mounts r,
|
||||
@{PROC}/filesystems r,
|
||||
/usr/bin/doveconf rix,
|
||||
/usr/lib/dovecot/anvil Px,
|
||||
/usr/lib/dovecot/auth Px,
|
||||
/usr/lib/dovecot/config Px,
|
||||
/usr/lib/dovecot/dict Px,
|
||||
/usr/lib/dovecot/dovecot-auth Pxmr,
|
||||
/usr/lib/dovecot/imap Pxmr,
|
||||
/usr/lib/dovecot/imap-login Pxmr,
|
||||
/usr/lib/dovecot/lmtp Px,
|
||||
/usr/lib/dovecot/log Px,
|
||||
/usr/lib/dovecot/managesieve Px,
|
||||
/usr/lib/dovecot/managesieve-login Pxmr,
|
||||
/usr/lib/dovecot/pop3 Px,
|
||||
/usr/lib/dovecot/pop3-login Pxmr,
|
||||
# temporarily commented out while testing
|
||||
#/usr/lib/dovecot/managesieve Px,
|
||||
/usr/lib/dovecot/managesieve-login Pxmr,
|
||||
/usr/lib/dovecot/ssl-build-param ixr,
|
||||
/usr/sbin/dovecot mr,
|
||||
/usr/lib/dovecot/ssl-build-param rix,
|
||||
/usr/lib/dovecot/ssl-params Px,
|
||||
/usr/sbin/dovecot mrix,
|
||||
/var/lib/dovecot/ w,
|
||||
/var/lib/dovecot/* krw,
|
||||
/var/lib/dovecot/* rwkl,
|
||||
/var/spool/postfix/private/auth w,
|
||||
/var/spool/postfix/private/dovecot-lmtp w,
|
||||
/{,var/}run/dovecot/ rw,
|
||||
/{,var/}run/dovecot/** rw,
|
||||
link /{,var/}run/dovecot/** -> /var/lib/dovecot/**,
|
||||
|
@@ -36,7 +36,6 @@
|
||||
/var/cache/samba/** rwk,
|
||||
/var/cache/samba/printing/printers.tdb mrw,
|
||||
/var/lib/samba/** rwk,
|
||||
/var/lib/sss/mc/passwd r,
|
||||
/var/lib/sss/pubconf/kdcinfo.* r,
|
||||
/{,var/}run/cups/cups.sock rw,
|
||||
/{,var/}run/dbus/system_bus_socket rw,
|
||||
|
@@ -1,33 +1,32 @@
|
||||
# Last Modified: Mon Mar 26 20:28:18 2012
|
||||
#include <tunables/global>
|
||||
|
||||
/usr/sbin/winbindd {
|
||||
#include <abstractions/base>
|
||||
#include <abstractions/nameservice>
|
||||
#include <abstractions/samba>
|
||||
|
||||
deny capability block_suspend,
|
||||
|
||||
capability ipc_lock,
|
||||
capability setuid,
|
||||
|
||||
/etc/samba/dhcp.conf r,
|
||||
/etc/samba/passdb.tdb rwk,
|
||||
/etc/samba/secrets.tdb rwk,
|
||||
@{PROC}/sys/kernel/core_pattern r,
|
||||
/tmp/.winbindd/ w,
|
||||
/tmp/krb5cc_* rwk,
|
||||
/usr/lib*/samba/idmap/*.so mr,
|
||||
/usr/lib*/samba/nss_info/*.so mr,
|
||||
/usr/lib*/samba/pdb/*.so mr,
|
||||
/usr/sbin/winbindd mr,
|
||||
/var/lib/samba/account_policy.tdb rwk,
|
||||
/var/lib/samba/gencache.tdb rwk,
|
||||
/var/lib/samba/gencache_notrans.tdb rwk,
|
||||
/var/lib/samba/group_mapping.tdb rwk,
|
||||
/var/lib/samba/messages.tdb rwk,
|
||||
/var/lib/samba/netsamlogon_cache.tdb rwk,
|
||||
/var/lib/samba/serverid.tdb rwk,
|
||||
/var/lib/samba/winbindd_cache.tdb rwk,
|
||||
/var/lib/samba/winbindd_privileged/pipe w,
|
||||
/var/log/samba/cores/ rw,
|
||||
/var/log/samba/cores/winbindd/ rw,
|
||||
/var/log/samba/cores/winbindd/** rw,
|
||||
/var/log/samba/log.wb-* w,
|
||||
/var/cache/samba/*.tdb rwk,
|
||||
/var/lib/samba/smb_krb5/krb5.conf.* rw,
|
||||
/var/lib/samba/smb_tmp_krb5.* rw,
|
||||
/var/lib/samba/winbindd_cache.tdb* rwk,
|
||||
/var/log/samba/log.winbindd rw,
|
||||
/{var/,}run/samba/winbindd.pid rwk,
|
||||
/{var/,}run/samba/winbindd/ rw,
|
||||
/{var/,}run/samba/winbindd/pipe w,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
#include <local/usr.sbin.winbindd>
|
||||
|
@@ -186,16 +186,16 @@ changehat_pthread: changehat_pthread.c changehat.h
|
||||
${CC} ${CFLAGS} ${LDFLAGS} $< -o $@ ${LDLIBS} -pthread
|
||||
|
||||
dbus_common.o: dbus_common.c dbus_common.h
|
||||
${CC} ${CFLAGS} ${LDFLAGS} $^ -c ${LDLIBS} $(shell pkg-config --cflags --libs dbus-1)
|
||||
${CC} ${CFLAGS} ${LDFLAGS} $< -c ${LDLIBS} $(shell pkg-config --cflags --libs dbus-1)
|
||||
|
||||
dbus_eavesdrop: dbus_eavesdrop.c dbus_common.o
|
||||
${CC} ${CFLAGS} ${LDFLAGS} $^ -o dbus_eavesdrop ${LDLIBS} $(shell pkg-config --cflags --libs dbus-1)
|
||||
${CC} ${CFLAGS} ${LDFLAGS} $^ -o $@ ${LDLIBS} $(shell pkg-config --cflags --libs dbus-1)
|
||||
|
||||
dbus_message: dbus_message.c dbus_common.o
|
||||
${CC} ${CFLAGS} ${LDFLAGS} $^ -o dbus_message ${LDLIBS} $(shell pkg-config --cflags --libs dbus-1)
|
||||
${CC} ${CFLAGS} ${LDFLAGS} $^ -o $@ ${LDLIBS} $(shell pkg-config --cflags --libs dbus-1)
|
||||
|
||||
dbus_service: dbus_message dbus_service.c dbus_common.o
|
||||
${CC} ${CFLAGS} ${LDFLAGS} $(filter-out dbus_message, $^) -o dbus_service ${LDLIBS} $(shell pkg-config --cflags --libs dbus-1)
|
||||
${CC} ${CFLAGS} ${LDFLAGS} $(filter-out dbus_message, $^) -o $@ ${LDLIBS} $(shell pkg-config --cflags --libs dbus-1)
|
||||
|
||||
tests: all
|
||||
@if [ `whoami` = "root" ] ;\
|
||||
|
@@ -26,16 +26,14 @@ common/Make.rules: $(COMMONDIR)/Make.rules
|
||||
ln -sf $(COMMONDIR) .
|
||||
endif
|
||||
|
||||
MODDIR = Immunix
|
||||
PERLTOOLS = aa-genprof aa-logprof aa-autodep aa-audit aa-complain aa-enforce \
|
||||
aa-unconfined aa-notify aa-disable aa-exec
|
||||
TOOLS = ${PERLTOOLS} aa-decode aa-status
|
||||
MODULES = ${MODDIR}/AppArmor.pm ${MODDIR}/Repository.pm \
|
||||
${MODDIR}/Config.pm ${MODDIR}/Severity.pm
|
||||
PYTOOLS = aa-easyprof
|
||||
PERLTOOLS = aa-exec aa-notify
|
||||
PYTOOLS = aa-easyprof aa-genprof aa-logprof aa-cleanprof aa-mergeprof \
|
||||
aa-autodep aa-audit aa-complain aa-enforce aa-disable \
|
||||
aa-status aa-unconfined
|
||||
TOOLS = ${PERLTOOLS} ${PYTOOLS} aa-decode
|
||||
PYSETUP = python-tools-setup.py
|
||||
|
||||
MANPAGES = ${TOOLS:=.8} logprof.conf.5 ${PYTOOLS:=.8}
|
||||
MANPAGES = ${TOOLS:=.8} logprof.conf.5
|
||||
|
||||
all: ${MANPAGES} ${HTMLMANPAGES}
|
||||
$(MAKE) -C po all
|
||||
@@ -45,12 +43,10 @@ all: ${MANPAGES} ${HTMLMANPAGES}
|
||||
DESTDIR=/
|
||||
BINDIR=${DESTDIR}/usr/sbin
|
||||
CONFDIR=${DESTDIR}/etc/apparmor
|
||||
VENDOR_PERL=$(shell perl -e 'use Config; print $$Config{"vendorlib"};')
|
||||
PERLDIR=${DESTDIR}${VENDOR_PERL}/${MODDIR}
|
||||
PYPREFIX=/usr
|
||||
|
||||
po/${NAME}.pot: ${TOOLS} ${PYTOOLS}
|
||||
$(MAKE) -C po ${NAME}.pot NAME=${NAME} SOURCES="${TOOLS} ${MODULES} ${PYTOOLS}"
|
||||
po/${NAME}.pot: ${TOOLS}
|
||||
$(MAKE) -C po ${NAME}.pot NAME=${NAME} SOURCES="${TOOLS} ${MODULES}"
|
||||
|
||||
.PHONY: install
|
||||
install: ${MANPAGES} ${HTMLMANPAGES}
|
||||
@@ -59,8 +55,6 @@ install: ${MANPAGES} ${HTMLMANPAGES}
|
||||
install -d ${BINDIR}
|
||||
ln -sf aa-status ${BINDIR}/apparmor_status
|
||||
install -m 755 ${TOOLS} ${BINDIR}
|
||||
install -d ${PERLDIR}
|
||||
install -m 644 ${MODULES} ${PERLDIR}
|
||||
$(MAKE) -C po install DESTDIR=${DESTDIR} NAME=${NAME}
|
||||
$(MAKE) install_manpages DESTDIR=${DESTDIR}
|
||||
$(MAKE) -C vim install DESTDIR=${DESTDIR}
|
||||
@@ -78,7 +72,7 @@ clean: _clean
|
||||
$(MAKE) -C vim clean
|
||||
rm -rf staging/ build/
|
||||
rm -f apparmor/*.pyc
|
||||
rm -rf test/__pycache__/
|
||||
rm -rf test/__pycache__/ apparmor/__pycache__/
|
||||
|
||||
# ${CAPABILITIES} is defined in common/Make.rules
|
||||
.PHONY: check_severity_db
|
||||
@@ -100,7 +94,7 @@ check: check_severity_db
|
||||
perl -c $$i || exit 1; \
|
||||
done
|
||||
tmpfile=$$(mktemp --tmpdir aa-pyflakes-XXXXXX); \
|
||||
for i in ${PYTOOLS} apparmor aa-status test/*.py; do \
|
||||
for i in ${PYTOOLS} apparmor test/*.py; do \
|
||||
echo Checking $$i; \
|
||||
pyflakes $$i 2>&1 | grep -v "undefined name '_'" > $$tmpfile; \
|
||||
test -s $$tmpfile && cat $$tmpfile && rm -f $$tmpfile && exit 1; \
|
||||
|
3
utils/README.md
Normal file
3
utils/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
Known Bugs:
|
||||
Will allow multiple letters in the () due to translation/unicode issues with regexing the key.
|
||||
User input will probably bug out in a different locale.
|
136
utils/aa-audit
136
utils/aa-audit
@@ -1,7 +1,6 @@
|
||||
#!/usr/bin/perl
|
||||
#! /usr/bin/env python
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2005 Novell, Inc. All Rights Reserved.
|
||||
# Copyright (c) 2011 Canonical, Ltd.
|
||||
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
@@ -12,121 +11,30 @@
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Novell, Inc.
|
||||
#
|
||||
# To contact Novell about this file by physical or electronic mail,
|
||||
# you may find current contact information at www.novell.com.
|
||||
# ----------------------------------------------------------------------
|
||||
import argparse
|
||||
import traceback
|
||||
|
||||
use strict;
|
||||
use FindBin;
|
||||
use Getopt::Long;
|
||||
import apparmor.tools
|
||||
|
||||
use Immunix::AppArmor;
|
||||
# setup module translations
|
||||
from apparmor.translations import init_translation
|
||||
_ = init_translation()
|
||||
|
||||
use Data::Dumper;
|
||||
parser = argparse.ArgumentParser(description=_('Switch the given programs to audit mode'))
|
||||
parser.add_argument('-d', '--dir', type=str, help=_('path to profiles'))
|
||||
parser.add_argument('-r', '--remove', action='store_true', help=_('remove audit mode'))
|
||||
parser.add_argument('program', type=str, nargs='+', help=_('name of program'))
|
||||
parser.add_argument('--trace', action='store_true', help=_('Show full trace'))
|
||||
args = parser.parse_args()
|
||||
|
||||
use Locale::gettext;
|
||||
use POSIX;
|
||||
try:
|
||||
audit = apparmor.tools.aa_tools('audit', args)
|
||||
|
||||
# initialize the local poo
|
||||
setlocale(LC_MESSAGES, "");
|
||||
textdomain("apparmor-utils");
|
||||
|
||||
$UI_Mode = "text";
|
||||
|
||||
# options variables
|
||||
my $help = '';
|
||||
|
||||
GetOptions(
|
||||
'dir|d=s' => \$profiledir,
|
||||
'help|h' => \$help,
|
||||
);
|
||||
|
||||
# tell 'em how to use it...
|
||||
&usage && exit if $help;
|
||||
|
||||
# let's convert it to full path...
|
||||
$profiledir = get_full_path($profiledir);
|
||||
|
||||
unless (-d $profiledir) {
|
||||
UI_Important("Can't find AppArmor profiles in $profiledir.");
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# what are we profiling?
|
||||
my @profiling = @ARGV;
|
||||
|
||||
unless (@profiling) {
|
||||
@profiling = (UI_GetString("Please enter the program to switch to audit mode: ", ""));
|
||||
}
|
||||
|
||||
for my $profiling (@profiling) {
|
||||
|
||||
next unless $profiling;
|
||||
|
||||
my $fqdbin;
|
||||
if (-e $profiling) {
|
||||
$fqdbin = get_full_path($profiling);
|
||||
chomp($fqdbin);
|
||||
} else {
|
||||
if ($profiling !~ /\//) {
|
||||
opendir(DIR,$profiledir);
|
||||
my @tmp_fqdbin = grep ( /$profiling/, readdir(DIR));
|
||||
closedir(DIR);
|
||||
if (scalar @tmp_fqdbin eq 1) {
|
||||
$fqdbin = "$profiledir/$tmp_fqdbin[0]";
|
||||
} else {
|
||||
my $which = which($profiling);
|
||||
if ($which) {
|
||||
$fqdbin = get_full_path($which);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-e $fqdbin) {
|
||||
|
||||
my $filename;
|
||||
if ($fqdbin =~ /^$profiledir\//) {
|
||||
$filename = $fqdbin;
|
||||
} else {
|
||||
$filename = getprofilefilename($fqdbin);
|
||||
}
|
||||
|
||||
# argh, skip directories
|
||||
next unless -f $filename;
|
||||
|
||||
# skip rpm backup files
|
||||
next if isSkippableFile($filename);
|
||||
|
||||
printf(gettext('Setting %s to audit mode.'), $fqdbin);
|
||||
print "\n";
|
||||
setprofileflags($filename, "audit");
|
||||
|
||||
my $cmd_info = qx(cat $filename | $parser -I$profiledir -r 2>&1 1>/dev/null);
|
||||
if ($? != 0) {
|
||||
UI_Info($cmd_info);
|
||||
exit $?;
|
||||
}
|
||||
|
||||
# if check_for_subdomain();
|
||||
} else {
|
||||
if ($profiling =~ /^[^\/]+$/) {
|
||||
UI_Info(sprintf(gettext('Can\'t find %s in the system path list. If the name of the application is correct, please run \'which %s\' as a user with the correct PATH environment set up in order to find the fully-qualified path.'), $profiling, $profiling));
|
||||
exit 1;
|
||||
} else {
|
||||
UI_Info(sprintf(gettext('%s does not exist, please double-check the path.'), $profiling));
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit 0;
|
||||
|
||||
sub usage {
|
||||
UI_Info(sprintf(gettext("usage: \%s [ -d /path/to/profiles ] [ program to switch to audit mode ]"), $0));
|
||||
exit 0;
|
||||
}
|
||||
audit.act()
|
||||
except Exception as e:
|
||||
if not args.trace:
|
||||
print(e.value + "\n")
|
||||
|
||||
else:
|
||||
traceback.print_exc()
|
||||
|
@@ -2,17 +2,30 @@
|
||||
|
||||
=head1 NAME
|
||||
|
||||
aa-audit - set a AppArmor security profile to I<audit> mode.
|
||||
aa-audit - set an AppArmor security profile to I<audit> mode.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<aa-audit I<E<lt>executableE<gt>> [I<E<lt>executableE<gt>> ...]>
|
||||
B<aa-audit I<E<lt>executableE<gt>> [I<E<lt>executableE<gt>> ...] [I<-d /path/to/profiles>] [I<-r>]>
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
B<-d --dir /path/to/profiles>
|
||||
|
||||
Specifies where to look for the AppArmor security profile set.
|
||||
Defaults to /etc/apparmor.d.
|
||||
|
||||
B<-r --remove>
|
||||
|
||||
Removes the audit mode for the profile.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
B<aa-audit> is used to set the audit mode for one or more profiles to audit.
|
||||
B<aa-audit> is used to set one or more profiles to audit mode.
|
||||
In this mode security policy is enforced and all access (successes and failures) are logged to the system log.
|
||||
|
||||
The I<--remove> option can be used to remove the audit mode for the profile.
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
If you find any bugs, please report them at
|
||||
|
119
utils/aa-autodep
119
utils/aa-autodep
@@ -1,7 +1,6 @@
|
||||
#!/usr/bin/perl
|
||||
#! /usr/bin/env python
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2005 Novell, Inc. All Rights Reserved.
|
||||
# Copyright (c) 2011 Canonical, Ltd.
|
||||
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
@@ -12,111 +11,21 @@
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Novell, Inc.
|
||||
#
|
||||
# To contact Novell about this file by physical or electronic mail,
|
||||
# you may find current contact information at www.novell.com.
|
||||
# ----------------------------------------------------------------------
|
||||
import argparse
|
||||
|
||||
use strict;
|
||||
use FindBin;
|
||||
use Getopt::Long;
|
||||
import apparmor.tools
|
||||
|
||||
use Immunix::AppArmor;
|
||||
# setup module translations
|
||||
from apparmor.translations import init_translation
|
||||
_ = init_translation()
|
||||
|
||||
use Data::Dumper;
|
||||
parser = argparse.ArgumentParser(description=_('Generate a basic AppArmor profile by guessing requirements'))
|
||||
parser.add_argument('--force', action='store_true', default=False, help=_('overwrite existing profile'))
|
||||
parser.add_argument('-d', '--dir', type=str, help=_('path to profiles'))
|
||||
parser.add_argument('program', type=str, nargs='+', help=_('name of program'))
|
||||
args = parser.parse_args()
|
||||
|
||||
use Locale::gettext;
|
||||
use POSIX;
|
||||
|
||||
# force $PATH to be sane
|
||||
$ENV{PATH} = "/bin:/sbin:/usr/bin:/usr/sbin";
|
||||
|
||||
# initialize the local poo
|
||||
setlocale(LC_MESSAGES, "");
|
||||
textdomain("apparmor-utils");
|
||||
|
||||
$UI_Mode = "text";
|
||||
|
||||
# options variables
|
||||
my $help = '';
|
||||
my $force = undef;
|
||||
|
||||
GetOptions(
|
||||
'force' => \$force,
|
||||
'dir|d=s' => \$profiledir,
|
||||
'help|h' => \$help,
|
||||
);
|
||||
|
||||
# tell 'em how to use it...
|
||||
&usage && exit if $help;
|
||||
|
||||
my $sd_mountpoint = check_for_subdomain();
|
||||
|
||||
# let's convert it to full path...
|
||||
$profiledir = get_full_path($profiledir);
|
||||
|
||||
unless (-d $profiledir) {
|
||||
UI_Important(sprintf(gettext('Can\'t find AppArmor profiles in %s.'), $profiledir));
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# what are we profiling?
|
||||
my @profiling = @ARGV;
|
||||
|
||||
unless (@profiling) {
|
||||
@profiling = (UI_GetString(gettext("Please enter the program to create a profile for: "), ""));
|
||||
}
|
||||
|
||||
for my $profiling (@profiling) {
|
||||
|
||||
next unless $profiling;
|
||||
|
||||
my $fqdbin;
|
||||
if (-e $profiling) {
|
||||
$fqdbin = get_full_path($profiling);
|
||||
chomp($fqdbin);
|
||||
} else {
|
||||
if ($profiling !~ /\//) {
|
||||
my $which = which($profiling);
|
||||
if ($which) {
|
||||
$fqdbin = get_full_path($which);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# make sure that the app they're requesting to profile is not marked as
|
||||
# not allowed to have it's own profile
|
||||
if ($qualifiers{$fqdbin}) {
|
||||
unless ($qualifiers{$fqdbin} =~ /p/) {
|
||||
UI_Info(sprintf(gettext('%s is currently marked as a program that should not have it\'s own profile. Usually, programs are marked this way if creating a profile for them is likely to break the rest of the system. If you know what you\'re doing and are certain you want to create a profile for this program, edit the corresponding entry in the [qualifiers] section in /etc/apparmor/logprof.conf.'), $fqdbin));
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (-e $fqdbin) {
|
||||
if (-e getprofilefilename($fqdbin) && !$force) {
|
||||
UI_Info(sprintf(gettext('Profile for %s already exists - skipping.'), $fqdbin));
|
||||
} else {
|
||||
autodep($fqdbin);
|
||||
reload($fqdbin) if $sd_mountpoint;
|
||||
}
|
||||
} else {
|
||||
if ($profiling =~ /^[^\/]+$/) {
|
||||
UI_Info(sprintf(gettext('Can\'t find %s in the system path list. If the name of the application is correct, please run \'which %s\' as a user with the correct PATH environment set up in order to find the fully-qualified path.'), $profiling, $profiling));
|
||||
exit 1;
|
||||
} else {
|
||||
UI_Info(sprintf(gettext('%s does not exist, please double-check the path.'), $profiling));
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit 0;
|
||||
|
||||
sub usage {
|
||||
UI_Info("usage: $0 [ --force ] [ -d /path/to/profiles ]");
|
||||
exit 0;
|
||||
}
|
||||
autodep = apparmor.tools.aa_tools('autodep', args)
|
||||
|
||||
autodep.act()
|
||||
|
@@ -26,7 +26,18 @@ aa-autodep - guess basic AppArmor profile requirements
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<aa-autodep I<E<lt>executableE<gt>> [I<E<lt>executableE<gt>> ...]>
|
||||
B<aa-autodep I<E<lt>executableE<gt>> [I<E<lt>executableE<gt>> ...] [I<-d /path/to/profiles>] [I<-f>]>
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
B<-d --dir /path/to/profiles>
|
||||
|
||||
Specifies where to look for the AppArmor security profile set.
|
||||
Defaults to /etc/apparmor.d.
|
||||
|
||||
B<-f --force>
|
||||
|
||||
Overwrites any existing AppArmor profile for the executable with the generated minimal AppArmor profile.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
@@ -37,6 +48,9 @@ a base profile containing a base include directive which includes basic
|
||||
profile entries needed by most programs. The profile is generated by
|
||||
recursively calling ldd(1) on the executables listed on the command line.
|
||||
|
||||
The I<--force> option will overwrite any existing profile for the executable with
|
||||
the newly generated minimal AppArmor profile.
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
This program does not perform full static analysis of executables, so
|
||||
|
31
utils/aa-cleanprof
Executable file
31
utils/aa-cleanprof
Executable file
@@ -0,0 +1,31 @@
|
||||
#! /usr/bin/env python
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# ----------------------------------------------------------------------
|
||||
import argparse
|
||||
|
||||
import apparmor.tools
|
||||
|
||||
# setup module translations
|
||||
from apparmor.translations import init_translation
|
||||
_ = init_translation()
|
||||
|
||||
parser = argparse.ArgumentParser(description=_('Cleanup the profiles for the given programs'))
|
||||
parser.add_argument('-d', '--dir', type=str, help=_('path to profiles'))
|
||||
parser.add_argument('program', type=str, nargs='+', help=_('name of program'))
|
||||
parser.add_argument('-s', '--silent', action='store_true', help=_('Silently overwrite with a clean profile'))
|
||||
args = parser.parse_args()
|
||||
|
||||
clean = apparmor.tools.aa_tools('cleanprof', args)
|
||||
|
||||
clean.act()
|
39
utils/aa-cleanprof.pod
Normal file
39
utils/aa-cleanprof.pod
Normal file
@@ -0,0 +1,39 @@
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
aa-cleanprof - clean an existing AppArmor security profile.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<aa-cleanprof I<E<lt>executableE<gt>> [I<E<lt>executableE<gt>> ...] [I<-d /path/to/profiles>] [I<-s>]>
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
B<-d --dir /path/to/profiles>
|
||||
|
||||
Specifies where to look for the AppArmor security profile set.
|
||||
Defaults to /etc/apparmor.d.
|
||||
|
||||
B<-s --silent>
|
||||
|
||||
Silently overwrites the profile without user prompt.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
B<aa-cleanprof> is used to perform a cleanup on one or more profiles.
|
||||
The tool removes any existing superfluous rules (rules that are covered
|
||||
under an include or another rule), reorders the rules to group similar rules
|
||||
together and removes all comments from the file.
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
If you find any bugs, please report them at
|
||||
L<https://bugs.launchpad.net/apparmor/+filebug>.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
apparmor(7), apparmor.d(5), aa-enforce(1), aa-complain(1), aa-disable(1),
|
||||
aa_change_hat(2), and L<http://wiki.apparmor.net>.
|
||||
|
||||
=cut
|
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/perl
|
||||
#! /usr/bin/env python
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2005 Novell, Inc. All Rights Reserved.
|
||||
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
@@ -11,121 +11,21 @@
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Novell, Inc.
|
||||
#
|
||||
# To contact Novell about this file by physical or electronic mail,
|
||||
# you may find current contact information at www.novell.com.
|
||||
# ----------------------------------------------------------------------
|
||||
import argparse
|
||||
|
||||
use strict;
|
||||
use FindBin;
|
||||
use Getopt::Long;
|
||||
import apparmor.tools
|
||||
|
||||
use Immunix::AppArmor;
|
||||
# setup module translations
|
||||
from apparmor.translations import init_translation
|
||||
_ = init_translation()
|
||||
|
||||
use Data::Dumper;
|
||||
|
||||
use Locale::gettext;
|
||||
use POSIX;
|
||||
|
||||
# initialize the local poo
|
||||
setlocale(LC_MESSAGES, "");
|
||||
textdomain("apparmor-utils");
|
||||
|
||||
$UI_Mode = "text";
|
||||
|
||||
# options variables
|
||||
my $help = '';
|
||||
|
||||
GetOptions(
|
||||
'dir|d=s' => \$profiledir,
|
||||
'help|h' => \$help,
|
||||
);
|
||||
|
||||
# tell 'em how to use it...
|
||||
&usage && exit if $help;
|
||||
|
||||
# let's convert it to full path...
|
||||
$profiledir = get_full_path($profiledir);
|
||||
|
||||
unless (-d $profiledir) {
|
||||
UI_Important("Can't find AppArmor profiles in $profiledir.");
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# what are we profiling?
|
||||
my @profiling = @ARGV;
|
||||
|
||||
unless (@profiling) {
|
||||
@profiling = (UI_GetString(gettext("Please enter the program to switch to complain mode: "), ""));
|
||||
}
|
||||
|
||||
for my $profiling (@profiling) {
|
||||
|
||||
next unless $profiling;
|
||||
|
||||
my $fqdbin;
|
||||
if (-e $profiling) {
|
||||
$fqdbin = get_full_path($profiling);
|
||||
chomp($fqdbin);
|
||||
} else {
|
||||
if ($profiling !~ /\//) {
|
||||
opendir(DIR,$profiledir);
|
||||
my @tmp_fqdbin = grep ( /$profiling/, readdir(DIR));
|
||||
closedir(DIR);
|
||||
if (scalar @tmp_fqdbin eq 1) {
|
||||
$fqdbin = "$profiledir/$tmp_fqdbin[0]";
|
||||
} else {
|
||||
my $which = which($profiling);
|
||||
if ($which) {
|
||||
$fqdbin = get_full_path($which);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-e $fqdbin) {
|
||||
|
||||
my $filename;
|
||||
if ($fqdbin =~ /^$profiledir\//) {
|
||||
$filename = $fqdbin;
|
||||
} else {
|
||||
$filename = getprofilefilename($fqdbin);
|
||||
}
|
||||
|
||||
# argh, skip directories
|
||||
next unless -f $filename;
|
||||
|
||||
# skip rpm backup files
|
||||
next if isSkippableFile($filename);
|
||||
|
||||
printf(gettext('Setting %s to complain mode.'), $fqdbin);
|
||||
print "\n";
|
||||
setprofileflags($filename, "complain");
|
||||
|
||||
my $cmd_info = qx(cat $filename | $parser -I$profiledir -r 2>&1 1>/dev/null);
|
||||
if ($? != 0) {
|
||||
UI_Info($cmd_info);
|
||||
exit $?;
|
||||
}
|
||||
|
||||
# if check_for_subdomain();
|
||||
} else {
|
||||
if ($profiling =~ /^[^\/]+$/) {
|
||||
UI_Info(sprintf(gettext('Can\'t find %s in the system path list. If the name of the application is correct, please run \'which %s\' as a user with the correct PATH environment set up in order to find the fully-qualified path.'), $profiling, $profiling));
|
||||
exit 1;
|
||||
} else {
|
||||
UI_Info(sprintf(gettext('%s does not exist, please double-check the path.'), $profiling));
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit 0;
|
||||
|
||||
sub usage {
|
||||
UI_Info(sprintf(gettext("usage: \%s [ -d /path/to/profiles ] [ program to switch to complain mode ]"), $0));
|
||||
exit 0;
|
||||
}
|
||||
parser = argparse.ArgumentParser(description=_('Switch the given program to complain mode'))
|
||||
parser.add_argument('-d', '--dir', type=str, help=_('path to profiles'))
|
||||
parser.add_argument('-r', '--remove', action='store_true', help=_('remove complain mode'))
|
||||
parser.add_argument('program', type=str, nargs='+', help=_('name of program'))
|
||||
args = parser.parse_args()
|
||||
|
||||
complain = apparmor.tools.aa_tools('complain', args)
|
||||
#print(args)
|
||||
complain.act()
|
||||
|
@@ -22,17 +22,31 @@
|
||||
|
||||
=head1 NAME
|
||||
|
||||
aa-complain - set a AppArmor security profile to I<complain> mode.
|
||||
aa-complain - set an AppArmor security profile to I<complain> mode.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<aa-complain I<E<lt>executableE<gt>> [I<E<lt>executableE<gt>> ...]>
|
||||
B<aa-complain I<E<lt>executableE<gt>> [I<E<lt>executableE<gt>> ...] [I<-d /path/to/profiles>] [I<-r>]>
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
B<-d --dir /path/to/profiles>
|
||||
|
||||
Specifies where to look for the AppArmor security profile set.
|
||||
Defaults to /etc/apparmor.d.
|
||||
|
||||
B<-r --remove>
|
||||
|
||||
Removes the complain mode for the profile.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
B<aa-complain> is used to set the enforcement mode for one or more profiles to
|
||||
complain. In this mode security policy is not enforced but rather access
|
||||
violations are logged to the system log.
|
||||
B<aa-complain> is used to set the enforcement mode for one or more profiles to I<complain> mode.
|
||||
In this mode security policy is not enforced but rather access violations
|
||||
are logged to the system log.
|
||||
|
||||
The I<--remove> option can be used to remove the complain mode for the profile,
|
||||
setting it to enforce mode by default.
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
|
148
utils/aa-disable
148
utils/aa-disable
@@ -1,7 +1,6 @@
|
||||
#!/usr/bin/perl
|
||||
#! /usr/bin/env python
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2005-2010 Novell, Inc. All Rights Reserved.
|
||||
# Copyright (c) 2011 Canonical, Inc. All Rights Reserved.
|
||||
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
@@ -12,141 +11,22 @@
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Canonical, Inc.
|
||||
#
|
||||
# To contact Canonical about this file by physical or electronic mail,
|
||||
# you may find current contact information at www.canonical.com.
|
||||
# ----------------------------------------------------------------------
|
||||
import argparse
|
||||
|
||||
use strict;
|
||||
use FindBin;
|
||||
use Getopt::Long;
|
||||
import apparmor.tools
|
||||
|
||||
use Immunix::AppArmor;
|
||||
# setup module translations
|
||||
from apparmor.translations import init_translation
|
||||
_ = init_translation()
|
||||
|
||||
use Data::Dumper;
|
||||
parser = argparse.ArgumentParser(description=_('Disable the profile for the given programs'))
|
||||
parser.add_argument('-d', '--dir', type=str, help=_('path to profiles'))
|
||||
parser.add_argument('-r', '--revert', action='store_true', help=_('enable the profile for the given programs'))
|
||||
parser.add_argument('program', type=str, nargs='+', help=_('name of program'))
|
||||
args = parser.parse_args()
|
||||
|
||||
use Locale::gettext;
|
||||
use POSIX;
|
||||
use File::Basename;
|
||||
disable = apparmor.tools.aa_tools('disable', args)
|
||||
|
||||
# initialize the local poo
|
||||
setlocale(LC_MESSAGES, "");
|
||||
textdomain("apparmor-utils");
|
||||
|
||||
$UI_Mode = "text";
|
||||
|
||||
# options variables
|
||||
my $help = '';
|
||||
|
||||
GetOptions(
|
||||
'dir|d=s' => \$profiledir,
|
||||
'help|h' => \$help,
|
||||
);
|
||||
|
||||
# tell 'em how to use it...
|
||||
&usage && exit if $help;
|
||||
|
||||
# let's convert it to full path...
|
||||
$profiledir = get_full_path($profiledir);
|
||||
|
||||
unless (-d $profiledir) {
|
||||
UI_Important("Can't find AppArmor profiles in $profiledir.");
|
||||
exit 1;
|
||||
}
|
||||
|
||||
my $disabledir = "$profiledir/disable";
|
||||
unless (-d $disabledir) {
|
||||
UI_Important("Can't find AppArmor disable directory '$disabledir'.");
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# what are we profiling?
|
||||
my @profiling = @ARGV;
|
||||
|
||||
unless (@profiling) {
|
||||
@profiling = (UI_GetString(gettext("Please enter the program whose profile should be disabled: "), ""));
|
||||
}
|
||||
|
||||
for my $profiling (@profiling) {
|
||||
|
||||
next unless $profiling;
|
||||
|
||||
my $fqdbin;
|
||||
if (-e $profiling) {
|
||||
$fqdbin = get_full_path($profiling);
|
||||
chomp($fqdbin);
|
||||
} else {
|
||||
if ($profiling !~ /\//) {
|
||||
opendir(DIR,$profiledir);
|
||||
my @tmp_fqdbin = grep ( /$profiling/, readdir(DIR));
|
||||
closedir(DIR);
|
||||
if (scalar @tmp_fqdbin eq 1) {
|
||||
$fqdbin = "$profiledir/$tmp_fqdbin[0]";
|
||||
} else {
|
||||
my $which = which($profiling);
|
||||
if ($which) {
|
||||
$fqdbin = get_full_path($which);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-e $fqdbin) {
|
||||
|
||||
my $filename;
|
||||
if ($fqdbin =~ /^$profiledir\//) {
|
||||
$filename = $fqdbin;
|
||||
} else {
|
||||
$filename = getprofilefilename($fqdbin);
|
||||
}
|
||||
|
||||
# argh, skip directories
|
||||
next unless -f $filename;
|
||||
|
||||
# skip package manager backup files
|
||||
next if isSkippableFile($filename);
|
||||
|
||||
my ($bname, $dname, $suffix) = File::Basename::fileparse($filename);
|
||||
if ($bname eq "") {
|
||||
UI_Info(sprintf(gettext('Could not find basename for %s.'), $filename));
|
||||
exit 1;
|
||||
}
|
||||
|
||||
printf(gettext('Disabling %s.'), $fqdbin);
|
||||
print "\n";
|
||||
|
||||
my $link = "$disabledir/$bname";
|
||||
if (! -e $link) {
|
||||
if (symlink($filename, $link) != 1) {
|
||||
UI_Info(sprintf(gettext('Could not create %s symlink.'), $link));
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
|
||||
my $cmd_info = qx(cat $filename | $parser -I$profiledir -R 2>&1 1>/dev/null);
|
||||
if ($? != 0) {
|
||||
UI_Info($cmd_info);
|
||||
exit $?;
|
||||
}
|
||||
|
||||
# if check_for_subdomain();
|
||||
} else {
|
||||
if ($profiling =~ /^[^\/]+$/) {
|
||||
UI_Info(sprintf(gettext('Can\'t find %s in the system path list. If the name of the application is correct, please run \'which %s\' as a user with the correct PATH environment set up in order to find the fully-qualified path.'), $profiling, $profiling));
|
||||
exit 1;
|
||||
} else {
|
||||
UI_Info(sprintf(gettext('%s does not exist, please double-check the path.'), $profiling));
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit 0;
|
||||
|
||||
sub usage {
|
||||
UI_Info(sprintf(gettext("usage: \%s [ -d /path/to/profiles ] [ program to have profile disabled ]"), $0));
|
||||
exit 0;
|
||||
}
|
||||
disable.act()
|
||||
|
||||
|
@@ -26,15 +26,28 @@ aa-disable - disable an AppArmor security profile
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<aa-disable I<E<lt>executableE<gt>> [I<E<lt>executableE<gt>> ...]>
|
||||
B<aa-disable I<E<lt>executableE<gt>> [I<E<lt>executableE<gt>> ...] [I<-d /path/to/profiles>] [I<-r>]>
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
B<-d --dir /path/to/profiles>
|
||||
|
||||
Specifies where to look for the AppArmor security profile set.
|
||||
Defaults to /etc/apparmor.d.
|
||||
|
||||
B<-r --revert>
|
||||
|
||||
Enables the profile and loads it.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
B<aa-disable> is used to disable the enforcement mode for one or more
|
||||
profiles. This command will unload the profile from the kernel and
|
||||
prevent the profile from being loaded on AppArmor startup. The
|
||||
I<aa-enforce> and I<aa-complain> utilities may be used to to change this
|
||||
behavior.
|
||||
B<aa-disable> is used to I<disable> one or more profiles.
|
||||
This command will unload the profile from the kernel and prevent the
|
||||
profile from being loaded on AppArmor startup.
|
||||
The I<aa-enforce> and I<aa-complain> utilities may be used to to change
|
||||
this behavior.
|
||||
|
||||
The I<--revert> option can be used to enable the profile.
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#! /usr/bin/env python
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2011-2012 Canonical Ltd.
|
||||
# Copyright (C) 2011-2013 Canonical Ltd.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
@@ -22,6 +22,7 @@ if __name__ == "__main__":
|
||||
|
||||
(opt, args) = apparmor.easyprof.parse_args()
|
||||
binary = None
|
||||
manifest = None
|
||||
|
||||
m = usage()
|
||||
if opt.show_policy_group and not opt.policy_groups:
|
||||
@@ -33,33 +34,65 @@ if __name__ == "__main__":
|
||||
if len(args) >= 1:
|
||||
binary = args[0]
|
||||
|
||||
# parse_manifest() returns a list of tuples (binary, options). Create a
|
||||
# list of these profile tuples to support multiple profiles in one manifest
|
||||
profiles = []
|
||||
if opt.manifest:
|
||||
try:
|
||||
easyp = apparmor.easyprof.AppArmorEasyProfile(binary, opt)
|
||||
# should hide this in a common function
|
||||
if sys.version_info[0] >= 3:
|
||||
f = open(opt.manifest, "r", encoding="utf-8")
|
||||
else:
|
||||
f = open(opt.manifest, "r")
|
||||
manifest = f.read()
|
||||
except EnvironmentError as e:
|
||||
error("Could not read '%s': %s (%d)\n" % (opt.manifest,
|
||||
os.strerror(e.errno),
|
||||
e.errno))
|
||||
profiles = apparmor.easyprof.parse_manifest(manifest, opt)
|
||||
else: # fake up a tuple list when processing command line args
|
||||
profiles.append( (binary, opt) )
|
||||
|
||||
count = 0
|
||||
for (binary, options) in profiles:
|
||||
if len(profiles) > 1:
|
||||
count += 1
|
||||
try:
|
||||
easyp = apparmor.easyprof.AppArmorEasyProfile(binary, options)
|
||||
except AppArmorException as e:
|
||||
error(e.value)
|
||||
except Exception:
|
||||
raise
|
||||
|
||||
if opt.list_templates:
|
||||
if options.list_templates:
|
||||
apparmor.easyprof.print_basefilenames(easyp.get_templates())
|
||||
sys.exit(0)
|
||||
elif opt.template and opt.show_template:
|
||||
files = [os.path.join(easyp.dirs['templates'], opt.template)]
|
||||
elif options.template and options.show_template:
|
||||
files = [os.path.join(easyp.dirs['templates'], options.template)]
|
||||
apparmor.easyprof.print_files(files)
|
||||
sys.exit(0)
|
||||
elif opt.list_policy_groups:
|
||||
elif options.list_policy_groups:
|
||||
apparmor.easyprof.print_basefilenames(easyp.get_policy_groups())
|
||||
sys.exit(0)
|
||||
elif opt.policy_groups and opt.show_policy_group:
|
||||
for g in opt.policy_groups.split(','):
|
||||
elif options.policy_groups and options.show_policy_group:
|
||||
for g in options.policy_groups.split(','):
|
||||
files = [os.path.join(easyp.dirs['policygroups'], g)]
|
||||
apparmor.easyprof.print_files(files)
|
||||
sys.exit(0)
|
||||
elif binary == None:
|
||||
error("Must specify full path to binary\n%s" % m)
|
||||
elif binary == None and not options.profile_name and \
|
||||
not options.manifest:
|
||||
error("Must specify binary and/or profile name\n%s" % m)
|
||||
|
||||
# if we made it here, generate a profile
|
||||
params = apparmor.easyprof.gen_policy_params(binary, opt)
|
||||
p = easyp.gen_policy(**params)
|
||||
sys.stdout.write('%s\n' % p)
|
||||
params = apparmor.easyprof.gen_policy_params(binary, options)
|
||||
if options.manifest and options.verify_manifest and \
|
||||
not apparmor.easyprof.verify_manifest(params):
|
||||
error("Manifest file requires review")
|
||||
|
||||
if options.output_format == "json":
|
||||
sys.stdout.write('%s\n' % easyp.gen_manifest(params))
|
||||
else:
|
||||
params['no_verify'] = options.no_verify
|
||||
try:
|
||||
easyp.output_policy(params, count, opt.output_directory)
|
||||
except AppArmorException as e:
|
||||
error(e)
|
||||
|
@@ -78,8 +78,15 @@ Like --read-path but also allow owner writes in additions to reads.
|
||||
=item -n NAME, --name=NAME
|
||||
|
||||
Specify NAME of policy. If not specified, NAME is set to the name of the
|
||||
binary. The NAME of the policy is often used as part of the path in the
|
||||
various templates.
|
||||
binary. The NAME of the policy is typically only used for profile meta
|
||||
data and does not specify the AppArmor profile name.
|
||||
|
||||
=item --profile-name=PROFILENAME
|
||||
|
||||
Specify the AppArmor profile name. When set, uses 'profile PROFILENAME' in the
|
||||
profile. When set and specifying a binary, uses 'profile PROFILENAME BINARY'
|
||||
in the profile. If not set, the binary will be used as the profile name and
|
||||
profile attachment.
|
||||
|
||||
=item --template-var="@{VAR}=VALUE"
|
||||
|
||||
@@ -110,6 +117,32 @@ Display policy groups specified with --policy.
|
||||
|
||||
Use PATH instead of system policy-groups directory.
|
||||
|
||||
=item --policy-version=VERSION
|
||||
|
||||
Must be used with --policy-vendor and is used to specify the version of policy
|
||||
groups and templates. When specified, B<aa-easyprof> looks for the subdirectory
|
||||
VENDOR/VERSION within the policy-groups and templates directory. The specified
|
||||
version must be a positive decimal number compatible with the JSON Number type.
|
||||
Eg, when using:
|
||||
|
||||
=over
|
||||
|
||||
$ aa-easyprof --templates-dir=/usr/share/apparmor/easyprof/templates \
|
||||
--policy-groups-dir=/usr/share/apparmor/easyprof/policygroups \
|
||||
--policy-vendor="foo" \
|
||||
--policy-version=1.0
|
||||
|
||||
=back
|
||||
|
||||
Then /usr/share/apparmor/easyprof/templates/foo/1.0 will be searched for
|
||||
templates and /usr/share/apparmor/easyprof/policygroups/foo/1.0 for policy
|
||||
groups.
|
||||
|
||||
=item --policy-vendor=VENDOR
|
||||
|
||||
Must be used with --policy-version and is used to specify the vendor for policy
|
||||
groups and templates. See --policy-version for more information.
|
||||
|
||||
=item --author
|
||||
|
||||
Specify author of the policy.
|
||||
@@ -122,6 +155,104 @@ Specify copyright of the policy.
|
||||
|
||||
Specify comment for the policy.
|
||||
|
||||
=item -m MANIFEST, --manifest=MANIFEST
|
||||
|
||||
B<aa-easyprof> also supports using a JSON manifest file for specifying options
|
||||
related to policy. Unlike command line arguments, the JSON file may specify
|
||||
multiple profiles. The structure of the JSON is:
|
||||
|
||||
{
|
||||
"security": {
|
||||
"profiles": {
|
||||
"<profile name 1>": {
|
||||
... attributes specific to this profile ...
|
||||
},
|
||||
"<profile name 2>": {
|
||||
...
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Each profile JSON object (ie, everything under a profile name) may specify any
|
||||
fields related to policy. The "security" JSON container object is optional and
|
||||
may be omitted. An example manifest file demonstrating all fields is:
|
||||
|
||||
{
|
||||
"security": {
|
||||
"profiles": {
|
||||
"com.example.foo": {
|
||||
"abstractions": [
|
||||
"audio",
|
||||
"gnome"
|
||||
],
|
||||
"author": "Your Name",
|
||||
"binary": "/opt/foo/**",
|
||||
"comment": "Unstructured single-line comment",
|
||||
"copyright": "Unstructured single-line copyright statement",
|
||||
"name": "My Foo App",
|
||||
"policy_groups": [
|
||||
"networking",
|
||||
"user-application"
|
||||
],
|
||||
"policy_vendor": "somevendor",
|
||||
"policy_version": 1.0,
|
||||
"read_path": [
|
||||
"/tmp/foo_r",
|
||||
"/tmp/bar_r/"
|
||||
],
|
||||
"template": "user-application",
|
||||
"template_variables": {
|
||||
"APPNAME": "foo",
|
||||
"VAR1": "bar",
|
||||
"VAR2": "baz"
|
||||
},
|
||||
"write_path": [
|
||||
"/tmp/foo_w",
|
||||
"/tmp/bar_w/"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
A manifest file does not have to include all the fields. Eg, a manifest file
|
||||
for an Ubuntu SDK application might be:
|
||||
|
||||
{
|
||||
"security": {
|
||||
"profiles": {
|
||||
"com.ubuntu.developer.myusername.MyCoolApp": {
|
||||
"policy_groups": [
|
||||
"networking",
|
||||
"online-accounts"
|
||||
],
|
||||
"policy_vendor": "ubuntu",
|
||||
"policy_version": 1.0,
|
||||
"template": "ubuntu-sdk",
|
||||
"template_variables": {
|
||||
"APPNAME": "MyCoolApp",
|
||||
"APPVERSION": "0.1.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
=item --verify-manifest
|
||||
|
||||
When used with --manifest, warn about potentially unsafe definitions in the
|
||||
manifest file.
|
||||
|
||||
=item --output-format=FORMAT
|
||||
|
||||
Specify either B<text> (default if unspecified) for AppArmor policy output or
|
||||
B<json> for JSON manifest format.
|
||||
|
||||
=item --output-directory=DIR
|
||||
|
||||
Specify output directory for profile. If unspecified, policy is sent to stdout.
|
||||
|
||||
=back
|
||||
|
||||
=head1 EXAMPLE
|
||||
@@ -130,7 +261,41 @@ Example usage for a program named 'foo' which is installed in /opt/foo:
|
||||
|
||||
=over
|
||||
|
||||
$ aa-easyprof --template=user-application --template-var="@{APPNAME}=foo" --policy-groups=opt-application,user-application /opt/foo/bin/FooApp
|
||||
$ aa-easyprof --template=user-application --template-var="@{APPNAME}=foo" \
|
||||
--policy-groups=opt-application,user-application \
|
||||
/opt/foo/bin/FooApp
|
||||
|
||||
=back
|
||||
|
||||
When using a manifest file:
|
||||
|
||||
=over
|
||||
|
||||
$ aa-easyprof --manifest=manifest.json
|
||||
|
||||
=back
|
||||
|
||||
To output a manifest file based on aa-easyprof arguments:
|
||||
|
||||
=over
|
||||
|
||||
$ aa-easyprof --output-format=json \
|
||||
--author="Your Name" \
|
||||
--comment="Unstructured single-line comment" \
|
||||
--copyright="Unstructured single-line copyright statement" \
|
||||
--name="My Foo App" \
|
||||
--profile-name="com.example.foo" \
|
||||
--template="user-application" \
|
||||
--policy-groups="user-application,networking" \
|
||||
--abstractions="audio,gnome" \
|
||||
--read-path="/tmp/foo_r" \
|
||||
--read-path="/tmp/bar_r/" \
|
||||
--write-path="/tmp/foo_w" \
|
||||
--write-path=/tmp/bar_w/ \
|
||||
--template-var="@{APPNAME}=foo" \
|
||||
--template-var="@{VAR1}=bar" \
|
||||
--template-var="@{VAR2}=baz" \
|
||||
"/opt/foo/**"
|
||||
|
||||
=back
|
||||
|
||||
|
141
utils/aa-enforce
141
utils/aa-enforce
@@ -1,7 +1,6 @@
|
||||
#!/usr/bin/perl
|
||||
#! /usr/bin/env python
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2005 Novell, Inc. All Rights Reserved.
|
||||
# Copyright (c) 2011 Canonical, Ltd.
|
||||
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
@@ -12,131 +11,23 @@
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Novell, Inc.
|
||||
#
|
||||
# To contact Novell about this file by physical or electronic mail,
|
||||
# you may find current contact information at www.novell.com.
|
||||
# ----------------------------------------------------------------------
|
||||
import argparse
|
||||
|
||||
use strict;
|
||||
use FindBin;
|
||||
use Getopt::Long;
|
||||
import apparmor.tools
|
||||
|
||||
use Immunix::AppArmor;
|
||||
# setup module translations
|
||||
from apparmor.translations import init_translation
|
||||
_ = init_translation()
|
||||
|
||||
use Data::Dumper;
|
||||
parser = argparse.ArgumentParser(description=_('Switch the given program to enforce mode'))
|
||||
parser.add_argument('-d', '--dir', type=str, help=_('path to profiles'))
|
||||
parser.add_argument('-r', '--remove', action='store_true', help=_('switch to complain mode'))
|
||||
parser.add_argument('program', type=str, nargs='+', help=_('name of program'))
|
||||
args = parser.parse_args()
|
||||
# Flipping the remove flag since complain = !enforce
|
||||
args.remove = not args.remove
|
||||
|
||||
use Locale::gettext;
|
||||
use POSIX;
|
||||
|
||||
# initialize the local poo
|
||||
setlocale(LC_MESSAGES, "");
|
||||
textdomain("apparmor-utils");
|
||||
|
||||
$UI_Mode = "text";
|
||||
|
||||
# options variables
|
||||
my $help = '';
|
||||
|
||||
GetOptions(
|
||||
'dir|d=s' => \$profiledir,
|
||||
'help|h' => \$help,
|
||||
);
|
||||
|
||||
# tell 'em how to use it...
|
||||
&usage && exit if $help;
|
||||
|
||||
# let's convert it to full path...
|
||||
$profiledir = get_full_path($profiledir);
|
||||
|
||||
unless (-d $profiledir) {
|
||||
UI_Important("Can't find AppArmor profiles in $profiledir.");
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# what are we profiling?
|
||||
my @profiling = @ARGV;
|
||||
|
||||
unless (@profiling) {
|
||||
@profiling = (UI_GetString(gettext("Please enter the program to switch to enforce mode: "), ""));
|
||||
}
|
||||
|
||||
for my $profiling (@profiling) {
|
||||
|
||||
next unless $profiling;
|
||||
|
||||
my $fqdbin;
|
||||
if (-e $profiling) {
|
||||
$fqdbin = get_full_path($profiling);
|
||||
chomp($fqdbin);
|
||||
} else {
|
||||
if ($profiling !~ /\//) {
|
||||
opendir(DIR,$profiledir);
|
||||
my @tmp_fqdbin = grep ( /$profiling/, readdir(DIR));
|
||||
closedir(DIR);
|
||||
if (scalar @tmp_fqdbin eq 1) {
|
||||
$fqdbin = "$profiledir/$tmp_fqdbin[0]";
|
||||
} else {
|
||||
my $which = which($profiling);
|
||||
if ($which) {
|
||||
$fqdbin = get_full_path($which);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-e $fqdbin) {
|
||||
my $filename;
|
||||
if ($fqdbin =~ /^$profiledir\//) {
|
||||
$filename = $fqdbin;
|
||||
} else {
|
||||
$filename = getprofilefilename($fqdbin);
|
||||
}
|
||||
|
||||
# argh, skip directories
|
||||
next unless -f $filename;
|
||||
|
||||
# skip rpm backup files
|
||||
next if isSkippableFile($filename);
|
||||
|
||||
printf(gettext('Setting %s to enforce mode.'), $fqdbin);
|
||||
print "\n";
|
||||
setprofileflags($filename, "");
|
||||
|
||||
# remove symlink in $profiledir/force-complain as well
|
||||
my $complainlink = $filename;
|
||||
$complainlink =~ s/^$profiledir/$profiledir\/force-complain/;
|
||||
-e $complainlink and unlink($complainlink);
|
||||
|
||||
# remove symlink in $profiledir/disable as well
|
||||
my $disablelink = $filename;
|
||||
$disablelink =~ s/^$profiledir/$profiledir\/disable/;
|
||||
-e $disablelink and unlink($disablelink);
|
||||
|
||||
my $cmd_info = qx(cat $filename | $parser -I$profiledir -r 2>&1 1>/dev/null);
|
||||
if ($? != 0) {
|
||||
UI_Info($cmd_info);
|
||||
exit $?;
|
||||
}
|
||||
|
||||
|
||||
# if check_for_subdomain();
|
||||
} else {
|
||||
if ($profiling =~ /^[^\/]+$/) {
|
||||
UI_Info(sprintf(gettext('Can\'t find %s in the system path list. If the name of the application is correct, please run \'which %s\' as a user with the correct PATH environment set up in order to find the fully-qualified path.'), $profiling, $profiling));
|
||||
exit 1;
|
||||
} else {
|
||||
UI_Info(sprintf(gettext('%s does not exist, please double-check the path.'), $profiling));
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit 0;
|
||||
|
||||
sub usage {
|
||||
UI_Info(sprintf(gettext("usage: \%s [ -d /path/to/profiles ] [ program to switch to enforce mode ]"), $0));
|
||||
exit 0;
|
||||
}
|
||||
enforce = apparmor.tools.aa_tools('complain', args)
|
||||
|
||||
enforce.act()
|
||||
|
@@ -27,16 +27,30 @@ being disabled or I<complain> mode.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<aa-enforce I<E<lt>executableE<gt>> [I<E<lt>executableE<gt>> ...]>
|
||||
B<aa-enforce I<E<lt>executableE<gt>> [I<E<lt>executableE<gt>> ...] [I<-d /path/to/profiles>] [I<-r>]>
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
B<-d --dir / path/to/profiles>
|
||||
|
||||
Specifies where to look for the AppArmor security profile set.
|
||||
Defaults to /etc/apparmor.d.
|
||||
|
||||
B<-r --remove>
|
||||
|
||||
Removes the enforce mode for the profile.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
B<aa-enforce> is used to set the enforcement mode for one or more profiles
|
||||
to I<enforce>. This command is only relevant in conjunction with the
|
||||
I<aa-complain> utility which sets a profile to complain mode and the
|
||||
I<aa-disable> utility which unloads and disables a profile. The default
|
||||
mode for a security policy is enforce and the I<aa-complain> utility must
|
||||
be run to change this behavior.
|
||||
B<aa-enforce> is used to set one or more profiles to I<enforce> mode.
|
||||
This command is only relevant in conjunction with the I<aa-complain> utility
|
||||
which sets a profile to complain mode and the I<aa-disable> utility which
|
||||
unloads and disables a profile.
|
||||
The default mode for a security policy is enforce and the I<aa-complain>
|
||||
utility must be run to change this behavior.
|
||||
|
||||
The I<--remove> option can be used to remove the enforce mode for the profile,
|
||||
setting it to complain mode.
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
|
298
utils/aa-genprof
298
utils/aa-genprof
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/perl
|
||||
#! /usr/bin/env python
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2005 Novell, Inc. All Rights Reserved.
|
||||
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
@@ -11,206 +11,154 @@
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Novell, Inc.
|
||||
#
|
||||
# To contact Novell about this file by physical or electronic mail,
|
||||
# you may find current contact information at www.novell.com.
|
||||
# ----------------------------------------------------------------------
|
||||
import argparse
|
||||
import atexit
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
use strict;
|
||||
use Getopt::Long;
|
||||
import apparmor.aa as apparmor
|
||||
|
||||
use Immunix::AppArmor;
|
||||
# setup module translations
|
||||
from apparmor.translations import init_translation
|
||||
_ = init_translation()
|
||||
|
||||
use Data::Dumper;
|
||||
def sysctl_read(path):
|
||||
value = None
|
||||
with open(path, 'r') as f_in:
|
||||
value = int(f_in.readline())
|
||||
return value
|
||||
|
||||
use Locale::gettext;
|
||||
use POSIX;
|
||||
def sysctl_write(path, value):
|
||||
if not value:
|
||||
return
|
||||
with open(path, 'w') as f_out:
|
||||
f_out.write(str(value))
|
||||
|
||||
sub sysctl_read($) {
|
||||
my $path = shift;
|
||||
my $value = undef;
|
||||
if (open(SYSCTL, "<$path")) {
|
||||
$value = int(<SYSCTL>);
|
||||
}
|
||||
close(SYSCTL);
|
||||
return $value;
|
||||
}
|
||||
def last_audit_entry_time():
|
||||
out = subprocess.check_output(['tail', '-1', '/var/log/audit/audit.log'], shell=True)
|
||||
logmark = None
|
||||
if re.search('^*msg\=audit\((\d+\.\d+\:\d+).*\).*$', out):
|
||||
logmark = re.search('^*msg\=audit\((\d+\.\d+\:\d+).*\).*$', out).groups()[0]
|
||||
else:
|
||||
logmark = ''
|
||||
return logmark
|
||||
|
||||
sub sysctl_write($$) {
|
||||
my $path = shift;
|
||||
my $value = shift;
|
||||
return if (!defined($value));
|
||||
if (open(SYSCTL, ">$path")) {
|
||||
print SYSCTL $value;
|
||||
close(SYSCTl);
|
||||
}
|
||||
}
|
||||
def restore_ratelimit():
|
||||
sysctl_write(ratelimit_sysctl, ratelimit_saved)
|
||||
|
||||
# force $PATH to be sane
|
||||
$ENV{PATH} = "/bin:/sbin:/usr/bin:/usr/sbin";
|
||||
parser = argparse.ArgumentParser(description=_('Generate profile for the given program'))
|
||||
parser.add_argument('-d', '--dir', type=str, help=_('path to profiles'))
|
||||
parser.add_argument('-f', '--file', type=str, help=_('path to logfile'))
|
||||
parser.add_argument('program', type=str, help=_('name of program to profile'))
|
||||
args = parser.parse_args()
|
||||
|
||||
# initialize the local poo
|
||||
setlocale(LC_MESSAGES, "");
|
||||
textdomain("apparmor-utils");
|
||||
|
||||
# options variables
|
||||
my $help = '';
|
||||
|
||||
GetOptions(
|
||||
'file|f=s' => \$filename,
|
||||
'dir|d=s' => \$profiledir,
|
||||
'help|h' => \$help,
|
||||
);
|
||||
|
||||
# tell 'em how to use it...
|
||||
&usage && exit if $help;
|
||||
|
||||
my $sd_mountpoint = check_for_subdomain();
|
||||
unless ($sd_mountpoint) {
|
||||
fatal_error(gettext("AppArmor does not appear to be started. Please enable AppArmor and try again."));
|
||||
}
|
||||
|
||||
# let's convert it to full path...
|
||||
$profiledir = get_full_path($profiledir);
|
||||
|
||||
unless (-d $profiledir) {
|
||||
fatal_error "Can't find AppArmor profiles in $profiledir.";
|
||||
}
|
||||
|
||||
# what are we profiling?
|
||||
my $profiling = shift;
|
||||
|
||||
unless ($profiling) {
|
||||
$profiling = UI_GetString(gettext("Please enter the program to profile: "), "")
|
||||
|| exit 0;
|
||||
}
|
||||
|
||||
my $fqdbin;
|
||||
if (-e $profiling) {
|
||||
$fqdbin = get_full_path($profiling);
|
||||
chomp($fqdbin);
|
||||
} else {
|
||||
if ($profiling !~ /\//) {
|
||||
my $which = which($profiling);
|
||||
if ($which) {
|
||||
$fqdbin = get_full_path($which);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unless ($fqdbin && -e $fqdbin) {
|
||||
if ($profiling =~ /^[^\/]+$/) {
|
||||
fatal_error(sprintf(gettext('Can\'t find %s in the system path list. If the name of the application is correct, please run \'which %s\' in the other window in order to find the fully-qualified path.'), $profiling, $profiling));
|
||||
} else {
|
||||
fatal_error(sprintf(gettext('%s does not exist, please double-check the path.'), $profiling));
|
||||
}
|
||||
}
|
||||
profiling = args.program
|
||||
profiledir = args.dir
|
||||
filename = args.file
|
||||
|
||||
|
||||
# make sure that the app they're requesting to profile is not marked as
|
||||
# not allowed to have it's own profile
|
||||
check_qualifiers($fqdbin);
|
||||
if filename:
|
||||
if not os.path.isfile(filename):
|
||||
raise apparmor.AppArmorException(_('The logfile %s does not exist. Please check the path') % filename)
|
||||
else:
|
||||
apparmor.filename = filename
|
||||
|
||||
# load all the include files
|
||||
loadincludes();
|
||||
aa_mountpoint = apparmor.check_for_apparmor()
|
||||
if not aa_mountpoint:
|
||||
raise apparmor.AppArmorException(_('It seems AppArmor was not started. Please enable AppArmor and try again.'))
|
||||
|
||||
my $profilefilename = getprofilefilename($fqdbin);
|
||||
if (-e $profilefilename) {
|
||||
$helpers{$fqdbin} = getprofileflags($profilefilename) || "enforce";
|
||||
} else {
|
||||
autodep($fqdbin);
|
||||
$helpers{$fqdbin} = "enforce";
|
||||
}
|
||||
if profiledir:
|
||||
apparmor.profile_dir = apparmor.get_full_path(profiledir)
|
||||
if not os.path.isdir(apparmor.profile_dir):
|
||||
raise apparmor.AppArmorException(_("%s is not a directory.") %profiledir)
|
||||
|
||||
if ($helpers{$fqdbin} eq "enforce") {
|
||||
complain($fqdbin);
|
||||
reload($fqdbin);
|
||||
}
|
||||
program = None
|
||||
#if os.path.exists(apparmor.which(profiling.strip())):
|
||||
if os.path.exists(profiling):
|
||||
program = apparmor.get_full_path(profiling)
|
||||
else:
|
||||
if '/' not in profiling:
|
||||
which = apparmor.which(profiling)
|
||||
if which:
|
||||
program = apparmor.get_full_path(which)
|
||||
|
||||
if not program or not os.path.exists(program):
|
||||
if '/' not in profiling:
|
||||
raise apparmor.AppArmorException(_("Can't find %s in the system path list. If the name of the application\nis correct, please run 'which %s' as a user with correct PATH\nenvironment set up in order to find the fully-qualified path and\nuse the full path as parameter.") %(profiling, profiling))
|
||||
else:
|
||||
raise apparmor.AppArmorException(_('%s does not exists, please double-check the path.') %profiling)
|
||||
|
||||
# Check if the program has been marked as not allowed to have a profile
|
||||
apparmor.check_qualifiers(program)
|
||||
|
||||
apparmor.loadincludes()
|
||||
|
||||
profile_filename = apparmor.get_profile_filename(program)
|
||||
if os.path.exists(profile_filename):
|
||||
apparmor.helpers[program] = apparmor.get_profile_flags(profile_filename, program)
|
||||
else:
|
||||
apparmor.autodep(program)
|
||||
apparmor.helpers[program] = 'enforce'
|
||||
|
||||
if apparmor.helpers[program] == 'enforce':
|
||||
apparmor.complain(program)
|
||||
apparmor.reload(program)
|
||||
|
||||
# When reading from syslog, it is possible to hit the default kernel
|
||||
# printk ratelimit. This will result in audit entries getting skipped,
|
||||
# making profile generation inaccurate. When using genprof, disable
|
||||
# the printk ratelimit, and restore it on exit.
|
||||
my $ratelimit_sysctl = "/proc/sys/kernel/printk_ratelimit";
|
||||
my $ratelimit_saved = sysctl_read($ratelimit_sysctl);
|
||||
END { sysctl_write($ratelimit_sysctl, $ratelimit_saved); }
|
||||
sysctl_write($ratelimit_sysctl, 0);
|
||||
ratelimit_sysctl = '/proc/sys/kernel/printk_ratelimit'
|
||||
ratelimit_saved = sysctl_read(ratelimit_sysctl)
|
||||
sysctl_write(ratelimit_sysctl, 0)
|
||||
|
||||
UI_Info(gettext("\nBefore you begin, you may wish to check if a\nprofile already exists for the application you\nwish to confine. See the following wiki page for\nmore information:\nhttp://wiki.apparmor.net/index.php/Profiles"));
|
||||
atexit.register(restore_ratelimit)
|
||||
|
||||
UI_Important(gettext("Please start the application to be profiled in \nanother window and exercise its functionality now.\n\nOnce completed, select the \"Scan\" button below in \norder to scan the system logs for AppArmor events. \n\nFor each AppArmor event, you will be given the \nopportunity to choose whether the access should be \nallowed or denied."));
|
||||
apparmor.UI_Info(_('\nBefore you begin, you may wish to check if a\nprofile already exists for the application you\nwish to confine. See the following wiki page for\nmore information:')+'\nhttp://wiki.apparmor.net/index.php/Profiles')
|
||||
|
||||
my $syslog = 1;
|
||||
my $logmark = "";
|
||||
my $done_profiling = 0;
|
||||
apparmor.UI_Important(_('Please start the application to be profiled in\nanother window and exercise its functionality now.\n\nOnce completed, select the "Scan" option below in \norder to scan the system logs for AppArmor events. \n\nFor each AppArmor event, you will be given the \nopportunity to choose whether the access should be \nallowed or denied.'))
|
||||
|
||||
$syslog = 0 if (-e "/var/log/audit/audit.log");
|
||||
syslog = True
|
||||
logmark = ''
|
||||
done_profiling = False
|
||||
|
||||
while (not $done_profiling) {
|
||||
if ($syslog) {
|
||||
$logmark = `date | md5sum`;
|
||||
chomp $logmark;
|
||||
$logmark = $1 if $logmark =~ /^([0-9a-f]+)/;
|
||||
system("$logger -p kern.warn 'GenProf: $logmark'");
|
||||
} else {
|
||||
$logmark = last_audit_entry_time();
|
||||
}
|
||||
eval {
|
||||
if os.path.exists('/var/log/audit/audit.log'):
|
||||
syslog = False
|
||||
|
||||
my $q = {};
|
||||
$q->{headers} = [ gettext("Profiling"), $fqdbin ];
|
||||
$q->{functions} = [ "CMD_SCAN", "CMD_FINISHED" ];
|
||||
$q->{default} = "CMD_SCAN";
|
||||
passno = 0
|
||||
while not done_profiling:
|
||||
if syslog:
|
||||
logmark = subprocess.check_output(['date | md5sum'], shell=True)
|
||||
logmark = logmark.decode('ascii').strip()
|
||||
logmark = re.search('^([0-9a-f]+)', logmark).groups()[0]
|
||||
t=subprocess.call("%s -p kern.warn 'GenProf: %s'"%(apparmor.logger, logmark), shell=True)
|
||||
|
||||
my ($ans, $arg) = UI_PromptUser($q);
|
||||
else:
|
||||
logmark = last_audit_entry_time()
|
||||
|
||||
if ($ans eq "CMD_SCAN") {
|
||||
q=apparmor.hasher()
|
||||
q['headers'] = [_('Profiling'), program]
|
||||
q['functions'] = ['CMD_SCAN', 'CMD_FINISHED']
|
||||
q['default'] = 'CMD_SCAN'
|
||||
ans, arg = apparmor.UI_PromptUser(q, 'noexit')
|
||||
|
||||
my $lp_ret = do_logprof_pass($logmark);
|
||||
if ans == 'CMD_SCAN':
|
||||
lp_ret = apparmor.do_logprof_pass(logmark, passno)
|
||||
passno += 1
|
||||
if lp_ret == 'FINISHED':
|
||||
done_profiling = True
|
||||
else:
|
||||
done_profiling = True
|
||||
|
||||
$done_profiling = 1 if $lp_ret eq "FINISHED";
|
||||
for p in sorted(apparmor.helpers.keys()):
|
||||
if apparmor.helpers[p] == 'enforce':
|
||||
apparmor.enforce(p)
|
||||
apparmor.reload(p)
|
||||
|
||||
} else {
|
||||
|
||||
$done_profiling = 1;
|
||||
|
||||
}
|
||||
};
|
||||
if ($@) {
|
||||
if ($@ =~ /FINISHING/) {
|
||||
$done_profiling = 1;
|
||||
} else {
|
||||
die $@;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for my $p (sort keys %helpers) {
|
||||
if ($helpers{$p} eq "enforce") {
|
||||
enforce($p);
|
||||
reload($p);
|
||||
}
|
||||
}
|
||||
|
||||
UI_Info(gettext("Reloaded AppArmor profiles in enforce mode."));
|
||||
UI_Info(gettext("\nPlease consider contributing your new profile! See\nthe following wiki page for more information:\nhttp://wiki.apparmor.net/index.php/Profiles\n"));
|
||||
UI_Info(sprintf(gettext('Finished generating profile for %s.'), $fqdbin));
|
||||
exit 0;
|
||||
|
||||
sub usage {
|
||||
UI_Info(sprintf(gettext("usage: \%s [ -d /path/to/profiles ] [ -f /path/to/logfile ] [ program to profile ]"), $0));
|
||||
exit 0;
|
||||
}
|
||||
|
||||
sub last_audit_entry_time {
|
||||
local $_ = `tail -1 /var/log/audit/audit.log`;
|
||||
my $logmark;
|
||||
if (/^*msg\=audit\((\d+\.\d+\:\d+).*\).*$/) {
|
||||
$logmark = $1;
|
||||
} else {
|
||||
$logmark = "";
|
||||
}
|
||||
return $logmark;
|
||||
}
|
||||
apparmor.UI_Info(_('\nReloaded AppArmor profiles in enforce mode.'))
|
||||
apparmor.UI_Info(_('\nPlease consider contributing your new profile!\nSee the following wiki page for more information:')+'\nhttp://wiki.apparmor.net/index.php/Profiles\n')
|
||||
apparmor.UI_Info(_('Finished generating profile for %s.')%program)
|
||||
sys.exit(0)
|
||||
|
@@ -26,7 +26,7 @@ aa-genprof - profile generation utility for AppArmor
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<aa-genprof I<E<lt>executableE<gt>> [I<-d /path/to/profiles>]>
|
||||
B<aa-genprof I<E<lt>executableE<gt>> [I<-d /path/to/profiles>] [I<-f /path/to/logfile>]>
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
@@ -35,6 +35,14 @@ B<-d --dir /path/to/profiles>
|
||||
Specifies where to look for the AppArmor security profile set.
|
||||
Defaults to /etc/apparmor.d.
|
||||
|
||||
B<-f --file /path/to/logfile>
|
||||
|
||||
Specifies the location of logfile.
|
||||
Default locations are read from F</etc/apparmor/logprof.conf>.
|
||||
Typical defaults are:
|
||||
/var/log/audit/audit.log
|
||||
/var/log/syslog
|
||||
/var/log/messages
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
@@ -64,7 +72,7 @@ using aa-logprof(1).
|
||||
After the user finishes selecting profile entries based on violations
|
||||
that were detected during the program execution, aa-genprof will reload
|
||||
the updated profiles in complain mode and again prompt the user for (S)can and
|
||||
(D)one. This cycle can then be repeated as necessary until all application
|
||||
(F)inish. This cycle can then be repeated as necessary until all application
|
||||
functionality has been exercised without generating access violations.
|
||||
|
||||
When the user eventually hits (F)inish, aa-genprof will set the main profile,
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/perl
|
||||
#! /usr/bin/env python
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2005 Novell, Inc. All Rights Reserved.
|
||||
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
@@ -11,62 +11,43 @@
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Novell, Inc.
|
||||
#
|
||||
# To contact Novell about this file by physical or electronic mail,
|
||||
# you may find current contact information at www.novell.com.
|
||||
# ----------------------------------------------------------------------
|
||||
import argparse
|
||||
import os
|
||||
|
||||
use strict;
|
||||
use Data::Dumper;
|
||||
use Getopt::Long;
|
||||
use Locale::gettext;
|
||||
use POSIX;
|
||||
import apparmor.aa as apparmor
|
||||
|
||||
use Immunix::AppArmor;
|
||||
# setup module translations
|
||||
from apparmor.translations import init_translation
|
||||
_ = init_translation()
|
||||
|
||||
# force $PATH to be sane
|
||||
$ENV{PATH} = "/bin:/sbin:/usr/bin:/usr/sbin";
|
||||
parser = argparse.ArgumentParser(description=_('Process log entries to generate profiles'))
|
||||
parser.add_argument('-d', '--dir', type=str, help=_('path to profiles'))
|
||||
parser.add_argument('-f', '--file', type=str, help=_('path to logfile'))
|
||||
parser.add_argument('-m', '--mark', type=str, help=_('mark in the log to start processing after'))
|
||||
args = parser.parse_args()
|
||||
|
||||
# initialize the local poo
|
||||
setlocale(LC_MESSAGES, "");
|
||||
textdomain("apparmor-utils");
|
||||
profiledir = args.dir
|
||||
filename = args.file
|
||||
logmark = args.mark or ''
|
||||
|
||||
setup_yast();
|
||||
|
||||
# options variables
|
||||
my $help = '';
|
||||
my $logmark;
|
||||
if filename:
|
||||
if not os.path.isfile(filename):
|
||||
raise apparmor.AppArmorException(_('The logfile %s does not exist. Please check the path') % filename)
|
||||
else:
|
||||
apparmor.filename = filename
|
||||
|
||||
GetOptions(
|
||||
'file|f=s' => \$filename,
|
||||
'dir|d=s' => \$profiledir,
|
||||
'logmark|m=s' => \$logmark,
|
||||
'help|h' => \$help,
|
||||
);
|
||||
aa_mountpoint = apparmor.check_for_apparmor()
|
||||
if not aa_mountpoint:
|
||||
raise apparmor.AppArmorException(_('It seems AppArmor was not started. Please enable AppArmor and try again.'))
|
||||
|
||||
# tell 'em how to use it...
|
||||
&usage && exit if $help;
|
||||
if profiledir:
|
||||
apparmor.profile_dir = apparmor.get_full_path(profiledir)
|
||||
if not os.path.isdir(apparmor.profile_dir):
|
||||
raise apparmor.AppArmorException("%s is not a directory."%profiledir)
|
||||
|
||||
# let's convert it to full path...
|
||||
$profiledir = get_full_path($profiledir);
|
||||
apparmor.loadincludes()
|
||||
|
||||
unless (-d $profiledir) {
|
||||
fatal_error "Can't find AppArmor profiles in $profiledir.";
|
||||
}
|
||||
|
||||
# load all the include files
|
||||
loadincludes();
|
||||
|
||||
do_logprof_pass($logmark);
|
||||
|
||||
shutdown_yast();
|
||||
|
||||
exit 0;
|
||||
|
||||
sub usage {
|
||||
UI_Info(sprintf(gettext("usage: \%s [ -d /path/to/profiles ] [ -f /path/to/logfile ] [ -m \"mark in log to start processing after\""), $0));
|
||||
exit 0;
|
||||
}
|
||||
apparmor.do_logprof_pass(logmark)
|
||||
|
||||
|
@@ -22,7 +22,7 @@
|
||||
|
||||
=head1 NAME
|
||||
|
||||
aa-logprof - utility program for managing AppArmor security profiles
|
||||
aa-logprof - utility for updating AppArmor security profiles
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
@@ -32,12 +32,17 @@ B<aa-logprof [I<-d /path/to/profiles>] [I<-f /path/to/logfile>] [I<-m E<lt>mark
|
||||
|
||||
B<-d --dir /path/to/profiles>
|
||||
|
||||
The path to where the AppArmor security profiles are stored
|
||||
Specifies where to look for the AppArmor security profile set.
|
||||
Defaults to /etc/apparmor.d.
|
||||
|
||||
B<-f --file /path/to/logfile>
|
||||
|
||||
The path to the location of the logfile that contains AppArmor
|
||||
security events.
|
||||
Specifies the location of logfile that contains AppArmor security events.
|
||||
Default locations are read from F</etc/apparmor/logprof.conf>.
|
||||
Typical defaults are:
|
||||
/var/log/audit/audit.log
|
||||
/var/log/syslog
|
||||
/var/log/messages
|
||||
|
||||
B< -m --logmark "mark">
|
||||
|
||||
@@ -47,9 +52,8 @@ B< -m --logmark "mark">
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
B<aa-logprof> is an interactive tool used to review AppArmor's
|
||||
complain mode output and generate new entries for AppArmor security
|
||||
profiles.
|
||||
B<aa-logprof> is an interactive tool used to review AppArmor generated
|
||||
messages and update AppArmor security profiles.
|
||||
|
||||
Running aa-logprof will scan the log file and if there are new AppArmor
|
||||
events that are not covered by the existing profile set, the user will
|
||||
@@ -71,11 +75,17 @@ The user is then presented with info about the access including profile,
|
||||
path, old mode if there was a previous entry in the profile for this path,
|
||||
new mode, the suggestion list, and given these options:
|
||||
|
||||
(A)llow, (D)eny, (N)ew, (G)lob last piece, (Q)uit
|
||||
(A)llow, (D)eny, (I)gnore, (N)ew, (G)lob last piece, (Q)uit
|
||||
|
||||
If the AppArmor profile was in complain mode when the event was generated,
|
||||
the default for this option is (A)llow, otherwise, it's (D)eny.
|
||||
|
||||
The (D)eny option adds a "deny" rule to the AppArmor profile, which
|
||||
silences logging.
|
||||
|
||||
The (I)gnore option allows user to ignore the event, without making any
|
||||
changes to the AppArmor profile.
|
||||
|
||||
The suggestion list is presented as a numbered list with includes
|
||||
at the top, the literal path in the middle, and the suggested globs
|
||||
at the bottom. If any globs are being suggested, the shortest glob
|
||||
@@ -109,9 +119,9 @@ Adding r access to /usr/share/themes/** would delete an entry for r
|
||||
access to /usr/share/themes/foo/*.gif if it exists in the profile.
|
||||
|
||||
If (Q)uit is selected at this point, aa-logprof will ignore all new pending
|
||||
capability and path accesses.
|
||||
accesses.
|
||||
|
||||
After all of the path accesses have been handled, logrof will write all
|
||||
After all of the accesses have been handled, logrof will write all
|
||||
updated profiles to the disk and reload them if AppArmor is running.
|
||||
|
||||
=head2 New Process (Execution) Events
|
||||
|
678
utils/aa-mergeprof
Executable file
678
utils/aa-mergeprof
Executable file
@@ -0,0 +1,678 @@
|
||||
#! /usr/bin/env python
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# ----------------------------------------------------------------------
|
||||
import argparse
|
||||
import re
|
||||
|
||||
import apparmor.aa
|
||||
import apparmor.aamode
|
||||
import apparmor.severity
|
||||
import apparmor.cleanprofile as cleanprofile
|
||||
|
||||
# setup module translations
|
||||
from apparmor.translations import init_translation
|
||||
_ = init_translation()
|
||||
|
||||
parser = argparse.ArgumentParser(description=_('Perform a 3way merge on the given profiles'))
|
||||
parser.add_argument('mine', type=str, help=_('your profile'))
|
||||
parser.add_argument('base', type=str, help=_('base profile'))
|
||||
parser.add_argument('other', type=str, help=_('other profile'))
|
||||
parser.add_argument('-d', '--dir', type=str, help=_('path to profiles'))
|
||||
parser.add_argument('-a', '--auto', action='store_true', help=_('Automatically merge profiles, exits incase of *x conflicts'))
|
||||
args = parser.parse_args()
|
||||
|
||||
profiles = [args.mine, args.base, args.other]
|
||||
|
||||
|
||||
def main():
|
||||
mergeprofiles = Merge(profiles)
|
||||
#Get rid of common/superfluous stuff
|
||||
mergeprofiles.clear_common()
|
||||
|
||||
if not args.auto:
|
||||
mergeprofiles.ask_the_questions('other')
|
||||
|
||||
mergeprofiles.clear_common()
|
||||
|
||||
mergeprofiles.ask_the_questions('base')
|
||||
|
||||
q = apparmor.aa.hasher()
|
||||
q['title'] = 'Changed Local Profiles'
|
||||
q['headers'] = []
|
||||
q['explanation'] = _('The following local profiles were changed. Would you like to save them?')
|
||||
q['functions'] = ['CMD_SAVE_CHANGES', 'CMD_VIEW_CHANGES', 'CMD_ABORT']
|
||||
q['default'] = 'CMD_VIEW_CHANGES'
|
||||
q['options'] = []
|
||||
q['selected'] = 0
|
||||
ans = ''
|
||||
arg = None
|
||||
programs = list(mergeprofiles.user.aa.keys())
|
||||
program = programs[0]
|
||||
while ans != 'CMD_SAVE_CHANGES':
|
||||
ans, arg = apparmor.aa.UI_PromptUser(q)
|
||||
if ans == 'CMD_SAVE_CHANGES':
|
||||
apparmor.aa.write_profile_ui_feedback(program)
|
||||
apparmor.aa.reload_base(program)
|
||||
elif ans == 'CMD_VIEW_CHANGES':
|
||||
for program in programs:
|
||||
apparmor.aa.original_aa[program] = apparmor.aa.deepcopy(apparmor.aa.aa[program])
|
||||
#oldprofile = apparmor.serialize_profile(apparmor.original_aa[program], program, '')
|
||||
newprofile = apparmor.aa.serialize_profile(mergeprofiles.user.aa[program], program, '')
|
||||
apparmor.aa.display_changes_with_comments(mergeprofiles.user.filename, newprofile)
|
||||
|
||||
|
||||
class Merge(object):
|
||||
def __init__(self, profiles):
|
||||
user, base, other = profiles
|
||||
|
||||
#Read and parse base profile and save profile data, include data from it and reset them
|
||||
apparmor.aa.read_profile(base, True)
|
||||
self.base = cleanprofile.Prof(base)
|
||||
|
||||
self.reset()
|
||||
|
||||
#Read and parse other profile and save profile data, include data from it and reset them
|
||||
apparmor.aa.read_profile(other, True)
|
||||
self.other = cleanprofile.Prof(other)
|
||||
|
||||
self.reset()
|
||||
|
||||
#Read and parse user profile
|
||||
apparmor.aa.read_profile(profiles[0], True)
|
||||
self.user = cleanprofile.Prof(user)
|
||||
|
||||
def reset(self):
|
||||
apparmor.aa.aa = apparmor.aa.hasher()
|
||||
apparmor.aa.filelist = apparmor.aa.hasher()
|
||||
apparmor.aa.include = dict()
|
||||
apparmor.aa.existing_profiles = apparmor.aa.hasher()
|
||||
apparmor.aa.original_aa = apparmor.aa.hasher()
|
||||
|
||||
def clear_common(self):
|
||||
deleted = 0
|
||||
#Remove off the parts in other profile which are common/superfluous from user profile
|
||||
user_other = cleanprofile.CleanProf(False, self.user, self.other)
|
||||
deleted += user_other.compare_profiles()
|
||||
|
||||
#Remove off the parts in base profile which are common/superfluous from user profile
|
||||
user_base = cleanprofile.CleanProf(False, self.user, self.base)
|
||||
deleted += user_base.compare_profiles()
|
||||
|
||||
#Remove off the parts in other profile which are common/superfluous from base profile
|
||||
# base_other = cleanprofile.CleanProf(False, self.base, self.other) # XXX base_other not used?
|
||||
deleted += user_base.compare_profiles()
|
||||
|
||||
def conflict_mode(self, profile, hat, allow, path, mode, new_mode, old_mode):
|
||||
m = new_mode
|
||||
o = old_mode
|
||||
new_mode = apparmor.aa.flatten_mode(new_mode)
|
||||
old_mode = apparmor.aa.flatten_mode(old_mode)
|
||||
conflict_modes = set('uUpPcCiIxX')
|
||||
conflict_x= (old_mode | new_mode) & conflict_modes
|
||||
if conflict_x:
|
||||
#We may have conflicting x modes
|
||||
if conflict_x & set('x'):
|
||||
conflict_x.remove('x')
|
||||
if conflict_x & set('X'):
|
||||
conflict_x.remove('X')
|
||||
if len(conflict_x) > 1:
|
||||
q = apparmor.aa.hasher()
|
||||
q['headers'] = [_('Path'), path]
|
||||
q['headers'] += [_('Select the appropriate mode'), '']
|
||||
options = []
|
||||
options.append('%s: %s' %(mode, apparmor.aa.mode_to_str_user(new_mode)))# - (old_mode & conflict_x))))
|
||||
options.append('%s: %s' %(mode, apparmor.aa.mode_to_str_user(old_mode)))#(old_mode | new_mode) - (new_mode & conflict_x))))
|
||||
q['options'] = options
|
||||
q['functions'] = ['CMD_ALLOW', 'CMD_ABORT']
|
||||
done = False
|
||||
while not done:
|
||||
ans, selected = apparmor.aa.UI_PromptUser(q)
|
||||
if ans == 'CMD_ALLOW':
|
||||
if selected == 0:
|
||||
self.user.aa[profile][hat][allow]['path'][path][mode] = m#apparmor.aa.owner_flatten_mode(new_mode)#(old_mode | new_mode) - (old_mode & conflict_x)
|
||||
return m
|
||||
elif selected == 1:
|
||||
return o
|
||||
pass#self.user.aa[profile][hat][allow][path][mode] = (old_mode | new_mode) - (new_mode & conflict_x)
|
||||
else:
|
||||
raise apparmor.aa.AppArmorException(_('Unknown selection'))
|
||||
done = True
|
||||
|
||||
def ask_the_questions(self, other):
|
||||
if other == 'other':
|
||||
other = self.other
|
||||
else:
|
||||
other = self.base
|
||||
#print(other.aa)
|
||||
|
||||
#Add the file-wide includes from the other profile to the user profile
|
||||
done = False
|
||||
options = list(map(lambda inc: '#include <%s>' %inc, sorted(other.filelist[other.filename]['include'].keys())))
|
||||
q = apparmor.aa.hasher()
|
||||
q['options'] = options
|
||||
default_option = 1
|
||||
q['selected'] = default_option - 1
|
||||
q['headers'] = [_('File includes'), _('Select the ones you wish to add')]
|
||||
q['functions'] = ['CMD_ALLOW', 'CMD_IGNORE_ENTRY', 'CMD_ABORT', 'CMD_FINISHED']
|
||||
q['default'] = 'CMD_ALLOW'
|
||||
while not done and options:
|
||||
ans, selected = apparmor.aa.UI_PromptUser(q)
|
||||
if ans == 'CMD_IGNORE_ENTRY':
|
||||
done = True
|
||||
elif ans == 'CMD_ALLOW':
|
||||
selection = options[selected]
|
||||
inc = apparmor.aa.re_match_include(selection)
|
||||
self.user.filelist[self.user.filename]['include'][inc] = True
|
||||
options.pop(selected)
|
||||
apparmor.aa.UI_Info(_('Adding %s to the file.') % selection)
|
||||
|
||||
sev_db = apparmor.aa.sev_db
|
||||
if not sev_db:
|
||||
sev_db = apparmor.severity.Severity(apparmor.aa.CONFDIR + '/severity.db', _('unknown'))
|
||||
for profile in sorted(other.aa.keys()):
|
||||
for hat in sorted(other.aa[profile].keys()):
|
||||
#Add the includes from the other profile to the user profile
|
||||
done = False
|
||||
options = list(map(lambda inc: '#include <%s>' %inc, sorted(other.aa[profile][hat]['include'].keys())))
|
||||
q = apparmor.aa.hasher()
|
||||
q['options'] = options
|
||||
default_option = 1
|
||||
q['selected'] = default_option - 1
|
||||
q['headers'] = [_('File includes'), _('Select the ones you wish to add')]
|
||||
q['functions'] = ['CMD_ALLOW', 'CMD_IGNORE_ENTRY', 'CMD_ABORT', 'CMD_FINISHED']
|
||||
q['default'] = 'CMD_ALLOW'
|
||||
while not done and options:
|
||||
ans, selected = apparmor.aa.UI_PromptUser(q)
|
||||
if ans == 'CMD_IGNORE_ENTRY':
|
||||
done = True
|
||||
elif ans == 'CMD_ALLOW':
|
||||
selection = options[selected]
|
||||
inc = apparmor.aa.re_match_include(selection)
|
||||
deleted = apparmor.aa.delete_duplicates(self.user.aa[profile][hat], inc)
|
||||
self.user.aa[profile][hat]['include'][inc] = True
|
||||
options.pop(selected)
|
||||
apparmor.aa.UI_Info(_('Adding %s to the file.') % selection)
|
||||
if deleted:
|
||||
apparmor.aa.UI_Info(_('Deleted %s previous matching profile entries.') % deleted)
|
||||
|
||||
#Add the capabilities
|
||||
for allow in ['allow', 'deny']:
|
||||
if other.aa[profile][hat].get(allow, False):
|
||||
continue
|
||||
for capability in sorted(other.aa[profile][hat][allow]['capability'].keys()):
|
||||
severity = sev_db.rank('CAP_%s' % capability)
|
||||
default_option = 1
|
||||
options = []
|
||||
newincludes = apparmor.aa.match_cap_includes(self.user.aa[profile][hat], capability)
|
||||
q = apparmor.aa.hasher()
|
||||
if newincludes:
|
||||
options += list(map(lambda inc: '#include <%s>' %inc, sorted(set(newincludes))))
|
||||
|
||||
if options:
|
||||
options.append('capability %s' % capability)
|
||||
q['options'] = [options]
|
||||
q['selected'] = default_option - 1
|
||||
|
||||
q['headers'] = [_('Profile'), apparmor.aa.combine_name(profile, hat)]
|
||||
q['headers'] += [_('Capability'), capability]
|
||||
q['headers'] += [_('Severity'), severity]
|
||||
|
||||
audit_toggle = 0
|
||||
|
||||
q['functions'] = ['CMD_ALLOW', 'CMD_DENY', 'CMD_IGNORE_ENTRY', 'CMD_ABORT', 'CMD_FINISHED']
|
||||
|
||||
q['default'] = 'CMD_ALLOW'
|
||||
|
||||
done = False
|
||||
while not done:
|
||||
ans, selected = apparmor.aa.UI_PromptUser(q)
|
||||
# Ignore the log entry
|
||||
if ans == 'CMD_IGNORE_ENTRY':
|
||||
done = True
|
||||
break
|
||||
|
||||
if ans == 'CMD_ALLOW':
|
||||
selection = ''
|
||||
if options:
|
||||
selection = options[selected]
|
||||
match = apparmor.aa.re_match_include(selection)
|
||||
if match:
|
||||
deleted = False
|
||||
inc = match
|
||||
deleted = apparmor.aa.delete_duplicates(self.user.aa[profile][hat], inc)
|
||||
self.user.aa[profile][hat]['include'][inc] = True
|
||||
|
||||
apparmor.aa.UI_Info(_('Adding %s to profile.') % selection)
|
||||
if deleted:
|
||||
apparmor.aa.UI_Info(_('Deleted %s previous matching profile entries.') % deleted)
|
||||
|
||||
self.user.aa[profile][hat]['allow']['capability'][capability]['set'] = True
|
||||
self.user.aa[profile][hat]['allow']['capability'][capability]['audit'] = other.aa[profile][hat]['allow']['capability'][capability]['audit']
|
||||
|
||||
apparmor.aa.changed[profile] = True
|
||||
|
||||
apparmor.aa.UI_Info(_('Adding capability %s to profile.'), capability)
|
||||
done = True
|
||||
|
||||
elif ans == 'CMD_DENY':
|
||||
self.user.aa[profile][hat]['deny']['capability'][capability]['set'] = True
|
||||
apparmor.aa.changed[profile] = True
|
||||
|
||||
apparmor.aa.UI_Info(_('Denying capability %s to profile.') % capability)
|
||||
done = True
|
||||
else:
|
||||
done = False
|
||||
|
||||
# Process all the path entries.
|
||||
for allow in ['allow', 'deny']:
|
||||
for path in sorted(other.aa[profile][hat][allow]['path'].keys()):
|
||||
#print(path, other.aa[profile][hat][allow]['path'][path])
|
||||
mode = other.aa[profile][hat][allow]['path'][path]['mode']
|
||||
|
||||
if self.user.aa[profile][hat][allow]['path'].get(path, False):
|
||||
mode = self.conflict_mode(profile, hat, allow, path, 'mode', other.aa[profile][hat][allow]['path'][path]['mode'], self.user.aa[profile][hat][allow]['path'][path]['mode'])
|
||||
self.conflict_mode(profile, hat, allow, path, 'audit', other.aa[profile][hat][allow]['path'][path]['audit'], self.user.aa[profile][hat][allow]['path'][path]['audit'])
|
||||
apparmor.aa.changed[profile] = True
|
||||
continue
|
||||
# Lookup modes from profile
|
||||
allow_mode = set()
|
||||
allow_audit = set()
|
||||
deny_mode = set()
|
||||
deny_audit = set()
|
||||
|
||||
fmode, famode, fm = apparmor.aa.rematchfrag(self.user.aa[profile][hat], 'allow', path)
|
||||
if fmode:
|
||||
allow_mode |= fmode
|
||||
if famode:
|
||||
allow_audit |= famode
|
||||
|
||||
cm, cam, m = apparmor.aa.rematchfrag(self.user.aa[profile][hat], 'deny', path)
|
||||
if cm:
|
||||
deny_mode |= cm
|
||||
if cam:
|
||||
deny_audit |= cam
|
||||
|
||||
imode, iamode, im = apparmor.aa.match_prof_incs_to_path(self.user.aa[profile][hat], 'allow', path)
|
||||
if imode:
|
||||
allow_mode |= imode
|
||||
if iamode:
|
||||
allow_audit |= iamode
|
||||
|
||||
cm, cam, m = apparmor.aa.match_prof_incs_to_path(self.user.aa[profile][hat], 'deny', path)
|
||||
if cm:
|
||||
deny_mode |= cm
|
||||
if cam:
|
||||
deny_audit |= cam
|
||||
|
||||
if deny_mode & apparmor.aa.AA_MAY_EXEC:
|
||||
deny_mode |= apparmor.aamode.ALL_AA_EXEC_TYPE
|
||||
|
||||
# Mask off the denied modes
|
||||
mode = mode - deny_mode
|
||||
|
||||
# If we get an exec request from some kindof event that generates 'PERMITTING X'
|
||||
# check if its already in allow_mode
|
||||
# if not add ix permission
|
||||
if mode & apparmor.aa.AA_MAY_EXEC:
|
||||
# Remove all type access permission
|
||||
mode = mode - apparmor.aamode.ALL_AA_EXEC_TYPE
|
||||
if not allow_mode & apparmor.aa.AA_MAY_EXEC:
|
||||
mode |= apparmor.aa.str_to_mode('ix')
|
||||
|
||||
# m is not implied by ix
|
||||
|
||||
### If we get an mmap request, check if we already have it in allow_mode
|
||||
##if mode & AA_EXEC_MMAP:
|
||||
## # ix implies m, so we don't need to add m if ix is present
|
||||
## if contains(allow_mode, 'ix'):
|
||||
## mode = mode - AA_EXEC_MMAP
|
||||
|
||||
if not mode:
|
||||
continue
|
||||
|
||||
matches = []
|
||||
|
||||
if fmode:
|
||||
matches += fm
|
||||
|
||||
if imode:
|
||||
matches += im
|
||||
|
||||
if not apparmor.aa.mode_contains(allow_mode, mode):
|
||||
default_option = 1
|
||||
options = []
|
||||
newincludes = []
|
||||
include_valid = False
|
||||
|
||||
for incname in apparmor.aa.include.keys():
|
||||
include_valid = False
|
||||
# If already present skip
|
||||
if self.user.aa[profile][hat][incname]:
|
||||
continue
|
||||
if incname.startswith(apparmor.aa.profile_dir):
|
||||
incname = incname.replace(apparmor.aa.profile_dir+'/', '', 1)
|
||||
|
||||
include_valid = apparmor.aa.valid_include('', incname)
|
||||
|
||||
if not include_valid:
|
||||
continue
|
||||
|
||||
cm, am, m = apparmor.aa.match_include_to_path(incname, 'allow', path)
|
||||
|
||||
if cm and apparmor.aa.mode_contains(cm, mode):
|
||||
dm = apparmor.aa.match_include_to_path(incname, 'deny', path)[0]
|
||||
# If the mode is denied
|
||||
if not mode & dm:
|
||||
if not list(filter(lambda s: '/**' == s, m)):
|
||||
newincludes.append(incname)
|
||||
# Add new includes to the options
|
||||
if newincludes:
|
||||
options += list(map(lambda s: '#include <%s>' % s, sorted(set(newincludes))))
|
||||
# We should have literal the path in options list too
|
||||
options.append(path)
|
||||
# Add any the globs matching path from logprof
|
||||
globs = apparmor.aa.glob_common(path)
|
||||
if globs:
|
||||
matches += globs
|
||||
# Add any user entered matching globs
|
||||
for user_glob in apparmor.aa.user_globs:
|
||||
if apparmor.aa.matchliteral(user_glob, path):
|
||||
matches.append(user_glob)
|
||||
|
||||
matches = list(set(matches))
|
||||
if path in matches:
|
||||
matches.remove(path)
|
||||
|
||||
options += apparmor.aa.order_globs(matches, path)
|
||||
default_option = len(options)
|
||||
|
||||
sev_db.unload_variables()
|
||||
sev_db.load_variables(apparmor.aa.get_profile_filename(profile))
|
||||
severity = sev_db.rank(path, apparmor.aa.mode_to_str(mode))
|
||||
sev_db.unload_variables()
|
||||
|
||||
audit_toggle = 0
|
||||
owner_toggle = 0
|
||||
if apparmor.aa.cfg['settings']['default_owner_prompt']:
|
||||
owner_toggle = apparmor.aa.cfg['settings']['default_owner_prompt']
|
||||
done = False
|
||||
while not done:
|
||||
q = apparmor.aa.hasher()
|
||||
q['headers'] = [_('Profile'), apparmor.aa.combine_name(profile, hat),
|
||||
_('Path'), path]
|
||||
|
||||
if allow_mode:
|
||||
mode |= allow_mode
|
||||
tail = ''
|
||||
s = ''
|
||||
prompt_mode = None
|
||||
if owner_toggle == 0:
|
||||
prompt_mode = apparmor.aa.flatten_mode(mode)
|
||||
tail = ' ' + _('(owner permissions off)')
|
||||
elif owner_toggle == 1:
|
||||
prompt_mode = mode
|
||||
elif owner_toggle == 2:
|
||||
prompt_mode = allow_mode | apparmor.aa.owner_flatten_mode(mode - allow_mode)
|
||||
tail = ' ' + _('(force new perms to owner)')
|
||||
else:
|
||||
prompt_mode = apparmor.aa.owner_flatten_mode(mode)
|
||||
tail = ' ' + _('(force all rule perms to owner)')
|
||||
|
||||
if audit_toggle == 1:
|
||||
s = apparmor.aa.mode_to_str_user(allow_mode)
|
||||
if allow_mode:
|
||||
s += ', '
|
||||
s += 'audit ' + apparmor.aa.mode_to_str_user(prompt_mode - allow_mode) + tail
|
||||
elif audit_toggle == 2:
|
||||
s = 'audit ' + apparmor.aa.mode_to_str_user(prompt_mode) + tail
|
||||
else:
|
||||
s = apparmor.aa.mode_to_str_user(prompt_mode) + tail
|
||||
|
||||
q['headers'] += [_('Old Mode'), apparmor.aa.mode_to_str_user(allow_mode),
|
||||
_('New Mode'), s]
|
||||
|
||||
else:
|
||||
s = ''
|
||||
tail = ''
|
||||
prompt_mode = None
|
||||
if audit_toggle:
|
||||
s = 'audit'
|
||||
if owner_toggle == 0:
|
||||
prompt_mode = apparmor.aa.flatten_mode(mode)
|
||||
tail = ' ' + _('(owner permissions off)')
|
||||
elif owner_toggle == 1:
|
||||
prompt_mode = mode
|
||||
else:
|
||||
prompt_mode = apparmor.aa.owner_flatten_mode(mode)
|
||||
tail = ' ' + _('(force perms to owner)')
|
||||
|
||||
s = apparmor.aa.mode_to_str_user(prompt_mode)
|
||||
q['headers'] += [_('Mode'), s]
|
||||
|
||||
q['headers'] += [_('Severity'), severity]
|
||||
q['options'] = options
|
||||
q['selected'] = default_option - 1
|
||||
q['functions'] = ['CMD_ALLOW', 'CMD_DENY', 'CMD_IGNORE_ENTRY', 'CMD_GLOB',
|
||||
'CMD_GLOBEXT', 'CMD_NEW', 'CMD_ABORT',
|
||||
'CMD_FINISHED', 'CMD_OTHER']
|
||||
|
||||
q['default'] = 'CMD_ALLOW'
|
||||
|
||||
|
||||
ans, selected = apparmor.aa.UI_PromptUser(q)
|
||||
|
||||
if ans == 'CMD_IGNORE_ENTRY':
|
||||
done = True
|
||||
break
|
||||
|
||||
if ans == 'CMD_OTHER':
|
||||
audit_toggle, owner_toggle = apparmor.aa.UI_ask_mode_toggles(audit_toggle, owner_toggle, allow_mode)
|
||||
elif ans == 'CMD_USER_TOGGLE':
|
||||
owner_toggle += 1
|
||||
if not allow_mode and owner_toggle == 2:
|
||||
owner_toggle += 1
|
||||
if owner_toggle > 3:
|
||||
owner_toggle = 0
|
||||
elif ans == 'CMD_ALLOW':
|
||||
path = options[selected]
|
||||
done = True
|
||||
match = apparmor.aa.re_match_include(path)
|
||||
if match:
|
||||
inc = match
|
||||
deleted = 0
|
||||
deleted = apparmor.aa.delete_duplicates(self.user.aa[profile][hat], inc)
|
||||
self.user.aa[profile][hat]['include'][inc] = True
|
||||
apparmor.aa.changed[profile] = True
|
||||
apparmor.aa.UI_Info(_('Adding %s to profile.') % path)
|
||||
if deleted:
|
||||
apparmor.aa.UI_Info(_('Deleted %s previous matching profile entries.') % deleted)
|
||||
|
||||
else:
|
||||
if self.user.aa[profile][hat]['allow']['path'][path].get('mode', False):
|
||||
mode |= self.user.aa[profile][hat]['allow']['path'][path]['mode']
|
||||
deleted = []
|
||||
for entry in self.user.aa[profile][hat]['allow']['path'].keys():
|
||||
if path == entry:
|
||||
continue
|
||||
|
||||
if apparmor.aa.matchregexp(path, entry):
|
||||
if apparmor.aa.mode_contains(mode, self.user.aa[profile][hat]['allow']['path'][entry]['mode']):
|
||||
deleted.append(entry)
|
||||
for entry in deleted:
|
||||
self.user.aa[profile][hat]['allow']['path'].pop(entry)
|
||||
deleted = len(deleted)
|
||||
|
||||
if owner_toggle == 0:
|
||||
mode = apparmor.aa.flatten_mode(mode)
|
||||
#elif owner_toggle == 1:
|
||||
# mode = mode
|
||||
elif owner_toggle == 2:
|
||||
mode = allow_mode | apparmor.aa.owner_flatten_mode(mode - allow_mode)
|
||||
elif owner_toggle == 3:
|
||||
mode = apparmor.aa.owner_flatten_mode(mode)
|
||||
|
||||
if not self.user.aa[profile][hat]['allow'].get(path, False):
|
||||
self.user.aa[profile][hat]['allow']['path'][path]['mode'] = self.user.aa[profile][hat]['allow']['path'][path].get('mode', set()) | mode
|
||||
|
||||
|
||||
tmpmode = set()
|
||||
if audit_toggle == 1:
|
||||
tmpmode = mode- allow_mode
|
||||
elif audit_toggle == 2:
|
||||
tmpmode = mode
|
||||
|
||||
self.user.aa[profile][hat]['allow']['path'][path]['audit'] = self.user.aa[profile][hat]['allow']['path'][path].get('audit', set()) | tmpmode
|
||||
|
||||
apparmor.aa.changed[profile] = True
|
||||
|
||||
apparmor.aa.UI_Info(_('Adding %s %s to profile') % (path, apparmor.aa.mode_to_str_user(mode)))
|
||||
if deleted:
|
||||
apparmor.aa.UI_Info(_('Deleted %s previous matching profile entries.') % deleted)
|
||||
|
||||
elif ans == 'CMD_DENY':
|
||||
path = options[selected].strip()
|
||||
# Add new entry?
|
||||
self.user.aa[profile][hat]['deny']['path'][path]['mode'] = self.user.aa[profile][hat]['deny']['path'][path].get('mode', set()) | (mode - allow_mode)
|
||||
|
||||
self.user.aa[profile][hat]['deny']['path'][path]['audit'] = self.user.aa[profile][hat]['deny']['path'][path].get('audit', set())
|
||||
|
||||
apparmor.aa.changed[profile] = True
|
||||
|
||||
done = True
|
||||
|
||||
elif ans == 'CMD_NEW':
|
||||
arg = options[selected]
|
||||
if not apparmor.aa.re_match_include(arg):
|
||||
ans = apparmor.aa.UI_GetString(_('Enter new path: '), arg)
|
||||
# if ans:
|
||||
# if not matchliteral(ans, path):
|
||||
# ynprompt = _('The specified path does not match this log entry:\n\n Log Entry: %s\n Entered Path: %s\nDo you really want to use this path?') % (path,ans)
|
||||
# key = apparmor.aa.UI_YesNo(ynprompt, 'n')
|
||||
# if key == 'n':
|
||||
# continue
|
||||
apparmor.aa.user_globs.append(ans)
|
||||
options.append(ans)
|
||||
default_option = len(options)
|
||||
|
||||
elif ans == 'CMD_GLOB':
|
||||
newpath = options[selected].strip()
|
||||
if not apparmor.aa.re_match_include(newpath):
|
||||
newpath = apparmor.aa.glob_path(newpath)
|
||||
|
||||
if newpath not in options:
|
||||
options.append(newpath)
|
||||
default_option = len(options)
|
||||
else:
|
||||
default_option = options.index(newpath) + 1
|
||||
|
||||
elif ans == 'CMD_GLOBEXT':
|
||||
newpath = options[selected].strip()
|
||||
if not apparmor.aa.re_match_include(newpath):
|
||||
newpath = apparmor.aa.glob_path_withext(newpath)
|
||||
|
||||
if newpath not in options:
|
||||
options.append(newpath)
|
||||
default_option = len(options)
|
||||
else:
|
||||
default_option = options.index(newpath) + 1
|
||||
|
||||
elif re.search('\d', ans):
|
||||
default_option = ans
|
||||
|
||||
#
|
||||
for allow in ['allow', 'deny']:
|
||||
for family in sorted(other.aa[profile][hat][allow]['netdomain']['rule'].keys()):
|
||||
# severity handling for net toggles goes here
|
||||
|
||||
for sock_type in sorted(other.aa[profile][hat][allow]['netdomain']['rule'][family].keys()):
|
||||
if apparmor.aa.profile_known_network(self.user.aa[profile][hat], family, sock_type):
|
||||
continue
|
||||
default_option = 1
|
||||
options = []
|
||||
newincludes = apparmor.aa.match_net_includes(self.user.aa[profile][hat], family, sock_type)
|
||||
q = apparmor.aa.hasher()
|
||||
if newincludes:
|
||||
options += list(map(lambda s: '#include <%s>'%s, sorted(set(newincludes))))
|
||||
if True:#options:
|
||||
options.append('network %s %s' % (family, sock_type))
|
||||
q['options'] = options
|
||||
q['selected'] = default_option - 1
|
||||
|
||||
q['headers'] = [_('Profile'), apparmor.aa.combine_name(profile, hat)]
|
||||
q['headers'] += [_('Network Family'), family]
|
||||
q['headers'] += [_('Socket Type'), sock_type]
|
||||
|
||||
audit_toggle = 0
|
||||
q['functions'] = ['CMD_ALLOW', 'CMD_DENY', 'CMD_IGNORE_ENTRY', 'CMD_AUDIT_NEW',
|
||||
'CMD_ABORT', 'CMD_FINISHED']
|
||||
|
||||
q['default'] = 'CMD_ALLOW'
|
||||
|
||||
done = False
|
||||
while not done:
|
||||
ans, selected = apparmor.aa.UI_PromptUser(q)
|
||||
if ans == 'CMD_IGNORE_ENTRY':
|
||||
done = True
|
||||
break
|
||||
|
||||
if ans.startswith('CMD_AUDIT'):
|
||||
audit_toggle = not audit_toggle
|
||||
audit = ''
|
||||
if audit_toggle:
|
||||
audit = 'audit'
|
||||
q['functions'] = ['CMD_ALLOW', 'CMD_DENY', 'CMD_AUDIT_OFF',
|
||||
'CMD_ABORT', 'CMD_FINISHED']
|
||||
else:
|
||||
q['functions'] = ['CMD_ALLOW', 'CMD_DENY', 'CMD_AUDIT_NEW',
|
||||
'CMD_ABORT', 'CMD_FINISHED']
|
||||
q['headers'] = [_('Profile'), apparmor.aa.combine_name(profile, hat)]
|
||||
q['headers'] += [_('Network Family'), audit + family]
|
||||
q['headers'] += [_('Socket Type'), sock_type]
|
||||
|
||||
elif ans == 'CMD_ALLOW':
|
||||
#print(options, selected)
|
||||
selection = options[selected]
|
||||
done = True
|
||||
if apparmor.aa.re_match_include(selection): #re.search('#include\s+<.+>$', selection):
|
||||
inc = apparmor.aa.re_match_include(selection) #re.search('#include\s+<(.+)>$', selection).groups()[0]
|
||||
deleted = 0
|
||||
deleted = apparmor.aa.delete_duplicates(self.user.aa[profile][hat], inc)
|
||||
|
||||
self.user.aa[profile][hat]['include'][inc] = True
|
||||
|
||||
apparmor.aa.changed[profile] = True
|
||||
|
||||
apparmor.aa.UI_Info(_('Adding %s to profile') % selection)
|
||||
if deleted:
|
||||
apparmor.aa.UI_Info(_('Deleted %s previous matching profile entries.') % deleted)
|
||||
|
||||
else:
|
||||
self.user.aa[profile][hat]['allow']['netdomain']['audit'][family][sock_type] = audit_toggle
|
||||
self.user.aa[profile][hat]['allow']['netdomain']['rule'][family][sock_type] = True
|
||||
|
||||
apparmor.aa.changed[profile] = True
|
||||
|
||||
apparmor.aa.UI_Info(_('Adding network access %s %s to profile.') % (family, sock_type))
|
||||
|
||||
elif ans == 'CMD_DENY':
|
||||
done = True
|
||||
self.user.aa[profile][hat]['deny']['netdomain']['rule'][family][sock_type] = True
|
||||
apparmor.aa.changed[profile] = True
|
||||
apparmor.aa.UI_Info(_('Denying network access %s %s to profile') % (family, sock_type))
|
||||
|
||||
else:
|
||||
done = False
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
33
utils/aa-mergeprof.pod
Normal file
33
utils/aa-mergeprof.pod
Normal file
@@ -0,0 +1,33 @@
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
aa-mergeprof - merge AppArmor security profiles.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<aa-mergeprof I<E<lt>mineE<gt>> I<E<lt>userE<gt>> I<E<lt>otherE<gt>> [I<-d /path/to/profiles>]>
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
B<-d --dir /path/to/profiles>
|
||||
|
||||
Specifies where to look for the AppArmor security profile set.
|
||||
Defaults to /etc/apparmor.d.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
B<aa-mergeprof>
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
If you find any bugs, please report them at
|
||||
L<https://bugs.launchpad.net/apparmor/+filebug>.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
apparmor(7), apparmor.d(5), aa_change_hat(2), aa-genprof(1),
|
||||
aa-logprof(1), aa-enforce(1), aa-audit(1), aa-complain(1),
|
||||
aa-disable(1), and L<http://wiki.apparmor.net>.
|
||||
|
||||
=cut
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user