mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-31 22:35:35 +00:00
Compare commits
288 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
ac03ae4e72 | ||
|
085d4cd0e2 | ||
|
f305bb1831 | ||
|
9f0415e1ab | ||
|
0acc2cd67c | ||
|
41091fd411 | ||
|
b5ffee530b | ||
|
ab49c3dbb0 | ||
|
92a6360570 | ||
|
f4346f63f6 | ||
|
6eef48828c | ||
|
8e0cfd04f4 | ||
|
bb9bc18a0e | ||
|
e3b04d4f81 | ||
|
9bdd2a3f6f | ||
|
46fb957dd4 | ||
|
f59bc8b952 | ||
|
5278708ea0 | ||
|
6a871a5082 | ||
|
3dd6034839 | ||
|
84791175e8 | ||
|
f1bca36c18 | ||
|
5a2db81f93 | ||
|
d86c290e85 | ||
|
593b1fb930 | ||
|
b27e323ded | ||
|
6377b1c492 | ||
|
4b33ae0e03 | ||
|
47e348d5c5 | ||
|
4b56928dc9 | ||
|
88d513a8ca | ||
|
30a3e58464 | ||
|
8916f1f4ad | ||
|
ba67b0cc98 | ||
|
6ff8c1ec1a | ||
|
384ce01def | ||
|
758ec0cdbd | ||
|
1439823d6f | ||
|
fb5ad3bace | ||
|
6563e50a79 | ||
|
f978971cb8 | ||
|
c98222686a | ||
|
018ac1ae74 | ||
|
3a933fa8c0 | ||
|
6d4060d8bd | ||
|
d6c48cc016 | ||
|
7f3ef49dd8 | ||
|
913f125d91 | ||
|
bcd9db816c | ||
|
e2a2229b5d | ||
|
2a427b9cde | ||
|
ee3823a4c0 | ||
|
71592615dc | ||
|
0acc6f8c93 | ||
|
e769a0f21f | ||
|
ab9b14ed10 | ||
|
0efbd7a68e | ||
|
0e15ddb98d | ||
|
49bd73172e | ||
|
de6ea8d82b | ||
|
d90afe7313 | ||
|
f74f044f9f | ||
|
202464213d | ||
|
7f62e44460 | ||
|
9a716c10de | ||
|
e4f9e9932f | ||
|
296af62fac | ||
|
41109b2b97 | ||
|
b9a2315f69 | ||
|
755c428649 | ||
|
6107a10909 | ||
|
7f24cc06f7 | ||
|
853d3d4473 | ||
|
006387d8bb | ||
|
07819f0e6d | ||
|
584c54e8e2 | ||
|
37050536cf | ||
|
da62b0d501 | ||
|
878cd26282 | ||
|
c0d515473d | ||
|
84e4c760ba | ||
|
f05d71e0ef | ||
|
8deb9f9c55 | ||
|
47b86e8210 | ||
|
583271e90a | ||
|
69403989d1 | ||
|
7d53f8c48d | ||
|
5177fee929 | ||
|
f2de2952da | ||
|
699e006e51 | ||
|
486616908d | ||
|
d76452551a | ||
|
be9f7c0363 | ||
|
f600897f4f | ||
|
d93ab72759 | ||
|
292d330d03 | ||
|
1ce2dd73c1 | ||
|
e32b4ba724 | ||
|
73c11c73e6 | ||
|
cddd93a3fa | ||
|
c003bff551 | ||
|
62d240166d | ||
|
3b2d0853b6 | ||
|
00d3d9e2a1 | ||
|
6aba270cc8 | ||
|
aed87dba0c | ||
|
67d67accdd | ||
|
26accb07ad | ||
|
dd8d3b496b | ||
|
5d9a135b44 | ||
|
0b8ed06b90 | ||
|
ef851bebca | ||
|
aecfd3db1d | ||
|
953db241b3 | ||
|
a0a0b2358e | ||
|
99503901b5 | ||
|
49a62ceccc | ||
|
3da5b3c31b | ||
|
60e741dfcf | ||
|
717219ad9e | ||
|
c977bed89f | ||
|
613c8589f2 | ||
|
e3cabbfb42 | ||
|
9959f50d76 | ||
|
350b50b1da | ||
|
6e7e0ddec7 | ||
|
2c250254c8 | ||
|
9d4cac38e2 | ||
|
29fd9b0a56 | ||
|
3074044aaa | ||
|
0d5c87c21e | ||
|
367710384d | ||
|
caf52a31a5 | ||
|
74da3290fb | ||
|
2e868fc541 | ||
|
43091fa27f | ||
|
1af3e65b2e | ||
|
c4080d6637 | ||
|
7116767ed5 | ||
|
6c0a1b4730 | ||
|
cf64ddcc95 | ||
|
4b9f72f930 | ||
|
fc75aabfd8 | ||
|
deeca7eb29 | ||
|
8d9f0d4dd8 | ||
|
dd7c113c98 | ||
|
1a80ef81e5 | ||
|
2cf6b596d1 | ||
|
1c2c2e7051 | ||
|
d956d76fde | ||
|
412e2bcbde | ||
|
3004390a6c | ||
|
95d2b6ed3d | ||
|
2e1d4f5b67 | ||
|
24c136f069 | ||
|
f9df4da913 | ||
|
4dff14d0b2 | ||
|
000cbb1f8a | ||
|
667b38528a | ||
|
d32501b204 | ||
|
9c33ba4359 | ||
|
205f19704a | ||
|
fdbe6e9f7f | ||
|
e409e5b66d | ||
|
ed37e5edc2 | ||
|
98d0f323a4 | ||
|
f052a62e4a | ||
|
01824ded0b | ||
|
68af901615 | ||
|
9dd1cbec0a | ||
|
d0ef880bbe | ||
|
d9be57a140 | ||
|
5094333f2c | ||
|
d47fdc7b42 | ||
|
860ccb3b13 | ||
|
1395a86f84 | ||
|
6bcb0928d2 | ||
|
f73180c395 | ||
|
43495f0033 | ||
|
99cb8cc7f1 | ||
|
7b47dee81e | ||
|
789309f419 | ||
|
e7488ebff1 | ||
|
498853ca6e | ||
|
e262991d18 | ||
|
90b8189547 | ||
|
34d1b5ddce | ||
|
9d09389290 | ||
|
b292de2ca0 | ||
|
e5daa5fa39 | ||
|
383bbd68d6 | ||
|
845507b8a1 | ||
|
6b2a8191a6 | ||
|
681fef917b | ||
|
b15f758490 | ||
|
c9e3e6e85a | ||
|
6920e3d717 | ||
|
ae595aea03 | ||
|
1251e0c143 | ||
|
b56fdec804 | ||
|
eacb977ebd | ||
|
29d287f94e | ||
|
9fd54008c4 | ||
|
0ffc0941a8 | ||
|
ed68e397aa | ||
|
c79607927d | ||
|
353ef34ca0 | ||
|
80a17a6106 | ||
|
44f2c6d2bc | ||
|
a7898cfe5b | ||
|
91b9b44f53 | ||
|
8fcfc27d56 | ||
|
791d40aa9d | ||
|
4ad98a8302 | ||
|
064541cb53 | ||
|
9618cc9a62 | ||
|
119522307f | ||
|
2a929f3f1c | ||
|
ec4de6e081 | ||
|
fde4f8a522 | ||
|
cad5d461ca | ||
|
922096a8be | ||
|
9d8340a8b3 | ||
|
1d8e388c93 | ||
|
28d5c335af | ||
|
8ea1054f50 | ||
|
36b699bcf6 | ||
|
0125d04924 | ||
|
ad169656bf | ||
|
0f7ccc49bb | ||
|
90e5294578 | ||
|
6d19a507ae | ||
|
fff8d65985 | ||
|
8e2595c634 | ||
|
711ca72c6b | ||
|
af8ccba6d2 | ||
|
fa5d235f28 | ||
|
bdb18c5ccf | ||
|
0cd0743b47 | ||
|
6e1e27a931 | ||
|
150350c42c | ||
|
61ee9623c5 | ||
|
458f696f8e | ||
|
331e54b36e | ||
|
85be9528ec | ||
|
5493e01408 | ||
|
da0daadf40 | ||
|
6d05fa4a6e | ||
|
f5df1bf45e | ||
|
a80c75e308 | ||
|
f5462aa931 | ||
|
91e73d54fe | ||
|
57cdc4257d | ||
|
4c04a05996 | ||
|
a492bcfc80 | ||
|
ec9292bd5e | ||
|
703cc22b52 | ||
|
4fd66468d8 | ||
|
b80aadd624 | ||
|
0dde5efc62 | ||
|
99b59f7169 | ||
|
061c76c5b1 | ||
|
dab2636a27 | ||
|
a41bff515f | ||
|
483f11d06c | ||
|
1140e54442 | ||
|
b54d1f2049 | ||
|
6e846245ab | ||
|
218cb42fbe | ||
|
df12e87fb5 | ||
|
5a2da347d4 | ||
|
cfbc1a2a79 | ||
|
51a0d5d863 | ||
|
3ab596ed83 | ||
|
d5824674d1 | ||
|
3ef80d788a | ||
|
d579fc51d4 | ||
|
8d68618f0b | ||
|
f6dcade84f | ||
|
0f4310d301 | ||
|
84ab95d263 | ||
|
eb2adf119b | ||
|
68041e0d2e | ||
|
4c0e6334b5 | ||
|
73cdd97596 | ||
|
dfe58983bb | ||
|
07b6148fd1 | ||
|
d04a03359c |
36
.gitignore
vendored
36
.gitignore
vendored
@@ -4,17 +4,10 @@ binutils/aa-enabled
|
||||
binutils/aa-enabled.1
|
||||
binutils/aa-exec
|
||||
binutils/aa-exec.1
|
||||
binutils/aa-features-abi
|
||||
binutils/aa-features-abi.1
|
||||
binutils/aa-status
|
||||
binutils/aa-status.8
|
||||
binutils/cJSON.o
|
||||
binutils/po/*.mo
|
||||
parser/po/*.mo
|
||||
parser/af_names.h
|
||||
parser/cap_names.h
|
||||
parser/generated_cap_names.h
|
||||
parser/generated_af_names.h
|
||||
parser/tst_lib
|
||||
parser/tst_misc
|
||||
parser/tst_regex
|
||||
@@ -30,7 +23,6 @@ parser/af_rule.o
|
||||
parser/af_unix.o
|
||||
parser/common_optarg.o
|
||||
parser/dbus.o
|
||||
parser/default_features.o
|
||||
parser/lib.o
|
||||
parser/libapparmor_re/aare_rules.o
|
||||
parser/libapparmor_re/chfa.o
|
||||
@@ -160,7 +152,6 @@ libraries/libapparmor/swig/perl/libapparmor_wrap.c
|
||||
libraries/libapparmor/swig/perl/libapparmor_wrap.o
|
||||
libraries/libapparmor/swig/perl/pm_to_blib
|
||||
libraries/libapparmor/swig/python/LibAppArmor.py
|
||||
libraries/libapparmor/swig/python/LibAppArmor.egg-info/
|
||||
libraries/libapparmor/swig/python/build/
|
||||
libraries/libapparmor/swig/python/libapparmor_wrap.c
|
||||
libraries/libapparmor/swig/python/Makefile
|
||||
@@ -177,7 +168,7 @@ libraries/libapparmor/swig/ruby/LibAppArmor_wrap.c
|
||||
libraries/libapparmor/swig/ruby/LibAppArmor_wrap.o
|
||||
libraries/libapparmor/swig/ruby/Makefile
|
||||
libraries/libapparmor/swig/ruby/Makefile.in
|
||||
libraries/libapparmor/swig/ruby/Makefile.bak
|
||||
libraries/libapparmor/swig/ruby/Makefile.new
|
||||
libraries/libapparmor/swig/ruby/Makefile.ruby
|
||||
libraries/libapparmor/swig/ruby/mkmf.log
|
||||
libraries/libapparmor/testsuite/.deps
|
||||
@@ -205,22 +196,14 @@ utils/*.tmp
|
||||
utils/po/*.mo
|
||||
utils/apparmor/*.pyc
|
||||
utils/apparmor/rule/*.pyc
|
||||
utils/apparmor.egg-info/
|
||||
utils/build/
|
||||
utils/htmlcov/
|
||||
utils/test/common_test.pyc
|
||||
utils/test/.coverage
|
||||
utils/test/coverage-report.txt
|
||||
utils/test/htmlcov/
|
||||
utils/vim/apparmor.vim
|
||||
utils/vim/apparmor.vim.5
|
||||
utils/vim/apparmor.vim.5.html
|
||||
utils/vim/pod2htmd.tmp
|
||||
tests/regression/apparmor/*.o
|
||||
tests/regression/apparmor/aa_policy_cache
|
||||
tests/regression/apparmor/access
|
||||
tests/regression/apparmor/at_secure
|
||||
tests/regression/apparmor/attach_disconnected
|
||||
tests/regression/apparmor/changehat
|
||||
tests/regression/apparmor/changehat_fail
|
||||
tests/regression/apparmor/changehat_fork
|
||||
@@ -235,10 +218,6 @@ tests/regression/apparmor/chgrp
|
||||
tests/regression/apparmor/chmod
|
||||
tests/regression/apparmor/chown
|
||||
tests/regression/apparmor/clone
|
||||
tests/regression/apparmor/dbus_eavesdrop
|
||||
tests/regression/apparmor/dbus_message
|
||||
tests/regression/apparmor/dbus_service
|
||||
tests/regression/apparmor/dbus_unrequested_reply
|
||||
tests/regression/apparmor/deleted
|
||||
tests/regression/apparmor/env_check
|
||||
tests/regression/apparmor/environ
|
||||
@@ -249,10 +228,7 @@ tests/regression/apparmor/fchdir
|
||||
tests/regression/apparmor/fchgrp
|
||||
tests/regression/apparmor/fchmod
|
||||
tests/regression/apparmor/fchown
|
||||
tests/regression/apparmor/fd_inheritance
|
||||
tests/regression/apparmor/fd_inheritor
|
||||
tests/regression/apparmor/fork
|
||||
tests/regression/apparmor/introspect
|
||||
tests/regression/apparmor/link
|
||||
tests/regression/apparmor/link_subset
|
||||
tests/regression/apparmor/mkdir
|
||||
@@ -263,20 +239,15 @@ tests/regression/apparmor/net_raw
|
||||
tests/regression/apparmor/open
|
||||
tests/regression/apparmor/openat
|
||||
tests/regression/apparmor/pipe
|
||||
tests/regression/apparmor/pivot_root
|
||||
tests/regression/apparmor/ptrace
|
||||
tests/regression/apparmor/ptrace_helper
|
||||
tests/regression/apparmor/pwrite
|
||||
tests/regression/apparmor/query_label
|
||||
tests/regression/apparmor/readdir
|
||||
tests/regression/apparmor/rename
|
||||
tests/regression/apparmor/rw
|
||||
tests/regression/apparmor/socketpair
|
||||
tests/regression/apparmor/swap
|
||||
tests/regression/apparmor/symlink
|
||||
tests/regression/apparmor/syscall_chroot
|
||||
tests/regression/apparmor/syscall_ioperm
|
||||
tests/regression/apparmor/syscall_iopl
|
||||
tests/regression/apparmor/syscall_mknod
|
||||
tests/regression/apparmor/syscall_mlockall
|
||||
tests/regression/apparmor/syscall_ptrace
|
||||
@@ -288,15 +259,10 @@ tests/regression/apparmor/syscall_setscheduler
|
||||
tests/regression/apparmor/syscall_sysctl
|
||||
tests/regression/apparmor/sysctl_proc
|
||||
tests/regression/apparmor/tcp
|
||||
tests/regression/apparmor/transition
|
||||
tests/regression/apparmor/unix_fd_client
|
||||
tests/regression/apparmor/unix_fd_server
|
||||
tests/regression/apparmor/unix_socket
|
||||
tests/regression/apparmor/unix_socket_client
|
||||
tests/regression/apparmor/unlink
|
||||
tests/regression/apparmor/uservars.inc
|
||||
tests/regression/apparmor/xattrs
|
||||
tests/regression/apparmor/xattrs_profile
|
||||
tests/regression/apparmor/coredump
|
||||
**/__pycache__/
|
||||
*.orig
|
||||
|
139
.gitlab-ci.yml
139
.gitlab-ci.yml
@@ -1,139 +0,0 @@
|
||||
---
|
||||
image: ubuntu:latest
|
||||
|
||||
# XXX - add a deploy stage to publish man pages, docs, and coverage
|
||||
# reports
|
||||
|
||||
stages:
|
||||
- build
|
||||
- test
|
||||
|
||||
.ubuntu-before_script:
|
||||
before_script:
|
||||
- export DEBIAN_FRONTEND=noninteractive
|
||||
- apt-get update -qq
|
||||
- apt-get install --no-install-recommends -y gcc perl liblocale-gettext-perl linux-libc-dev lsb-release make
|
||||
- lsb_release -a
|
||||
- uname -a
|
||||
|
||||
.install-c-build-deps: &install-c-build-deps
|
||||
- apt-get install --no-install-recommends -y build-essential apache2-dev autoconf automake bison dejagnu flex libpam-dev libtool pkg-config python3-all-dev python3-setuptools ruby-dev swig zlib1g-dev
|
||||
|
||||
build-all:
|
||||
stage: build
|
||||
extends:
|
||||
- .ubuntu-before_script
|
||||
artifacts:
|
||||
name: ${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA}
|
||||
expire_in: 30 days
|
||||
untracked: true
|
||||
paths:
|
||||
- libraries/libapparmor/
|
||||
- parser/
|
||||
- binutils/
|
||||
- utils/
|
||||
- changehat/mod_apparmor/
|
||||
- changehat/pam_apparmor/
|
||||
- profiles/
|
||||
script:
|
||||
- *install-c-build-deps
|
||||
- cd libraries/libapparmor && ./autogen.sh && ./configure --with-perl --with-python --prefix=/usr && make && cd ../.. || { cat config.log ; exit 1 ; }
|
||||
- make -C parser
|
||||
- make -C binutils
|
||||
- make -C utils
|
||||
- make -C changehat/mod_apparmor
|
||||
- make -C changehat/pam_apparmor
|
||||
- make -C profiles
|
||||
|
||||
test-libapparmor:
|
||||
stage: test
|
||||
needs: ["build-all"]
|
||||
extends:
|
||||
- .ubuntu-before_script
|
||||
script:
|
||||
- *install-c-build-deps
|
||||
- make -C libraries/libapparmor check
|
||||
|
||||
test-parser:
|
||||
stage: test
|
||||
needs: ["build-all"]
|
||||
extends:
|
||||
- .ubuntu-before_script
|
||||
script:
|
||||
- *install-c-build-deps
|
||||
- make -C parser check
|
||||
|
||||
test-binutils:
|
||||
stage: test
|
||||
needs: ["build-all"]
|
||||
extends:
|
||||
- .ubuntu-before_script
|
||||
script:
|
||||
- make -C binutils check
|
||||
|
||||
test-utils:
|
||||
stage: test
|
||||
needs: ["build-all"]
|
||||
extends:
|
||||
- .ubuntu-before_script
|
||||
script:
|
||||
- apt-get install --no-install-recommends -y libc6-dev libjs-jquery libjs-jquery-throttle-debounce libjs-jquery-isonscreen libjs-jquery-tablesorter pyflakes3 python3-coverage python3-notify2 python3-psutil python3-setuptools
|
||||
# See apparmor/apparmor#221
|
||||
- make -C parser/tst gen_dbus
|
||||
- make -C parser/tst gen_xtrans
|
||||
- make -C utils check
|
||||
- make -C utils/test coverage-regression
|
||||
artifacts:
|
||||
paths:
|
||||
- utils/test/htmlcov/
|
||||
when: always
|
||||
|
||||
test-mod-apparmor:
|
||||
stage: test
|
||||
needs: ["build-all"]
|
||||
extends:
|
||||
- .ubuntu-before_script
|
||||
script:
|
||||
- make -C changehat/mod_apparmor check
|
||||
|
||||
test-profiles:
|
||||
stage: test
|
||||
needs: ["build-all"]
|
||||
extends:
|
||||
- .ubuntu-before_script
|
||||
script:
|
||||
- make -C profiles check-parser
|
||||
- make -C profiles check-abstractions.d
|
||||
- make -C profiles check-extras
|
||||
|
||||
shellcheck:
|
||||
stage: test
|
||||
needs: []
|
||||
extends:
|
||||
- .ubuntu-before_script
|
||||
script:
|
||||
- apt-get install --no-install-recommends -y file shellcheck xmlstarlet
|
||||
- shellcheck --version
|
||||
- './tests/bin/shellcheck-tree --format=checkstyle
|
||||
| xmlstarlet tr tests/checkstyle2junit.xslt
|
||||
> shellcheck.xml'
|
||||
artifacts:
|
||||
when: always
|
||||
reports:
|
||||
junit: shellcheck.xml
|
||||
|
||||
# Disabled due to aa-logprof dependency on /sbin/apparmor_parser existing
|
||||
# - make -C profiles check-profiles
|
||||
|
||||
# test-pam_apparmor:
|
||||
# - stage: test
|
||||
# - script:
|
||||
# - cd changehat/pam_apparmor && make check
|
||||
|
||||
include:
|
||||
- template: SAST.gitlab-ci.yml
|
||||
- template: Secret-Detection.gitlab-ci.yml
|
||||
|
||||
variables:
|
||||
SAST_EXCLUDED_ANALYZERS: "eslint,flawfinder,semgrep,spotbugs"
|
||||
SAST_BANDIT_EXCLUDED_PATHS: "*/tst/*, */test/*"
|
@@ -1,10 +0,0 @@
|
||||
# Don't follow source'd scripts
|
||||
disable=SC1090
|
||||
disable=SC1091
|
||||
|
||||
# dash supports 'local'
|
||||
disable=SC2039
|
||||
disable=SC3043
|
||||
|
||||
# dash supports 'echo -n'
|
||||
disable=SC3037
|
36
Makefile
36
Makefile
@@ -8,20 +8,18 @@ all:
|
||||
COMMONDIR=common
|
||||
include ${COMMONDIR}/Make.rules
|
||||
|
||||
DIRS=libraries/libapparmor \
|
||||
binutils \
|
||||
parser \
|
||||
DIRS=parser \
|
||||
profiles \
|
||||
utils \
|
||||
libraries/libapparmor \
|
||||
changehat/mod_apparmor \
|
||||
changehat/pam_apparmor \
|
||||
profiles \
|
||||
tests
|
||||
|
||||
# with conversion to git, we don't export from the remote
|
||||
REPO_URL?=git@gitlab.com:apparmor/apparmor.git
|
||||
REPO_BRANCH?=master
|
||||
REPO_BRANCH?=apparmor-2.10
|
||||
|
||||
COVERITY_DIR=cov-int
|
||||
RELEASE_DIR=apparmor-${VERSION}
|
||||
__SETUP_DIR?=.
|
||||
|
||||
@@ -38,9 +36,9 @@ TAR_EXCLUSIONS=
|
||||
|
||||
.PHONY: tarball
|
||||
tarball: clean
|
||||
REPO_VERSION=`$(value REPO_VERSION_CMD)` && \
|
||||
$(MAKE) export_dir __EXPORT_DIR=${RELEASE_DIR} __REPO_VERSION=$${REPO_VERSION} && \
|
||||
$(MAKE) setup __SETUP_DIR=${RELEASE_DIR} && \
|
||||
REPO_VERSION=`$(value REPO_VERSION_CMD)` ; \
|
||||
make export_dir __EXPORT_DIR=${RELEASE_DIR} __REPO_VERSION=$${REPO_VERSION} ; \
|
||||
make setup __SETUP_DIR=${RELEASE_DIR} ; \
|
||||
tar ${TAR_EXCLUSIONS} -cvzf ${RELEASE_DIR}.tar.gz ${RELEASE_DIR}
|
||||
|
||||
.PHONY: snapshot
|
||||
@@ -51,16 +49,6 @@ snapshot: clean
|
||||
$(MAKE) setup __SETUP_DIR=${SNAPSHOT_NAME} && \
|
||||
tar ${TAR_EXCLUSIONS} -cvzf ${SNAPSHOT_NAME}.tar.gz ${SNAPSHOT_NAME}
|
||||
|
||||
.PHONY: coverity
|
||||
coverity: snapshot
|
||||
cd $(SNAPSHOT_NAME)/libraries/libapparmor && ./configure --with-python
|
||||
$(foreach dir, libraries/libapparmor utils, \
|
||||
cov-build --dir $(COVERITY_DIR) --no-command --fs-capture-search $(SNAPSHOT_NAME)/$(dir); \
|
||||
mv $(COVERITY_DIR)/build-log.txt $(COVERITY_DIR)/build-log-python-$(subst /,.,$(dir)).txt ;)
|
||||
cov-build --dir $(COVERITY_DIR) -- sh -c \
|
||||
"$(foreach dir, $(filter-out utils profiles tests, $(DIRS)), \
|
||||
$(MAKE) -C $(SNAPSHOT_NAME)/$(dir);) "
|
||||
tar -cvzf $(SNAPSHOT_NAME)-$(COVERITY_DIR).tar.gz $(COVERITY_DIR)
|
||||
|
||||
.PHONY: export_dir
|
||||
export_dir:
|
||||
@@ -70,20 +58,14 @@ export_dir:
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
-rm -rf ${RELEASE_DIR} ./apparmor-${VERSION}~* ${COVERITY_DIR}
|
||||
-rm -rf ${RELEASE_DIR} ./apparmor-${VERSION}~*
|
||||
for dir in $(DIRS); do \
|
||||
$(MAKE) -C $$dir clean; \
|
||||
make -C $$dir clean; \
|
||||
done
|
||||
|
||||
.PHONY: setup
|
||||
setup:
|
||||
cd $(__SETUP_DIR)/libraries/libapparmor && ./autogen.sh
|
||||
# parser has an extra doc to build
|
||||
$(MAKE) -C $(__SETUP_DIR)/parser extra_docs
|
||||
# libraries/libapparmor needs configure to have run before
|
||||
# building docs
|
||||
$(foreach dir, $(filter-out libraries/libapparmor tests, $(DIRS)), \
|
||||
$(MAKE) -C $(__SETUP_DIR)/$(dir) docs;)
|
||||
|
||||
.PHONY: tag
|
||||
tag:
|
||||
|
102
README.md
102
README.md
@@ -35,41 +35,22 @@ and questions to the
|
||||
[AppArmor mailing list](https://lists.ubuntu.com/mailman/listinfo/apparmor).
|
||||
|
||||
Bug reports can be filed against the AppArmor project on
|
||||
[GitLab](https://gitlab.com/apparmor/apparmor/-/issues) or reported to the mailing
|
||||
[launchpad](https://bugs.launchpad.net/apparmor) or reported to the mailing
|
||||
list directly for those who wish not to register for an account on
|
||||
GitLab. See the
|
||||
launchpad. See the
|
||||
[wiki page](https://gitlab.com/apparmor/apparmor/wikis/home#reporting-bugs)
|
||||
for more information.
|
||||
|
||||
Security issues can be filed in GitLab by opening up a new [issue](https://gitlab.com/apparmor/apparmor/-/issues) and selecting the tick box ```This issue is confidential and should only be visible to team members with at least Reporter access.``` or directed to `security@apparmor.net`. Additional details can be found
|
||||
Security issues can be filed as security bugs on launchpad
|
||||
or directed to `security@apparmor.net`. Additional details can be found
|
||||
in the [wiki](https://gitlab.com/apparmor/apparmor/wikis/home#reporting-security-vulnerabilities).
|
||||
|
||||
|
||||
--------------
|
||||
Privacy Policy
|
||||
--------------
|
||||
|
||||
The AppArmor security project respects users privacy and data and does not collect data from or on its users beyond what is required for a given component to function.
|
||||
|
||||
The AppArmor kernel security module will log violations to the audit subsystem, and those will be logged/forwarded/recorded on the user's system(s) according to how the administrator has logging configured. Again this is not forwarded to or collected by the AppArmor project.
|
||||
|
||||
The AppArmor userspace tools do not collect information on the system user beyond the logs and information needed to interact with the user. This is not forwarded to, nor collected by the AppArmor project.
|
||||
|
||||
Users may submit information as part of an email, bug report or merge request, etc. and that will be recorded as part of the mailing list, bug/issue tracker, or code repository but only as part of a user initiated action.
|
||||
|
||||
The AppArmor project does not collect information from contributors beyond their interactions with the AppArmor project, code, and community. However contributors are subject to the terms and conditions and privacy policy of the individual platforms (currently GitLab) should they choose to contribute through those platforms. And those platforms may collect data on the user that the AppArmor project does not.
|
||||
|
||||
Currently GitLab requires a user account to submit patches or report bugs and issues. If a contributor does not wish to create an account for these platforms the mailing list is available. Membership in the list is not required. Content from non-list members will be sent to moderation, to ensure that it is on topic, so there may be a delay in choosing to interact in this way.
|
||||
|
||||
|
||||
-------------
|
||||
Source Layout
|
||||
-------------
|
||||
|
||||
AppArmor consists of several different parts:
|
||||
|
||||
```
|
||||
binutils/ source for basic utilities written in compiled languages
|
||||
changehat/ source for using changehat with Apache, PAM and Tomcat
|
||||
common/ common makefile rules
|
||||
desktop/ empty
|
||||
@@ -111,7 +92,7 @@ $ export PYTHON_VERSION=3
|
||||
$ export PYTHON_VERSIONS=python3
|
||||
```
|
||||
|
||||
### libapparmor:
|
||||
libapparmor:
|
||||
|
||||
```
|
||||
$ cd ./libraries/libapparmor
|
||||
@@ -126,16 +107,14 @@ $ make install
|
||||
generate Ruby bindings to libapparmor.]
|
||||
|
||||
|
||||
### Binary Utilities:
|
||||
|
||||
```
|
||||
$ cd binutils
|
||||
Utilities:
|
||||
$ cd utils
|
||||
$ make
|
||||
$ make check
|
||||
$ make install
|
||||
```
|
||||
|
||||
### Parser:
|
||||
parser:
|
||||
|
||||
```
|
||||
$ cd parser
|
||||
@@ -145,16 +124,7 @@ $ make install
|
||||
```
|
||||
|
||||
|
||||
### Utilities:
|
||||
|
||||
```
|
||||
$ cd utils
|
||||
$ make
|
||||
$ make check PYFLAKES=/usr/bin/pyflakes3
|
||||
$ make install
|
||||
```
|
||||
|
||||
### Apache mod_apparmor:
|
||||
Apache mod_apparmor:
|
||||
|
||||
```
|
||||
$ cd changehat/mod_apparmor
|
||||
@@ -163,7 +133,7 @@ $ make install
|
||||
```
|
||||
|
||||
|
||||
### PAM AppArmor:
|
||||
PAM AppArmor:
|
||||
|
||||
```
|
||||
$ cd changehat/pam_apparmor
|
||||
@@ -172,7 +142,7 @@ $ make install
|
||||
```
|
||||
|
||||
|
||||
### Profiles:
|
||||
Profiles:
|
||||
|
||||
```
|
||||
$ cd profiles
|
||||
@@ -181,7 +151,7 @@ $ make check # depends on the parser having been built first
|
||||
$ make install
|
||||
```
|
||||
|
||||
[Note that for the parser, binutils, and utils, if you only wish to build/use
|
||||
[Note that for the parser and the utils, if you only with to build/use
|
||||
some of the locale languages, you can override the default by passing
|
||||
the LANGS arguments to make; e.g. make all install "LANGS=en_US fr".]
|
||||
|
||||
@@ -201,20 +171,6 @@ tests/regression/apparmor/README.
|
||||
|
||||
To run:
|
||||
|
||||
### Regression tests - using apparmor userspace installed on host
|
||||
```
|
||||
$ cd tests/regression/apparmor (requires root)
|
||||
$ make USE_SYSTEM=1
|
||||
$ sudo make tests USE_SYSTEM=1
|
||||
$ sudo bash open.sh -r # runs and saves the last testcase from open.sh
|
||||
```
|
||||
|
||||
### Regression tests - using apparmor userspace from the tree.
|
||||
- [build libapparmor](#libapparmor)
|
||||
- [build binutils](#binary-utilities)
|
||||
- [build apparmor parser](#parser)
|
||||
- [build Pam apparmor](#pam-apparmor)
|
||||
|
||||
```
|
||||
$ cd tests/regression/apparmor (requires root)
|
||||
$ make
|
||||
@@ -306,30 +262,6 @@ $ ./stress.sh
|
||||
|
||||
(see stress.sh -h for options)
|
||||
|
||||
Coverity Support
|
||||
----------------
|
||||
Coverity scans are available to AppArmor developers at
|
||||
https://scan.coverity.com/projects/apparmor.
|
||||
|
||||
In order to submit a Coverity build for analysis, the cov-build binary
|
||||
must be discoverable from your PATH. See the "To Setup" section of
|
||||
https://scan.coverity.com/download?tab=cxx to obtain a pre-built copy of
|
||||
cov-build.
|
||||
|
||||
To generate a compressed tarball of an intermediate Coverity directory:
|
||||
|
||||
```
|
||||
$ make coverity
|
||||
```
|
||||
|
||||
The compressed tarball is written to
|
||||
apparmor-<SNAPSHOT_VERSION>-cov-int.tar.gz, where <SNAPSHOT_VERSION>
|
||||
is something like 2.10.90~3328, and must be uploaded to
|
||||
https://scan.coverity.com/projects/apparmor/builds/new for analysis. You must
|
||||
include the snapshot version in Coverity's project build submission form, in
|
||||
the "Project Version" field, so that it is quickly obvious to all AppArmor
|
||||
developers what snapshot of the AppArmor repository was used for the analysis.
|
||||
|
||||
-----------------------------------------------
|
||||
Building and Installing AppArmor Kernel Patches
|
||||
-----------------------------------------------
|
||||
@@ -345,15 +277,9 @@ The AppArmor userspace utilities are written with some assumptions about
|
||||
installed and available versions of other tools. This is a (possibly
|
||||
incomplete) list of known version dependencies:
|
||||
|
||||
The Python utilities require a minimum of Python 3.3.
|
||||
The Python utilities require a minimum of Python 2.7 or Python 3.3.
|
||||
|
||||
The aa-notify tool's Python dependencies can be satisfied by installing the
|
||||
following packages (Debian package names, other distros may vary):
|
||||
* python3-notify2
|
||||
* python3-psutil
|
||||
|
||||
Perl is no longer needed since none of the utilities shipped to end users depend
|
||||
on it anymore.
|
||||
Some utilities (aa-exec, aa-notify and aa-decode) require Perl 5.10.1 or newer.
|
||||
|
||||
Most shell scripts are written for POSIX-compatible sh. aa-decode expects
|
||||
bash, probably version 3.2 and higher.
|
||||
|
@@ -1,175 +0,0 @@
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2015
|
||||
# Canonical Ltd. (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 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.
|
||||
# ----------------------------------------------------------------------
|
||||
NAME=aa-binutils
|
||||
all:
|
||||
COMMONDIR=../common/
|
||||
|
||||
include $(COMMONDIR)/Make.rules
|
||||
|
||||
DESTDIR=/
|
||||
BINDIR=${DESTDIR}/usr/bin
|
||||
SBINDIR=${DESTDIR}/usr/sbin
|
||||
LOCALEDIR=/usr/share/locale
|
||||
MANPAGES=aa-enabled.1 aa-exec.1 aa-features-abi.1 aa-status.8
|
||||
|
||||
WARNINGS = -Wall
|
||||
CPP_WARNINGS =
|
||||
ifndef CFLAGS
|
||||
CFLAGS = -g -O2 -pipe
|
||||
|
||||
ifdef DEBUG
|
||||
CFLAGS += -pg -D DEBUG
|
||||
endif
|
||||
ifdef COVERAGE
|
||||
CFLAGS = -g -pg -fprofile-arcs -ftest-coverage
|
||||
endif
|
||||
endif #CFLAGS
|
||||
|
||||
EXTRA_CFLAGS = ${CFLAGS} ${CPPFLAGS} ${EXTRA_CXXFLAGS} ${CPP_WARNINGS} $(EXTRA_WARNINGS)
|
||||
|
||||
#INCLUDEDIR = /usr/src/linux/include
|
||||
INCLUDEDIR =
|
||||
|
||||
ifdef INCLUDEDIR
|
||||
CFLAGS += -I$(INCLUDEDIR)
|
||||
endif
|
||||
|
||||
# Internationalization support. Define a package and a LOCALEDIR
|
||||
EXTRA_CFLAGS+=-DPACKAGE=\"${NAME}\" -DLOCALEDIR=\"${LOCALEDIR}\"
|
||||
|
||||
SRCS = aa_enabled.c
|
||||
HDRS =
|
||||
BINTOOLS = aa-enabled aa-exec aa-features-abi
|
||||
SBINTOOLS = aa-status
|
||||
|
||||
AALIB = -Wl,-Bstatic -lapparmor -Wl,-Bdynamic -lpthread
|
||||
|
||||
ifdef WITH_LIBINTL
|
||||
AALIB += -lintl
|
||||
endif
|
||||
|
||||
ifdef USE_SYSTEM
|
||||
# Using the system libapparmor so Makefile dependencies can't be used
|
||||
LIBAPPARMOR_A =
|
||||
INCLUDE_APPARMOR =
|
||||
APPARMOR_H =
|
||||
LIBAPPARMOR_LDFLAGS =
|
||||
else
|
||||
LIBAPPARMOR_SRC = ../libraries/libapparmor/
|
||||
LOCAL_LIBAPPARMOR_INCLUDE = $(LIBAPPARMOR_SRC)/include
|
||||
LOCAL_LIBAPPARMOR_LDPATH = $(LIBAPPARMOR_SRC)/src/.libs
|
||||
|
||||
LIBAPPARMOR_A = $(LOCAL_LIBAPPARMOR_LDPATH)/libapparmor.a
|
||||
INCLUDE_APPARMOR = -I$(LOCAL_LIBAPPARMOR_INCLUDE)
|
||||
APPARMOR_H = $(LOCAL_LIBAPPARMOR_INCLUDE)/sys/apparmor.h
|
||||
LIBAPPARMOR_LDFLAGS = -L$(LOCAL_LIBAPPARMOR_LDPATH)
|
||||
endif
|
||||
EXTRA_CFLAGS += $(INCLUDE_APPARMOR)
|
||||
LDFLAGS += $(LIBAPPARMOR_LDFLAGS)
|
||||
|
||||
ifdef V
|
||||
VERBOSE = 1
|
||||
endif
|
||||
ifndef VERBOSE
|
||||
VERBOSE = 0
|
||||
endif
|
||||
ifeq ($(VERBOSE),1)
|
||||
BUILD_OUTPUT =
|
||||
Q =
|
||||
else
|
||||
BUILD_OUTPUT = > /dev/null 2>&1
|
||||
Q = @
|
||||
endif
|
||||
export Q VERBOSE BUILD_OUTPUT
|
||||
|
||||
po/%.pot: %.c
|
||||
$(MAKE) -C po $(@F) NAME=$* SOURCES=$*.c
|
||||
|
||||
# targets arranged this way so that people who don't want full docs can
|
||||
# pick specific targets they want.
|
||||
arch: $(BINTOOLS) $(SBINTOOLS)
|
||||
|
||||
manpages: $(MANPAGES)
|
||||
|
||||
docs: manpages
|
||||
|
||||
indep: docs
|
||||
$(Q)$(MAKE) -C po all
|
||||
|
||||
all: arch indep
|
||||
|
||||
.PHONY: coverage
|
||||
coverage:
|
||||
$(MAKE) clean $(BINTOOLS) $(SBINTOOLS) COVERAGE=1
|
||||
|
||||
ifndef USE_SYSTEM
|
||||
$(LIBAPPARMOR_A):
|
||||
@if [ ! -f $@ ]; then \
|
||||
echo "error: $@ is missing. Pick one of these possible solutions:" 1>&2; \
|
||||
echo " 1) Build against the in-tree libapparmor by building it first and then trying again. See the top-level README for help." 1>&2; \
|
||||
echo " 2) Build against the system libapparmor by adding USE_SYSTEM=1 to your make command." 1>&2;\
|
||||
exit 1; \
|
||||
fi
|
||||
endif
|
||||
|
||||
aa-features-abi: aa_features_abi.c $(LIBAPPARMOR_A)
|
||||
$(CC) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $< $(LIBS) $(AALIB)
|
||||
|
||||
aa-enabled: aa_enabled.c $(LIBAPPARMOR_A)
|
||||
$(CC) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $< $(LIBS) $(AALIB)
|
||||
|
||||
aa-exec: aa_exec.c $(LIBAPPARMOR_A)
|
||||
$(CC) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $< $(LIBS) $(AALIB)
|
||||
|
||||
aa-status: aa_status.c cJSON.o $(LIBAPPARMOR_A)
|
||||
$(CC) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $< $(LIBS) $(AALIB) cJSON.o
|
||||
|
||||
cJSON.o: cJSON.c cJSON.h
|
||||
$(CC) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
.SILENT: check
|
||||
.PHONY: check
|
||||
check: check_pod_files tests
|
||||
|
||||
.SILENT: tests
|
||||
tests: $(BINTOOLS) $(SBINTOOLS) $(TESTS)
|
||||
echo "no tests atm"
|
||||
|
||||
.PHONY: install
|
||||
install: install-indep install-arch
|
||||
|
||||
.PHONY: install-arch
|
||||
install-arch: arch
|
||||
install -m 755 -d ${BINDIR}
|
||||
install -m 755 ${BINTOOLS} ${BINDIR}
|
||||
install -m 755 -d ${SBINDIR}
|
||||
ln -sf aa-status ${SBINDIR}/apparmor_status
|
||||
install -m 755 ${SBINTOOLS} ${SBINDIR}
|
||||
|
||||
.PHONY: install-indep
|
||||
install-indep: indep
|
||||
$(MAKE) -C po install NAME=${NAME} DESTDIR=${DESTDIR}
|
||||
$(MAKE) install_manpages DESTDIR=${DESTDIR}
|
||||
ln -sf aa-status.8 ${DESTDIR}/${MANDIR}/man8/apparmor_status.8
|
||||
|
||||
ifndef VERBOSE
|
||||
.SILENT: clean
|
||||
endif
|
||||
.PHONY: clean
|
||||
clean: pod_clean
|
||||
rm -f core core.* *.o *.s *.a *~ *.gcda *.gcno
|
||||
rm -f gmon.out
|
||||
rm -f $(BINTOOLS) $(SBINTOOLS) $(TESTS)
|
||||
$(MAKE) -s -C po clean
|
||||
|
@@ -48,11 +48,6 @@ Do not output anything to stdout. This option is intended to be used by
|
||||
scripts that simply want to use the exit code to determine if AppArmor is
|
||||
enabled.
|
||||
|
||||
=item -x, --exclusive
|
||||
|
||||
Require AppArmor to have exclusive access to shared LSM interfaces to
|
||||
be considered enabled.
|
||||
|
||||
=back
|
||||
|
||||
=head1 EXIT STATUS
|
||||
@@ -61,31 +56,27 @@ Upon exiting, B<aa-enabled> will set its exit status to the following values:
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<0>
|
||||
=item 0:
|
||||
|
||||
if AppArmor is enabled.
|
||||
|
||||
=item B<1>
|
||||
=item 1:
|
||||
|
||||
if AppArmor is not enabled/loaded.
|
||||
|
||||
=item B<2>
|
||||
=item 2:
|
||||
|
||||
intentionally not used as an B<aa-enabled> exit status.
|
||||
|
||||
=item B<3>
|
||||
=item 3:
|
||||
|
||||
if the AppArmor control files aren't available under /sys/kernel/security/.
|
||||
|
||||
=item B<4>
|
||||
=item 4:
|
||||
|
||||
if B<aa-enabled> doesn't have enough privileges to read the apparmor control files.
|
||||
|
||||
=item B<10>
|
||||
|
||||
AppArmor is enabled but does not have access to shared LSM interfaces.
|
||||
|
||||
=item B<64>
|
||||
=item 64:
|
||||
|
||||
if any unexpected error or condition is encountered.
|
||||
|
||||
@@ -94,7 +85,7 @@ if any unexpected error or condition is encountered.
|
||||
=head1 BUGS
|
||||
|
||||
If you find any bugs, please report them at
|
||||
L<https://gitlab.com/apparmor/apparmor/-/issues>.
|
||||
L<https://bugs.launchpad.net/apparmor/+filebug>.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
|
@@ -1,97 +0,0 @@
|
||||
# This publication is intellectual property of Canonical Ltd. Its contents
|
||||
# can be duplicated, either in part or in whole, provided that a copyright
|
||||
# label is visibly located on each copy.
|
||||
#
|
||||
# All information found in this book has been compiled with utmost
|
||||
# attention to detail. However, this does not guarantee complete accuracy.
|
||||
# Neither Canonical Ltd, the authors, nor the translators shall be held
|
||||
# liable for possible errors or the consequences thereof.
|
||||
#
|
||||
# Many of the software and hardware descriptions cited in this book
|
||||
# are registered trademarks. All trade names are subject to copyright
|
||||
# restrictions and may be registered trade marks. Canonical Ltd
|
||||
# essentially adheres to the manufacturer's spelling.
|
||||
#
|
||||
# Names of products and trademarks appearing in this book (with or without
|
||||
# specific notation) are likewise subject to trademark and trade protection
|
||||
# laws and may thus fall under copyright restrictions.
|
||||
#
|
||||
|
||||
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
aa-features-abi - Extract, validate and manipulate AppArmor feature abis
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<aa-features-abi> [OPTIONS] <SOURCE> [OUTPUT OPTIONS]
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
B<aa-features-abi> is used to extract a features abi and output to
|
||||
either stdout or a specified file. A SOURCE_OPTION must be specified.
|
||||
If an output option is not specified the features abi is written to
|
||||
stdout.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
B<aa-features-abi> accepts the following arguments:
|
||||
|
||||
=over 4
|
||||
|
||||
=item -h, --help
|
||||
|
||||
Display a brief usage guide.
|
||||
|
||||
=item -d, --debug
|
||||
|
||||
show messages with debugging information
|
||||
|
||||
=item -v, --verbose
|
||||
|
||||
show messages with stats
|
||||
|
||||
=back
|
||||
|
||||
=head1 SOURCE
|
||||
|
||||
=over 4
|
||||
|
||||
=item -x, --extract
|
||||
|
||||
Extract the features abi for the kernel
|
||||
|
||||
=item -f FILE, --file=FILE
|
||||
|
||||
Load the features abi from FILE and send it to OUTPUT OPTIONS.
|
||||
|
||||
=back
|
||||
|
||||
=head1 OUTPUT OPTIONS
|
||||
|
||||
=over 4
|
||||
|
||||
=item --stdout
|
||||
|
||||
Write the features abi to I<stdout>, this is the default if no output option
|
||||
is specified.
|
||||
|
||||
=item -w FILE, --write FILE
|
||||
|
||||
Write the features abi to I<FILE>.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
If you find any bugs, please report them at
|
||||
L<https://gitlab.com/apparmor/apparmor/-/issues>.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
apparmor(7), apparmor.d(5), aa_features(3), and L<https://wiki.apparmor.net>.
|
||||
|
||||
=cut
|
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libintl.h>
|
||||
#define _(s) gettext(s)
|
||||
|
||||
#include <sys/apparmor.h>
|
||||
|
||||
void print_help(const char *command)
|
||||
{
|
||||
printf(_("%s: [options]\n"
|
||||
" options:\n"
|
||||
" -x | --exclusive Shared interfaces must be available\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"),
|
||||
command);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
/* Exit statuses and meanings are documented in the aa-enabled.pod file */
|
||||
static void exit_with_error(int saved_errno, int quiet)
|
||||
{
|
||||
switch(saved_errno) {
|
||||
case ENOSYS:
|
||||
if (!quiet)
|
||||
printf(_("No - not available on this system.\n"));
|
||||
exit(1);
|
||||
case ECANCELED:
|
||||
if (!quiet)
|
||||
printf(_("No - disabled at boot.\n"));
|
||||
exit(1);
|
||||
case ENOENT:
|
||||
if (!quiet)
|
||||
printf(_("Maybe - policy interface not available.\n"));
|
||||
exit(3);
|
||||
case EPERM:
|
||||
case EACCES:
|
||||
if (!quiet)
|
||||
printf(_("Maybe - insufficient permissions to determine availability.\n"));
|
||||
exit(4);
|
||||
case EBUSY:
|
||||
if (!quiet)
|
||||
printf(_("Partially - public shared interfaces are not available.\n"));
|
||||
exit(10);
|
||||
}
|
||||
if (!quiet)
|
||||
printf(_("Error - %s\n"), strerror(saved_errno));
|
||||
exit(64);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, enabled;
|
||||
int quiet = 0;
|
||||
int require_shared = 0;
|
||||
|
||||
setlocale(LC_MESSAGES, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
if (argc > 3) {
|
||||
printf(_("unknown or incompatible options\n"));
|
||||
print_help(argv[0]);
|
||||
}
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--quiet") == 0 ||
|
||||
strcmp(argv[i], "-q") == 0) {
|
||||
quiet = 1;
|
||||
} else if (strcmp(argv[i], "--exclusive") == 0 ||
|
||||
strcmp(argv[i], "-x") == 0) {
|
||||
require_shared = 1;
|
||||
} else if (strcmp(argv[i], "--help") == 0 ||
|
||||
strcmp(argv[i], "-h") == 0) {
|
||||
print_help(argv[0]);
|
||||
} else {
|
||||
printf(_("unknown option '%s'\n"), argv[1]);
|
||||
print_help(argv[0]);
|
||||
}
|
||||
}
|
||||
|
||||
enabled = aa_is_enabled();
|
||||
if (!enabled) {
|
||||
if (require_shared || errno != EBUSY)
|
||||
exit_with_error(errno, quiet);
|
||||
}
|
||||
if (!quiet)
|
||||
printf(_("Yes\n"));
|
||||
exit(0);
|
||||
}
|
@@ -1,232 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015
|
||||
* Canonical, Ltd. (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 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. or Canonical
|
||||
* Ltd.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <libintl.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/apparmor.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#define _(s) gettext(s)
|
||||
|
||||
static const char *opt_profile = NULL;
|
||||
static const char *opt_namespace = NULL;
|
||||
static bool opt_debug = false;
|
||||
static bool opt_immediate = false;
|
||||
static bool opt_verbose = false;
|
||||
static pid_t pid = 0;
|
||||
|
||||
static void usage(const char *name, bool error)
|
||||
{
|
||||
FILE *stream = stdout;
|
||||
int status = EXIT_SUCCESS;
|
||||
|
||||
if (error) {
|
||||
stream = stderr;
|
||||
status = EXIT_FAILURE;
|
||||
}
|
||||
|
||||
fprintf(stream,
|
||||
_("USAGE: %s [OPTIONS] <prog> <args>\n"
|
||||
"\n"
|
||||
"Confine <prog> with the specified PROFILE.\n"
|
||||
"\n"
|
||||
"OPTIONS:\n"
|
||||
" -p PROFILE, --profile=PROFILE PROFILE to confine <prog> with\n"
|
||||
" -n NAMESPACE, --namespace=NAMESPACE NAMESPACE to confine <prog> in\n"
|
||||
" -d, --debug show messages with debugging information\n"
|
||||
" -i, --immediate change profile immediately instead of at exec\n"
|
||||
" -v, --verbose show messages with stats\n"
|
||||
" -h, --help display this help\n"
|
||||
"\n"), name);
|
||||
exit(status);
|
||||
}
|
||||
|
||||
#define error(fmt, args...) _error(_("[%ld] aa-exec: ERROR: " fmt "\n"), (long)pid, ## args)
|
||||
static void _error(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#define debug(fmt, args...) _debug(_("[%ld] aa-exec: DEBUG: " fmt "\n"), (long)pid, ## args)
|
||||
static void _debug(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (!opt_debug)
|
||||
return;
|
||||
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
#define verbose(fmt, args...) _verbose(_("[%ld] " fmt "\n"), (long)pid, ## args)
|
||||
static void _verbose(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (!opt_verbose)
|
||||
return;
|
||||
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static void verbose_print_argv(char **argv)
|
||||
{
|
||||
if (!opt_verbose)
|
||||
return;
|
||||
|
||||
fprintf(stderr, _("[%ld] exec"), (long)pid);
|
||||
for (; *argv; argv++)
|
||||
fprintf(stderr, " %s", *argv);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
static char **parse_args(int argc, char **argv)
|
||||
{
|
||||
int opt;
|
||||
struct option long_opts[] = {
|
||||
{"debug", no_argument, 0, 'd'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"profile", required_argument, 0, 'p'},
|
||||
{"namespace", required_argument, 0, 'n'},
|
||||
{"immediate", no_argument, 0, 'i'},
|
||||
{"verbose", no_argument, 0, 'v'},
|
||||
};
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "+dhp:n:iv", long_opts, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
opt_debug = true;
|
||||
break;
|
||||
case 'h':
|
||||
usage(argv[0], false);
|
||||
break;
|
||||
case 'p':
|
||||
if (opt_profile)
|
||||
error("Multiple -p/--profile parameters given");
|
||||
opt_profile = optarg;
|
||||
break;
|
||||
case 'n':
|
||||
if (opt_namespace)
|
||||
error("Multiple -n/--namespace parameters given");
|
||||
opt_namespace = optarg;
|
||||
break;
|
||||
case 'i':
|
||||
opt_immediate = true;
|
||||
break;
|
||||
case 'v':
|
||||
opt_verbose = true;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0], true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind >= argc)
|
||||
usage(argv[0], true);
|
||||
|
||||
return argv + optind;
|
||||
}
|
||||
|
||||
static void build_name(char *name, size_t name_len,
|
||||
const char *namespace, const char *profile)
|
||||
{
|
||||
size_t required_len = 1; /* reserve 1 byte for NUL-terminator */
|
||||
|
||||
if (namespace)
|
||||
required_len += 1 + strlen(namespace) + 3; /* :<NAMESPACE>:// */
|
||||
|
||||
if (profile)
|
||||
required_len += strlen(profile);
|
||||
|
||||
if (required_len > name_len)
|
||||
error("name too long (%zu > %zu)", required_len, name_len);
|
||||
|
||||
name[0] = '\0';
|
||||
|
||||
if (namespace) {
|
||||
strcat(name, ":");
|
||||
strcat(name, namespace);
|
||||
strcat(name, "://");
|
||||
}
|
||||
|
||||
if (profile)
|
||||
strcat(name, profile);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char name[PATH_MAX];
|
||||
int rc = 0;
|
||||
|
||||
/* IMPORTANT: pid must be initialized before doing anything else since
|
||||
* it is used in a global context when printing messages
|
||||
*/
|
||||
pid = getpid();
|
||||
|
||||
argv = parse_args(argc, argv);
|
||||
|
||||
if (opt_namespace || opt_profile)
|
||||
build_name(name, sizeof(name), opt_namespace, opt_profile);
|
||||
else
|
||||
goto exec;
|
||||
|
||||
if (opt_immediate) {
|
||||
verbose("aa_change_profile(\"%s\")", name);
|
||||
rc = aa_change_profile(name);
|
||||
debug("%d = aa_change_profile(\"%s\")", rc, name);
|
||||
} else {
|
||||
verbose("aa_change_onexec(\"%s\")", name);
|
||||
rc = aa_change_onexec(name);
|
||||
debug("%d = aa_change_onexec(\"%s\")", rc, name);
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
if (errno == ENOENT) {
|
||||
error("%s '%s' does not exist",
|
||||
opt_profile ? "profile" : "namespace", name);
|
||||
} else if (errno == EACCES) {
|
||||
error("insufficient permissions to change to the %s '%s'",
|
||||
opt_profile ? "profile" : "namespace", name);
|
||||
} else if (errno == EINVAL) {
|
||||
error("AppArmor interface not available");
|
||||
} else {
|
||||
error("%m");
|
||||
}
|
||||
}
|
||||
|
||||
exec:
|
||||
verbose_print_argv(argv);
|
||||
execvp(argv[0], argv);
|
||||
error("Failed to execute \"%s\": %m", argv[0]);
|
||||
}
|
@@ -1,207 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2020
|
||||
* Canonical, Ltd. (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 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 Ltd.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <libintl.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/apparmor.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#define _(s) gettext(s)
|
||||
|
||||
#include "../libraries/libapparmor/src/private.h"
|
||||
|
||||
static const char *progname = NULL;
|
||||
static const char *opt_file = NULL;
|
||||
static const char *opt_write = NULL;
|
||||
static bool opt_debug = false;
|
||||
static bool opt_verbose = false;
|
||||
static bool opt_extract = false;
|
||||
|
||||
static void usage(const char *name, bool error)
|
||||
{
|
||||
FILE *stream = stdout;
|
||||
int status = EXIT_SUCCESS;
|
||||
|
||||
if (error) {
|
||||
stream = stderr;
|
||||
status = EXIT_FAILURE;
|
||||
}
|
||||
|
||||
fprintf(stream,
|
||||
_("USAGE: %s [OPTIONS] <SOURCE> [OUTPUT OPTIONS]\n"
|
||||
"\n"
|
||||
"Output AppArmor feature abi from SOURCE to OUTPUT"
|
||||
"\n"
|
||||
"OPTIONS:\n"
|
||||
#if 0
|
||||
" -d, --debug show messages with debugging information\n"
|
||||
" -v, --verbose show messages with stats\n"
|
||||
#endif
|
||||
" -h, --help display this help\n"
|
||||
"SOURCE:\n"
|
||||
" -f F, --file=F load features abi from file F\n"
|
||||
" -x, --extract extract features abi from the kernel\n"
|
||||
"OUTPUT OPTIONS:\n"
|
||||
" --stdout default, write features to stdout\n"
|
||||
" -w F, --write=F write features abi to the file F instead of stdout\n"
|
||||
"\n"), name);
|
||||
exit(status);
|
||||
}
|
||||
|
||||
#define error(fmt, args...) _error(_("%s: ERROR: " fmt " - %m\n"), progname, ## args)
|
||||
static void _error(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#if 0
|
||||
#define debug(fmt, args...) _debug(_("%s: DEBUG: " fmt "\n"), progname, ## args)
|
||||
static void _debug(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (!opt_debug)
|
||||
return;
|
||||
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
#define verbose(fmt, args...) _verbose(_(fmt "\n"), ## args)
|
||||
static void _verbose(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (!opt_verbose)
|
||||
return;
|
||||
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define ARG_STDOUT 128
|
||||
|
||||
static char **parse_args(int argc, char **argv)
|
||||
{
|
||||
int opt;
|
||||
struct option long_opts[] = {
|
||||
{"debug", no_argument, 0, 'd'},
|
||||
{"verbose", no_argument, 0, 'v'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"extract", no_argument, 0, 'x'},
|
||||
{"file", required_argument, 0, 'f'},
|
||||
{"write", required_argument, 0, 'w'},
|
||||
{"stdout", no_argument, 0, ARG_STDOUT},
|
||||
};
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "+dvhxf:l:w:", long_opts, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
opt_debug = true;
|
||||
break;
|
||||
case 'v':
|
||||
opt_verbose = true;
|
||||
break;
|
||||
case 'h':
|
||||
usage(argv[0], false);
|
||||
break;
|
||||
case 'x':
|
||||
opt_extract = true;
|
||||
break;
|
||||
case 'f':
|
||||
opt_file = optarg;
|
||||
break;
|
||||
case 'w':
|
||||
opt_write = optarg;
|
||||
break;
|
||||
case ARG_STDOUT:
|
||||
opt_write = NULL;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0], true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return argv + optind;
|
||||
}
|
||||
|
||||
|
||||
/* TODO: add features intersection and testing */
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct aa_features *features;
|
||||
autoclose int in = -1;
|
||||
autoclose int out = -1;
|
||||
int rc = 0;
|
||||
|
||||
progname = argv[0];
|
||||
|
||||
argv = parse_args(argc, argv);
|
||||
|
||||
if (!opt_extract && !opt_file)
|
||||
usage(argv[0], true);
|
||||
if (opt_extract && opt_file) {
|
||||
error("options --extract and --file are mutually exclusive");
|
||||
}
|
||||
if (opt_extract) {
|
||||
rc = aa_features_new_from_kernel(&features);
|
||||
if (rc == -1)
|
||||
error("failed to extract features abi from the kernel");
|
||||
}
|
||||
if (opt_file) {
|
||||
in = open(opt_file, O_RDONLY);
|
||||
if (in == -1)
|
||||
error("failed to open file '%s'", opt_file);
|
||||
rc = aa_features_new_from_file(&features, in);
|
||||
if (rc == -1)
|
||||
error("failed to load features abi from file '%s'", opt_file);
|
||||
}
|
||||
|
||||
|
||||
if (opt_write) {
|
||||
out = open(opt_write, O_WRONLY | O_CREAT, 00600);
|
||||
if (out == -1)
|
||||
error("failed to open output file '%s'", opt_write);
|
||||
} else {
|
||||
out = fileno(stdout);
|
||||
if (out == -1)
|
||||
error("failed to get stdout");
|
||||
}
|
||||
rc = aa_features_write_to_fd(features, out);
|
||||
if (rc == -1)
|
||||
error("failed to write features abi");
|
||||
|
||||
return 0;
|
||||
}
|
@@ -1,676 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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 _GNU_SOURCE /* for asprintf() */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include <sys/apparmor.h>
|
||||
#include <sys/apparmor_private.h>
|
||||
|
||||
#include "cJSON.h"
|
||||
|
||||
#define autofree __attribute((cleanup(_aa_autofree)))
|
||||
#define autofclose __attribute((cleanup(_aa_autofclose)))
|
||||
|
||||
#define AA_EXIT_ENABLED 0
|
||||
#define AA_EXIT_DISABLED 1
|
||||
#define AA_EXIT_NO_POLICY 2
|
||||
#define AA_EXIT_NO_CONTROL 3
|
||||
#define AA_EXIT_NO_PERM 4
|
||||
#define AA_EXIT_INTERNAL_ERROR 42
|
||||
|
||||
/* NOTE: Increment this whenever the JSON format changes */
|
||||
static const unsigned char aa_status_json_version[] = "2";
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
||||
#define __unused __attribute__ ((__unused__))
|
||||
|
||||
struct profile {
|
||||
char *name;
|
||||
char *status;
|
||||
};
|
||||
|
||||
static void free_profiles(struct profile *profiles, size_t n) {
|
||||
while (n > 0) {
|
||||
n--;
|
||||
free(profiles[n].name);
|
||||
free(profiles[n].status);
|
||||
}
|
||||
free(profiles);
|
||||
}
|
||||
|
||||
struct process {
|
||||
char *pid;
|
||||
char *profile;
|
||||
char *exe;
|
||||
char *mode;
|
||||
};
|
||||
|
||||
static void free_processes(struct process *processes, size_t n) {
|
||||
while (n > 0) {
|
||||
n--;
|
||||
free(processes[n].pid);
|
||||
free(processes[n].profile);
|
||||
free(processes[n].exe);
|
||||
free(processes[n].mode);
|
||||
}
|
||||
free(processes);
|
||||
}
|
||||
|
||||
static int verbose = 0;
|
||||
|
||||
#define dprintf(...) \
|
||||
do { \
|
||||
if (verbose) \
|
||||
printf(__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define dfprintf(...) \
|
||||
do { \
|
||||
if (verbose) \
|
||||
fprintf(__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
|
||||
static int get_profiles(struct profile **profiles, size_t *n) {
|
||||
autofree char *apparmorfs = NULL;
|
||||
autofree char *apparmor_profiles = NULL;
|
||||
struct stat st;
|
||||
autofclose FILE *fp = NULL;
|
||||
autofree char *line = NULL;
|
||||
size_t len = 0;
|
||||
int ret;
|
||||
|
||||
*profiles = NULL;
|
||||
*n = 0;
|
||||
|
||||
ret = stat("/sys/module/apparmor", &st);
|
||||
if (ret != 0) {
|
||||
dfprintf(stderr, "apparmor not present.\n");
|
||||
ret = AA_EXIT_DISABLED;
|
||||
goto exit;
|
||||
}
|
||||
dprintf("apparmor module is loaded.\n");
|
||||
|
||||
ret = aa_find_mountpoint(&apparmorfs);
|
||||
if (ret == -1) {
|
||||
dfprintf(stderr, "apparmor filesystem is not mounted.\n");
|
||||
ret = AA_EXIT_NO_CONTROL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
apparmor_profiles = malloc(strlen(apparmorfs) + 10); // /profiles\0
|
||||
if (apparmor_profiles == NULL) {
|
||||
ret = AA_EXIT_INTERNAL_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
sprintf(apparmor_profiles, "%s/profiles", apparmorfs);
|
||||
|
||||
fp = fopen(apparmor_profiles, "r");
|
||||
if (fp == NULL) {
|
||||
if (errno == EACCES) {
|
||||
dfprintf(stderr, "You do not have enough privilege to read the profile set.\n");
|
||||
} else {
|
||||
dfprintf(stderr, "Could not open %s: %s", apparmor_profiles, strerror(errno));
|
||||
}
|
||||
ret = AA_EXIT_NO_PERM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
while (getline(&line, &len, fp) != -1) {
|
||||
struct profile *_profiles;
|
||||
autofree char *status = NULL;
|
||||
autofree char *name = NULL;
|
||||
char *tmpname = aa_splitcon(line, &status);
|
||||
|
||||
if (!tmpname) {
|
||||
dfprintf(stderr, "Error: failed profile name split of '%s'.\n", line);
|
||||
ret = AA_EXIT_INTERNAL_ERROR;
|
||||
// skip this entry and keep processing
|
||||
continue;
|
||||
}
|
||||
name = strdup(tmpname);
|
||||
|
||||
if (status)
|
||||
status = strdup(status);
|
||||
// give up if out of memory
|
||||
if (name == NULL || status == NULL) {
|
||||
free_profiles(*profiles, *n);
|
||||
*profiles = NULL;
|
||||
*n = 0;
|
||||
ret = AA_EXIT_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
_profiles = realloc(*profiles, (*n + 1) * sizeof(**profiles));
|
||||
if (_profiles == NULL) {
|
||||
free_profiles(*profiles, *n);
|
||||
*profiles = NULL;
|
||||
*n = 0;
|
||||
ret = AA_EXIT_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
// steal name and status
|
||||
_profiles[*n].name = name;
|
||||
_profiles[*n].status = status;
|
||||
name = NULL;
|
||||
status = NULL;
|
||||
*n = *n + 1;
|
||||
*profiles = _profiles;
|
||||
}
|
||||
|
||||
exit:
|
||||
return ret == 0 ? (*n > 0 ? AA_EXIT_ENABLED : AA_EXIT_NO_POLICY) : ret;
|
||||
}
|
||||
|
||||
static int compare_profiles(const void *a, const void *b) {
|
||||
return strcmp(((struct profile *)a)->name,
|
||||
((struct profile *)b)->name);
|
||||
}
|
||||
|
||||
static int filter_profiles(struct profile *profiles,
|
||||
size_t n,
|
||||
const char *filter,
|
||||
struct profile **filtered,
|
||||
size_t *nfiltered)
|
||||
{
|
||||
int ret = 0;
|
||||
size_t i;
|
||||
|
||||
*filtered = NULL;
|
||||
*nfiltered = 0;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (filter == NULL || strcmp(profiles[i].status, filter) == 0) {
|
||||
struct profile *_filtered = realloc(*filtered, (*nfiltered + 1) * sizeof(**filtered));
|
||||
if (_filtered == NULL) {
|
||||
free_profiles(*filtered, *nfiltered);
|
||||
*filtered = NULL;
|
||||
*nfiltered = 0;
|
||||
ret = AA_EXIT_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
_filtered[*nfiltered].name = strdup(profiles[i].name);
|
||||
_filtered[*nfiltered].status = strdup(profiles[i].status);
|
||||
*filtered = _filtered;
|
||||
*nfiltered = *nfiltered + 1;
|
||||
}
|
||||
}
|
||||
if (*nfiltered != 0) {
|
||||
qsort(*filtered, *nfiltered, sizeof(*profiles), compare_profiles);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int get_processes(struct profile *profiles,
|
||||
size_t n,
|
||||
struct process **processes,
|
||||
size_t *nprocesses)
|
||||
{
|
||||
DIR *dir = NULL;
|
||||
struct dirent *entry = NULL;
|
||||
int ret = 0;
|
||||
|
||||
*processes = NULL;
|
||||
*nprocesses = 0;
|
||||
|
||||
dir = opendir("/proc");
|
||||
if (dir == NULL) {
|
||||
ret = AA_EXIT_INTERNAL_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
size_t i;
|
||||
int rc;
|
||||
int ispid = 1;
|
||||
autofree char *profile = NULL;
|
||||
autofree char *mode = NULL; /* be careful */
|
||||
autofree char *exe = NULL;
|
||||
autofree char *real_exe = NULL;
|
||||
autofclose FILE *fp = NULL;
|
||||
autofree char *line = NULL;
|
||||
|
||||
// ignore non-pid entries
|
||||
for (i = 0; ispid && i < strlen(entry->d_name); i++) {
|
||||
ispid = (isdigit(entry->d_name[i]) ? 1 : 0);
|
||||
}
|
||||
if (!ispid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
rc = aa_getprocattr(atoi(entry->d_name), "current", &profile, &mode);
|
||||
if (rc == -1 && errno != ENOMEM) {
|
||||
/* fail to access */
|
||||
continue;
|
||||
} else if (rc == -1 ||
|
||||
asprintf(&exe, "/proc/%s/exe", entry->d_name) == -1) {
|
||||
fprintf(stderr, "ERROR: Failed to allocate memory\n");
|
||||
ret = AA_EXIT_INTERNAL_ERROR;
|
||||
goto exit;
|
||||
} else if (mode) {
|
||||
/* TODO: make this not needed. Mode can now be autofreed */
|
||||
mode = strdup(mode);
|
||||
}
|
||||
// get executable - readpath can allocate for us but seems
|
||||
// to fail in some cases with errno 2 - no such file or
|
||||
// directory - whereas readlink() can succeed in these
|
||||
// cases - and readpath() seems to have the same behaviour
|
||||
// as in python with better canonicalized results so try it
|
||||
// first and fallack to readlink if it fails
|
||||
// coverity[toctou]
|
||||
real_exe = realpath(exe, NULL);
|
||||
if (real_exe == NULL) {
|
||||
int res;
|
||||
// ensure enough space for NUL terminator
|
||||
real_exe = calloc(PATH_MAX + 1, sizeof(char));
|
||||
if (real_exe == NULL) {
|
||||
fprintf(stderr, "ERROR: Failed to allocate memory\n");
|
||||
ret = AA_EXIT_INTERNAL_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
res = readlink(exe, real_exe, PATH_MAX);
|
||||
if (res == -1) {
|
||||
continue;
|
||||
}
|
||||
real_exe[res] = '\0';
|
||||
}
|
||||
|
||||
|
||||
if (mode == NULL) {
|
||||
// is unconfined so keep only if this has a
|
||||
// matching profile. TODO: fix to use attachment
|
||||
for (i = 0; i < n; i++) {
|
||||
if (strcmp(profiles[i].name, real_exe) == 0) {
|
||||
profile = strdup(real_exe);
|
||||
mode = strdup("unconfined");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (profile != NULL && mode != NULL) {
|
||||
struct process *_processes = realloc(*processes,
|
||||
(*nprocesses + 1) * sizeof(**processes));
|
||||
if (_processes == NULL) {
|
||||
free_processes(*processes, *nprocesses);
|
||||
*processes = NULL;
|
||||
*nprocesses = 0;
|
||||
ret = AA_EXIT_INTERNAL_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
_processes[*nprocesses].pid = strdup(entry->d_name);
|
||||
_processes[*nprocesses].profile = profile;
|
||||
_processes[*nprocesses].exe = strdup(real_exe);
|
||||
_processes[*nprocesses].mode = mode;
|
||||
*processes = _processes;
|
||||
*nprocesses = *nprocesses + 1;
|
||||
profile = NULL;
|
||||
mode = NULL;
|
||||
ret = AA_EXIT_ENABLED;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
if (dir != NULL) {
|
||||
closedir(dir);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int filter_processes(struct process *processes,
|
||||
size_t n,
|
||||
const char *filter,
|
||||
struct process **filtered,
|
||||
size_t *nfiltered)
|
||||
{
|
||||
size_t i;
|
||||
int ret = 0;
|
||||
|
||||
*filtered = NULL;
|
||||
*nfiltered = 0;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (filter == NULL || strcmp(processes[i].mode, filter) == 0) {
|
||||
struct process *_filtered = realloc(*filtered, (*nfiltered + 1) * sizeof(**filtered));
|
||||
if (_filtered == NULL) {
|
||||
free_processes(*filtered, *nfiltered);
|
||||
*filtered = NULL;
|
||||
*nfiltered = 0;
|
||||
ret = AA_EXIT_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
_filtered[*nfiltered].pid = strdup(processes[i].pid);
|
||||
_filtered[*nfiltered].profile = strdup(processes[i].profile);
|
||||
_filtered[*nfiltered].exe = strdup(processes[i].exe);
|
||||
_filtered[*nfiltered].mode = strdup(processes[i].mode);
|
||||
*filtered = _filtered;
|
||||
*nfiltered = *nfiltered + 1;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns error code if AppArmor is not enabled
|
||||
*/
|
||||
static int simple_filtered_count(const char *filter) {
|
||||
size_t n;
|
||||
struct profile *profiles;
|
||||
int ret;
|
||||
|
||||
ret = get_profiles(&profiles, &n);
|
||||
if (ret == 0) {
|
||||
size_t nfiltered;
|
||||
struct profile *filtered = NULL;
|
||||
ret = filter_profiles(profiles, n, filter, &filtered, &nfiltered);
|
||||
printf("%zd\n", nfiltered);
|
||||
free_profiles(filtered, nfiltered);
|
||||
}
|
||||
free_profiles(profiles, n);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int simple_filtered_process_count(const char *filter) {
|
||||
size_t nprocesses, nprofiles;
|
||||
struct profile *profiles = NULL;
|
||||
struct process *processes = NULL;
|
||||
int ret;
|
||||
|
||||
ret = get_profiles(&profiles, &nprofiles);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
ret = get_processes(profiles, nprofiles, &processes, &nprocesses);
|
||||
if (ret == 0) {
|
||||
size_t nfiltered;
|
||||
struct process *filtered = NULL;
|
||||
ret = filter_processes(processes, nprocesses, filter, &filtered, &nfiltered);
|
||||
printf("%zd\n", nfiltered);
|
||||
free_processes(filtered, nfiltered);
|
||||
}
|
||||
free_profiles(profiles, nprofiles);
|
||||
free_processes(processes, nprocesses);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cmd_enabled(__unused const char *command) {
|
||||
int res = aa_is_enabled();
|
||||
return res == 1 ? 0 : 1;
|
||||
}
|
||||
|
||||
|
||||
static int cmd_profiled(__unused const char *command) {
|
||||
return simple_filtered_count(NULL);
|
||||
}
|
||||
|
||||
static int cmd_enforced(__unused const char *command) {
|
||||
return simple_filtered_count("enforce");
|
||||
}
|
||||
|
||||
static int cmd_complaining(__unused const char *command) {
|
||||
return simple_filtered_count("complain");
|
||||
}
|
||||
|
||||
static int cmd_kill(__unused const char *command) {
|
||||
return simple_filtered_count("kill");
|
||||
}
|
||||
|
||||
static int cmd_unconfined(__unused const char *command) {
|
||||
return simple_filtered_count("unconfined");
|
||||
}
|
||||
|
||||
static int cmd_process_mixed(__unused const char *command) {
|
||||
return simple_filtered_process_count("mixed");
|
||||
}
|
||||
|
||||
|
||||
static int compare_processes_by_profile(const void *a, const void *b) {
|
||||
return strcmp(((struct process *)a)->profile,
|
||||
((struct process *)b)->profile);
|
||||
}
|
||||
|
||||
static int compare_processes_by_executable(const void *a, const void *b) {
|
||||
return strcmp(((struct process *)a)->exe,
|
||||
((struct process *)b)->exe);
|
||||
}
|
||||
|
||||
static int detailed_output(FILE *json) {
|
||||
size_t nprofiles = 0, nprocesses = 0;
|
||||
struct profile *profiles = NULL;
|
||||
struct process *processes = NULL;
|
||||
const char *profile_statuses[] = {"enforce", "complain", "kill", "unconfined"};
|
||||
const char *process_statuses[] = {"enforce", "complain", "unconfined", "mixed", "kill"};
|
||||
int ret;
|
||||
size_t i;
|
||||
int need_finish = 0;
|
||||
|
||||
ret = get_profiles(&profiles, &nprofiles);
|
||||
if (ret != 0) {
|
||||
goto exit;
|
||||
}
|
||||
ret = get_processes(profiles, nprofiles, &processes, &nprocesses);
|
||||
if (ret != 0) {
|
||||
dfprintf(stderr, "Failed to get processes: %d....\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (json) {
|
||||
fprintf(json, "{\"version\": \"%s\", \"profiles\": {", aa_status_json_version);
|
||||
} else {
|
||||
dprintf("%zd profiles are loaded.\n", nprofiles);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(profile_statuses); i++) {
|
||||
size_t nfiltered = 0, j;
|
||||
struct profile *filtered = NULL;
|
||||
ret = filter_profiles(profiles, nprofiles, profile_statuses[i], &filtered, &nfiltered);
|
||||
if (ret != 0) {
|
||||
goto exit;
|
||||
}
|
||||
if (!json) {
|
||||
dprintf("%zd profiles are in %s mode.\n", nfiltered, profile_statuses[i]);
|
||||
}
|
||||
|
||||
for (j = 0; j < nfiltered; j++) {
|
||||
if (json) {
|
||||
fprintf(json, "%s\"%s\": \"%s\"",
|
||||
i == 0 && j == 0 ? "" : ", ", filtered[j].name, profile_statuses[i]);
|
||||
} else {
|
||||
dprintf(" %s\n", filtered[j].name);
|
||||
}
|
||||
}
|
||||
|
||||
free_profiles(filtered, nfiltered);
|
||||
}
|
||||
if (json) {
|
||||
fprintf(json, "}, \"processes\": {");
|
||||
} else {
|
||||
dprintf("%zd processes have profiles defined.\n", nprocesses);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(process_statuses); i++) {
|
||||
size_t nfiltered = 0, j;
|
||||
struct process *filtered = NULL;
|
||||
ret = filter_processes(processes, nprocesses, process_statuses[i], &filtered, &nfiltered);
|
||||
if (ret != 0) {
|
||||
goto exit;
|
||||
}
|
||||
if (!json) {
|
||||
if (strcmp(process_statuses[i], "unconfined") == 0) {
|
||||
dprintf("%zd processes are unconfined but have a profile defined.\n", nfiltered);
|
||||
} else {
|
||||
dprintf("%zd processes are in %s mode.\n", nfiltered, process_statuses[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!json) {
|
||||
qsort(filtered, nfiltered, sizeof(*filtered), compare_processes_by_profile);
|
||||
for (j = 0; j < nfiltered; j++) {
|
||||
dprintf(" %s (%s) %s\n", filtered[j].exe, filtered[j].pid,
|
||||
// hide profile name if matches executable
|
||||
(strcmp(filtered[j].profile, filtered[j].exe) == 0 ?
|
||||
"" :
|
||||
filtered[j].profile));
|
||||
}
|
||||
} else {
|
||||
// json output requires processes to be grouped per executable
|
||||
qsort(filtered, nfiltered, sizeof(*filtered), compare_processes_by_executable);
|
||||
for (j = 0; j < nfiltered; j++) {
|
||||
if (j > 0 && strcmp(filtered[j].exe, filtered[j - 1].exe) == 0) {
|
||||
// same executable
|
||||
fprintf(json, ", {\"profile\": \"%s\", \"pid\": \"%s\", \"status\": \"%s\"}",
|
||||
filtered[j].profile, filtered[j].pid, filtered[j].mode);
|
||||
} else {
|
||||
fprintf(json, "%s\"%s\": [{\"profile\": \"%s\", \"pid\": \"%s\", \"status\": \"%s\"}",
|
||||
// first element will be a unique executable
|
||||
j == 0 && !need_finish ? "" : "], ",
|
||||
filtered[j].exe, filtered[j].profile, filtered[j].pid, filtered[j].mode);
|
||||
}
|
||||
|
||||
need_finish = 1;
|
||||
}
|
||||
}
|
||||
free_processes(filtered, nfiltered);
|
||||
}
|
||||
if (json) {
|
||||
if (need_finish > 0) {
|
||||
fprintf(json, "]");
|
||||
}
|
||||
fprintf(json, "}}\n");
|
||||
}
|
||||
|
||||
exit:
|
||||
free_processes(processes, nprocesses);
|
||||
free_profiles(profiles, nprofiles);
|
||||
return ret == 0 ? (nprofiles > 0 ? AA_EXIT_ENABLED : AA_EXIT_NO_POLICY) : ret;
|
||||
}
|
||||
|
||||
static int cmd_json(__unused const char *command) {
|
||||
detailed_output(stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_pretty_json(__unused const char *command) {
|
||||
autofree char *buffer = NULL;
|
||||
autofree char *pretty = NULL;
|
||||
cJSON *json;
|
||||
FILE *f; /* no autofclose - want explicit close to sync */
|
||||
size_t size;
|
||||
int ret;
|
||||
|
||||
f = open_memstream(&buffer, &size);
|
||||
if (!f) {
|
||||
dfprintf(stderr, "Failed to open memstream: %m\n");
|
||||
return AA_EXIT_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
ret = detailed_output(f);
|
||||
fclose(f);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
json = cJSON_Parse(buffer);
|
||||
if (!json) {
|
||||
dfprintf(stderr, "Failed to parse json output");
|
||||
return AA_EXIT_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
pretty = cJSON_Print(json);
|
||||
if (!pretty) {
|
||||
dfprintf(stderr, "Failed to print pretty json");
|
||||
return AA_EXIT_INTERNAL_ERROR;
|
||||
}
|
||||
fprintf(stdout, "%s\n", pretty);
|
||||
|
||||
return AA_EXIT_ENABLED;
|
||||
}
|
||||
|
||||
static int cmd_verbose(__unused const char *command) {
|
||||
verbose = 1;
|
||||
return detailed_output(NULL);
|
||||
}
|
||||
|
||||
static int print_usage(const char *command)
|
||||
{
|
||||
printf("Usage: %s [OPTIONS]\n"
|
||||
"Displays various information about the currently loaded AppArmor policy.\n"
|
||||
"OPTIONS (one only):\n"
|
||||
" --enabled returns error code if AppArmor not enabled\n"
|
||||
" --profiled prints the number of loaded policies\n"
|
||||
" --enforced prints the number of loaded enforcing policies\n"
|
||||
" --complaining prints the number of loaded non-enforcing policies\n"
|
||||
" --kill prints the number of loaded enforcing policies that kill tasks on policy violations\n"
|
||||
" --special-unconfined prints the number of loaded non-enforcing policies in the special unconfined mode\n"
|
||||
" --process-mixed prints the number processes with mixed profile modes\n"
|
||||
" --json displays multiple data points in machine-readable JSON format\n"
|
||||
" --pretty-json same data as --json, formatted for human consumption as well\n"
|
||||
" --verbose (default) displays multiple data points about loaded policy set\n"
|
||||
" --help this message\n",
|
||||
command);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct command {
|
||||
const char * const name;
|
||||
int (*cmd)(const char *command);
|
||||
};
|
||||
|
||||
static struct command commands[] = {
|
||||
{"--enabled", cmd_enabled},
|
||||
{"--profiled", cmd_profiled},
|
||||
{"--enforced", cmd_enforced},
|
||||
{"--complaining", cmd_complaining},
|
||||
{"--kill", cmd_kill},
|
||||
{"--special-unconfined", cmd_unconfined},
|
||||
{"--process-mixed", cmd_process_mixed},
|
||||
{"--json", cmd_json},
|
||||
{"--pretty-json", cmd_pretty_json},
|
||||
{"--verbose", cmd_verbose},
|
||||
{"-v", cmd_verbose},
|
||||
{"--help", print_usage},
|
||||
{"-h", print_usage},
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret = EXIT_SUCCESS;
|
||||
int _ret;
|
||||
int (*cmd)(const char*) = cmd_verbose;
|
||||
|
||||
if (argc > 2) {
|
||||
dfprintf(stderr, "Error: Too many options.\n");
|
||||
cmd = print_usage;
|
||||
ret = EXIT_FAILURE;
|
||||
} else if (argc == 2) {
|
||||
int (*_cmd)(const char*) = NULL;
|
||||
size_t i;
|
||||
for (i = 0; i < ARRAY_SIZE(commands); i++) {
|
||||
if (strcmp(argv[1], commands[i].name) == 0) {
|
||||
_cmd = commands[i].cmd;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_cmd == NULL) {
|
||||
dfprintf(stderr, "Error: Invalid command.\n");
|
||||
cmd = print_usage;
|
||||
ret = EXIT_FAILURE;
|
||||
} else {
|
||||
cmd = _cmd;
|
||||
}
|
||||
}
|
||||
|
||||
_ret = cmd(argv[0]);
|
||||
exit(ret == EXIT_FAILURE ? ret : _ret);
|
||||
}
|
3074
binutils/cJSON.c
3074
binutils/cJSON.c
File diff suppressed because it is too large
Load Diff
293
binutils/cJSON.h
293
binutils/cJSON.h
@@ -1,293 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef cJSON__h
|
||||
#define cJSON__h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
|
||||
#define __WINDOWS__
|
||||
#endif
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
|
||||
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options:
|
||||
|
||||
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
|
||||
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
|
||||
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
|
||||
|
||||
For *nix builds that support visibility attribute, you can define similar behavior by
|
||||
|
||||
setting default visibility to hidden by adding
|
||||
-fvisibility=hidden (for gcc)
|
||||
or
|
||||
-xldscope=hidden (for sun cc)
|
||||
to CFLAGS
|
||||
|
||||
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
|
||||
|
||||
*/
|
||||
|
||||
#define CJSON_CDECL __cdecl
|
||||
#define CJSON_STDCALL __stdcall
|
||||
|
||||
/* export symbols by default, this is necessary for copy pasting the C and header file */
|
||||
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_EXPORT_SYMBOLS
|
||||
#endif
|
||||
|
||||
#if defined(CJSON_HIDE_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) type CJSON_STDCALL
|
||||
#elif defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
|
||||
#elif defined(CJSON_IMPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
|
||||
#endif
|
||||
#else /* !__WINDOWS__ */
|
||||
#define CJSON_CDECL
|
||||
#define CJSON_STDCALL
|
||||
|
||||
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
|
||||
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
|
||||
#else
|
||||
#define CJSON_PUBLIC(type) type
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* project version */
|
||||
#define CJSON_VERSION_MAJOR 1
|
||||
#define CJSON_VERSION_MINOR 7
|
||||
#define CJSON_VERSION_PATCH 13
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* cJSON Types: */
|
||||
#define cJSON_Invalid (0)
|
||||
#define cJSON_False (1 << 0)
|
||||
#define cJSON_True (1 << 1)
|
||||
#define cJSON_NULL (1 << 2)
|
||||
#define cJSON_Number (1 << 3)
|
||||
#define cJSON_String (1 << 4)
|
||||
#define cJSON_Array (1 << 5)
|
||||
#define cJSON_Object (1 << 6)
|
||||
#define cJSON_Raw (1 << 7) /* raw json */
|
||||
|
||||
#define cJSON_IsReference 256
|
||||
#define cJSON_StringIsConst 512
|
||||
|
||||
/* The cJSON structure: */
|
||||
typedef struct cJSON
|
||||
{
|
||||
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
|
||||
struct cJSON *next;
|
||||
struct cJSON *prev;
|
||||
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
|
||||
struct cJSON *child;
|
||||
|
||||
/* The type of the item, as above. */
|
||||
int type;
|
||||
|
||||
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
|
||||
char *valuestring;
|
||||
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
|
||||
int valueint;
|
||||
/* The item's number, if type==cJSON_Number */
|
||||
double valuedouble;
|
||||
|
||||
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
|
||||
char *string;
|
||||
} cJSON;
|
||||
|
||||
typedef struct cJSON_Hooks
|
||||
{
|
||||
/* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
|
||||
void *(CJSON_CDECL *malloc_fn)(size_t sz);
|
||||
void (CJSON_CDECL *free_fn)(void *ptr);
|
||||
} cJSON_Hooks;
|
||||
|
||||
typedef int cJSON_bool;
|
||||
|
||||
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
|
||||
* This is to prevent stack overflows. */
|
||||
#ifndef CJSON_NESTING_LIMIT
|
||||
#define CJSON_NESTING_LIMIT 1000
|
||||
#endif
|
||||
|
||||
/* returns the version of cJSON as a string */
|
||||
CJSON_PUBLIC(const char*) cJSON_Version(void);
|
||||
|
||||
/* Supply malloc, realloc and free functions to cJSON */
|
||||
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
|
||||
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
|
||||
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
|
||||
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
|
||||
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
|
||||
/* Render a cJSON entity to text for transfer/storage. */
|
||||
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
|
||||
/* Render a cJSON entity to text for transfer/storage without any formatting. */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
|
||||
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
|
||||
/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
|
||||
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
|
||||
/* Delete a cJSON entity and all subentities. */
|
||||
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
|
||||
|
||||
/* Returns the number of items in an array (or object). */
|
||||
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
|
||||
/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
|
||||
/* Get item "string" from object. Case insensitive. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
|
||||
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
|
||||
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
|
||||
|
||||
/* Check item type and return its value */
|
||||
CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item);
|
||||
CJSON_PUBLIC(double) cJSON_GetNumberValue(cJSON *item);
|
||||
|
||||
/* These functions check the type of an item */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
|
||||
|
||||
/* These calls create a cJSON item of the appropriate type. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
|
||||
/* raw json */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
|
||||
|
||||
/* Create a string where valuestring references a string so
|
||||
* it will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
|
||||
/* Create an object/array that only references it's elements so
|
||||
* they will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
|
||||
|
||||
/* These utilities create an Array of count items.
|
||||
* The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);
|
||||
|
||||
/* Append item to the specified array/object. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
|
||||
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
|
||||
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
|
||||
* writing to `item->string` */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
|
||||
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
|
||||
|
||||
/* Remove/Detach items from Arrays/Objects. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
|
||||
/* Update array items. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
|
||||
|
||||
/* Duplicate a cJSON item */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
|
||||
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
|
||||
* need to be released. With recurse!=0, it will duplicate any children connected to the item.
|
||||
* The item->next and ->prev pointers are always zero on return from Duplicate. */
|
||||
/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
|
||||
* case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
|
||||
|
||||
/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
|
||||
* The input pointer json cannot point to a read-only address area, such as a string constant,
|
||||
* but should point to a readable and writable adress area. */
|
||||
CJSON_PUBLIC(void) cJSON_Minify(char *json);
|
||||
|
||||
/* Helper functions for creating and adding items to an object at the same time.
|
||||
* They return the added item or NULL on failure. */
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
|
||||
|
||||
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
|
||||
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
|
||||
/* helper for the cJSON_SetNumberValue macro */
|
||||
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
|
||||
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
|
||||
/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
|
||||
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
|
||||
|
||||
/* Macro for iterating over an array or object */
|
||||
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
|
||||
|
||||
/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
|
||||
CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
|
||||
CJSON_PUBLIC(void) cJSON_free(void *object);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@@ -1,19 +0,0 @@
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (C) 2015 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.
|
||||
# ----------------------------------------------------------------------
|
||||
all:
|
||||
|
||||
# As translations get added, they will automatically be included, unless
|
||||
# the lang is explicitly added to DISABLED_LANGS; e.g. DISABLED_LANGS=en es
|
||||
|
||||
DISABLED_LANGS=
|
||||
|
||||
COMMONDIR=../../common
|
||||
include $(COMMONDIR)/Make-po.rules
|
||||
|
||||
XGETTEXT_ARGS+=--language=C --keyword=_ $(shell if [ -f ${NAME}.pot ] ; then echo -n -j ; fi)
|
||||
|
@@ -1,66 +0,0 @@
|
||||
# Copyright (C) 2015 Canonical Ltd
|
||||
# This file is distributed under the same license as the AppArmor package.
|
||||
# John Johansen <john.johansen@canonical.com>, 2015.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: apparmor@lists.ubuntu.com\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr ""
|
@@ -1,73 +0,0 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR Canonical Ltd
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: apparmor@lists.ubuntu.com\n"
|
||||
"POT-Creation-Date: 2020-10-14 03:52-0700\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: ../aa_enabled.c:21
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -x | --exclusive Shared interfaces must be available\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:37
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:41
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:50
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:54
|
||||
#, c-format
|
||||
msgid "Partially - public shared interfaces are not available.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:58
|
||||
#, c-format
|
||||
msgid "Error - %s\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:73
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:87
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:98
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr ""
|
@@ -1,55 +0,0 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR Canonical Ltd
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: apparmor@lists.ubuntu.com\n"
|
||||
"POT-Creation-Date: 2020-10-14 03:52-0700\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: ../aa_exec.c:50
|
||||
#, c-format
|
||||
msgid ""
|
||||
"USAGE: %s [OPTIONS] <prog> <args>\n"
|
||||
"\n"
|
||||
"Confine <prog> with the specified PROFILE.\n"
|
||||
"\n"
|
||||
"OPTIONS:\n"
|
||||
" -p PROFILE, --profile=PROFILE\t\tPROFILE to confine <prog> with\n"
|
||||
" -n NAMESPACE, --namespace=NAMESPACE\tNAMESPACE to confine <prog> in\n"
|
||||
" -d, --debug\t\t\t\tshow messages with debugging information\n"
|
||||
" -i, --immediate\t\t\tchange profile immediately instead of at exec\n"
|
||||
" -v, --verbose\t\t\t\tshow messages with stats\n"
|
||||
" -h, --help\t\t\t\tdisplay this help\n"
|
||||
"\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_exec.c:65
|
||||
#, c-format
|
||||
msgid "[%ld] aa-exec: ERROR: "
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_exec.c:76
|
||||
#, c-format
|
||||
msgid "[%ld] aa-exec: DEBUG: "
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_exec.c:89
|
||||
#, c-format
|
||||
msgid "[%ld] "
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_exec.c:107
|
||||
#, c-format
|
||||
msgid "[%ld] exec"
|
||||
msgstr ""
|
@@ -1,51 +0,0 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR Canonical Ltd
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: apparmor@lists.ubuntu.com\n"
|
||||
"POT-Creation-Date: 2020-10-14 03:52-0700\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: ../aa_features_abi.c:53
|
||||
#, c-format
|
||||
msgid ""
|
||||
"USAGE: %s [OPTIONS] <SOURCE> [OUTPUT OPTIONS]\n"
|
||||
"\n"
|
||||
"Output AppArmor feature abi from SOURCE to OUTPUT\n"
|
||||
"OPTIONS:\n"
|
||||
" -d, --debug show messages with debugging information\n"
|
||||
" -v, --verbose show messages with stats\n"
|
||||
" -h, --help display this help\n"
|
||||
"SOURCE:\n"
|
||||
" -f F, --file=F load features abi from file F\n"
|
||||
" -x, --extract extract features abi from the kernel\n"
|
||||
"OUTPUT OPTIONS:\n"
|
||||
" --stdout default, write features to stdout\n"
|
||||
" -w F, --write=F write features abi to the file F instead of stdout\n"
|
||||
"\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_features_abi.c:73
|
||||
#, c-format
|
||||
msgid "%s: ERROR: "
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_features_abi.c:85
|
||||
#, c-format
|
||||
msgid "%s: DEBUG: "
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_features_abi.c:98
|
||||
msgid "\n"
|
||||
msgstr ""
|
@@ -1,71 +0,0 @@
|
||||
# Afrikaans translation for apparmor
|
||||
# Copyright (c) 2020 Rosetta Contributors and Canonical Ltd 2020
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2020-03-04 17:55+0000\n"
|
||||
"Last-Translator: bernard stafford <Unknown>\n"
|
||||
"Language-Team: Afrikaans <af@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2020-03-05 05:40+0000\n"
|
||||
"X-Generator: Launchpad (build e0878392dc799b267dea80578fa65500a5d74155)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [opsies]\n"
|
||||
" opsies:\n"
|
||||
" -q | --quiet Moenie druk uit enige boodskappe\n"
|
||||
" -h | --help Afdruk hulp\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "onbekende of onversoenbare opsies\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "onbekende opsie '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Ja\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "Geen - nie beskikbaar op hierdie stelsel.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "Nee - gestremde by stewel.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Miskien - beleid koppelvlak nie beskikbaar.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "Miskien - onvoldoende toestemmings om beskikbaarheid te bepaal.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Fout - '%s'\n"
|
@@ -1,73 +0,0 @@
|
||||
# German translation for apparmor
|
||||
# Copyright (c) 2016 Rosetta Contributors and Canonical Ltd 2016
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2016.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: AppArmor list <apparmor@lists.ubuntu.com>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2018-02-09 23:55+0000\n"
|
||||
"Last-Translator: Tobias Bannert <tobannert@gmail.com>\n"
|
||||
"Language-Team: German <de@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2019-04-18 05:33+0000\n"
|
||||
"X-Generator: Launchpad (build 18928)\n"
|
||||
"Language: de\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [Optionen]\n"
|
||||
" Optionen:\n"
|
||||
" -q | --quiet Keine Nachrichten anzeigen\n"
|
||||
" -h | --help Hilfetext anzeigen\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "unbekannte oder nicht kompatible Optionen\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "unbekannte Option »%s«\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Ja\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "Nein – auf diesem System nicht verfügbar.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "Nein – beim Start deaktiviert.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Vielleicht – Richtlinienschnittstelle nicht verfügbar.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
"Vielleicht – ungenügende Berechtigungen, um die Verfügbarkeit zu prüfen\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Fehler – »%s«\n"
|
@@ -1,72 +0,0 @@
|
||||
# English (United Kingdom) translation for apparmor
|
||||
# Copyright (c) 2016 Rosetta Contributors and Canonical Ltd 2016
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2016.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: AppArmor list <apparmor@lists.ubuntu.com>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2016-02-18 06:22+0000\n"
|
||||
"Last-Translator: Andi Chandler <Unknown>\n"
|
||||
"Language-Team: English (United Kingdom) <en_GB@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2019-04-18 05:33+0000\n"
|
||||
"X-Generator: Launchpad (build 18928)\n"
|
||||
"Language: en_GB\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "unknown or incompatible options\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "unknown option '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Yes\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "No - not available on this system.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "No - disabled at boot.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Maybe - policy interface not available.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "Maybe - insufficient permissions to determine availability.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Error - '%s'\n"
|
@@ -1,71 +0,0 @@
|
||||
# Spanish translation for apparmor
|
||||
# Copyright (c) 2019 Rosetta Contributors and Canonical Ltd 2019
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2019.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2019-06-09 14:01+0000\n"
|
||||
"Last-Translator: Adolfo Jayme <fitoschido@gmail.com>\n"
|
||||
"Language-Team: Spanish <es@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2019-06-10 04:32+0000\n"
|
||||
"X-Generator: Launchpad (build 18978)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [opciones]\n"
|
||||
" opciones:\n"
|
||||
" -q | --quiet No emitir ningún mensaje\n"
|
||||
" -h | --help Mostrar la ayuda\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "opciones desconocidas o incompatibles\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "se desconoce la opción «%s»\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Sí\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "No; no disponible en este sistema.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "No; desactivado durante el arranque.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Quizá; interfaz de directiva no disponible.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "Quizá; permisos insuficientes para determinar disponibilidad.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Error: «%s»\n"
|
@@ -1,67 +0,0 @@
|
||||
# Persian translation for apparmor
|
||||
# Copyright (c) 2019 Rosetta Contributors and Canonical Ltd 2019
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2019.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2019-12-27 08:16+0000\n"
|
||||
"Last-Translator: VahidNameni <Unknown>\n"
|
||||
"Language-Team: Persian <fa@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2019-12-28 05:38+0000\n"
|
||||
"X-Generator: Launchpad (build bceb5ef013b87ef7aafe0755545ceb689ca7ac60)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "تنظیم نامعلوم یا ناسازگار\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "تنظیم '%s' ناشناخته است\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "بله\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "خیر- در این سیستم موجود نیست.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "خیر - غیرفعال در زمان boot.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "شاید - رابط سیاست گذاری در دسترس نیست.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "شاید - دسترسی ناکافی جهت شناسایی در دسترس پذیری.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "خطا - '%s'\n"
|
@@ -1,67 +0,0 @@
|
||||
# Finnish translation for apparmor
|
||||
# Copyright (c) 2020 Rosetta Contributors and Canonical Ltd 2020
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2020-01-29 07:44+0000\n"
|
||||
"Last-Translator: Jiri Grönroos <Unknown>\n"
|
||||
"Language-Team: Finnish <fi@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2020-01-30 05:40+0000\n"
|
||||
"X-Generator: Launchpad (build b8d1327fd820d6bf500589d6da587d5037c7d88e)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "tuntemattomat tai yhteensopimattomat valinnat\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "tuntematon valinta '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Kyllä\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "Ei - ei käytettävissä tässä järjestelmässä.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "Ei - poistettu käytöstä käynnistyksen yhteydessä.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Virhe - '%s'\n"
|
@@ -1,72 +0,0 @@
|
||||
# Indonesian translation for apparmor
|
||||
# Copyright (c) 2016 Rosetta Contributors and Canonical Ltd 2016
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2016.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: AppArmor list <apparmor@lists.ubuntu.com>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2016-01-20 08:59+0000\n"
|
||||
"Last-Translator: Ari Setyo Wibowo <mr.a.contact@gmail.com>\n"
|
||||
"Language-Team: Indonesian <id@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2019-04-18 05:33+0000\n"
|
||||
"X-Generator: Launchpad (build 18928)\n"
|
||||
"Language: id\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [options]\n"
|
||||
" pilihan:\n"
|
||||
" -q | --quiet Jangan tampilkan pesan apapun\n"
|
||||
" -h | --help Tampilkan bantuan\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "pilihan yang tidak dikenali atau tidak kompatibel\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "pilihan tidak dikenali '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Ya\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "Tidak - tidak tersedia di sistem ini.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "Tidak - nonaktifkan saat boot.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Mungkin - kebijakan antarmuka tidak tersedia.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "Mungkin - izin tidak memadai untuk menentukan ketersediaan.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Kesalahan - '%s'\n"
|
@@ -1,72 +0,0 @@
|
||||
# Portuguese translation for apparmor
|
||||
# Copyright (c) 2016 Rosetta Contributors and Canonical Ltd 2016
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2016.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: AppArmor list <apparmor@lists.ubuntu.com>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2016-03-03 08:34+0000\n"
|
||||
"Last-Translator: Ivo Xavier <ivofernandes12@gmail.com>\n"
|
||||
"Language-Team: Portuguese <pt@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2019-04-18 05:33+0000\n"
|
||||
"X-Generator: Launchpad (build 18928)\n"
|
||||
"Language: pt\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [opções]\n"
|
||||
" opções:\n"
|
||||
" -q | --silencioso Não mostrar mensagens\n"
|
||||
" -h | --ajuda Mostar ajuda\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "opções desconhecidas ou incompatíveis\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "opção desconhecida '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Sim\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "Não - não disponível neste sistema.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "Não - desligado ao iniciar.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Talvez - política de interface não disponível.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "Talvez - permissões insuficientes para determinar disponibilidade.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Erro - '%s'\n"
|
@@ -1,72 +0,0 @@
|
||||
# Romanian translation for apparmor
|
||||
# Copyright (c) 2020 Rosetta Contributors and Canonical Ltd 2020
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2020-02-20 21:47+0000\n"
|
||||
"Last-Translator: Daniel Slavu <Unknown>\n"
|
||||
"Language-Team: Romanian <ro@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2020-02-21 05:39+0000\n"
|
||||
"X-Generator: Launchpad (build 19413b719a8df7423ab1390528edadce9e0e4aca)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [opțiuni]\n"
|
||||
" opțiuni:\n"
|
||||
" -q | --calm Nu imprima niciun mesaj\n"
|
||||
" -h | - ajutor Imprimare ajutor\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "opțiuni necunoscute sau incompatibile\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "opțiune necunoscută '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Da\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "Nu - nu este disponibil pe acest sistem.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "Nu - dezactivat la pornire.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Poate - interfața politică nu este disponibilă.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
"Poate - permisiuni insuficiente pentru a determina disponibilitatea.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Eroare - '%s'\n"
|
@@ -1,72 +0,0 @@
|
||||
# Russian translation for apparmor
|
||||
# Copyright (c) 2016 Rosetta Contributors and Canonical Ltd 2016
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2016.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: AppArmor list <apparmor@lists.ubuntu.com>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2016-03-29 14:46+0000\n"
|
||||
"Last-Translator: Eugene Roskin <Unknown>\n"
|
||||
"Language-Team: Russian <ru@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2019-04-18 05:33+0000\n"
|
||||
"X-Generator: Launchpad (build 18928)\n"
|
||||
"Language: ru\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [параметры]\n"
|
||||
" параметры:\n"
|
||||
" -q | --quiet не выводить никакие сообщения\n"
|
||||
" -h | --help вывести справку\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "неизвестные или несовместимые параметры\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "неизвестный параметр '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Да\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "Нет - недоступно на этой системе.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "Нет - выключено при загрузке.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Возможно - интерфейс политики недоступен.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "Возможно - недостаточно разрешений для определения доступности.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Ошибка - '%s'\n"
|
@@ -1,72 +0,0 @@
|
||||
# Swedish translation for apparmor
|
||||
# Copyright (c) 2018 Rosetta Contributors and Canonical Ltd 2018
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2018.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2018-09-08 03:51+0000\n"
|
||||
"Last-Translator: Jonatan Nyberg <Unknown>\n"
|
||||
"Language-Team: Swedish <sv@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2019-04-18 05:33+0000\n"
|
||||
"X-Generator: Launchpad (build 18928)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [options]\n"
|
||||
" flaggor:\n"
|
||||
" -q | --quiet Skriv inte ut några meddelanden\n"
|
||||
" -h | --help Skriv ut hjälp\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "okända eller inkompatibla flaggor\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "okänd flagga '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Ja\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "Nej - inte tillgänglig på detta system.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "Nej - inaktiverad vid uppstart.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Kanske - policy gränssnitt inte tillgängliga.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
"Kanske - otillräckliga behörigheter för att bestämma tillgängligheten.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Fel - '%s'\n"
|
@@ -1,71 +0,0 @@
|
||||
# Swahili translation for apparmor
|
||||
# Copyright (c) 2019 Rosetta Contributors and Canonical Ltd 2019
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2019.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2019-11-14 12:33+0000\n"
|
||||
"Last-Translator: Swahilinux Administration <admin@swahilinux.org>\n"
|
||||
"Language-Team: Swahili <sw@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2019-11-15 04:30+0000\n"
|
||||
"X-Generator: Launchpad (build c597c3229eb023b1e626162d5947141bf7befb13)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [chaguzi]\n"
|
||||
" chaguzi:\n"
|
||||
" -q | --quiet Usichapishe jumbe yoyote\n"
|
||||
" -h | --help Chapisha msaada\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "chaguo lisilojulikana au lisilofaa\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "chaguo lisilojulikana '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Ndio\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "La - haipo kwenye mfumo huu.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "La - ilizimwa kwenye washi.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Labda - kiolesura cha faragha hakipo.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "Labda - hamna ruhusa ya kutosha ili kuamua kama ipo.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Dosari - '%s'\n"
|
@@ -1,72 +0,0 @@
|
||||
# Turkish translation for apparmor
|
||||
# Copyright (c) 2018 Rosetta Contributors and Canonical Ltd 2018
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2018.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2018-05-19 23:10+0000\n"
|
||||
"Last-Translator: Kudret EMRE <kudretemre@hotmail.com>\n"
|
||||
"Language-Team: Turkish <tr@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2019-04-18 05:33+0000\n"
|
||||
"X-Generator: Launchpad (build 18928)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [seçenekler]\n"
|
||||
" seçenekler:\n"
|
||||
" -q | --quiet Hiçbir mesajı gösterme\n"
|
||||
" -h | --help Yardımı görüntüler\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "bilinmeyen veya uyumsuz seçenekler\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "bilinmeyen seçenek '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Evet\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "Hayır - Bu sistemde kullanılabilir değil.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "Hayır - önyüklemede devredışı bırakıldı.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Belki - policy arayüzü kullanılabilir değil.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
"Belki - kullanılabilir olup olmadığını denetlemek için yetersiz yetki.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Hata - '%s'\n"
|
@@ -1,6 +1,5 @@
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2004, 2005 NOVELL (All rights reserved)
|
||||
# Copyright (c) 2016 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
|
||||
@@ -70,26 +69,21 @@ libapparmor by adding USE_SYSTEM=1 to your make command.${nl}\
|
||||
LDLIBS = -lapparmor
|
||||
endif
|
||||
|
||||
APXS_CFLAGS="-Wc,$(EXTRA_WARNINGS)"
|
||||
|
||||
.PHONY: libapparmor_check
|
||||
.SILENT: libapparmor_check
|
||||
libapparmor_check: ; $(ERROR_MESSAGE)
|
||||
|
||||
all: libapparmor_check $(TARGET) docs
|
||||
|
||||
.PHONY: docs
|
||||
docs: ${MANPAGES} ${HTMLMANPAGES}
|
||||
all: libapparmor_check $(TARGET) ${MANPAGES} ${HTMLMANPAGES}
|
||||
|
||||
%.so: %.c
|
||||
${APXS} ${LIBAPPARMOR_FLAGS} ${APXS_CFLAGS} -c $< ${LDLIBS}
|
||||
${APXS} ${LIBAPPARMOR_FLAGS} -c $< ${LDLIBS}
|
||||
mv .libs/$@ .
|
||||
|
||||
.PHONY: install
|
||||
install: ${TARGET} ${MANPAGES}
|
||||
mkdir -p ${DESTDIR}/${APXS_INSTALL_DIR}
|
||||
install -m 755 $< ${DESTDIR}/${APXS_INSTALL_DIR}
|
||||
$(MAKE) install_manpages DESTDIR=${DESTDIR}
|
||||
make install_manpages DESTDIR=${DESTDIR}
|
||||
|
||||
.PHONY: clean
|
||||
clean: pod_clean
|
||||
|
@@ -30,10 +30,6 @@
|
||||
|
||||
/* #define DEBUG */
|
||||
|
||||
#ifndef unused_
|
||||
#define unused_ __attribute__ ((unused))
|
||||
#endif
|
||||
|
||||
/* should the following be configurable? */
|
||||
#define DEFAULT_HAT "HANDLING_UNTRUSTED_INPUT"
|
||||
#define DEFAULT_URI_HAT "DEFAULT_URI"
|
||||
@@ -69,7 +65,7 @@ typedef struct {
|
||||
* memory will be wiped out, and the magic_token will be lost, so apache
|
||||
* wouldn't be able to change_hat back out. */
|
||||
static int
|
||||
aa_init(apr_pool_t *p, unused_ apr_pool_t *plog, unused_ apr_pool_t *ptemp, unused_ server_rec *s)
|
||||
aa_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
|
||||
{
|
||||
apr_file_t *file;
|
||||
apr_size_t size = sizeof(magic_token);
|
||||
@@ -93,7 +89,7 @@ aa_init(apr_pool_t *p, unused_ apr_pool_t *plog, unused_ apr_pool_t *ptemp, unus
|
||||
* to protect ourselves from bugs in parsing network input, but before
|
||||
* we change_hat to the uri specific hat. */
|
||||
static void
|
||||
aa_child_init(unused_ apr_pool_t *p, unused_ server_rec *s)
|
||||
aa_child_init(apr_pool_t *p, server_rec *s)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -264,7 +260,7 @@ aa_exit_hat(request_rec *r)
|
||||
}
|
||||
|
||||
static const char *
|
||||
aa_cmd_ch_path(unused_ cmd_parms *cmd, unused_ void *mconfig, const char *parm1)
|
||||
aa_cmd_ch_path(cmd_parms *cmd, void *mconfig, const char *parm1)
|
||||
{
|
||||
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, "directory config change hat %s",
|
||||
parm1 ? parm1 : "DEFAULT");
|
||||
@@ -291,7 +287,7 @@ immunix_cmd_ch_path(cmd_parms *cmd, void *mconfig, const char *parm1)
|
||||
}
|
||||
|
||||
static const char *
|
||||
aa_cmd_ch_srv(cmd_parms *cmd, unused_ void *mconfig, const char *parm1)
|
||||
aa_cmd_ch_srv(cmd_parms *cmd, void *mconfig, const char *parm1)
|
||||
{
|
||||
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, "server config change hat %s",
|
||||
parm1 ? parm1 : "DEFAULT");
|
||||
@@ -351,7 +347,7 @@ aa_merge_dir_config(apr_pool_t *p, void *parent, void *child)
|
||||
*/
|
||||
|
||||
static void *
|
||||
aa_create_srv_config(apr_pool_t *p, unused_ server_rec *srv)
|
||||
aa_create_srv_config(apr_pool_t *p, server_rec *srv)
|
||||
{
|
||||
apparmor_srv_cfg *newcfg = (apparmor_srv_cfg *) apr_pcalloc(p, sizeof(*newcfg));
|
||||
|
||||
@@ -401,7 +397,7 @@ static const command_rec mod_apparmor_cmds[] = {
|
||||
};
|
||||
|
||||
static void
|
||||
register_hooks(unused_ apr_pool_t *p)
|
||||
register_hooks(apr_pool_t *p)
|
||||
{
|
||||
ap_hook_post_config(aa_init, NULL, NULL, APR_HOOK_MIDDLE);
|
||||
ap_hook_child_init(aa_child_init, NULL, NULL, APR_HOOK_MIDDLE);
|
||||
@@ -412,7 +408,7 @@ register_hooks(unused_ apr_pool_t *p)
|
||||
|
||||
module AP_MODULE_DECLARE_DATA apparmor_module = {
|
||||
STANDARD20_MODULE_STUFF,
|
||||
aa_create_dir_config, /* dir config creator */
|
||||
aa_create_dir_config, /* dir config creater */
|
||||
NULL, /* dir merger --- default is to override */
|
||||
/* immunix_merge_dir_config, */ /* dir merger --- default is to override */
|
||||
aa_create_srv_config, /* server config */
|
||||
|
@@ -135,11 +135,11 @@ 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://gitlab.com/apparmor/apparmor/-/issues>.
|
||||
them at L<https://bugs.launchpad.net/apparmor/+filebug>.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
apparmor(7), apparmor_parser(8), aa_change_hat(2) and
|
||||
apparmor(7), subdomain.conf(5), apparmor_parser(8), aa_change_hat(2) and
|
||||
L<https://wiki.apparmor.net>.
|
||||
|
||||
=cut
|
||||
|
@@ -1,6 +1,5 @@
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 1999, 2004, 2005 NOVELL (All rights reserved)
|
||||
# Copyright (c) 2016 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
|
||||
@@ -54,8 +53,8 @@ libapparmor by adding USE_SYSTEM=1 to your make command.${nl}\
|
||||
AA_LINK_FLAGS = -L$(LIBAPPARMOR_PATH)
|
||||
AA_LDLIBS = -lapparmor
|
||||
endif
|
||||
EXTRA_CFLAGS=$(CFLAGS) $(CPPFLAGS) -fPIC -shared -Wall $(EXTRA_WARNINGS) $(LIBAPPARMOR_INCLUDE)
|
||||
LINK_FLAGS=-Xlinker -x $(AA_LINK_FLAGS) $(LDFLAGS)
|
||||
EXTRA_CFLAGS=$(CFLAGS) $(CPPFLAGS) -fPIC -shared -Wall $(LIBAPPARMOR_INCLUDE)
|
||||
LINK_FLAGS=-Xlinker -x $(AA_LINK_FLAGS)
|
||||
LIBS=-lpam $(AA_LDLIBS)
|
||||
OBJECTS=${NAME}.o get_options.o
|
||||
|
||||
@@ -63,11 +62,7 @@ OBJECTS=${NAME}.o get_options.o
|
||||
.SILENT: libapparmor_check
|
||||
libapparmor_check: ; $(ERROR_MESSAGE)
|
||||
|
||||
all: libapparmor_check $(NAME).so docs
|
||||
|
||||
.PHONY: docs
|
||||
# docs: we should have some
|
||||
docs:
|
||||
all: libapparmor_check $(NAME).so
|
||||
|
||||
$(NAME).so: ${OBJECTS}
|
||||
$(CC) $(EXTRA_CFLAGS) $(LINK_FLAGS) -o $@ ${OBJECTS} $(LIBS)
|
||||
@@ -82,7 +77,7 @@ SECDIR ?= ${DESTDIR}/lib/security
|
||||
.PHONY: install
|
||||
install: $(NAME).so
|
||||
install -m 755 -d $(SECDIR)
|
||||
install -m 755 $(NAME).so $(SECDIR)/
|
||||
install -m 555 $(NAME).so $(SECDIR)/
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
|
@@ -45,10 +45,6 @@
|
||||
|
||||
int debug_flag = 0;
|
||||
|
||||
#ifndef unused_
|
||||
#define unused_ __attribute__ ((unused))
|
||||
#endif
|
||||
|
||||
static struct config default_config = {
|
||||
.hat_type[0] = eGroupname,
|
||||
.hat_type[1] = eDefault,
|
||||
@@ -58,14 +54,14 @@ static struct config default_config = {
|
||||
/* --- session management functions (only) --- */
|
||||
|
||||
PAM_EXTERN int
|
||||
pam_sm_close_session (unused_ pam_handle_t *pamh, unused_ int flags,
|
||||
unused_ int argc, unused_ const char **argv)
|
||||
pam_sm_close_session (pam_handle_t *pamh, int flags,
|
||||
int argc, const char **argv)
|
||||
{
|
||||
return PAM_IGNORE;
|
||||
}
|
||||
|
||||
PAM_EXTERN
|
||||
int pam_sm_open_session(pam_handle_t *pamh, unused_ int flags,
|
||||
int pam_sm_open_session(pam_handle_t *pamh, int flags,
|
||||
int argc, const char **argv)
|
||||
{
|
||||
int fd, retval, pam_retval = PAM_SUCCESS;
|
||||
|
@@ -66,8 +66,8 @@ under src/jni_src.
|
||||
cp dist/libJNIChangeHat.so /usr/lib
|
||||
|
||||
[Note: you must ensure that the target directory is passed to tomcat via the
|
||||
java.library.path property. This can be accomplished by setting the JAVA_OPTS
|
||||
environment variable, export JAVA_OPTS=-Djava.library.path, or set via the
|
||||
java.library.path propert. This can be accomplished by setting the JAVA_OPTS
|
||||
enviroment variable, export JAVA_OPTS=-Djava.library.path, or set via the
|
||||
env variable LD_LIBRARY_PATH to include this directory so that tomcat can
|
||||
find this library at startup]
|
||||
|
||||
@@ -108,13 +108,13 @@ under src/jni_src.
|
||||
Once the installation steps above have been started you are ready to begin
|
||||
creating a profile for your application. The profile creation tool genprof will
|
||||
guide you through generating a profile and its support for change_hat will
|
||||
prompt you create discrete hats as requested by the changeHatValve during
|
||||
prompt you create discrete hats as requested byt the changeHatValve during
|
||||
tomcat execution.
|
||||
|
||||
1. Create a basic profile for the tomcat server.
|
||||
|
||||
- Run the command "genprof PATH_TO_CATALINA.SH"
|
||||
- In a separate window start tomcat and then stop tomcat
|
||||
- In a seperate window start tomcat and then stop tomcat
|
||||
- In the genprof window press "S" to scan for events
|
||||
- Answer the questions about the initial profile for tomcat
|
||||
|
||||
@@ -124,7 +124,7 @@ tomcat execution.
|
||||
- Stop the tomcat server
|
||||
- Deploy your WAR file or equivalent files under the container.
|
||||
- execute "genprof PATH_TO_CATALINA.SH"
|
||||
- In a separate window start tomcat and then exercise your web application
|
||||
- In a seperate window start tomcat and then exercise your web application
|
||||
- In the genprof window press "S" to scan for events
|
||||
During the prompting you will be asked questions similar to:
|
||||
|
||||
@@ -180,7 +180,7 @@ all subsequent resource requests will be mediated in this hew hat (or security
|
||||
context).
|
||||
If you choose to use the default hat: genprof will mediate all resource
|
||||
requests in the default hat for the duration of processing this request.
|
||||
When the request processing is complete the valve will change_hat back to the
|
||||
When the request processng is complete the valve will change_hat back to the
|
||||
parent context.
|
||||
|
||||
|
||||
|
@@ -66,8 +66,8 @@ under src/jni_src.
|
||||
cp dist/libJNIChangeHat.so /usr/lib
|
||||
|
||||
[Note: you must ensure that the target directory is passed to tomcat via the
|
||||
java.library.path property. This can be accomplished by setting the JAVA_OPTS
|
||||
environment variable, export JAVA_OPTS=-Djava.library.path, or set via the
|
||||
java.library.path propert. This can be accomplished by setting the JAVA_OPTS
|
||||
enviroment variable, export JAVA_OPTS=-Djava.library.path, or set via the
|
||||
env variable LD_LIBRARY_PATH to include this directory so that tomcat can
|
||||
find this library at startup]
|
||||
|
||||
@@ -108,13 +108,13 @@ under src/jni_src.
|
||||
Once the installation steps above have been started you are ready to begin
|
||||
creating a profile for your application. The profile creation tool genprof will
|
||||
guide you through generating a profile and its support for change_hat will
|
||||
prompt you create discrete hats as requested by the changeHatValve during
|
||||
prompt you create discrete hats as requested byt the changeHatValve during
|
||||
tomcat execution.
|
||||
|
||||
1. Create a basic profile for the tomcat server.
|
||||
|
||||
- Run the command "genprof PATH_TO_CATALINA.SH"
|
||||
- In a separate window start tomcat and then stop tomcat
|
||||
- In a seperate window start tomcat and then stop tomcat
|
||||
- In the genprof window press "S" to scan for events
|
||||
- Answer the questions about the initial profile for tomcat
|
||||
|
||||
@@ -124,7 +124,7 @@ tomcat execution.
|
||||
- Stop the tomcat server
|
||||
- Deploy your WAR file or equivalent files under the container.
|
||||
- execute "genprof PATH_TO_CATALINA.SH"
|
||||
- In a separate window start tomcat and then exercise your web application
|
||||
- In a seperate window start tomcat and then exercise your web application
|
||||
- In the genprof window press "S" to scan for events
|
||||
During the prompting you will be asked questions similar to:
|
||||
|
||||
@@ -180,7 +180,7 @@ all subsequent resource requests will be mediated in this hew hat (or security
|
||||
context).
|
||||
If you choose to use the default hat: genprof will mediate all resource
|
||||
requests in the default hat for the duration of processing this request.
|
||||
When the request processing is complete the valve will change_hat back to the
|
||||
When the request processng is complete the valve will change_hat back to the
|
||||
parent context.
|
||||
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (c) 1999-2008 NOVELL (All rights reserved)
|
||||
# Copyright 2009-2015 Canonical Ltd.
|
||||
# Copyright 2009-2010 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
|
||||
@@ -21,7 +21,7 @@
|
||||
# exist
|
||||
LOCALEDIR=/usr/share/locale
|
||||
|
||||
XGETTEXT_ARGS=--copyright-holder="Canonical Ltd" --msgid-bugs-address=apparmor@lists.ubuntu.com -d ${NAME}
|
||||
XGETTEXT_ARGS=--copyright-holder="NOVELL, Inc." --msgid-bugs-address=apparmor@lists.ubuntu.com -d ${NAME}
|
||||
|
||||
# When making the .pot file, it's expected that the parent Makefile will
|
||||
# pass in the list of sources in the SOURCES variable
|
||||
|
@@ -47,7 +47,7 @@ endef
|
||||
REPO_VERSION_CMD=[ -x /usr/bin/git ] && /usr/bin/git describe --tags --long --abbrev=16 --match 'v*' 2> /dev/null || awk '{ print $2 }' common/.stamp_rev
|
||||
|
||||
ifndef PYTHON_VERSIONS
|
||||
PYTHON_VERSIONS = $(call map, pathsearch, python3)
|
||||
PYTHON_VERSIONS = $(call map, pathsearch, python2 python3)
|
||||
endif
|
||||
|
||||
ifndef PYTHON
|
||||
@@ -57,18 +57,6 @@ endif
|
||||
#Helper function to be used with $(call pyalldo, run_test_with_all.py)
|
||||
pyalldo=set -e; $(foreach py, $(PYTHON_VERSIONS), $(py) $(1);)
|
||||
|
||||
# Common set of compiler warnings
|
||||
_EXTRA_WARNINGS = -Wall -Wsign-compare -Wmissing-field-initializers -Wformat -Wformat-security -Wunused-parameter -Wimplicit-fallthrough
|
||||
EXTRA_WARNINGS := $(shell for warning in ${_EXTRA_WARNINGS} ; do \
|
||||
if ${CC} $${warning} -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then \
|
||||
echo "$${warning}"; \
|
||||
else \
|
||||
echo "***" >&2 ; \
|
||||
echo "WARNING: unable to use $${warning} with ${CC}, dropping" >&2 ; \
|
||||
echo "***" >&2 ; \
|
||||
fi ; \
|
||||
done)
|
||||
|
||||
.PHONY: version
|
||||
.SILENT: version
|
||||
version:
|
||||
@@ -77,7 +65,7 @@ version:
|
||||
.PHONY: repo_version
|
||||
.SILENT: repo_version
|
||||
repo_version:
|
||||
echo $(shell $(value REPO_VERSION_CMD))
|
||||
$(value REPO_VERSION_CMD)
|
||||
|
||||
.PHONY: pod_clean
|
||||
ifndef VERBOSE
|
||||
@@ -86,6 +74,40 @@ endif
|
||||
pod_clean:
|
||||
-rm -f ${MANPAGES} *.[0-9].gz ${HTMLMANPAGES} pod2htm*.tmp
|
||||
|
||||
# =====================
|
||||
# generate list of capabilities based on
|
||||
# /usr/include/linux/capabilities.h for use in multiple locations in
|
||||
# the source tree
|
||||
# =====================
|
||||
|
||||
# emits defined capabilities in a simple list, e.g. "CAP_NAME CAP_NAME2"
|
||||
CAPABILITIES=$(shell echo "\#include <linux/capability.h>" | cpp -dM | LC_ALL=C sed -n -e '/CAP_EMPTY_SET/d' -e 's/^\#define[ \t]\+CAP_\([A-Z0-9_]\+\)[ \t]\+\([0-9xa-f]\+\)\(.*\)$$/CAP_\1/p' | LC_ALL=C sort)
|
||||
|
||||
.PHONY: list_capabilities
|
||||
list_capabilities: /usr/include/linux/capability.h
|
||||
@echo "$(CAPABILITIES)"
|
||||
|
||||
# =====================
|
||||
# generate list of network protocols based on
|
||||
# sys/socket.h for use in multiple locations in
|
||||
# the source tree
|
||||
# =====================
|
||||
|
||||
# These are the families that it doesn't make sense for apparmor
|
||||
# to mediate. We use PF_ here since that is what is required in
|
||||
# bits/socket.h, but we will rewrite these as AF_.
|
||||
|
||||
FILTER_FAMILIES=PF_UNIX
|
||||
|
||||
__FILTER=$(shell echo $(strip $(FILTER_FAMILIES)) | sed -e 's/ /\\\|/g')
|
||||
|
||||
# emits the AF names in a "AF_NAME NUMBER," pattern
|
||||
AF_NAMES=$(shell echo "\#include <sys/socket.h>" | cpp -dM | LC_ALL=C sed -n -e '/$(__FILTER)/d' -e 's/PF_LOCAL/PF_UNIX/' -e 's/^\#define[ \t]\+PF_\([A-Z0-9_]\+\)[ \t]\+\([0-9]\+\).*$$/AF_\1 \2,/p' | sort -n -k2)
|
||||
|
||||
.PHONY: list_af_names
|
||||
list_af_names:
|
||||
@echo "$(AF_NAMES)"
|
||||
|
||||
# =====================
|
||||
# manpages
|
||||
# =====================
|
||||
|
@@ -1 +1 @@
|
||||
3.1.5
|
||||
2.10.6
|
||||
|
@@ -1,19 +0,0 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
# =====================
|
||||
# generate list of network protocols based on
|
||||
# sys/socket.h for use in multiple locations in
|
||||
# the source tree
|
||||
# =====================
|
||||
|
||||
# It doesn't make sense for AppArmor to mediate PF_UNIX, filter it out. Search
|
||||
# for "PF_" constants since that is what is required in bits/socket.h, but
|
||||
# rewrite as "AF_".
|
||||
|
||||
echo "#include <sys/socket.h>" | \
|
||||
cpp -dM | \
|
||||
LC_ALL=C sed -n \
|
||||
-e '/PF_UNIX/d' \
|
||||
-e 's/PF_LOCAL/PF_UNIX/' \
|
||||
-e 's/^#define[ \t]\+PF_\([A-Z0-9_]\+\)[ \t]\+\([0-9]\+\).*$/AF_\1 \2,/p' | \
|
||||
sort -n -k2
|
@@ -1,14 +0,0 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
# =====================
|
||||
# generate list of capabilities based on
|
||||
# /usr/include/linux/capabilities.h for use in multiple locations in
|
||||
# the source tree
|
||||
# =====================
|
||||
|
||||
echo "#include <linux/capability.h>" | \
|
||||
cpp -dM | \
|
||||
LC_ALL=C sed -n \
|
||||
-e '/CAP_EMPTY_SET/d' \
|
||||
-e 's/^\#define[ \t]\+CAP_\([A-Z0-9_]\+\)[ \t]\+\([0-9xa-f]\+\)\(.*\)$/CAP_\1/p' | \
|
||||
LC_ALL=C sort
|
137
deprecated/rc.aaeventd.redhat
Normal file
137
deprecated/rc.aaeventd.redhat
Normal file
@@ -0,0 +1,137 @@
|
||||
#!/bin/sh
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
|
||||
# NOVELL (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 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.
|
||||
# ----------------------------------------------------------------------
|
||||
# rc.apparmor by Steve Beattie
|
||||
#
|
||||
# /etc/init.d/aaeventd
|
||||
# and its symbolic link
|
||||
# /sbin/rcaaeventd
|
||||
#
|
||||
# chkconfig: 2345 01 99
|
||||
# description: AppArmor Notification and Reporting daemon
|
||||
#
|
||||
### BEGIN INIT INFO
|
||||
# Provides: aaeventd
|
||||
# Required-Start: apparmor
|
||||
# Required-Stop:
|
||||
# Default-Start: 2 3 5
|
||||
# Default-Stop:
|
||||
# Short-Description: AppArmor Notification and Reporting
|
||||
# Description: AppArmor Notification and Reporting daemon
|
||||
### END INIT INFO
|
||||
APPARMOR_FUNCTIONS=/lib/apparmor/rc.apparmor.functions
|
||||
|
||||
# source function library
|
||||
if [ -f /etc/init.d/functions ]; then
|
||||
. /etc/init.d/functions
|
||||
elif [ -f /etc/rc.d/init.d/functions ]; then
|
||||
. /etc/rc.d/init.d/functions
|
||||
elif [ -f /lib/lsb/init-functions ]; then
|
||||
. /lib/lsb/init-functions
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
|
||||
sd_log_success_msg() {
|
||||
echo -n "$*"
|
||||
success
|
||||
echo
|
||||
}
|
||||
|
||||
sd_log_warning_msg() {
|
||||
echo -n "$*"
|
||||
warning
|
||||
echo
|
||||
}
|
||||
|
||||
sd_log_skipped_msg() {
|
||||
echo -n "$*"
|
||||
warning
|
||||
echo
|
||||
}
|
||||
|
||||
sd_log_failure_msg() {
|
||||
echo -n "$*"
|
||||
failure
|
||||
echo
|
||||
}
|
||||
|
||||
sd_action() {
|
||||
STRING=$1
|
||||
shift
|
||||
action "${STRING} " "$@"
|
||||
return $?
|
||||
}
|
||||
|
||||
start_aa_event() {
|
||||
if [ -x "$AA_EV_BIN" -a "${APPARMOR_ENABLE_AAEVENTD}" = "yes" ] ; then
|
||||
sd_action "Starting AppArmor Event daemon" daemon --pidfile $AA_EV_PIDFILE $AA_EV_BIN -p $AA_EV_PIDFILE
|
||||
elif [ -x "$SD_EV_BIN" -a "${APPARMOR_ENABLE_AAEVENTD}" = "yes" ] ; then
|
||||
sd_action "Starting AppArmor Event daemon" daemon --pidfile $SD_EV_PIDFILE $SD_EV_BIN -p $SD_EV_PIDFILE
|
||||
fi
|
||||
}
|
||||
|
||||
stop_aa_event() {
|
||||
if [ -x "$AA_EV_BIN" -a -f "$AA_EV_PIDFILE" ] ; then
|
||||
sd_action "Shutting down AppArmor Event daemon" killproc -p $AA_EV_PIDFILE -INT $AA_EV_BIN
|
||||
fi
|
||||
if [ -f "$SD_EV_PIDFILE" ] ; then
|
||||
sd_action "Shutting down AppArmor Event daemon" killproc -p $SD_EV_PIDFILE -INT $SD_EV_BIN
|
||||
fi
|
||||
}
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 {start|stop|restart|try-restart|reload|force-reload|status}"
|
||||
}
|
||||
|
||||
# source apparmor function library
|
||||
if [ -f "${APPARMOR_FUNCTIONS}" ]; then
|
||||
. ${APPARMOR_FUNCTIONS}
|
||||
else
|
||||
sd_log_failure_msg "Unable to find AppArmor initscript functions"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
start_aa_event
|
||||
rc=$?
|
||||
;;
|
||||
stop)
|
||||
stop_aa_event
|
||||
rc=$?
|
||||
;;
|
||||
restart|reload|force-reload|try-restart)
|
||||
stop_aa_event
|
||||
start_aa_event
|
||||
rc=$?
|
||||
;;
|
||||
status)
|
||||
echo -n "Checking for service AppArmor Event daemon:"
|
||||
if [ "${APPARMOR_ENABLE_AAEVENTD}" = "yes" ]; then
|
||||
/sbin/checkproc -p $AA_EV_PIDFILE $AA_EV_BIN
|
||||
rc_status -v
|
||||
else
|
||||
rc_status -u
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
exit $rc
|
133
deprecated/rc.aaeventd.suse
Normal file
133
deprecated/rc.aaeventd.suse
Normal file
@@ -0,0 +1,133 @@
|
||||
#!/bin/sh
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 1999, 2000, 2001, 2002, 2003 2004, 2005, 2006, 2007
|
||||
# NOVELL (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 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.
|
||||
# ----------------------------------------------------------------------
|
||||
# rc.apparmor by Steve Beattie
|
||||
#
|
||||
# /etc/init.d/aaeventd
|
||||
# and its symbolic link
|
||||
# /sbin/rcaaeventd
|
||||
#
|
||||
# chkconfig: 2345 01 99
|
||||
# description: AppArmor Notification and Reporting daemon
|
||||
#
|
||||
### BEGIN INIT INFO
|
||||
# Provides: aaeventd
|
||||
# Required-Start: apparmor
|
||||
# Required-Stop: $null
|
||||
# Default-Start: 2 3 5
|
||||
# Default-Stop:
|
||||
# Short-Description: AppArmor Notification and Reporting
|
||||
# Description: AppArmor Notification and Reporting daemon
|
||||
### END INIT INFO
|
||||
APPARMOR_FUNCTIONS=/lib/apparmor/rc.apparmor.functions
|
||||
|
||||
# source function library
|
||||
if [ -f /etc/init.d/functions ]; then
|
||||
. /etc/init.d/functions
|
||||
elif [ -f /etc/rc.d/init.d/functions ]; then
|
||||
. /etc/rc.d/init.d/functions
|
||||
elif [ -f /lib/lsb/init-functions ]; then
|
||||
. /lib/lsb/init-functions
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Ugh, SUSE doesn't implement action
|
||||
sd_action() {
|
||||
STRING=$1
|
||||
shift
|
||||
"$@"
|
||||
rc=$?
|
||||
if [ $rc -eq 0 ] ; then
|
||||
log_success_msg $"$STRING "
|
||||
else
|
||||
log_failure_msg $"$STRING "
|
||||
fi
|
||||
return $rc
|
||||
}
|
||||
|
||||
sd_log_success_msg() {
|
||||
log_success_msg $*
|
||||
}
|
||||
|
||||
sd_log_warning_msg() {
|
||||
log_warning_msg $*
|
||||
}
|
||||
|
||||
sd_log_failure_msg() {
|
||||
log_failure_msg $*
|
||||
}
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 {start|stop|restart|try-restart|reload|force-reload|status}"
|
||||
}
|
||||
|
||||
start_aa_event() {
|
||||
if [ -x "$AA_EV_BIN" -a "${APPARMOR_ENABLE_AAEVENTD}" = "yes" ] ; then
|
||||
sd_action "Starting AppArmor Event daemon" startproc -p $AA_EV_PIDFILE $AA_EV_BIN -p $AA_EV_PIDFILE
|
||||
elif [ -x "$SD_EV_BIN" -a "${APPARMOR_ENABLE_AAEVENTD}" = "yes" ] ; then
|
||||
sd_action "Starting AppArmor Event daemon" startproc -p $SD_EV_PIDFILE $SD_EV_BIN -p $SD_EV_PIDFILE
|
||||
fi
|
||||
}
|
||||
|
||||
stop_aa_event() {
|
||||
if [ -x "$AA_EV_BIN" -a -f "$AA_EV_PIDFILE" ] ; then
|
||||
sd_action "Shutting down AppArmor Event daemon" killproc -G -p $AA_EV_PIDFILE -INT $AA_EV_BIN
|
||||
fi
|
||||
if [ -f "$SD_EV_PIDFILE" ] ; then
|
||||
sd_action "Shutting down AppArmor Event daemon" killproc -G -p $SD_EV_PIDFILE -INT $SD_EV_BIN
|
||||
fi
|
||||
}
|
||||
|
||||
# source apparmor function library
|
||||
if [ -f "${APPARMOR_FUNCTIONS}" ]; then
|
||||
. ${APPARMOR_FUNCTIONS}
|
||||
else
|
||||
sd_log_failure_msg "Unable to find AppArmor initscript functions"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
start_aa_event
|
||||
rc=$?
|
||||
;;
|
||||
stop)
|
||||
stop_aa_event
|
||||
rc=$?
|
||||
;;
|
||||
restart|reload|force-reload|try-restart)
|
||||
stop_aa_event
|
||||
start_aa_event
|
||||
rc=$?
|
||||
;;
|
||||
status)
|
||||
echo -n "Checking for service AppArmor Event daemon:"
|
||||
if [ "${APPARMOR_ENABLE_AAEVENTD}" = "yes" ]; then
|
||||
/sbin/checkproc -p $AA_EV_PIDFILE $AA_EV_BIN
|
||||
rc_status -v
|
||||
else
|
||||
rc_status -u
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
exit $rc
|
||||
|
6860
deprecated/utils/Immunix/AppArmor.pm
Executable file
6860
deprecated/utils/Immunix/AppArmor.pm
Executable file
File diff suppressed because it is too large
Load Diff
124
deprecated/utils/Immunix/Config.pm
Normal file
124
deprecated/utils/Immunix/Config.pm
Normal file
@@ -0,0 +1,124 @@
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2006 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.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
package Immunix::Config;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Carp;
|
||||
use Cwd qw(cwd realpath);
|
||||
use File::Basename;
|
||||
use File::Temp qw/ tempfile tempdir /;
|
||||
use Data::Dumper;
|
||||
use Locale::gettext;
|
||||
use POSIX;
|
||||
|
||||
require Exporter;
|
||||
our @ISA = qw(Exporter);
|
||||
our @EXPORT = qw(
|
||||
read_config
|
||||
write_config
|
||||
find_first_file
|
||||
find_first_dir
|
||||
);
|
||||
|
||||
our $confdir = "/etc/apparmor";
|
||||
|
||||
# config vars
|
||||
our $cfg;
|
||||
our $repo_cfg;
|
||||
|
||||
sub read_config {
|
||||
my $filename = shift;
|
||||
my $config;
|
||||
|
||||
if (open(CONF, "$confdir/$filename")) {
|
||||
my $which;
|
||||
while (<CONF>) {
|
||||
chomp;
|
||||
# ignore comments
|
||||
next if /^\s*#/;
|
||||
if (m/^\[(\S+)\]/) {
|
||||
$which = $1;
|
||||
} elsif (m/^\s*(\S+)\s*=\s*(.*)\s*$/) {
|
||||
my ($key, $value) = ($1, $2);
|
||||
$config->{$which}{$key} = $value;
|
||||
}
|
||||
}
|
||||
close(CONF);
|
||||
}
|
||||
|
||||
# LP: #692406
|
||||
# Explicitly disable the repository until there is an alternative, since
|
||||
# the OpenSUSE site went away
|
||||
if ($filename eq "repository.conf") {
|
||||
$config->{repository}{enabled} = "no";
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
sub write_config {
|
||||
my ($filename, $config) = @_;
|
||||
if (open(my $CONF, ">$confdir/$filename")) {
|
||||
for my $section (sort keys %$config) {
|
||||
print $CONF "[$section]\n";
|
||||
|
||||
for my $key (sort keys %{$config->{$section}}) {
|
||||
print $CONF " $key = $config->{$section}{$key}\n"
|
||||
if ($config->{$section}{$key});
|
||||
}
|
||||
}
|
||||
chmod(0600, $CONF);
|
||||
close($CONF);
|
||||
} else {
|
||||
die "Can't write config file $filename: $!";
|
||||
}
|
||||
}
|
||||
|
||||
sub find_first_file {
|
||||
my $list = shift;
|
||||
return if ( not defined $list );
|
||||
my $filename;
|
||||
for my $f (split(/\s+/, $list)) {
|
||||
if (-f $f) {
|
||||
$filename = $f;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
return $filename;
|
||||
}
|
||||
|
||||
sub find_first_dir {
|
||||
my $list = shift;
|
||||
return if ( not defined $list );
|
||||
my $dirname;
|
||||
for my $f (split(/\s+/, $list)) {
|
||||
if (-d $f) {
|
||||
$dirname = $f;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
return $dirname;
|
||||
}
|
||||
|
||||
1;
|
2024
deprecated/utils/Immunix/Reports.pm
Executable file
2024
deprecated/utils/Immunix/Reports.pm
Executable file
File diff suppressed because it is too large
Load Diff
354
deprecated/utils/Immunix/Repository.pm
Normal file
354
deprecated/utils/Immunix/Repository.pm
Normal file
@@ -0,0 +1,354 @@
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2008 Dominic Reynolds
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
package Immunix::Repository;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Carp;
|
||||
use Cwd qw(cwd realpath);
|
||||
use Data::Dumper;
|
||||
use File::Basename;
|
||||
use File::Temp qw/ tempfile tempdir /;
|
||||
use Immunix::Config;
|
||||
use Locale::gettext;
|
||||
use POSIX;
|
||||
use RPC::XML;
|
||||
use RPC::XML::Client;
|
||||
|
||||
|
||||
require Exporter;
|
||||
our @ISA = qw(Exporter);
|
||||
our @EXPORT = qw(
|
||||
get_repo_client
|
||||
did_result_succeed
|
||||
get_result_error
|
||||
user_login
|
||||
user_register
|
||||
upload_profile
|
||||
fetch_profile_by_id
|
||||
fetch_profiles_by_user
|
||||
fetch_profiles_by_name
|
||||
fetch_profiles_by_name_and_user
|
||||
fetch_newer_profile
|
||||
get_repo_config
|
||||
set_repo_config
|
||||
);
|
||||
|
||||
our %clients;
|
||||
our %uid2login;
|
||||
our $DEBUGGING = 0;
|
||||
our $repo_cfg;
|
||||
our $aa_cfg;
|
||||
|
||||
sub get_repo_client ($) {
|
||||
my $repo_url = shift;
|
||||
unless ( $clients{$repo_url} ) {
|
||||
$clients{$repo_url} = new RPC::XML::Client $repo_url;
|
||||
}
|
||||
return $clients{$repo_url};
|
||||
}
|
||||
|
||||
sub did_result_succeed {
|
||||
my $result = shift;
|
||||
|
||||
my $ref = ref $result;
|
||||
return ($ref && $ref ne "RPC::XML::fault") ? 1 : 0;
|
||||
}
|
||||
|
||||
sub get_result_error {
|
||||
my $result = shift;
|
||||
|
||||
if (ref $result) {
|
||||
if (ref $result eq "RPC::XML::fault") {
|
||||
$result = $result->string;
|
||||
} else {
|
||||
$result = $$result;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
sub user_login ($$$) {
|
||||
my ($repo_url,$user,$pass) = @_;
|
||||
my ($status,$detail);
|
||||
my $repo_client = get_repo_client( $repo_url );
|
||||
if ( $repo_client ) {
|
||||
my $res = $repo_client->send_request('LoginConfirm', $user, $pass);
|
||||
if (did_result_succeed($res)) {
|
||||
$status = 1;
|
||||
$detail = "";
|
||||
} else {
|
||||
$status = 0;
|
||||
$detail = get_result_error($res);
|
||||
}
|
||||
}
|
||||
return $status,$detail;
|
||||
}
|
||||
|
||||
|
||||
sub user_register ($$$$) {
|
||||
my ($repo_url,$user,$pass,$email) = @_;
|
||||
my $repo_client = get_repo_client( $repo_url );
|
||||
my ($status,$detail);
|
||||
if ( $repo_client ) {
|
||||
my $res = $repo_client->send_request('Signup', $user, $pass, $email);
|
||||
if (did_result_succeed($res)) {
|
||||
$status = 1;
|
||||
$detail = "";
|
||||
} else {
|
||||
$status = 0;
|
||||
$detail = get_result_error($res);
|
||||
}
|
||||
}
|
||||
return $status,$detail;
|
||||
}
|
||||
|
||||
sub upload_profile ($$$$$$$) {
|
||||
my ($repo_url,$user,$pass,$distro,$pname,$profile,$changelog) = @_;
|
||||
my ($status,$detail);
|
||||
my $repo_client = get_repo_client( $repo_url );
|
||||
my $res = $repo_client->send_request( 'Create', $user, $pass, $distro,
|
||||
$pname, $profile, $changelog);
|
||||
if (did_result_succeed($res)) {
|
||||
$detail = $res->value;
|
||||
$status = 1;
|
||||
} else {
|
||||
$detail = get_result_error($res);
|
||||
$status = 0;
|
||||
}
|
||||
return $status,$detail;
|
||||
}
|
||||
|
||||
sub fetch_profile_by_id ($$) {
|
||||
my ($repo_url,$id) = @_;
|
||||
my $repo_client = get_repo_client( $repo_url );
|
||||
my $repo_profile;
|
||||
my ($status,$detail);
|
||||
my $res = $repo_client->send_request('Show', $id);
|
||||
if (did_result_succeed($res)) {
|
||||
$status = 1;
|
||||
$detail = $res->value();
|
||||
} else {
|
||||
$status = 0;
|
||||
$detail = get_result_error($res);
|
||||
}
|
||||
|
||||
return $status, $detail;
|
||||
}
|
||||
|
||||
|
||||
sub fetch_profiles ($$$$) {
|
||||
my ($repo_url,$distro,$username,$fqdn) = @_;
|
||||
my $p_hash = {};
|
||||
my ($status,$detail);
|
||||
my $repo_client = get_repo_client( $repo_url );
|
||||
my $res =
|
||||
$repo_client->send_request('FindProfiles', $distro, $fqdn, $username);
|
||||
if (did_result_succeed($res)) {
|
||||
$status = 1;
|
||||
for my $p ( @$res ) {
|
||||
my $p_repo = $p->{profile}->value();
|
||||
$p_repo =~ s/flags=\(complain\)// if ( $p_repo ); #strip complain flag
|
||||
$p->{profile} = $p_repo;
|
||||
$p->{user_id} = $p->{user_id}->value();
|
||||
$p->{id} = $p->{id}->value();
|
||||
$p->{name} = $p->{name}->value();
|
||||
$p->{created_at} = $p->{created_at}->value();
|
||||
$p->{downloaded_count} = $p->{downloaded_count}->value();
|
||||
}
|
||||
$detail = $res;
|
||||
} else {
|
||||
$status = 0;
|
||||
$detail = get_result_error($res);
|
||||
}
|
||||
return $status,$detail;
|
||||
}
|
||||
|
||||
sub fetch_profiles_by_user ($$$) {
|
||||
my ($repo_url,$distro,$username) = @_;
|
||||
my $p_hash = {};
|
||||
my ($status,$detail) = fetch_profiles( $repo_url, $distro, $username, "" );
|
||||
if ( $status ) {
|
||||
for my $p ( @$detail ) {
|
||||
my $p_repo = $p->{profile};
|
||||
if ($p_repo ne "") {
|
||||
$p->{username} = $username;
|
||||
$p_hash->{$p->{name}} = $p;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return ($status,$detail);
|
||||
}
|
||||
return($status,$p_hash);
|
||||
}
|
||||
|
||||
|
||||
sub fetch_profiles_by_name_and_user ($$$$) {
|
||||
my ($repo_url,$distro,$fqdbin, $username) = @_;
|
||||
my $p_hash = {};
|
||||
my ($status,$detail) = fetch_profiles( $repo_url, $distro, $username, $fqdbin );
|
||||
if ( $status ) {
|
||||
for my $p ( @$detail ) {
|
||||
my $p_repo = $p->{profile}?$p->{profile}:"";
|
||||
$p_hash->{$p->{name}} = $p if ($p_repo ne "");
|
||||
}
|
||||
} else {
|
||||
return ($status,$detail);
|
||||
}
|
||||
return($status,$p_hash);
|
||||
}
|
||||
|
||||
|
||||
sub fetch_profiles_by_name ($$$) {
|
||||
my ($repo_url,$distro,$fqdbin) = @_;
|
||||
my ($status,$detail,$data);
|
||||
$detail = {};
|
||||
($status,$data) = fetch_profiles( $repo_url, $distro, "", $fqdbin);
|
||||
if ($status) {
|
||||
my @uids;
|
||||
for my $p (@$data) {
|
||||
push @uids, $p->{user_id};
|
||||
}
|
||||
my ($status_unames,$unames) = fetch_usernames_from_uids($repo_url, @uids);
|
||||
if ( $status_unames ) {
|
||||
for my $p (@$data) {
|
||||
if ( $unames->{$p->{user_id}} ) {
|
||||
$p->{username} = $unames->{$p->{user_id}};
|
||||
} else {
|
||||
$p->{username} = "unkown-" . $p->{user_id};
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
print STDOUT "ERROR UID\n";
|
||||
}
|
||||
for my $p (@$data) {
|
||||
$p->{profile_type} = "REPOSITORY";
|
||||
$detail->{$p->{username}} = $p;
|
||||
}
|
||||
} else {
|
||||
$detail = $data;
|
||||
}
|
||||
return $status,$detail;
|
||||
}
|
||||
|
||||
|
||||
sub fetch_newer_profile ($$$$$) {
|
||||
my ($repo_url,$distro,$user,$id,$profile) = @_;
|
||||
my $repo_client = get_repo_client( $repo_url );
|
||||
my $p;
|
||||
my ($status,$detail);
|
||||
|
||||
if ($repo_client) {
|
||||
my $res =
|
||||
$repo_client->send_request('FindProfiles', $distro, $profile, $user);
|
||||
if (did_result_succeed($res)) {
|
||||
my @profiles;
|
||||
my @profile_list = @{$res->value};
|
||||
$status = 1;
|
||||
|
||||
if (@profile_list) {
|
||||
if ($profile_list[0]->{id} > $id) {
|
||||
$p = $profile_list[0];
|
||||
}
|
||||
}
|
||||
$detail = $p;
|
||||
} else {
|
||||
$status = 0;
|
||||
$detail = get_result_error($res);
|
||||
}
|
||||
}
|
||||
return $status,$detail;
|
||||
}
|
||||
|
||||
sub fetch_usernames_from_uids ($) {
|
||||
my ($repo_url,@searchuids) = @_;
|
||||
my ($status,$result) = (1,{});
|
||||
my @uids;
|
||||
|
||||
for my $uid ( @searchuids ) {
|
||||
if ( $uid2login{$uid} ) {
|
||||
$result->{$uid} = $uid2login{$uid};
|
||||
} else {
|
||||
push @uids, $uid;
|
||||
}
|
||||
}
|
||||
if (@uids) {
|
||||
my $repo_client = get_repo_client( $repo_url );
|
||||
#RPC::XML will serialize the array into XML with the is_utf8 flag set
|
||||
#which causes, HTTP:Message to fail. Looping on the array elements
|
||||
#stops this from happening, and since these are all numbers it
|
||||
#will not cause problems.
|
||||
for my $foo (@uids) {
|
||||
Encode::_utf8_off($foo);
|
||||
}
|
||||
my $res = $repo_client->send_request('LoginNamesFromUserIds', [@uids]);
|
||||
if (did_result_succeed($res)) {
|
||||
my @usernames = @{ $res->value };
|
||||
for my $uid (@uids) {
|
||||
my $username = shift @usernames;
|
||||
$uid2login{$uid} = $username;
|
||||
$result->{$uid} = $uid2login{$uid};
|
||||
}
|
||||
} else {
|
||||
$status = 0;
|
||||
$result = get_result_error($res);
|
||||
}
|
||||
}
|
||||
return $status,$result;
|
||||
}
|
||||
|
||||
sub get_repo_config {
|
||||
unless ( $repo_cfg ) {
|
||||
$repo_cfg = Immunix::Config::read_config("repository.conf");
|
||||
}
|
||||
unless ( $aa_cfg ) {
|
||||
$aa_cfg = Immunix::Config::read_config("logprof.conf");
|
||||
}
|
||||
return {
|
||||
"url" => $aa_cfg->{repository}{url},
|
||||
"distro" => $aa_cfg->{repository}{distro},
|
||||
"enabled" => $repo_cfg->{repository}{enabled},
|
||||
"upload" => $repo_cfg->{repository}{upload},
|
||||
"user" => $repo_cfg->{repository}{user},
|
||||
"password" => $repo_cfg->{repository}{pass},
|
||||
"email" => $repo_cfg->{repository}{email}
|
||||
};
|
||||
}
|
||||
|
||||
sub set_repo_config ($) {
|
||||
my $cfg = shift;
|
||||
my ($url,$distro,$enabled,$upload,$user,$pass);
|
||||
unless ( $repo_cfg ) {
|
||||
$repo_cfg = Immunix::Config::read_config("repository.conf");
|
||||
}
|
||||
unless ( $aa_cfg ) {
|
||||
$aa_cfg = Immunix::Config::read_config("logprof.conf");
|
||||
}
|
||||
$repo_cfg->{repository}{enabled} = $cfg->{enabled} if ( $cfg->{enabled} );
|
||||
$repo_cfg->{repository}{upload} = $cfg->{upload} if ( $cfg->{upload} );
|
||||
$repo_cfg->{repository}{user} = $cfg->{user} if ( $cfg->{user} );
|
||||
$repo_cfg->{repository}{pass} = $cfg->{password}if ( $cfg->{password} );
|
||||
$repo_cfg->{repository}{email} = $cfg->{email} if ( $cfg->{email} );
|
||||
$aa_cfg->{repository}{distro} = $cfg->{distro} if ( $cfg->{distro} );
|
||||
$aa_cfg->{repository}{url} = $cfg->{url} if ( $cfg->{url} );
|
||||
write_config("repository.conf", $repo_cfg);
|
||||
write_config("logprof.conf", $aa_cfg);
|
||||
}
|
||||
|
||||
|
||||
1;
|
221
deprecated/utils/Immunix/Severity.pm
Normal file
221
deprecated/utils/Immunix/Severity.pm
Normal file
@@ -0,0 +1,221 @@
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2005-2006 Novell/SUSE
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
package Immunix::Severity;
|
||||
use strict;
|
||||
use Data::Dumper;
|
||||
|
||||
my ($debug) = 0;
|
||||
|
||||
sub debug {
|
||||
print @_ if $debug;
|
||||
}
|
||||
|
||||
sub new {
|
||||
my $self = {};
|
||||
$self->{DATABASENAME} = undef;
|
||||
$self->{CAPABILITIES} = {};
|
||||
$self->{FILES} = {};
|
||||
$self->{REGEXPS} = {};
|
||||
$self->{DEFAULT_RANK} = 10;
|
||||
bless($self);
|
||||
shift;
|
||||
$self->init(@_) if @_;
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub init ($;$) {
|
||||
my ($self, $resource, $read, $write, $execute, $severity);
|
||||
$self = shift;
|
||||
$self->{DATABASENAME} = shift;
|
||||
$self->{DEFAULT_RANK} = shift if defined $_[0];
|
||||
open(DATABASE, $self->{DATABASENAME})
|
||||
or die "Could not open severity db $self->{DATABASENAME}: $!\n";
|
||||
while (<DATABASE>) {
|
||||
chomp();
|
||||
next if m/^\s*#/;
|
||||
next if m/^\s*$/;
|
||||
|
||||
# leading whitespace is fine; maybe it shouldn't be?
|
||||
if (/^\s*\/(\S+)\s+(\d+)\s+(\d+)\s+(\d+)\s*$/) {
|
||||
my ($path, $read, $write, $execute) = ($1, $2, $3, $4);
|
||||
|
||||
if (index($path, "*") == -1) {
|
||||
|
||||
$self->{FILES}{$path} = {
|
||||
r => $read,
|
||||
w => $write,
|
||||
x => $execute
|
||||
};
|
||||
|
||||
} else {
|
||||
|
||||
my $ptr = $self->{REGEXPS};
|
||||
my @pieces = split(/\//, $path);
|
||||
|
||||
while (my $piece = shift @pieces) {
|
||||
if (index($piece, "*") != -1) {
|
||||
my $path = join("/", $piece, @pieces);
|
||||
my $regexp = convert_regexp($path);
|
||||
$ptr->{$regexp}{SD_RANK} = {
|
||||
r => $read,
|
||||
w => $write,
|
||||
x => $execute
|
||||
};
|
||||
last;
|
||||
} else {
|
||||
$ptr->{$piece} = {} unless exists $ptr->{$piece};
|
||||
$ptr = $ptr->{$piece};
|
||||
}
|
||||
}
|
||||
}
|
||||
} elsif (m|^\s*CAP|) {
|
||||
($resource, $severity) = split;
|
||||
$self->{CAPABILITIES}{$resource} = $severity;
|
||||
} else {
|
||||
print "unexpected database line: $_\n";
|
||||
}
|
||||
}
|
||||
close(DATABASE);
|
||||
debug Dumper($self);
|
||||
return $self;
|
||||
}
|
||||
|
||||
#rank:
|
||||
# handle capability
|
||||
# handle file
|
||||
#
|
||||
# handle capability
|
||||
# if the name is in the database, return it
|
||||
# otherwise, send a diagnostic message to stderr and return the default
|
||||
#
|
||||
# handle file
|
||||
# initialize the current return value to 0
|
||||
# loop over each entry in the database;
|
||||
# find the max() value for each mode that matches and set a 'found' flag
|
||||
# if the found flag has not been set, return the default;
|
||||
# otherwise, return the maximum from the database
|
||||
|
||||
sub handle_capability ($) {
|
||||
my ($self, $resource) = @_;
|
||||
|
||||
my $ret = $self->{CAPABILITIES}{$resource};
|
||||
if (!defined($ret)) {
|
||||
return "unexpected capability rank input: $resource\n";
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
sub check_subtree {
|
||||
my ($tree, $mode, $sev, $first, @rest) = @_;
|
||||
|
||||
# reassemble the remaining path from this directory level
|
||||
my $path = join("/", $first, @rest);
|
||||
|
||||
# first check if we have a literal directory match to descend into
|
||||
if ($tree->{$first}) {
|
||||
$sev = check_subtree($tree->{$first}, $mode, $sev, @rest);
|
||||
}
|
||||
|
||||
# if we didn't get a severity already, check for matching globs
|
||||
unless ($sev) {
|
||||
|
||||
# check each glob at this directory level
|
||||
for my $chunk (grep { index($_, "*") != -1 } keys %{$tree}) {
|
||||
|
||||
# does it match the rest of our path?
|
||||
if ($path =~ /^$chunk$/) {
|
||||
|
||||
# if we've got a ranking, check if it's higher than
|
||||
# current one, if any
|
||||
if ($tree->{$chunk}->{SD_RANK}) {
|
||||
for my $m (split(//, $mode)) {
|
||||
if ((!defined $sev)
|
||||
|| $tree->{$chunk}->{SD_RANK}->{$m} > $sev)
|
||||
{
|
||||
$sev = $tree->{$chunk}->{SD_RANK}->{$m};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $sev;
|
||||
}
|
||||
|
||||
sub handle_file ($$) {
|
||||
my ($self, $resource, $mode) = @_;
|
||||
|
||||
# strip off the initial / from the path we're checking
|
||||
$resource = substr($resource, 1);
|
||||
|
||||
# break the path into directory-level chunks
|
||||
my @pieces = split(/\//, $resource);
|
||||
|
||||
my $sev;
|
||||
|
||||
# if there's a exact match for this path in the db, use that instead of
|
||||
# checking the globs
|
||||
if ($self->{FILES}{$resource}) {
|
||||
|
||||
# check each piece of the passed mode against the db entry
|
||||
for my $m (split(//, $mode)) {
|
||||
if ((!defined $sev) || $self->{FILES}{$resource}{$m} > $sev) {
|
||||
$sev = $self->{FILES}{$resource}{$m};
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
# descend into the regexp tree looking for matches
|
||||
$sev = check_subtree($self->{REGEXPS}, $mode, $sev, @pieces);
|
||||
|
||||
}
|
||||
|
||||
return (defined $sev) ? $sev : $self->{DEFAULT_RANK};
|
||||
}
|
||||
|
||||
sub rank ($;$) {
|
||||
my ($self, $resource, $mode) = @_;
|
||||
|
||||
if (substr($resource, 0, 1) eq "/") {
|
||||
return $self->handle_file($resource, $mode);
|
||||
} elsif (substr($resource, 0, 3) eq "CAP") {
|
||||
return $self->handle_capability($resource);
|
||||
} else {
|
||||
return "unexpected rank input: $resource\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub convert_regexp ($) {
|
||||
my ($input) = shift;
|
||||
|
||||
# we need to convert subdomain regexps to perl regexps
|
||||
my $regexp = $input;
|
||||
|
||||
# escape + . [ and ] characters
|
||||
$regexp =~ s/(\+|\.|\[|\])/\\$1/g;
|
||||
|
||||
# convert ** globs to match anything
|
||||
$regexp =~ s/\*\*/.SDPROF_INTERNAL_GLOB/g;
|
||||
|
||||
# convert * globs to match anything at current path level
|
||||
$regexp =~ s/\*/[^\/]SDPROF_INTERNAL_GLOB/g;
|
||||
|
||||
# convert {foo,baz} to (foo|baz)
|
||||
$regexp =~ y/\{\}\,/\(\)\|/ if $regexp =~ /\{.*\,.*\}/;
|
||||
|
||||
# twiddle the escaped * chars back
|
||||
$regexp =~ s/SDPROF_INTERNAL_GLOB/\*/g;
|
||||
return $regexp;
|
||||
}
|
||||
|
||||
1; # so the require or use succeeds
|
62
deprecated/utils/Makefile
Normal file
62
deprecated/utils/Makefile
Normal file
@@ -0,0 +1,62 @@
|
||||
# ----------------------------------------------------------------------
|
||||
# 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 $(COMMONDIR)/Make.rules
|
||||
|
||||
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: pod_clean
|
||||
rm -f core core.* *.o *.s *.a *~
|
||||
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;
|
||||
}
|
||||
|
940
deprecated/utils/aa-eventd
Executable file
940
deprecated/utils/aa-eventd
Executable file
@@ -0,0 +1,940 @@
|
||||
#!/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.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
use strict;
|
||||
|
||||
use Data::Dumper;
|
||||
use DBI;
|
||||
use Fcntl;
|
||||
use File::Temp qw(tempfile);
|
||||
use Getopt::Long;
|
||||
use POSIX 'setsid';
|
||||
use Time::Local;
|
||||
use File::Tail;
|
||||
|
||||
use Immunix::Severity;
|
||||
require LibAppArmor;
|
||||
|
||||
##########################################################################
|
||||
# locations
|
||||
|
||||
my $productname = "apparmor";
|
||||
|
||||
my $cfgdir = "/etc/$productname";
|
||||
my $dbdir = "/var/log/$productname";
|
||||
|
||||
my $cfgfile = "$cfgdir/notify.cfg";
|
||||
my $errlog = "$dbdir/event-dispatch.log";
|
||||
|
||||
my $logfile = "/var/log/audit/audit.log";
|
||||
my $syslogfile = "/var/log/messages";
|
||||
|
||||
##########################################################################
|
||||
|
||||
# options variables
|
||||
my $pidfile = '';
|
||||
|
||||
GetOptions('pidfile|p=s' => \$pidfile);
|
||||
|
||||
my $DEBUG = 0;
|
||||
|
||||
my $config;
|
||||
|
||||
my $verbose = { last_notify => 0 };
|
||||
my $summary = { last_notify => 0 };
|
||||
my $terse = { last_notify => 0 };
|
||||
|
||||
# we don't want to call str2time on every line and also batch up event dbs
|
||||
# a month at a time, so we need to keep track of a few extra things
|
||||
my $timestamp = 0;
|
||||
my $lasttime = "";
|
||||
my $counter = 0;
|
||||
my $thismonth = 0;
|
||||
my $nextmonth = 0;
|
||||
|
||||
# pop open a connection to the severity database
|
||||
my $sevdb = new Immunix::Severity("$cfgdir/severity.db", -1);
|
||||
|
||||
my $REdate = '\w{3}\s+\d+\s+\d{2}:\d{2}:\d{2}';
|
||||
|
||||
my $last_inserted_time;
|
||||
my $last_inserted_counter;
|
||||
|
||||
##########################################################################
|
||||
|
||||
# commit how often?
|
||||
my $timeout = 5;
|
||||
|
||||
# keep track of when we commited last
|
||||
my $last_flush_time = 0;
|
||||
|
||||
# keep track of some statistics
|
||||
my $max = 0;
|
||||
my $inserts = 0;
|
||||
my $total = 0;
|
||||
|
||||
my @commit_buffer;
|
||||
my @debug_buffer;
|
||||
|
||||
my @verbose_buffer;
|
||||
my @summary_buffer;
|
||||
my @terse_buffer;
|
||||
|
||||
my $date_module = "None";
|
||||
|
||||
my %templates = (
|
||||
"path" => "(time,counter,type,op,profile,sdmode,mode_req,mode_deny,resource,prog,pid,severity) VALUES(?,?,?,?,?,?,?,?,?,?,?,?)",
|
||||
"link" => "(time,counter,type,op,profile,sdmode,resource,target,prog,pid,severity) VALUES(?,?,?,?,?,?,?,?,?,?,?)",
|
||||
"chattr" => "(time,counter,type,op,profile,sdmode,resource,mode_req,mode_deny,prog,pid,severity) VALUES(?,?,?,?,?,?,?,?,?,?,?,?)",
|
||||
"capability" => "(time,counter,type,op,profile,sdmode,resource,prog,pid,severity) VALUES(?,?,?,?,?,?,?,?,?,?)",
|
||||
"capable" => "(time,counter,type,op,prog,pid,profile) VALUES(?,?,?,?,?,?,?)",
|
||||
"unknown_hat" => "(time,counter,type,op,profile,sdmode,resource,pid) VALUES(?,?,?,?,?,?,?,?)",
|
||||
"fork" => "(time,counter,type,op,profile,sdmode,pid,resource) VALUES(?,?,?,?,?,?,?,?)",
|
||||
"changing_profile" => "(time,counter,type,op,profile,sdmode,pid) VALUES(?,?,?,?,?,?,?)",
|
||||
"profile_replacement" => "(time,counter,type,op,profile,sdmode,prog,pid,severity) VALUES(?,?,?,?,?,?,?,?,?)",
|
||||
"net" => "(time,counter,type,op,net_family,net_socktype,net_proto,pid,profile) VALUES(?,?,?,?,?,?,?,?,?)",
|
||||
"removed" => "(time,counter,type,op,severity) VALUES(?,?,?,?,?)",
|
||||
"initialized" => "(time,counter,type,op,resource,severity) VALUES(?,?,?,?,?,?)",
|
||||
"ctrl_var" => "(time,counter,type,op,resource,mode_req,mode_deny,severity) VALUES(?,?,?,?,?,?,?,?)",
|
||||
"profile_load" => "(time,counter,type,op,resource,prog,pid) VALUES(?,?,?,?,?,?,?)",
|
||||
);
|
||||
|
||||
##########################################################################
|
||||
# generic functions
|
||||
|
||||
sub errlog ($) {
|
||||
my $mesg = shift;
|
||||
my $localtime = localtime(time);
|
||||
print ERRLOG "[$localtime] $mesg\n";
|
||||
}
|
||||
|
||||
sub readconfig () {
|
||||
my $cfg = {};
|
||||
|
||||
# record when we read the config file
|
||||
$cfg->{load_time} = time;
|
||||
|
||||
if (open(CFG, $cfgfile)) {
|
||||
|
||||
# yank in the values we need
|
||||
while (<CFG>) {
|
||||
$cfg->{$1} = $2 if /^(\S+)\s+(.+)\s*$/;
|
||||
}
|
||||
close(CFG);
|
||||
}
|
||||
|
||||
return $cfg;
|
||||
}
|
||||
|
||||
sub daemonize {
|
||||
chdir '/' or die "Can't chdir to /: $!";
|
||||
open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
|
||||
open STDOUT, '>/dev/null' or die "Can't write to /dev/null: $!";
|
||||
defined(my $pid = fork) or die "Can't fork: $!";
|
||||
exit if $pid;
|
||||
setsid or die "Can't start a new session: $!";
|
||||
open STDERR, '>&STDOUT' or die "Can't dup stdout: $!";
|
||||
}
|
||||
|
||||
sub parsedate ($) {
|
||||
my $time = shift;
|
||||
my $timestamp = 0;
|
||||
if ($date_module eq 'TimeDate') {
|
||||
$timestamp = Date::Parse::str2time($time);
|
||||
} elsif ($date_module eq 'DateManip') {
|
||||
$timestamp = Date::Manip::UnixDate(Date::Manip::ParseDateString($time), '%s');
|
||||
} else {
|
||||
errlog "No date module found, exiing";
|
||||
kill HUP => -$$;
|
||||
}
|
||||
|
||||
return $timestamp;
|
||||
}
|
||||
|
||||
##########################################################################
|
||||
# database handling functions
|
||||
|
||||
sub connect_database ($) {
|
||||
my $dbdir = shift;
|
||||
|
||||
my $dbh = DBI->connect("dbi:SQLite:dbname=$dbdir/events.db", "", "", {RaiseError=>1});
|
||||
|
||||
# we'll do the commits ourselves so performance doesn't suck
|
||||
$dbh->{AutoCommit} = 0;
|
||||
|
||||
# bump up our cache size a little
|
||||
$dbh->do("PRAGMA cache_size = 20000;");
|
||||
|
||||
# figure out if the tables already exist or not
|
||||
my %existing_tables;
|
||||
my $sth = $dbh->prepare("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name;");
|
||||
$sth->execute;
|
||||
while (my @row = $sth->fetchrow_array) {
|
||||
$existing_tables{ $row[0] } = 1;
|
||||
}
|
||||
$sth->finish;
|
||||
|
||||
# create the info table and fill in the appropriate values for this db
|
||||
unless ($existing_tables{info}) {
|
||||
|
||||
my $host = `hostname -f`;
|
||||
chomp $host;
|
||||
|
||||
$dbh->do("CREATE TABLE info (name,value)");
|
||||
$sth = $dbh->prepare("INSERT INTO info(name,value) VALUES(?,?)");
|
||||
$sth->execute("version", "0.2");
|
||||
$sth->execute("host", "$host");
|
||||
}
|
||||
|
||||
# create the events table
|
||||
unless ($existing_tables{events}) {
|
||||
$dbh->do(
|
||||
"CREATE TABLE events (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
time INTEGER NOT NULL,
|
||||
counter INTEGER NOT NULL,
|
||||
op,
|
||||
pid,
|
||||
sdmode,
|
||||
type,
|
||||
mode_deny,
|
||||
mode_req,
|
||||
resource,
|
||||
target,
|
||||
profile,
|
||||
prog,
|
||||
name_alt,
|
||||
attr,
|
||||
parent,
|
||||
active_hat,
|
||||
net_family,
|
||||
net_proto,
|
||||
net_socktype,
|
||||
severity INTEGER
|
||||
)"
|
||||
);
|
||||
|
||||
# set up the indexes we want
|
||||
#my @indexes = qw(time type sdmode mode resource profile prog severity);
|
||||
my @indexes = qw(time type op sdmode mode_req mode_deny resource profile prog severity);
|
||||
for my $index (@indexes) {
|
||||
$dbh->do("CREATE INDEX " . $index . "_idx ON events($index)");
|
||||
}
|
||||
}
|
||||
# make sure our changes actually get saved
|
||||
$dbh->commit || errlog "Error commiting changes: $!";
|
||||
|
||||
# mark the db as up to date as of now
|
||||
$last_flush_time = time;
|
||||
|
||||
return $dbh;
|
||||
}
|
||||
|
||||
##########################################################################
|
||||
|
||||
sub verbose_notify_handler {
|
||||
my ($email, $file, $last, $level, $unknown) = @_;
|
||||
|
||||
$last = localtime($last);
|
||||
|
||||
my $now = time;
|
||||
|
||||
my $host = `hostname -f`;
|
||||
chomp $host;
|
||||
|
||||
my $subj = "Verbose Security Report for $host.";
|
||||
my $mesg = "The following security events occured since $last:\n\n";
|
||||
|
||||
my @events;
|
||||
if (open(V, $file)) {
|
||||
while (<V>) {
|
||||
chomp;
|
||||
if (/^(\d+) (\d+) (.+)$/) {
|
||||
my ($timestamp, $counter, $logmsg) = ($1, $2, $3);
|
||||
push @events, [ $timestamp, $counter ];
|
||||
$mesg .= "$logmsg\n";
|
||||
}
|
||||
}
|
||||
close(V);
|
||||
|
||||
if (@events) {
|
||||
if ($DEBUG) {
|
||||
my $count = scalar @events;
|
||||
errlog "[$count events] sending verbose notification to $email.";
|
||||
}
|
||||
|
||||
# actually send out the notification...
|
||||
open(MAIL, "| sendmail -F 'AppArmor Security Notification' $email");
|
||||
print MAIL "To: $email\n";
|
||||
print MAIL "Subject: $subj\n\n";
|
||||
print MAIL "$mesg\n";
|
||||
print MAIL ".\n";
|
||||
close(MAIL);
|
||||
}
|
||||
|
||||
# delete the verbose notification logfile once we've processed it
|
||||
unlink($file);
|
||||
}
|
||||
}
|
||||
|
||||
sub summary_notify_handler {
|
||||
my ($email, $file, $last, $level, $unknown) = @_;
|
||||
|
||||
$last = localtime($last);
|
||||
|
||||
my $now = time;
|
||||
|
||||
my $host = `hostname -f`;
|
||||
chomp $host;
|
||||
|
||||
my $subj = "Summary Security Report for $host.";
|
||||
my $mesg = "The following security events occured since $last:\n\n";
|
||||
|
||||
my @events;
|
||||
if (open(V, $file)) {
|
||||
while (<V>) {
|
||||
chomp;
|
||||
if (/^(\d+) (\d+) (.+)$/) {
|
||||
my ($timestamp, $counter, $logmsg) = ($1, $2, $3);
|
||||
push @events, [ $timestamp, $counter ];
|
||||
$mesg .= "$logmsg\n";
|
||||
}
|
||||
}
|
||||
close(V);
|
||||
|
||||
if (@events) {
|
||||
if ($DEBUG) {
|
||||
my $count = scalar @events;
|
||||
errlog "[$count events] sending summary notification to $email.";
|
||||
}
|
||||
|
||||
# actually send out the notification...
|
||||
open(MAIL, "| sendmail -F 'AppArmor Security Notification' $email");
|
||||
print MAIL "To: $email\n";
|
||||
print MAIL "Subject: $subj\n\n";
|
||||
print MAIL "$mesg\n";
|
||||
print MAIL ".\n";
|
||||
close(MAIL);
|
||||
}
|
||||
|
||||
# delete the verbose notification logfile once we've processed it
|
||||
unlink($file);
|
||||
}
|
||||
}
|
||||
|
||||
sub terse_notify_handler {
|
||||
my ($email, $file, $last, $level, $unknown) = @_;
|
||||
|
||||
$last = localtime($last);
|
||||
|
||||
my $now = time;
|
||||
|
||||
my $host = `hostname -f`;
|
||||
chomp $host;
|
||||
|
||||
my @events;
|
||||
my $count = 0;
|
||||
if (open(V, $file)) {
|
||||
while (<V>) {
|
||||
chomp;
|
||||
if (/^(\d+) (\d+) (.+)$/) {
|
||||
my ($timestamp, $counter, $logmsg) = ($1, $2, $3);
|
||||
push @events, [ $timestamp, $counter ];
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
close(V);
|
||||
|
||||
if ($count) {
|
||||
if ($DEBUG) {
|
||||
errlog "[$count events] sending terse notification to $email.";
|
||||
}
|
||||
my $subj = "Security Report for $host.";
|
||||
my $mesg = "$host has had $count security events since $last.";
|
||||
|
||||
# actually send out the notification...
|
||||
open(MAIL, "| sendmail -F 'AppArmor Security Notification' $email");
|
||||
print MAIL "To: $email\n";
|
||||
print MAIL "Subject: $subj\n\n";
|
||||
print MAIL "$mesg\n";
|
||||
print MAIL ".\n";
|
||||
close(MAIL);
|
||||
}
|
||||
|
||||
# delete the terse notification logfile once we've processed it
|
||||
unlink($file);
|
||||
}
|
||||
}
|
||||
|
||||
sub fork_into_background {
|
||||
my ($name, $func, @args) = @_;
|
||||
|
||||
my $pid = fork;
|
||||
|
||||
if (not defined $pid) {
|
||||
|
||||
# something bad happened, just log it...
|
||||
errlog "couldn't fork for \"$name\": $!"
|
||||
|
||||
} elsif ($pid == 0) {
|
||||
|
||||
# we're in the child process now...
|
||||
|
||||
# set our process name
|
||||
$0 = $name;
|
||||
|
||||
# call our subroutine
|
||||
my $ret = &$func(@args);
|
||||
|
||||
exit($ret);
|
||||
}
|
||||
|
||||
return $pid;
|
||||
}
|
||||
|
||||
##########################################################################
|
||||
# Parse event record into key-value pairs
|
||||
sub parseEvent($) {
|
||||
|
||||
my %ev = ();
|
||||
my $msg = shift;
|
||||
chomp($msg);
|
||||
|
||||
my $event = LibAppArmor::parse_record($msg);
|
||||
|
||||
# resource is an alternate term for 'name1' below
|
||||
# mode is an alternate term for 'mode_deny' below
|
||||
$ev{'time'} = LibAppArmor::aa_log_record::swig_epoch_get($event);
|
||||
$ev{'op'} = LibAppArmor::aa_log_record::swig_operation_get($event);
|
||||
$ev{'pid'} = LibAppArmor::aa_log_record::swig_pid_get($event);
|
||||
$ev{'mode_deny'} = LibAppArmor::aa_log_record::swig_denied_mask_get($event);
|
||||
$ev{'mode_req'} = LibAppArmor::aa_log_record::swig_requested_mask_get($event);
|
||||
$ev{'profile'}= LibAppArmor::aa_log_record::swig_profile_get($event);
|
||||
$ev{'prog'} = LibAppArmor::aa_log_record::swig_name_get($event);
|
||||
$ev{'name2'} = LibAppArmor::aa_log_record::swig_name2_get($event);
|
||||
$ev{'attr'} = LibAppArmor::aa_log_record::swig_attribute_get($event);
|
||||
$ev{'parent'} = LibAppArmor::aa_log_record::swig_parent_get($event);
|
||||
$ev{'magic_token'} = LibAppArmor::aa_log_record::swig_magic_token_get($event);
|
||||
$ev{'resource'} = LibAppArmor::aa_log_record::swig_info_get($event);
|
||||
$ev{'active_hat'} = LibAppArmor::aa_log_record::swig_active_hat_get($event);
|
||||
$ev{'sdmode'} = LibAppArmor::aa_log_record::swig_event_get($event);
|
||||
|
||||
# NetDomain
|
||||
if ( $ev{'op'} && $ev{'op'} =~ /socket/ ) {
|
||||
next if $ev{'op'} =~ /create/;
|
||||
$ev{'net_family'} = LibAppArmor::aa_log_record::swig_net_family_get($event);
|
||||
$ev{'net_proto'} = LibAppArmor::aa_log_record::swig_net_protocol_get($event);
|
||||
$ev{'net_socktype'} = LibAppArmor::aa_log_record::swig_net_sock_type_get($event);
|
||||
}
|
||||
|
||||
LibAppArmor::free_record($event);
|
||||
|
||||
if ( ! $ev{'time'} ) { $ev{'time'} = time; }
|
||||
|
||||
# remove null responses
|
||||
for (keys(%ev)) {
|
||||
if ( ! $ev{$_} || $ev{$_} !~ /\w+/) {delete($ev{$_}); }
|
||||
#errlog "EVENT: $_ is $ev{$_}";
|
||||
}
|
||||
|
||||
if ( $ev{'sdmode'} ) {
|
||||
#0 = invalid, 1 = error, 2 = AUDIT, 3 = ALLOW/PERMIT,
|
||||
#4 = DENIED/REJECTED, 5 = HINT, 6 = STATUS/config change
|
||||
if ( $ev{'sdmode'} == 2 ) { $ev{'sdmode'} = "AUDITING"; }
|
||||
elsif ( $ev{'sdmode'} == 3 ) { $ev{'sdmode'} = "PERMITING"; }
|
||||
elsif ( $ev{'sdmode'} == 4 ) { $ev{'sdmode'} = "REJECTING"; }
|
||||
else { delete($ev{'sdmode'}); }
|
||||
}
|
||||
|
||||
return \%ev;
|
||||
}
|
||||
|
||||
sub process_event ($$) {
|
||||
|
||||
my $dbh = shift;
|
||||
my $logmsg = shift;
|
||||
my $sth;
|
||||
my $severity = "";
|
||||
my @eventList = ();
|
||||
my $type = undef;
|
||||
my $time = undef;
|
||||
|
||||
return unless $logmsg && $logmsg =~ /APPARMOR/;
|
||||
my $ev = parseEvent($logmsg);
|
||||
|
||||
# skip logprof hints
|
||||
if ( ! $ev->{'op'} || $ev->{'op'} eq 'clone') { return; }
|
||||
|
||||
$time = time; # XXX - do we want current time or $ev->{'time'}?
|
||||
|
||||
if ($time ne $lasttime) {
|
||||
$counter = 0;
|
||||
$timestamp = $time;
|
||||
$lasttime = $time;
|
||||
}
|
||||
|
||||
$counter++;
|
||||
|
||||
# some statistics...
|
||||
$max = $counter if $counter > $max;
|
||||
|
||||
# if we already have events in the db, make sure we don't try to re-enter
|
||||
# duplicates if we start up again and parse the same logfile over again
|
||||
if ($last_inserted_time) {
|
||||
return if $timestamp < $last_inserted_time;
|
||||
|
||||
if ($timestamp == $last_inserted_time) {
|
||||
return if $counter <= $last_inserted_counter;
|
||||
}
|
||||
|
||||
$last_inserted_time = undef;
|
||||
}
|
||||
|
||||
if ( $ev->{'sdmode'} && $ev->{'sdmode'} eq "REJECTING") {
|
||||
$severity = $sevdb->rank($ev->{'prog'}, $ev->{'mode_req'});
|
||||
if ( ! $severity ) { $severity = "-1"; }
|
||||
|
||||
# we only do notification for enforce mode events
|
||||
if ($config->{verbose_freq}) {
|
||||
if ( ($severity >= $config->{verbose_level})
|
||||
|| (($severity == -1) && $config->{verbose_unknown}))
|
||||
{
|
||||
push @verbose_buffer, [ $timestamp, $counter, $logmsg ];
|
||||
}
|
||||
}
|
||||
|
||||
if ($config->{summary_freq}) {
|
||||
if ( ($severity >= $config->{summary_level})
|
||||
|| (($severity == -1) && $config->{summary_unknown}))
|
||||
{
|
||||
push @summary_buffer, [ $timestamp, $counter, "path",
|
||||
$ev->{'prog'}, $ev->{'mode_req'}, $ev->{'resource'} ];
|
||||
}
|
||||
}
|
||||
|
||||
if ($config->{terse_freq}) {
|
||||
if ( ($severity >= $config->{terse_level})
|
||||
|| (($severity == -1) && $config->{terse_unknown}))
|
||||
{
|
||||
push @terse_buffer, [ $timestamp, $counter, "dummy" ];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
unless ( $ev->{'op'} ) {
|
||||
my $errmsg = "ERROR: No operation found: ";
|
||||
for my $k (sort keys(%$ev)) {
|
||||
$errmsg .= "$k is $ev->{$k}, ";
|
||||
}
|
||||
errlog("$errmsg\n");
|
||||
return;
|
||||
}
|
||||
|
||||
# Format the message to match the db template
|
||||
if ($ev->{'op'} eq 'link' ) {
|
||||
$type = 'link';
|
||||
push(@eventList, [$time,$counter,$type,$ev->{'profile'},$ev->{'sdmode'},
|
||||
$ev->{'resource'},$ev->{'target'},$ev->{'prog'},$ev->{'pid'},$severity]);
|
||||
} elsif ($ev->{'op'} eq 'attribute') {
|
||||
$type = 'chattr';
|
||||
push(@eventList, []);
|
||||
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'profile'},$ev->{'sdmode'},
|
||||
$ev->{'resource'},$ev->{'mode_req'},$ev->{'mode_deny'},$ev->{'prog'},
|
||||
$ev->{'pid'},$severity]);
|
||||
} elsif ($ev->{'op'} eq 'capability') {
|
||||
$type = 'capability';
|
||||
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'profile'},$ev->{'sdmode'},
|
||||
$ev->{'resource'},$ev->{'prog'},$ev->{'pid'},$severity]);
|
||||
} elsif ($ev->{'op'} eq 'capable') {
|
||||
$type = 'capable';
|
||||
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'prog'},
|
||||
$ev->{'profile'},$ev->{'pid'}]);
|
||||
} elsif ($ev->{'op'} =~ /ontrol variable/ ) {
|
||||
$type = 'ctrl_var';
|
||||
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'resource'},
|
||||
$ev->{'mode_req'},$ev->{'mode_deny'},$severity]);
|
||||
} elsif ($ev->{'op'} eq 'unknown_hat') {
|
||||
$type = 'unknown_hat';
|
||||
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'profile'},$ev->{'sdmode'},
|
||||
$ev->{'resource'},$ev->{'pid'},$severity]);
|
||||
} elsif ($ev->{'op'} eq 'fork') {
|
||||
$type = 'fork';
|
||||
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'profile'},$ev->{'sdmode'},
|
||||
$ev->{'pid'},$ev->{'resource'}]);
|
||||
} elsif ($ev->{'op'} eq 'changing_profile') {
|
||||
$type = 'changing_profile';
|
||||
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'profile'},$ev->{'sdmode'},
|
||||
$ev->{'pid'}]);
|
||||
} elsif ($ev->{'op'} eq 'profile_load') {
|
||||
$type = 'profile_load';
|
||||
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'resource'},
|
||||
$ev->{'prog'},$ev->{'pid'}]);
|
||||
} elsif ($ev->{'op'} eq 'profile_replace') {
|
||||
$type = 'profile_replacement';
|
||||
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'profile'},$ev->{'sdmode'},
|
||||
$ev->{'prog'},$ev->{'pid'},$severity]);
|
||||
} elsif ($ev->{'op'} eq 'removed') {
|
||||
$type = 'removed';
|
||||
push(@eventList, [$time,$counter,$type,$ev->{'op'},$severity]);
|
||||
} elsif ($ev->{'op'} eq 'initialized') {
|
||||
$type = 'initialized';
|
||||
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'resource'},$severity]);
|
||||
} elsif ( $ev->{'op'} =~ /socket/) {
|
||||
$type = 'net';
|
||||
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'net_family'},
|
||||
$ev->{'net_sock_type'},$ev->{'net_proto'},$ev->{'pid'},$ev->{'profile'}]);
|
||||
} else {
|
||||
$type = 'path';
|
||||
if ( ! $ev->{'prog'} ) { $ev->{'prog'} = "NIL"; }
|
||||
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'profile'},
|
||||
$ev->{'sdmode'},$ev->{'mode_req'},$ev->{'mode_deny'},$ev->{'resource'},
|
||||
$ev->{'prog'},$ev->{'pid'},$severity]);
|
||||
}
|
||||
|
||||
push(@commit_buffer, @eventList);
|
||||
$inserts++;
|
||||
|
||||
}
|
||||
|
||||
sub dump_events {
|
||||
my ($which, @events) = @_;
|
||||
|
||||
if ($DEBUG) {
|
||||
my $count = scalar @events;
|
||||
errlog "dumping $count events to $which db.";
|
||||
}
|
||||
|
||||
if (open(F, ">>$dbdir/$which.db")) {
|
||||
for my $event (@events) {
|
||||
my @event = @$event;
|
||||
print F "@event\n";
|
||||
}
|
||||
close(F);
|
||||
} else {
|
||||
errlog "can't write to $dbdir/$which.db: $!";
|
||||
}
|
||||
}
|
||||
|
||||
sub check_timers ($) {
|
||||
my $dbh = shift;
|
||||
|
||||
# what time is it right... NOW
|
||||
my $now = time;
|
||||
|
||||
# make sure we commit periodically
|
||||
if (($inserts > 10000) || ($now >= ($last_flush_time + $timeout))) {
|
||||
|
||||
my $last_prepare = "";
|
||||
my $sth;
|
||||
|
||||
for my $event (sort { $a->[0] cmp $b->[0] } @commit_buffer) {
|
||||
my @event = @{$event};
|
||||
|
||||
#my $type = shift @event;
|
||||
my $type = $event[2];
|
||||
|
||||
eval {
|
||||
if ($type ne $last_prepare) {
|
||||
$sth = $dbh->prepare("INSERT INTO events $templates{$type}");
|
||||
$last_prepare = $type;
|
||||
}
|
||||
|
||||
$sth->execute(@event);
|
||||
};
|
||||
|
||||
if ($@) {
|
||||
print ERRLOG "DBI Execution failed: $DBI::errstr\n";
|
||||
}
|
||||
|
||||
#$sth->execute(@event);
|
||||
}
|
||||
|
||||
$dbh->commit || errlog "Error commiting changes: $!";
|
||||
|
||||
# need to get the time again to include how much time it takes to
|
||||
# actually write all this crap to the db
|
||||
$now = time;
|
||||
|
||||
if ($DEBUG && $inserts) {
|
||||
$total += $inserts;
|
||||
my $delta = $now - $last_flush_time;
|
||||
my $rate = int($inserts / $delta);
|
||||
errlog "$rate/s $inserts in ${delta}s total=$total max=$max";
|
||||
}
|
||||
|
||||
$last_flush_time = $now;
|
||||
|
||||
@commit_buffer = ();
|
||||
|
||||
$max = 0;
|
||||
$inserts = 0;
|
||||
|
||||
if (@verbose_buffer) {
|
||||
|
||||
# if we've got verbose events, dump them
|
||||
dump_events("verbose", @verbose_buffer);
|
||||
|
||||
# and clear out our buffer
|
||||
@verbose_buffer = ();
|
||||
}
|
||||
|
||||
if (@terse_buffer) {
|
||||
|
||||
# if we've got terse events, dump them
|
||||
dump_events("terse", @terse_buffer);
|
||||
|
||||
# and clear out our buffer
|
||||
@terse_buffer = ();
|
||||
}
|
||||
|
||||
# bail out if we don't have notification configured
|
||||
return unless -f $cfgfile;
|
||||
|
||||
# what time did we last read the config file?
|
||||
my $load_time = $config->{load_time};
|
||||
|
||||
# check when the config file was last modified...
|
||||
my $mtime = (stat($cfgfile))[9];
|
||||
|
||||
# if it's been changed since we last read the config file, we need to
|
||||
# load the new settings
|
||||
if ($load_time < $mtime) {
|
||||
errlog "Reloading changed config file.";
|
||||
$config = readconfig();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# bail out if we don't have notification configured
|
||||
return unless -f $cfgfile;
|
||||
|
||||
if ($config->{terse_freq}) {
|
||||
if (($terse->{last_notify} + $config->{terse_freq}) <= $now) {
|
||||
if (-f "$dbdir/terse.db") {
|
||||
$DEBUG && errlog "doing terse notification...";
|
||||
|
||||
# get a temporary filename...
|
||||
my ($fh, $filename) = tempfile("terseXXXXXX", DIR => $dbdir);
|
||||
|
||||
# overwrite the temp file we just created...
|
||||
rename("$dbdir/terse.db", $filename);
|
||||
|
||||
if ($DEBUG) {
|
||||
errlog "terse file is $filename";
|
||||
}
|
||||
|
||||
# do the actual notification in the background
|
||||
fork_into_background("terse-notification",
|
||||
\&terse_notify_handler,
|
||||
$config->{terse_email},
|
||||
$filename,
|
||||
$terse->{last_notify},
|
||||
$config->{terse_level},
|
||||
$config->{terse_unknown});
|
||||
|
||||
# ...keep track of when we last sent out a notify
|
||||
$terse->{last_notify} = $now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($config->{summary_freq}) {
|
||||
if (($summary->{last_notify} + $config->{summary_freq}) <= $now) {
|
||||
if (-f "$dbdir/summary.db") {
|
||||
$DEBUG && errlog "doing summary notification...";
|
||||
|
||||
# get a temporary filename...
|
||||
my ($fh, $filename) = tempfile("summaryXXXXXX", DIR => $dbdir);
|
||||
|
||||
# overwrite the temp file we just created...
|
||||
rename("$dbdir/summary.db", $filename);
|
||||
|
||||
# do the actual notification in the background
|
||||
fork_into_background("summary-notification",
|
||||
\&summary_notify_handler,
|
||||
$config->{summary_email},
|
||||
$filename,
|
||||
$summary->{last_notify},
|
||||
$config->{summary_level},
|
||||
$config->{summary_unknown});
|
||||
|
||||
# ...keep track of when we last sent out a notify
|
||||
$summary->{last_notify} = $now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($config->{verbose_freq}) {
|
||||
if (($verbose->{last_notify} + $config->{verbose_freq}) <= $now) {
|
||||
if (-f "$dbdir/verbose.db") {
|
||||
$DEBUG && errlog "doing verbose notification...";
|
||||
|
||||
# get a temporary filename...
|
||||
my ($fh, $filename) = tempfile("verboseXXXXXX", DIR => $dbdir);
|
||||
|
||||
# overwrite the temp file we just created...
|
||||
rename("$dbdir/verbose.db", $filename);
|
||||
|
||||
if ($DEBUG) {
|
||||
errlog "verbose file is $filename";
|
||||
}
|
||||
|
||||
# do the actual notification in the background
|
||||
fork_into_background("verbose-notification",
|
||||
\&verbose_notify_handler,
|
||||
$config->{verbose_email},
|
||||
$filename,
|
||||
$verbose->{last_notify},
|
||||
$config->{verbose_level},
|
||||
$config->{verbose_unknown});
|
||||
|
||||
# ...keep track of when we last sent out a notify
|
||||
$verbose->{last_notify} = $now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sub get_last_event {
|
||||
my $dbh = shift;
|
||||
|
||||
my ($time, $counter);
|
||||
|
||||
# get the oldest timestamp...
|
||||
my $sth = $dbh->prepare('SELECT MAX(time) FROM events');
|
||||
$sth->execute;
|
||||
my @row = $sth->fetchrow_array || (0);
|
||||
$time = $row[0];
|
||||
if ($time) {
|
||||
|
||||
# get the highest counter for this timestamp...
|
||||
$sth = $dbh->prepare("SELECT MAX(counter) FROM events WHERE time = $time");
|
||||
$sth->execute;
|
||||
@row = $sth->fetchrow_array || (0);
|
||||
$counter = $row[0];
|
||||
}
|
||||
|
||||
return ($time, $counter);
|
||||
}
|
||||
|
||||
##########################################################################
|
||||
# start the real magic...
|
||||
|
||||
my $finished;
|
||||
|
||||
# make sure we exit if someone sends us the right signal
|
||||
sub sig_handler {
|
||||
my $signame = shift;
|
||||
|
||||
errlog("Caught signal '$signame'. Exiting...");
|
||||
$finished = 1;
|
||||
}
|
||||
|
||||
# set up our error log without buffering
|
||||
open(ERRLOG, ">>$dbdir/event-dispatch.log");
|
||||
my $oldfd = select(ERRLOG);
|
||||
$| = 1;
|
||||
select($oldfd);
|
||||
|
||||
$config = readconfig();
|
||||
|
||||
# fork off into the background. we need to do this before we connect to
|
||||
# the db, otherwise, we'll get an ugly error about rolling back a
|
||||
# connection that's being destroyed
|
||||
daemonize;
|
||||
|
||||
# automagically reap child processes
|
||||
$SIG{INT} = \&sig_handler;
|
||||
$SIG{TERM} = \&sig_handler;
|
||||
$SIG{CHLD} = 'IGNORE';
|
||||
|
||||
# Sigh, portable dates in perl sucks
|
||||
eval "use Date::Parse";
|
||||
if (!$@) {
|
||||
$date_module = 'TimeDate';
|
||||
} else {
|
||||
eval "use Date::Manip";
|
||||
if (!$@) {
|
||||
$date_module = 'DateManip';
|
||||
} else {
|
||||
errlog "Unable to load Date module; use either TimeDate or Date::Manip";
|
||||
$finished = 1;
|
||||
}
|
||||
}
|
||||
|
||||
# if they want us to write a pid, do it
|
||||
if ($pidfile) {
|
||||
if (open(PIDFILE, ">$pidfile")) {
|
||||
print PIDFILE "$$\n";
|
||||
close(PIDFILE);
|
||||
}
|
||||
}
|
||||
|
||||
my $dbh = connect_database($dbdir);
|
||||
|
||||
($last_inserted_time, $last_inserted_counter) = get_last_event($dbh);
|
||||
|
||||
my $auditlog = File::Tail->new(
|
||||
name => $logfile,
|
||||
debug => 1,
|
||||
tail => -1,
|
||||
interval => 1,
|
||||
maxinterval => 5,
|
||||
adjustafter => 20,
|
||||
errmode => "return",
|
||||
ignore_noexistant => 1
|
||||
);
|
||||
my $syslog = File::Tail->new(
|
||||
name => $syslogfile,
|
||||
debug => 1,
|
||||
tail => -1,
|
||||
interval => 1,
|
||||
maxinterval => 5,
|
||||
adjustafter => 20,
|
||||
errmode => "return",
|
||||
ignore_noexistant => 1
|
||||
);
|
||||
my $line = '';
|
||||
|
||||
# process complete lines from the buffer...
|
||||
while (not $finished) {
|
||||
my ($nfound, $timeleft, @pending) = File::Tail::select(undef, undef, undef, $timeout, ($auditlog, $syslog));
|
||||
|
||||
foreach (@pending) {
|
||||
process_event($dbh, $_->read);
|
||||
}
|
||||
|
||||
# see if we should flush pending entries to disk and/or do notification
|
||||
check_timers($dbh);
|
||||
}
|
||||
|
||||
# make sure we don't exit with any pending events not written to the db
|
||||
$dbh->commit || errlog "Error commiting changes: $!";
|
||||
$dbh->disconnect || errlog "Error disconnecting from db: $!";
|
||||
|
||||
# close our error/debugging log file
|
||||
close(ERRLOG);
|
||||
|
||||
unlink($pidfile) if $pidfile;
|
||||
|
||||
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:\nhttps://gitlab.com/apparmor/apparmor/wikis/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:\nhttps://gitlab.com/apparmor/apparmor/wikis/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;
|
||||
}
|
||||
|
821
deprecated/utils/aa-repo.pl
Normal file
821
deprecated/utils/aa-repo.pl
Normal file
@@ -0,0 +1,821 @@
|
||||
#!/usr/bin/perl
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2008 Dominic Reynolds. 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.
|
||||
#
|
||||
#
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
#
|
||||
my $usage =
|
||||
"aa-repo.pl --command args\n";
|
||||
|
||||
my $usage_search =
|
||||
" --search [author=XXX] [prog=XXX] [id=XXX]
|
||||
Search the repository for profiles matching the search criteria
|
||||
and return the results.
|
||||
NOTE: One --search switch per option
|
||||
|
||||
--verbose|v
|
||||
Verbosity level. Supply either one or two switches. Two switches
|
||||
adds full profile text in returned search results.\n";
|
||||
|
||||
my $usage_push =
|
||||
|
||||
" --push [--profile=XXX|all] [--changelog=XXX]
|
||||
Push local profiles to repository, uses configured user and upon
|
||||
overwrite of an existing profile in the repository then prompt
|
||||
user with a diff for confirmation XXX the name of the application
|
||||
whose profile should be uploaded or \"all\" to upload all
|
||||
profiles. Multiple --profile switches may be passed to supply
|
||||
multiple profile names
|
||||
|
||||
e.g. --push --profile /usr/sbin/mdnsd --profile /usr/sbin/ftp
|
||||
e.g. --push --profile all\n";
|
||||
|
||||
my $usage_pull =
|
||||
" --pull [--author=XXX] [--profile=XXX] or [--id=XXX] [--mode=complain]
|
||||
pull remote profiles and install on local system
|
||||
If operation will change local profiles then prompt user with
|
||||
diff for confirmation
|
||||
NOTE: One --pull switch per option and there are three acceptable
|
||||
combinations
|
||||
|
||||
--pull --author=XXX
|
||||
* pull all profiles in the repo for the author
|
||||
|
||||
--pull --author=XXX --profile=XXXX
|
||||
* pull the profile for prog owned by author
|
||||
|
||||
--pull --id=XXXX
|
||||
* pull the profile with id
|
||||
|
||||
--pull --mode=complain
|
||||
* set the profile(s) to complain mode when installed
|
||||
|
||||
Profiles are checked for conflicts with currently installed
|
||||
profiles and presented as a list to the user to confirm and view.\n";
|
||||
|
||||
|
||||
my $usage_sync =
|
||||
" --sync [--up] [--down] [--noconfirm]
|
||||
Synchronize local profile set with the repository - showing
|
||||
changes and allowing prompting the user with the diffs and
|
||||
suggest the newest version to be activated. If the --all option
|
||||
is passed then treat profiles not marked as remote as new
|
||||
profiles that will be uploaded to the repository.\n";
|
||||
|
||||
my $usage_stat =
|
||||
" --status
|
||||
Show the current status of the local profile set. This operation
|
||||
is similar to sync but does not prompt the user to up|down load
|
||||
changes\n";
|
||||
|
||||
my $usage_getconfig =
|
||||
" --getconfig|c
|
||||
Print the current configuration for the repsository\n";
|
||||
|
||||
|
||||
my $usage_setconfig =
|
||||
" --setconfig [url=xxx] [username=xxxx] [password=xxxx] [enabled=(yes|no)]
|
||||
[upload=(yes|no)]
|
||||
Set the configuration options for the repository.
|
||||
NOTE: One --setconfig switch per option\n";
|
||||
|
||||
my $usage_bottom =
|
||||
" --quiet|q Don't prompt user - assume that all changes should be made.
|
||||
|
||||
ISSUES:
|
||||
o Should changes made to the system be recorded somehow? An audit event?
|
||||
o Should the tool allow a repo/distro to be passed for each operation?
|
||||
|
||||
";
|
||||
|
||||
use strict;
|
||||
use Getopt::Long;
|
||||
|
||||
use Immunix::AppArmor;
|
||||
use Immunix::Repository;
|
||||
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");
|
||||
|
||||
# options variables
|
||||
my $help = '';
|
||||
my $verbose = '';
|
||||
|
||||
my ( $id, $author, $mode, %search, $sync, $getconfig, $push,
|
||||
$pull, %setconfig, @profiles, $all, $changelog, $stat );
|
||||
|
||||
GetOptions(
|
||||
'search=s%' => \%search,
|
||||
'sync=s' => \$sync,
|
||||
'status' => \$stat,
|
||||
'getconfig|c' => \$getconfig,
|
||||
'setconfig=s%' => \%setconfig,
|
||||
'push' => \$push,
|
||||
'id=s' => \$id,
|
||||
'author=s' => \$author,
|
||||
'profile=s' => \@profiles,
|
||||
'changelog=s' => \$changelog,
|
||||
'pull' => \$pull,
|
||||
'all|a' => \$all,
|
||||
'help|h' => \$help,
|
||||
'verbose|v+' => \$verbose
|
||||
);
|
||||
|
||||
#
|
||||
# Root privs required to run the repo tool
|
||||
#
|
||||
if ( geteuid() != 0 ) {
|
||||
print STDERR gettext(
|
||||
"You must be logged in with root user privileges to use this program.\n"
|
||||
);
|
||||
exit;
|
||||
}
|
||||
|
||||
# --help
|
||||
# tell 'em how to use it...
|
||||
&usage && exit if $help;
|
||||
|
||||
my $config = get_repo_config();
|
||||
|
||||
#
|
||||
# --getconfig operation
|
||||
#
|
||||
&config && exit if $getconfig;
|
||||
|
||||
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."
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#
|
||||
# --setconfig operation
|
||||
#
|
||||
if ( keys %setconfig ) {
|
||||
$config->{url} = $setconfig{url} if ( $setconfig{url} );
|
||||
$config->{distro} = $setconfig{distro} if ( $setconfig{distro} );
|
||||
$config->{enabled} = $setconfig{enabled} if ( $setconfig{enabled} );
|
||||
$config->{email} = $setconfig{email} if ( $setconfig{email} );
|
||||
$config->{user} = $setconfig{username} if ( $setconfig{username} );
|
||||
$config->{password} = $setconfig{password} if ( $setconfig{password} );
|
||||
$config->{upload} = $setconfig{upload} if ( $setconfig{upload} );
|
||||
set_repo_config( $config );
|
||||
}
|
||||
|
||||
#
|
||||
# --push operation
|
||||
#
|
||||
if ( $push ) {
|
||||
my ($conflicts, $repo_profiles, $local_profiles, @overrides);
|
||||
if ( ! @profiles ) {
|
||||
print STDERR gettext(
|
||||
"Must supply at least one profile using \"--profile XXX\" to --push\n"
|
||||
);
|
||||
exit 1;
|
||||
} else {
|
||||
print STDERR Data::Dumper->Dump([@profiles], [qw(*profiles)]);
|
||||
}
|
||||
my $changelog = $changelog?$changelog:"none";
|
||||
push_profiles( \@profiles, $changelog, 1 );
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# --pull operation
|
||||
#
|
||||
if ( $pull ) {
|
||||
my $type = "";
|
||||
if ( $id ) {
|
||||
if ( $author || @profiles ) {
|
||||
print STDERR gettext(
|
||||
"Option --id=XX is only allowed by itself and not in combination to
|
||||
other options for the --pull command.\n"
|
||||
);
|
||||
exit 1;
|
||||
}
|
||||
$type = "id";
|
||||
}
|
||||
if ( @profiles && ! $author ) {
|
||||
print STDERR gettext(
|
||||
"Option --profile=XX requires that the --author=XX option be supplied
|
||||
to distinguish a specific profile.\n"
|
||||
);
|
||||
exit 1;
|
||||
} else {
|
||||
$type = "profile";
|
||||
}
|
||||
|
||||
my $mode = $mode eq "complain"?1:0;
|
||||
pull_profiles( \@profiles, $type, $mode, 1 );
|
||||
}
|
||||
|
||||
#
|
||||
# --search operation
|
||||
#
|
||||
if ( keys %search ) {
|
||||
if ( $search{id} ) {
|
||||
my($status,$result) = fetch_profile_by_id( $config->{url},
|
||||
$search{id} );
|
||||
if ($status) {
|
||||
my $title = sprintf(gettext( "Profile ID %s\n"), $search{id});
|
||||
console_print_search_results( $title,
|
||||
"profile",
|
||||
{ $result->{name} => $result }
|
||||
);
|
||||
|
||||
} else {
|
||||
print STDERR "ERROR $result\n";
|
||||
}
|
||||
} elsif ( $search{author} && $search{prog} ) {
|
||||
my($status,$result) =
|
||||
fetch_profiles_by_name_and_user( $config->{url},
|
||||
$config->{distro},
|
||||
$search{prog},
|
||||
$search{author}
|
||||
);
|
||||
if ( $status ) {
|
||||
my $title =
|
||||
sprintf(gettext("Profiles matching user: %s and program: %s\n"),
|
||||
$search{author},
|
||||
$search{prog}
|
||||
);
|
||||
console_print_search_results( $title, "profile", $result );
|
||||
} else {
|
||||
print STDERR "ERROR $result\n";
|
||||
}
|
||||
} elsif ( $search{author} ) {
|
||||
my($status,$result) = fetch_profiles_by_user( $config->{url},
|
||||
$config->{distro},
|
||||
$search{author}
|
||||
);
|
||||
if ( $status ) {
|
||||
my $title = sprintf(gettext( "Profiles for %s\n"), $search{author});
|
||||
console_print_search_results( $title, "profile", $result );
|
||||
} else {
|
||||
print STDERR "ERROR $result\n";
|
||||
}
|
||||
} elsif ( $search{prog} ) {
|
||||
my($status,$result) = fetch_profiles_by_name( $config->{url},
|
||||
$config->{distro},
|
||||
$search{prog},
|
||||
);
|
||||
if ( $status ) {
|
||||
my $title = sprintf(gettext("Profiles matching program: %s\n"),
|
||||
$search{prog});
|
||||
console_print_search_results( $title, "user", $result );
|
||||
} else {
|
||||
print STDERR "ERROR $result\n";
|
||||
}
|
||||
} else {
|
||||
print STDERR
|
||||
"Unsupported search criteria. Please specify at least one of
|
||||
author=XXX prog=XXX id=XXX\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ( $stat ) {
|
||||
my ( $local_profiles, $remote_profiles );
|
||||
my $msg =
|
||||
" The following profiles are stored in the repository but
|
||||
are not synchronized with the copy in the repository\n";
|
||||
|
||||
my ($status, $result) = fetch_profiles_by_user( $config->{url},
|
||||
$config->{distro},
|
||||
$config->{user}
|
||||
);
|
||||
if ( $status ) {
|
||||
$remote_profiles = $result;
|
||||
} else {
|
||||
print STDERR sprintf(gettext("ERROR connecting to repository: %s\n"),
|
||||
$result);
|
||||
exit;
|
||||
}
|
||||
|
||||
readprofiles();
|
||||
$local_profiles = serialize_local_profiles( \%sd );
|
||||
my ($local_only,$unsynched,$synched,$conflicts) = ({}, {}, {});
|
||||
$unsynched = find_profile_conflicts($remote_profiles, $local_profiles);
|
||||
for my $p ( keys %$local_profiles ) {
|
||||
if ( ! $remote_profiles->{$p} ) {
|
||||
$local_only->{$p} = $local_profiles->{$p};
|
||||
}
|
||||
}
|
||||
|
||||
for my $p ( keys %$remote_profiles ) {
|
||||
$synched->{$p} =
|
||||
$remote_profiles->{$p}->{profile} if ( ! %$unsynched->{$p} );
|
||||
}
|
||||
UI_status($synched, $unsynched, $local_only);
|
||||
}
|
||||
|
||||
######################
|
||||
# Helper functions
|
||||
######################
|
||||
|
||||
#
|
||||
# Compare the local profile set with the remote profile set.
|
||||
# Return a list of the conflicting profiles as a list
|
||||
# { PROFILE_NAME => [LOCAL_PROFILE, REMOTE_PROFILE] ]
|
||||
#
|
||||
#
|
||||
# remote_profiles = repository profiles as returned by one of the
|
||||
# Immunix::Repository::fetch... functions
|
||||
# local_profiles = hash ref containing
|
||||
# { name => serialized local profile }
|
||||
#
|
||||
#
|
||||
|
||||
sub find_profile_conflicts ($$) {
|
||||
my ($remote_profiles,$local_profiles) = @_;
|
||||
my $conflicts = {};
|
||||
for my $p ( keys(%$local_profiles) ) {
|
||||
if ( $local_profiles->{$p} and $remote_profiles->{$p} ) {
|
||||
my $p_local = $local_profiles->{$p};
|
||||
my $p_remote = $remote_profiles->{$p}->{profile};
|
||||
chomp($p_local);
|
||||
chomp($p_remote);
|
||||
if ( $p_remote ne $p_local ) {
|
||||
$conflicts->{$p} = [ $p_local, $p_remote ];
|
||||
}
|
||||
}
|
||||
}
|
||||
return( $conflicts );
|
||||
}
|
||||
|
||||
sub serialize_local_profiles ($) {
|
||||
my $profiles = shift;
|
||||
my $local_profiles = {};
|
||||
for my $p ( keys %$profiles ) {
|
||||
my $serialize_opts = {};
|
||||
$serialize_opts->{NO_FLAGS} = 1;
|
||||
my $p_local = serialize_profile( $profiles->{$p},
|
||||
$p,
|
||||
$serialize_opts );
|
||||
$local_profiles->{$p} = $p_local;
|
||||
}
|
||||
return $local_profiles;
|
||||
}
|
||||
|
||||
|
||||
sub console_print_search_results ($$$) {
|
||||
my ($title, $type,$result) = @_;
|
||||
open(PAGER, "| less") or die "Can't open pager";
|
||||
print PAGER $title;
|
||||
print PAGER "Found " . values(%$result) . " profiles \n";
|
||||
for my $p ( values(%$result) ) {
|
||||
if ( $verbose ) {
|
||||
if ( $type eq "user" ) {
|
||||
print PAGER " Author [ " . $p->{username} . " ]\n";
|
||||
} elsif ( $type eq "profile" ) {
|
||||
print PAGER " Name [ " . $p->{name} . " ]\n";
|
||||
}
|
||||
print PAGER " Created [ " . $p->{created_at} . " ]\n";
|
||||
print PAGER " Downloads [ " . $p->{downloaded_count} . " ]\n";
|
||||
print PAGER " ID [ " . $p->{id} . " ]\n";
|
||||
if ( $verbose > 1 ) {
|
||||
print PAGER " Profile [ \n" . $p->{profile} . " ]\n\n";
|
||||
} else {
|
||||
print PAGER "\n";
|
||||
}
|
||||
} else {
|
||||
my $data = $type eq "user"?$p->{username}:$p->{name};
|
||||
print PAGER " " . $data . "\n";
|
||||
}
|
||||
}
|
||||
close PAGER;
|
||||
}
|
||||
|
||||
sub UI_resolve_profile_conflicts {
|
||||
|
||||
my ($explanation, $conflict_hash) = @_;
|
||||
my $url = $config->{url};
|
||||
my @conflicts = map { [ $_,
|
||||
$conflict_hash->{$_}->[0],
|
||||
$conflict_hash->{$_}->[1]
|
||||
] }
|
||||
keys %$conflict_hash;
|
||||
my @commits = [];
|
||||
my $title = "Profile conflicts";
|
||||
my %resolution = ();
|
||||
my $q = {};
|
||||
$q->{title} = $title;
|
||||
$q->{headers} = [ "Repository", $url, ];
|
||||
|
||||
$q->{explanation} = $explanation;
|
||||
|
||||
$q->{functions} = [ "CMD_OVERWRITE",
|
||||
"CMD_KEEP",
|
||||
"CMD_VIEW_CHANGES",
|
||||
"CMD_ABORT",
|
||||
"CMD_CONTINUE", ];
|
||||
|
||||
$q->{default} = "CMD_OVERWRITE";
|
||||
$q->{options} = [ map { $_->[0] } @conflicts ];
|
||||
$q->{selected} = 0;
|
||||
|
||||
my ($ans, $arg);
|
||||
do {
|
||||
($ans, $arg) = UI_PromptUser($q);
|
||||
|
||||
if ($ans eq "CMD_VIEW_CHANGES") {
|
||||
display_changes($conflicts[$arg]->[2], $conflicts[$arg]->[1]);
|
||||
}
|
||||
if ( $ans eq "CMD_OVERWRITE") {
|
||||
$q->{options} =
|
||||
[ map { $_ =~ /$conflicts[$arg]->[0]( K| O)?$/?
|
||||
$conflicts[$arg]->[0] . " O":
|
||||
$_ }
|
||||
@{$q->{options}}
|
||||
];
|
||||
$resolution{$conflicts[$arg]->[0]} = "O";
|
||||
}
|
||||
if ( $ans eq "CMD_KEEP") {
|
||||
$q->{options} =
|
||||
[ map { $_ =~ /$conflicts[$arg]->[0]( K| O)?$/?
|
||||
$conflicts[$arg]->[0] . " K":
|
||||
$_ }
|
||||
@{$q->{options}}
|
||||
];
|
||||
$resolution{$conflicts[$arg]->[0]} = "K";
|
||||
}
|
||||
$q->{selected} = ($arg+1) % @conflicts;
|
||||
} until $ans =~ /^CMD_CONTINUE/;
|
||||
if ($ans eq "CMD_CONTINUE") {
|
||||
my @results = ();
|
||||
for my $p ( keys %resolution ) {
|
||||
if ( $resolution{$p} eq "O" ) {
|
||||
push @results, $p;
|
||||
}
|
||||
}
|
||||
return @results;
|
||||
}
|
||||
}
|
||||
|
||||
sub UI_display_profiles {
|
||||
my ($explanation, $profile_hash) = @_;
|
||||
my $url = $config->{url};
|
||||
my @profiles = map { [ $_, $profile_hash->{$_} ] } keys %$profile_hash;
|
||||
my $title = gettext("Profiles");
|
||||
my $q = {};
|
||||
$q->{title} = $title;
|
||||
$q->{headers} = [ "Repository", $url, ];
|
||||
|
||||
$q->{explanation} = $explanation;
|
||||
|
||||
$q->{functions} = [ "CMD_VIEW",
|
||||
"CMD_CONTINUE", ];
|
||||
|
||||
$q->{default} = "CMD_CONTINUE";
|
||||
$q->{options} = [ map { $_->[0] } @profiles ];
|
||||
$q->{selected} = 0;
|
||||
|
||||
my ($ans, $arg);
|
||||
do {
|
||||
($ans, $arg) = UI_PromptUser($q);
|
||||
|
||||
if ($ans eq "CMD_VIEW") {
|
||||
my $pager = get_pager();
|
||||
open ( PAGER, "| $pager" ) or die "Can't open $pager";
|
||||
print PAGER gettext("Profile: ") . $profiles[$arg]->[0] . "\n";
|
||||
print PAGER $profiles[$arg]->[1];
|
||||
close PAGER;
|
||||
}
|
||||
$q->{selected} = ($arg+1) % @profiles;
|
||||
} until $ans =~ /^CMD_CONTINUE/;
|
||||
return;
|
||||
}
|
||||
|
||||
sub UI_display_profile_conflicts {
|
||||
my ($explanation, $conflict_hash) = @_;
|
||||
my $url = $config->{url};
|
||||
my @conflicts = map { [ $_,
|
||||
$conflict_hash->{$_}->[0],
|
||||
$conflict_hash->{$_}->[1]
|
||||
] }
|
||||
keys %$conflict_hash;
|
||||
my @commits = [];
|
||||
my $title = gettext("Profile conflicts");
|
||||
my $q = {};
|
||||
$q->{title} = $title;
|
||||
$q->{headers} = [ "Repository", $url, ];
|
||||
|
||||
$q->{explanation} = $explanation;
|
||||
|
||||
$q->{functions} = [ "CMD_VIEW_CHANGES",
|
||||
"CMD_CONTINUE", ];
|
||||
|
||||
$q->{default} = "CMD_CONTINUE";
|
||||
$q->{options} = [ map { $_->[0] } @conflicts ];
|
||||
$q->{selected} = 0;
|
||||
|
||||
my ($ans, $arg);
|
||||
do {
|
||||
($ans, $arg) = UI_PromptUser($q);
|
||||
|
||||
if ($ans eq "CMD_VIEW_CHANGES") {
|
||||
display_changes($conflicts[$arg]->[2], $conflicts[$arg]->[1]);
|
||||
}
|
||||
$q->{selected} = ($arg+1) % @conflicts;
|
||||
} until $ans =~ /^CMD_CONTINUE/;
|
||||
return;
|
||||
}
|
||||
|
||||
sub usage {
|
||||
if ( $help eq "push" ) {
|
||||
print STDERR $usage . $usage_push ."\n";
|
||||
} elsif ( $help eq "pull" ) {
|
||||
print STDERR $usage . $usage_pull ."\n";
|
||||
} elsif ( $help eq "sync" ) {
|
||||
print STDERR $usage . $usage_sync ."\n";
|
||||
} elsif ( $help eq "getconfig" ) {
|
||||
print STDERR $usage . $usage_getconfig ."\n";
|
||||
} elsif ( $help eq "setconfig" ) {
|
||||
print STDERR $usage . $usage_setconfig ."\n";
|
||||
} elsif ( $help eq "status" ) {
|
||||
print STDERR $usage . $usage_stat ."\n";
|
||||
} elsif ( $help eq "search" ) {
|
||||
print STDERR $usage . $usage_search ."\n";
|
||||
} else {
|
||||
open(PAGER, "| less") or die "Can't open pager";
|
||||
print PAGER $usage .
|
||||
$usage_search .
|
||||
$usage_push .
|
||||
$usage_pull .
|
||||
$usage_sync .
|
||||
$usage_stat .
|
||||
$usage_setconfig .
|
||||
$usage_getconfig .
|
||||
$usage_bottom . "\n";
|
||||
close PAGER;
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# --getconfig helper function
|
||||
#
|
||||
sub config {
|
||||
my $configstr = gettext("Current config\n");
|
||||
my $config = get_repo_config();
|
||||
$configstr .= "\turl:\t\t$config->{url}\n";
|
||||
$configstr .= "\tdistro:\t\t$config->{distro}\n";
|
||||
$configstr .= "\tenabled:\t$config->{enabled}\n";
|
||||
$configstr .= "\temail:\t\t$config->{email}\n";
|
||||
$configstr .= "\tusername:\t$config->{user}\n";
|
||||
$configstr .= "\tpassword:\t$config->{password}\n";
|
||||
$configstr .= "\tupload:\t\t$config->{upload}\n";
|
||||
print STDERR $configstr . "\n";
|
||||
}
|
||||
|
||||
#
|
||||
# helper function to push profiles to the repository
|
||||
# used by --push and --sync options
|
||||
#
|
||||
sub push_profiles($$$) {
|
||||
my ( $p_ref, $changelog, $confirm ) = @_;
|
||||
my ( $conflicts, $remote_profiles, $local_profiles, @overrides );
|
||||
my @profiles = @$p_ref;
|
||||
|
||||
my $conflict_msg =
|
||||
" The following profile(s) selected for upload conflicts with a profile already
|
||||
stored in the repository for your account. Please choose whether to keep the
|
||||
current version or overwrite it.\n";
|
||||
$all = 0;
|
||||
|
||||
readprofiles();
|
||||
my ($status, $result) = fetch_profiles_by_user( $config->{url},
|
||||
$config->{distro},
|
||||
$config->{user}
|
||||
);
|
||||
if ( $status ) {
|
||||
$remote_profiles = $result;
|
||||
} else {
|
||||
print STDERR sprintf(gettext("ERROR connecting to repository: %s\n"),
|
||||
$result);
|
||||
exit;
|
||||
}
|
||||
|
||||
$all = 1 if ( grep(/^all$/, @profiles) );
|
||||
|
||||
if ( $all ) {
|
||||
$local_profiles = serialize_local_profiles( \%sd );
|
||||
} else {
|
||||
my $local_sd = {};
|
||||
for my $p ( @profiles ) {
|
||||
if ( !$sd{$p} ) {
|
||||
print STDERR
|
||||
sprintf(gettext("Profile for [%s] does not exist\n"), $p);
|
||||
exit;
|
||||
}
|
||||
$local_sd->{$p} = $sd{$p};
|
||||
}
|
||||
$local_profiles = serialize_local_profiles( $local_sd );
|
||||
}
|
||||
|
||||
$conflicts = find_profile_conflicts($remote_profiles, $local_profiles);
|
||||
|
||||
if ( keys %$conflicts ) {
|
||||
@overrides = UI_resolve_profile_conflicts( $conflict_msg, $conflicts );
|
||||
}
|
||||
|
||||
if ( $local_profiles ) {
|
||||
my @uploads;
|
||||
for my $p ( keys %$local_profiles ) {
|
||||
unless ( $conflicts->{$p} and !grep(/^$p$/, @overrides) ) {
|
||||
print STDERR gettext("Uploading ") . $p . "... ";
|
||||
my ($status,$result) = upload_profile( $config->{url},
|
||||
$config->{user},
|
||||
$config->{password},
|
||||
$config->{distro},
|
||||
$p,
|
||||
$local_profiles->{$p},
|
||||
$changelog
|
||||
);
|
||||
print STDERR gettext("done") . "\n";
|
||||
}
|
||||
if ( $status ) {
|
||||
push @uploads, $p;
|
||||
} else {
|
||||
print STDERR gettext("Error uploading") . "$p: $result\n";
|
||||
}
|
||||
}
|
||||
if ( @uploads ) {
|
||||
#
|
||||
# Currently the upload API with the repository returns the
|
||||
# the current users profile set before the update so we have
|
||||
# to refetch to obtain the metadata to update the local profiles
|
||||
#
|
||||
my $repo_p = [];
|
||||
print STDERR gettext("Updating local profile metedata....\n");
|
||||
my ($status,$result) = fetch_profiles_by_user( $config->{url},
|
||||
$config->{distro},
|
||||
$config->{user} );
|
||||
if ( $status ) {
|
||||
for my $p ( @uploads ) {
|
||||
push( @$repo_p, [$p, $result->{$p}] ) if ( $result->{$p} );
|
||||
}
|
||||
activate_repo_profiles( $config->{url}, $repo_p, 0 );
|
||||
print STDERR gettext(" done\n");
|
||||
} else {
|
||||
print STDERR gettext(
|
||||
"Failed to retrieve updated profiles from the repository. Error: "
|
||||
) . $result . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Helper function for pulling profiles from the repository
|
||||
# used by --pull and --sync options
|
||||
#
|
||||
sub pull_profiles($$$$) {
|
||||
my ( $p_ref, $mode, $confirm, $opts ) = @_;
|
||||
my @profiles = @$p_ref;
|
||||
my ( $conflicts, $commit_list, $remote_profiles,
|
||||
$local_profiles, @overrides );
|
||||
|
||||
my $conflict_msg =
|
||||
" The following profiles selected for download conflict with profiles
|
||||
already deployed on the system. Please choose whether to keep the local
|
||||
version or overwrite with the version from the repository\n";
|
||||
|
||||
readprofiles();
|
||||
|
||||
if ( $opts->{id} ) {
|
||||
my ($status,$newp) = fetch_profile_by_id( $config->{url}, $opts->{id} );
|
||||
if ( ! $status ) {
|
||||
print STDERR gettext(
|
||||
sprintf("Error occured during operation\n\t[%s]\n",
|
||||
$newp
|
||||
)
|
||||
);
|
||||
exit 1;
|
||||
} else {
|
||||
$remote_profiles = { $newp->{name} => $newp->{profile} };
|
||||
}
|
||||
} elsif ( @profiles && $opts->{author} ) {
|
||||
$remote_profiles = {};
|
||||
for my $p ( @profiles ) {
|
||||
my ($status,$profiles) =
|
||||
fetch_profiles_by_name_and_user( $config->{url},
|
||||
$config->{distro},
|
||||
$p,
|
||||
$opts->{author} );
|
||||
if ( ! $status ) {
|
||||
print STDERR gettext(sprintf(
|
||||
"Error occured during operation\n\t[%s]\n",
|
||||
$profiles
|
||||
)
|
||||
);
|
||||
exit 1;
|
||||
} else {
|
||||
$remote_profiles->{$p} = $profiles->{$p};
|
||||
}
|
||||
}
|
||||
} elsif ( $opts->{author} ) {
|
||||
my ($status,$profiles) = fetch_profiles_by_user( $config->{url},
|
||||
$config->{distro},
|
||||
$opts->{author} );
|
||||
if ( ! $status ) {
|
||||
print STDERR gettext(sprintf(
|
||||
"Error occured during operation\n\t[%s]\n",
|
||||
$profiles
|
||||
)
|
||||
);
|
||||
exit 1;
|
||||
} else {
|
||||
$remote_profiles = $profiles;
|
||||
}
|
||||
}
|
||||
$local_profiles = serialize_local_profiles( \%sd );
|
||||
$conflicts = find_profile_conflicts( $remote_profiles, $local_profiles );
|
||||
if ( keys %$conflicts ) {
|
||||
@overrides = UI_resolve_profile_conflicts( $conflict_msg, $conflicts );
|
||||
}
|
||||
for my $p ( keys %$remote_profiles ) {
|
||||
unless ( $conflicts->{$p} and !grep(/^$p$/, @overrides) ) {
|
||||
$remote_profiles->{$p}->{username} = $opts->{author};
|
||||
push @$commit_list, [$p, $remote_profiles->{$p}];
|
||||
}
|
||||
}
|
||||
|
||||
if ( $commit_list and @$commit_list ) {
|
||||
activate_repo_profiles( $config->{url}, $commit_list, $mode );
|
||||
system("rcapparmor reload");
|
||||
} else {
|
||||
UI_Info(gettext("No changes to make"));
|
||||
}
|
||||
}
|
||||
|
||||
sub UI_status {
|
||||
|
||||
my ($synched, $unsynched, $local) = @_;
|
||||
my $url = $config->{url};
|
||||
my $synched_text = gettext("Synchronized repository profiles:\t\t") .
|
||||
keys %$synched;
|
||||
my $unsynched_text = gettext("Unsynchronized repository profiles:\t") .
|
||||
keys %$unsynched;
|
||||
my $local_text = gettext("Local only profiles :\t\t\t") . keys %$local;
|
||||
my $options = [ $synched_text, $unsynched_text, $local_text ];
|
||||
my $title = gettext("Profile Status");
|
||||
my $explanation = gettext(
|
||||
" This is the current status of active profiles on the system.
|
||||
To view the profiles or unsyncronized changes select VIEW\n"
|
||||
);
|
||||
my $q = {};
|
||||
$q->{title} = $title;
|
||||
$q->{headers} = [ "Repository", $url, ];
|
||||
$q->{explanation} = $explanation;
|
||||
$q->{functions} = [ "CMD_VIEW", "CMD_FINISHED", ];
|
||||
$q->{default} = "CMD_FINISHED";
|
||||
$q->{options} = $options;
|
||||
$q->{selected} = 0;
|
||||
|
||||
my ($ans, $arg);
|
||||
do {
|
||||
($ans, $arg) = UI_PromptUser($q);
|
||||
|
||||
if ($ans eq "CMD_VIEW") {
|
||||
if ( $arg == 0 ) {
|
||||
UI_display_profiles(
|
||||
gettext("Profiles stored in the repository"),
|
||||
$synched
|
||||
);
|
||||
} elsif ( $arg == 1 ) {
|
||||
UI_display_profile_conflicts(
|
||||
gettext("Unsyncronised profile changes"),
|
||||
$unsynched
|
||||
);
|
||||
} elsif ( $arg == 2 ) {
|
||||
UI_display_profiles(
|
||||
gettext("Profiles stored in the repository"),
|
||||
$local
|
||||
);
|
||||
}
|
||||
}
|
||||
} until $ans =~ /^CMD_FINSHED/;
|
||||
}
|
||||
|
||||
|
218
deprecated/utils/aa-status
Normal file
218
deprecated/utils/aa-status
Normal file
@@ -0,0 +1,218 @@
|
||||
#!/usr/bin/perl -w
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2005-2006 Novell/SUSE
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
|
||||
use strict;
|
||||
use Getopt::Long;
|
||||
use Cwd 'abs_path';
|
||||
|
||||
my $confdir = "/etc/apparmor";
|
||||
my $sd_mountpoint;
|
||||
my $check_enabled = 0;
|
||||
my $count_enforced = 0;
|
||||
my $count_profiled = 0;
|
||||
my $count_complain = 0;
|
||||
my $verbose = 0;
|
||||
my $help;
|
||||
|
||||
GetOptions(
|
||||
'complaining' => \$count_complain,
|
||||
'enabled' => \$check_enabled,
|
||||
'enforced' => \$count_enforced,
|
||||
'profiled' => \$count_profiled,
|
||||
'verbose|v' => \$verbose,
|
||||
'help|h' => \$help,
|
||||
) or usage();
|
||||
|
||||
sub usage {
|
||||
print "Usage: $0 [OPTIONS]\n";
|
||||
print "Displays various information about the currently loaded AppArmor policy.\n";
|
||||
print "OPTIONS (one only):\n";
|
||||
print " --enabled returns error code if subdomain not enabled\n";
|
||||
print " --profiled prints the number of loaded policies\n";
|
||||
print " --enforced prints the number of loaded enforcing policies\n";
|
||||
print " --complaining prints the number of loaded non-enforcing policies\n";
|
||||
print " --verbose (default) displays multiple data points about loaded policy set\n";
|
||||
print " --help this message\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
$verbose = 1 if ($count_complain + $check_enabled + $count_enforced + $count_profiled == 0);
|
||||
usage() if $help or ($count_complain + $check_enabled + $count_enforced + $count_profiled + $verbose > 1);
|
||||
|
||||
sub is_subdomain_loaded() {
|
||||
return 1 if (-d "/sys/module/apparmor");
|
||||
if(open(MODULES, "/proc/modules")) {
|
||||
while(<MODULES>) {
|
||||
return 1 if m/^(subdomain|apparmor)\s+/;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub find_subdomainfs() {
|
||||
|
||||
my $sd_mountpoint;
|
||||
if(open(MOUNTS, "/proc/mounts")) {
|
||||
while(<MOUNTS>) {
|
||||
$sd_mountpoint = "$1/apparmor" if m/^\S+\s+(\S+)\s+securityfs\s/ && -e "$1/apparmor";
|
||||
$sd_mountpoint = "$1/subdomain" if m/^\S+\s+(\S+)\s+securityfs\s/ && -e "$1/subdomain";
|
||||
$sd_mountpoint = $1 if m/^\S+\s+(\S+)\s+subdomainfs\s/ && -e "$1";
|
||||
}
|
||||
close(MOUNTS);
|
||||
}
|
||||
|
||||
return $sd_mountpoint;
|
||||
}
|
||||
|
||||
sub get_profiles {
|
||||
my $mountpoint = shift;
|
||||
my %profiles = ();
|
||||
|
||||
if (open(PROFILES, "$mountpoint/profiles")) {
|
||||
while(<PROFILES>) {
|
||||
$profiles{$1} = $2 if m/^([^\(]+)\s+\((\w+)\)$/;
|
||||
}
|
||||
close(PROFILES);
|
||||
}
|
||||
return (%profiles);
|
||||
}
|
||||
|
||||
sub get_processes {
|
||||
my %profiles = @_;
|
||||
my %processes = ();
|
||||
if (opendir(PROC, "/proc")) {
|
||||
my $file;
|
||||
while (defined($file = readdir(PROC))) {
|
||||
if ($file =~ m/^\d+/) {
|
||||
if (open(CURRENT, "/proc/$file/attr/current")) {
|
||||
while (<CURRENT>) {
|
||||
if (m/^([^\(]+)\s+\((\w+)\)$/) {
|
||||
$processes{$file}{'profile'} = $1;
|
||||
$processes{$file}{'mode'} = $2;
|
||||
} elsif (grep(abs_path("/proc/$file/exe") eq $_ , keys(%profiles))) {
|
||||
# keep only unconfined processes that have a profile defined
|
||||
$processes{$file}{'profile'} = abs_path("/proc/$file/exe");
|
||||
$processes{$file}{'mode'} = 'unconfined';
|
||||
}
|
||||
}
|
||||
close(CURRENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(PROC);
|
||||
}
|
||||
return (%processes);
|
||||
}
|
||||
|
||||
my $is_loaded = is_subdomain_loaded();
|
||||
|
||||
if (!$is_loaded) {
|
||||
print STDERR "apparmor module is not loaded.\n" if $verbose;
|
||||
exit 1;
|
||||
}
|
||||
|
||||
print "apparmor module is loaded.\n" if $verbose;
|
||||
|
||||
$sd_mountpoint = find_subdomainfs();
|
||||
if (!$sd_mountpoint) {
|
||||
print STDERR "apparmor filesystem is not mounted.\n" if $verbose;
|
||||
exit 3;
|
||||
}
|
||||
|
||||
if (! -r "$sd_mountpoint/profiles") {
|
||||
print STDERR "You do not have enough privilege to read the profile set.\n" if $verbose;
|
||||
exit 4;
|
||||
}
|
||||
|
||||
#print "subdomainfs is at $sd_mountpoint.\n" if $verbose;
|
||||
|
||||
# processes is a hash table :
|
||||
# * keys : processes pid
|
||||
# * values : hash containing information about the running process:
|
||||
# * 'profile' : name of the profile applied to the running process
|
||||
# * 'mode' : mode of the profile applied to the running process
|
||||
my %processes = ();
|
||||
my %enforced_processes = ();
|
||||
my %complain_processes = ();
|
||||
my %unconfined_processes = ();
|
||||
|
||||
# profiles is a hash table :
|
||||
# * keys : profile name
|
||||
# * value : profile mode
|
||||
my %profiles;
|
||||
my @enforced_profiles = ();
|
||||
my @complain_profiles = ();
|
||||
|
||||
%profiles = get_profiles($sd_mountpoint);
|
||||
@enforced_profiles = grep { $profiles{$_} eq 'enforce' } keys %profiles;
|
||||
@complain_profiles = grep { $profiles{$_} eq 'complain' } keys %profiles;
|
||||
|
||||
# we consider the case where no profiles are loaded to be "disabled" as well
|
||||
my $rc = (keys(%profiles) == 0) ? 2 : 0;
|
||||
|
||||
if ($check_enabled) {
|
||||
exit $rc;
|
||||
}
|
||||
|
||||
if ($count_profiled) {
|
||||
print scalar(keys(%profiles)). "\n";
|
||||
exit $rc;
|
||||
}
|
||||
|
||||
if ($count_enforced) {
|
||||
print $#enforced_profiles + 1 . "\n";
|
||||
exit $rc;
|
||||
}
|
||||
|
||||
if ($count_complain) {
|
||||
print $#complain_profiles + 1 . "\n";
|
||||
exit $rc;
|
||||
}
|
||||
|
||||
|
||||
if ($verbose) {
|
||||
print keys(%profiles) . " profiles are loaded.\n";
|
||||
print $#enforced_profiles + 1 . " profiles are in enforce mode.\n";
|
||||
for (sort(@enforced_profiles)) {
|
||||
print " " . $_ . "\n";
|
||||
}
|
||||
print $#complain_profiles + 1 . " profiles are in complain mode.\n";
|
||||
for (sort(@complain_profiles)) {
|
||||
print " " . $_ . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
%processes = get_processes(%profiles);
|
||||
if ($verbose) {
|
||||
for (keys(%processes)) {
|
||||
$enforced_processes{$_} = $processes{$_} if $processes{$_}{'mode'} eq 'enforce';
|
||||
$complain_processes{$_} = $processes{$_} if $processes{$_}{'mode'} eq 'complain';
|
||||
# some early code uses unconfined instead of unconfined.
|
||||
$unconfined_processes{$_} = $processes{$_} if $processes{$_}{'mode'} =~ /uncon(fi|strai)ned/;
|
||||
}
|
||||
print keys(%processes) . " processes have profiles defined.\n";
|
||||
print keys(%enforced_processes) . " processes are in enforce mode :\n";
|
||||
for (sort { $enforced_processes{$a}{'profile'} cmp $enforced_processes{$b}{'profile'} } keys(%enforced_processes)) {
|
||||
print " " . $enforced_processes{$_}{'profile'} . " ($_) \n";
|
||||
}
|
||||
print keys(%complain_processes) . " processes are in complain mode.\n";
|
||||
for (sort { $complain_processes{$a}{'profile'} cmp $complain_processes{$b}{'profile'} } keys(%complain_processes)) {
|
||||
print " " . $complain_processes{$_}{'profile'} . " ($_) \n";
|
||||
}
|
||||
print keys(%unconfined_processes) . " processes are unconfined but have a profile defined.\n";
|
||||
for (sort { $unconfined_processes{$a}{'profile'} cmp $unconfined_processes{$b}{'profile'} } keys(%unconfined_processes)) {
|
||||
print " " . $unconfined_processes{$_}{'profile'} . " ($_) \n";
|
||||
}
|
||||
}
|
||||
|
||||
exit $rc;
|
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";
|
||||
}
|
||||
}
|
||||
}
|
135
deprecated/utils/convert-profile.pl
Executable file
135
deprecated/utils/convert-profile.pl
Executable file
@@ -0,0 +1,135 @@
|
||||
#! /usr/bin/perl -w
|
||||
|
||||
# Very simple script to try converting AppArmor profiles to the new
|
||||
# profile syntax as of April 2007.
|
||||
#
|
||||
# Copyright (C) 2007 Andreas Gruenbacher <agruen@suse.de>
|
||||
#
|
||||
# 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.
|
||||
|
||||
use FileHandle;
|
||||
use File::Temp;
|
||||
use Getopt::Std;
|
||||
use strict;
|
||||
|
||||
sub match($) {
|
||||
my ($str) = @_;
|
||||
my @fields;
|
||||
|
||||
@fields = ($str =~ /^(\s*)([@\/]\S*)(\s.*,)$/);
|
||||
if (!@fields) {
|
||||
@fields = ($str =~ /^(\s*")((?:[^"]|\\")*)("\s.*,)$/);
|
||||
}
|
||||
|
||||
return @fields;
|
||||
}
|
||||
|
||||
sub alterations($) {
|
||||
my ($str) = @_;
|
||||
|
||||
if ($str =~ /^([^{]*){([^}]*,[^}]*)}(.*)$/) {
|
||||
my @strs = map { "$1$_$3" } split(/,/, $2);
|
||||
return map { alterations($_) } @strs;
|
||||
} else {
|
||||
return ($str);
|
||||
}
|
||||
}
|
||||
|
||||
my %known_dirs;
|
||||
|
||||
sub remember_pathname($) {
|
||||
my ($str) = @_;
|
||||
my $pathname;
|
||||
|
||||
for (split /(\/)/, $str) {
|
||||
if ($_ eq '/' && $pathname ne '') {
|
||||
#print "<<>> $pathname\n";
|
||||
$known_dirs{$pathname} = 1;
|
||||
}
|
||||
$pathname .= $_;
|
||||
}
|
||||
}
|
||||
|
||||
sub add_slash($$) {
|
||||
my ($str, $perms) = @_;
|
||||
|
||||
return exists $known_dirs{$str} || -d $str;
|
||||
}
|
||||
|
||||
sub never_add_slash($$) {
|
||||
my ($str, $perms) = @_;
|
||||
|
||||
return $perms =~ /[lmx]/ || $str =~ /\.(so|cf|db|conf|config|log|pid|so\*)$/ ||
|
||||
$str =~ /(\*\*|\/)$/ || (-e $str && ! -d $str);
|
||||
|
||||
}
|
||||
|
||||
our($opt_i);
|
||||
getopts('i');
|
||||
|
||||
foreach my $filename (@ARGV) {
|
||||
my $fh_in;
|
||||
|
||||
$fh_in = new FileHandle("< $filename")
|
||||
or die "$filename: $!\n";
|
||||
|
||||
while (<$fh_in>) {
|
||||
if (my @fields = match($_)) {
|
||||
for my $x (alterations($fields[1])) {
|
||||
remember_pathname($x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (@ARGV == 0) {
|
||||
print "Usage: $0 profile ...\n";
|
||||
print "Tries to convert the profile to the new profile syntax, and\n" .
|
||||
"prints the result to standard output. The result may need" .
|
||||
"further review.\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
foreach my $filename (@ARGV) {
|
||||
my ($fh_in, $fh_out, $tmpname);
|
||||
|
||||
$fh_in = new FileHandle("< $filename")
|
||||
or die "$filename: $!\n";
|
||||
|
||||
if ($opt_i) {
|
||||
($fh_out, $tmpname) = mkstemp("$filename.XXXXXX")
|
||||
or die "$!\n";
|
||||
*STDOUT = $fh_out;
|
||||
}
|
||||
|
||||
while (<$fh_in>) {
|
||||
if (my @fields = match($_)) {
|
||||
for my $x (alterations($fields[1])) {
|
||||
if (never_add_slash($x, $fields[2])) {
|
||||
print $_;
|
||||
} elsif (add_slash($x, $fields[2])) {
|
||||
print "$fields[0]$x/$fields[2] # (dir)\n";
|
||||
} else {
|
||||
print "$fields[0]$x/$fields[2] # (maybe-dir)\n";
|
||||
print $_;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
print $_;
|
||||
}
|
||||
}
|
||||
|
||||
if ($opt_i) {
|
||||
rename $tmpname, $filename
|
||||
or die "$filename: $!\n";
|
||||
}
|
||||
}
|
||||
|
||||
# vim: smartindent softtabstop=4 shiftwidth=4
|
201
deprecated/utils/repair_obsolete_profiles
Executable file
201
deprecated/utils/repair_obsolete_profiles
Executable file
@@ -0,0 +1,201 @@
|
||||
#!/usr/bin/perl -wi
|
||||
# automatically repair apparmor profiles that have had their supporting
|
||||
# infrastructure refactored out from underneath them
|
||||
|
||||
# note -i in shebang line -- this program will modify in-place
|
||||
# profiles or #include chunks specified on the command line without
|
||||
# backups. Please make some yourself and inspect the changes made by
|
||||
# this tool to ensure they look correct.
|
||||
|
||||
# It'll try to fix up #include files (supplied by SUSE/Immunix) that have
|
||||
# moved; it will also inspect many #include files that exist solely
|
||||
# for netdomain rule separation, and either remove the #include line
|
||||
# from profiles/includes or suck in the contents of the specific file,
|
||||
# depending if there was any non-netdomain content.
|
||||
|
||||
# If you haven't modified any of the files listed in the @useless array,
|
||||
# you probably don't have to concern yourself with the complicated part
|
||||
# of the previous paragraph. If you did modify any of those files, this
|
||||
# tool will inspect those for changes, try to update any lines in those
|
||||
# files for correctness, and insert those lines directly into the
|
||||
# referencing profiles.
|
||||
|
||||
our %count_cache;
|
||||
|
||||
# count the number of 'interesting' lines in the file
|
||||
sub numlines ($) {
|
||||
my $name = $_[0];
|
||||
|
||||
return $count_cache{$name} if $count_cache{$name};
|
||||
|
||||
open FH, $name or return 1; # can't tell -> not empty
|
||||
|
||||
my $linecount=0;
|
||||
while(<FH>) {
|
||||
if (m/^[^#]*#include/) {
|
||||
$linecount++;
|
||||
} elsif (m/^\s*#/) {
|
||||
# just a comment, skip it
|
||||
} elsif (m/\s*tcp_/) {
|
||||
# netdomain rules are unenforced, skip it
|
||||
} elsif (m/\s*udp_/) {
|
||||
# netdomain rules are unenforced, skip it
|
||||
} elsif (m/\S+/) {
|
||||
$linecount++;
|
||||
}
|
||||
}
|
||||
close FH;
|
||||
|
||||
$count_cache{$name} = $linecount;
|
||||
|
||||
return $linecount;
|
||||
}
|
||||
|
||||
# given a single line from a profile, perform some search/replace
|
||||
# operations to reflect new locations for old files.
|
||||
#
|
||||
# change #include lines that reference files in the @useless array:
|
||||
# don't print the #include any more, and either suck in the contents of
|
||||
# the referenced file (calling itself recursively to fix up _those_
|
||||
# files) or just leave well enough alone, if the file had no
|
||||
# 'interesting' lines as defined above.
|
||||
|
||||
%transforms = (
|
||||
# renamed around SuSE 9.3
|
||||
"abstractions/kde3" => "abstractions/kde",
|
||||
"abstractions/user-GTK" => "abstractions/gnome",
|
||||
"abstractions/user-Xauthority" => "abstractions/X",
|
||||
|
||||
# user-custom -> program-chunks around SHASS 1.1, but these changed dirs
|
||||
"user-custom/fonts" => "abstractions/fonts",
|
||||
"user-custom/kde3" => "abstractions/kde",
|
||||
"user-custom/user-GTK" => "abstractions/gnome",
|
||||
"user-custom/user-mail" => "abstractions/user-mail",
|
||||
"user-custom/user-manpages" => "abstractions/user-manpages",
|
||||
"user-custom/user-Xauthority" => "abstractions/X",
|
||||
"user-custom/user-tmp" => "abstractions/user-tmp",
|
||||
|
||||
# try to forget the -files
|
||||
"program-chunks/base-files" => "abstractions/base",
|
||||
"program-chunks/nameservice-files" => "abstractions/nameservice",
|
||||
"immunix-standard/base-files" => "abstractions/base",
|
||||
"immunix-standard/nameservice-files" => "abstractions/nameservice",
|
||||
|
||||
# immunix-standard -> program-chunks
|
||||
"immunix-standard/postfix-bounce" => "program-chunks/postfix-bounce",
|
||||
"immunix-standard/postfix-cleanup" => "program-chunks/postfix-cleanup",
|
||||
"immunix-standard/postfix-common" => "program-chunks/postfix-common",
|
||||
"immunix-standard/postfix-flush" => "program-chunks/postfix-flush",
|
||||
"immunix-standard/postfix-local" => "program-chunks/postfix-local",
|
||||
"immunix-standard/postfix-master" => "program-chunks/postfix-master",
|
||||
"immunix-standard/postfix-nqmgr" => "program-chunks/postfix-nqmgr",
|
||||
"immunix-standard/postfix-pickup" => "program-chunks/postfix-pickup",
|
||||
"immunix-standard/postfix-proxymap" => "program-chunks/postfix-proxymap",
|
||||
"immunix-standard/postfix-qmgr" => "program-chunks/postfix-qmgr",
|
||||
"immunix-standard/postfix-showq" => "program-chunks/postfix-showq",
|
||||
"immunix-standard/postfix-smtp" => "program-chunks/postfix-smtp",
|
||||
"immunix-standard/postfix-smtpd" => "program-chunks/postfix-smtpd",
|
||||
"immunix-standard/postfix-trivial-rewrite" => "program-chunks/postfix-trivial-rewrite",
|
||||
"immunix-standard/apache-default-uri" => "program-chunks/apache-default-uri",
|
||||
"immunix-standard/at" => "program-chunks/at",
|
||||
);
|
||||
|
||||
# chunks that immunix tools never populated -- lets remove the ones that
|
||||
# don't have any useful information
|
||||
my @useless = qw{
|
||||
program-chunks/base-nd
|
||||
program-chunks/portmap-nd
|
||||
program-chunks/postfix-local-nd
|
||||
program-chunks/postfix-master-nd
|
||||
program-chunks/postfix-proxymap-nd
|
||||
program-chunks/postfix-smtpd-nd
|
||||
program-chunks/postfix-smtp-nd
|
||||
user-custom/base-nd
|
||||
user-custom/portmap-nd
|
||||
user-custom/postfix-local-nd
|
||||
user-custom/postfix-master-nd
|
||||
user-custom/postfix-proxymap-nd
|
||||
user-custom/postfix-smtpd-nd
|
||||
user-custom/postfix-smtp-nd
|
||||
immunix-standard/base-nd
|
||||
immunix-standard/portmap-nd
|
||||
immunix-standard/postfix-local-nd
|
||||
immunix-standard/postfix-master-nd
|
||||
immunix-standard/postfix-proxymap-nd
|
||||
immunix-standard/postfix-smtpd-nd
|
||||
immunix-standard/postfix-smtp-nd
|
||||
program-chunks/at
|
||||
program-chunks/fam
|
||||
program-chunks/httpd
|
||||
program-chunks/identd
|
||||
program-chunks/imapd
|
||||
program-chunks/ipop2d
|
||||
program-chunks/ipop3d
|
||||
program-chunks/lpd
|
||||
program-chunks/mutt
|
||||
program-chunks/named
|
||||
program-chunks/nmbd
|
||||
program-chunks/ntalkd
|
||||
program-chunks/ntpd
|
||||
program-chunks/postgres
|
||||
program-chunks/rpc.lockd
|
||||
program-chunks/rpc.nfsd
|
||||
program-chunks/rpc.statd
|
||||
program-chunks/samba
|
||||
program-chunks/sendmail.sendmail
|
||||
program-chunks/shells
|
||||
program-chunks/slocate
|
||||
program-chunks/snmpd
|
||||
program-chunks/spamc
|
||||
program-chunks/sshd
|
||||
program-chunks/swat
|
||||
program-chunks/syslogd
|
||||
program-chunks/talk
|
||||
program-chunks/xfs
|
||||
};
|
||||
|
||||
# create an alternation to speed up the regexp below
|
||||
my $useless = join('|', @useless);
|
||||
|
||||
sub fixup ($) {
|
||||
$line = $_[0];
|
||||
|
||||
$line =~ s/#include\s+<([^>]+)>/$i = (exists $transforms{$1}) ? $transforms{$1} : "$1"; "#include <$i>"/e;
|
||||
|
||||
if ($line =~ m/\s*#include\s+<($useless)>/) {
|
||||
my $file = $1;
|
||||
if (numlines("/etc/subdomain.d/$file") > 0) {
|
||||
my $succ = open INC, "/etc/subdomain.d/$file";
|
||||
if (not $succ) {
|
||||
print STDERR "Error opening /etc/subdomain.d/$file\n";
|
||||
} else {
|
||||
while(my $included_line = <INC>) {
|
||||
print fixup_loop($included_line);
|
||||
}
|
||||
close INC;
|
||||
}
|
||||
}
|
||||
$line = ""; # this line has been handled by the file
|
||||
}
|
||||
|
||||
return $line;
|
||||
}
|
||||
|
||||
# call fixup on a single entry repeatedly -- this way, we can encode
|
||||
# 'small' changes in the fixup routine when they are made, rather than
|
||||
# encoding all possible starting points and which specific end point
|
||||
# they should go to.
|
||||
sub fixup_loop ($) {
|
||||
my $line = $_[0];
|
||||
my $saved;
|
||||
do {
|
||||
$saved = $line;
|
||||
$line = fixup($saved);
|
||||
} until ($line eq $saved);
|
||||
return $line;
|
||||
}
|
||||
|
||||
# main entry point; fix each line in every file in argv.
|
||||
while(<>) {
|
||||
print fixup_loop($_);
|
||||
}
|
@@ -1,36 +0,0 @@
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2016 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.
|
||||
# ----------------------------------------------------------------------
|
||||
NAME = documentation
|
||||
all:
|
||||
COMMONDIR=../common/
|
||||
|
||||
include $(COMMONDIR)/Make.rules
|
||||
|
||||
all: docs
|
||||
|
||||
SOURCES:= $(wildcard *.odt)
|
||||
DOCS:=$(SOURCES:.odt=.pdf)
|
||||
|
||||
.PHONY: docs
|
||||
docs: $(DOCS)
|
||||
|
||||
%.pdf: %.odt
|
||||
unoconv -v -f pdf --output "$@" "$<"
|
||||
|
||||
.PHONY: clean
|
||||
ifndef VERBOSE
|
||||
.SILENT: clean
|
||||
endif
|
||||
clean:
|
||||
rm -f *.pdf
|
||||
|
@@ -1,25 +0,0 @@
|
||||
The apparmor logo (logo-default-red.svg) was created by Noah Davis and
|
||||
released under the LGPL (licence included below).
|
||||
|
||||
Logo variants and uses:
|
||||
|
||||
logo-default-red.svg - default logo and coloration used for the apparmor
|
||||
project. Created for larger (64x64) uses.
|
||||
Not optimized for small 16x16 tiles.
|
||||
|
||||
|
||||
|
||||
License
|
||||
* Copyright (c) 2018 Noah Davis <noahadvs@gmail.com>
|
||||
*
|
||||
* The appaprmor logo is licensed under the terms of the GNU
|
||||
* Lesser General Public License, version 2.1. Please see the file
|
||||
* COPYING.LGPL.
|
||||
*
|
||||
* This logo file 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
@@ -1 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg height="64" width="64" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientUnits="userSpaceOnUse" x1="55" x2="55" xlink:href="#j" y1="54" y2="9"/><linearGradient id="b"><stop offset="0" stop-color="#bf4231"/><stop offset="1" stop-color="#e05e4c"/></linearGradient><linearGradient id="c" gradientUnits="userSpaceOnUse" x1="32" x2="32" y1="58" y2="6"><stop offset="0" stop-color="#173f4f"/><stop offset="1" stop-color="#2f5361"/></linearGradient><linearGradient id="d" gradientUnits="userSpaceOnUse" x1="55" x2="55" xlink:href="#b" y1="54" y2="9"/><linearGradient id="e" gradientUnits="userSpaceOnUse" x1="20" x2="45" xlink:href="#k" y1="22" y2="47"/><linearGradient id="f" gradientUnits="userSpaceOnUse" x1="37" x2="37" y1="46" y2="38"><stop offset="0" stop-color="#be4434"/><stop offset=".25" stop-color="#c44837"/><stop offset="1" stop-color="#cb4c3b"/></linearGradient><linearGradient id="g" gradientUnits="userSpaceOnUse" x1="26" x2="50" xlink:href="#k" y1="16" y2="40"/><linearGradient id="h" gradientUnits="userSpaceOnUse" x1="40" x2="47" xlink:href="#k" y1="38" y2="45"/><linearGradient id="i" gradientUnits="userSpaceOnUse" x1="43" x2="46" xlink:href="#k" y1="44" y2="47"/><linearGradient id="j"><stop offset="0" stop-color="#eff0f1"/><stop offset="1" stop-color="#fcfcfc"/></linearGradient><linearGradient id="k"><stop offset="0" stop-color="#292c2f"/><stop offset="1" stop-opacity="0"/></linearGradient><linearGradient id="l" gradientUnits="userSpaceOnUse" x1="32" x2="32" xlink:href="#j" y1="54" y2="9"/><linearGradient id="m" gradientUnits="userSpaceOnUse" x1="32" x2="32" xlink:href="#b" y1="54" y2="9"/><path d="m32 6c-6.33333 3.35447-12.66667 4.72491-19 6v25.001953c0 7 10.26331 16.561337 19 20.998047 8.73669-4.43671 19-13.998047 19-20.998047v-25.001953c-6.33333-1.27509-12.66667-2.64553-19-6z" fill="url(#c)" stroke-linecap="square" stroke-width="2"/><path d="m13 36.001953v1c0 7 10.26331 16.561337 19 20.998047 8.73669-4.43671 19-13.998047 19-20.998047v-1c0 7-10.26331 16.561337-19 20.998047-8.73669-4.43671-19-13.998047-19-20.998047z" fill="#292c2f" opacity=".2" stroke-linecap="square" stroke-width="2"/><path d="m48 14-26.304688 32.304688 11.208985 11.208984c8.525508-4.614773 18.095703-13.751033 18.095703-20.511719v-20.001953z" fill="url(#i)" opacity=".2"/><path d="m40.824219 12.349609-17.617188 35.238282c2.735569 2.548653 5.806349 4.895376 8.792969 6.412109 7.392765-3.754157 16-12.076982 16-18v-22c-2.403402-.483885-4.789398-1.006952-7.175781-1.650391z" fill="url(#d)"/><path d="m32 9c-5.358808 2.838395-10.64102 3.921074-16 5v22c0 3.530034 3.17163 7.828219 7.207031 11.587891l17.617188-35.238282c-2.934573-.791246-5.868718-1.784199-8.824219-3.349609z" fill="url(#a)"/><path d="m24 14-8 16 20.935547 20.935547c1.522034-1.10756 3.001377-2.336903 4.361328-3.638672l-1.296875-1.296875-7-14z" fill="url(#e)" opacity=".2"/><path d="m28 14 12 32 8-16h-4z" fill="url(#g)" opacity=".2"/><g stroke-width="1.857143"><path d="m24 14 16 32 8-16h-4l-1 2h-6l-9-18zm14 20h4l-2 4z" fill="url(#l)"/><path d="m24 14-8 16h4l1-2h6l8.5 17.000001h4zm0 8 2 4h-4z" fill="url(#m)"/><path d="m32 38 4 8h4l-4-8z" fill="url(#f)"/></g><path d="m48 30-8 16 3.617188 3.617188c4.013144-3.887728 7.018045-8.222958 7.351562-11.9375.019301-.229864.03125-.456776.03125-.677735v-4.001953z" fill="url(#h)" opacity=".2"/></svg>
|
Before Width: | Height: | Size: 3.3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 33 KiB |
Binary file not shown.
Before Width: | Height: | Size: 6.6 KiB |
Binary file not shown.
Before Width: | Height: | Size: 50 KiB |
@@ -1,118 +0,0 @@
|
||||
From 24b6ac149a57c2d3d5a9920e64d914e8ff00d346 Mon Sep 17 00:00:00 2001
|
||||
From: Vegard Nossum <vegard.nossum@oracle.com>
|
||||
Date: Thu, 7 Jul 2016 13:41:11 -0700
|
||||
Subject: [PATCH 01/27] apparmor: fix oops, validate buffer size in
|
||||
apparmor_setprocattr()
|
||||
|
||||
When proc_pid_attr_write() was changed to use memdup_user apparmor's
|
||||
(interface violating) assumption that the setprocattr buffer was always
|
||||
a single page was violated.
|
||||
|
||||
The size test is not strictly speaking needed as proc_pid_attr_write()
|
||||
will reject anything larger, but for the sake of robustness we can keep
|
||||
it in.
|
||||
|
||||
SMACK and SELinux look safe to me, but somebody else should probably
|
||||
have a look just in case.
|
||||
|
||||
Based on original patch from Vegard Nossum <vegard.nossum@oracle.com>
|
||||
modified for the case that apparmor provides null termination.
|
||||
|
||||
Fixes: bb646cdb12e75d82258c2f2e7746d5952d3e321a
|
||||
Reported-by: Vegard Nossum <vegard.nossum@oracle.com>
|
||||
Cc: Al Viro <viro@zeniv.linux.org.uk>
|
||||
Cc: John Johansen <john.johansen@canonical.com>
|
||||
Cc: Paul Moore <paul@paul-moore.com>
|
||||
Cc: Stephen Smalley <sds@tycho.nsa.gov>
|
||||
Cc: Eric Paris <eparis@parisplace.org>
|
||||
Cc: Casey Schaufler <casey@schaufler-ca.com>
|
||||
Cc: stable@kernel.org
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
Reviewed-by: Tyler Hicks <tyhicks@canonical.com>
|
||||
Signed-off-by: James Morris <james.l.morris@oracle.com>
|
||||
---
|
||||
security/apparmor/lsm.c | 36 +++++++++++++++++++-----------------
|
||||
1 file changed, 19 insertions(+), 17 deletions(-)
|
||||
|
||||
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
|
||||
index dec607c..5ee8201 100644
|
||||
--- a/security/apparmor/lsm.c
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -523,34 +523,34 @@ static int apparmor_setprocattr(struct task_struct *task, char *name,
|
||||
{
|
||||
struct common_audit_data sa;
|
||||
struct apparmor_audit_data aad = {0,};
|
||||
- char *command, *args = value;
|
||||
+ char *command, *largs = NULL, *args = value;
|
||||
size_t arg_size;
|
||||
int error;
|
||||
|
||||
if (size == 0)
|
||||
return -EINVAL;
|
||||
- /* args points to a PAGE_SIZE buffer, AppArmor requires that
|
||||
- * the buffer must be null terminated or have size <= PAGE_SIZE -1
|
||||
- * so that AppArmor can null terminate them
|
||||
- */
|
||||
- if (args[size - 1] != '\0') {
|
||||
- if (size == PAGE_SIZE)
|
||||
- return -EINVAL;
|
||||
- args[size] = '\0';
|
||||
- }
|
||||
-
|
||||
/* task can only write its own attributes */
|
||||
if (current != task)
|
||||
return -EACCES;
|
||||
|
||||
- args = value;
|
||||
+ /* AppArmor requires that the buffer must be null terminated atm */
|
||||
+ if (args[size - 1] != '\0') {
|
||||
+ /* null terminate */
|
||||
+ largs = args = kmalloc(size + 1, GFP_KERNEL);
|
||||
+ if (!args)
|
||||
+ return -ENOMEM;
|
||||
+ memcpy(args, value, size);
|
||||
+ args[size] = '\0';
|
||||
+ }
|
||||
+
|
||||
+ error = -EINVAL;
|
||||
args = strim(args);
|
||||
command = strsep(&args, " ");
|
||||
if (!args)
|
||||
- return -EINVAL;
|
||||
+ goto out;
|
||||
args = skip_spaces(args);
|
||||
if (!*args)
|
||||
- return -EINVAL;
|
||||
+ goto out;
|
||||
|
||||
arg_size = size - (args - (char *) value);
|
||||
if (strcmp(name, "current") == 0) {
|
||||
@@ -576,10 +576,12 @@ static int apparmor_setprocattr(struct task_struct *task, char *name,
|
||||
goto fail;
|
||||
} else
|
||||
/* only support the "current" and "exec" process attributes */
|
||||
- return -EINVAL;
|
||||
+ goto fail;
|
||||
|
||||
if (!error)
|
||||
error = size;
|
||||
+out:
|
||||
+ kfree(largs);
|
||||
return error;
|
||||
|
||||
fail:
|
||||
@@ -588,9 +590,9 @@ fail:
|
||||
aad.profile = aa_current_profile();
|
||||
aad.op = OP_SETPROCATTR;
|
||||
aad.info = name;
|
||||
- aad.error = -EINVAL;
|
||||
+ aad.error = error = -EINVAL;
|
||||
aa_audit_msg(AUDIT_APPARMOR_DENIED, &sa, NULL);
|
||||
- return -EINVAL;
|
||||
+ goto out;
|
||||
}
|
||||
|
||||
static int apparmor_task_setrlimit(struct task_struct *task,
|
||||
--
|
||||
2.7.4
|
||||
|
@@ -1,33 +0,0 @@
|
||||
From 444bc4f95ec283cd0fb9777f4890bd9bc307809d Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Mon, 11 Apr 2016 16:55:10 -0700
|
||||
Subject: [PATCH 02/27] apparmor: fix refcount bug in profile replacement
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
Acked-by: Seth Arnold <seth.arnold@canonical.com>
|
||||
---
|
||||
security/apparmor/policy.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
|
||||
index 705c287..222052f 100644
|
||||
--- a/security/apparmor/policy.c
|
||||
+++ b/security/apparmor/policy.c
|
||||
@@ -1189,12 +1189,12 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
|
||||
aa_get_profile(newest);
|
||||
aa_put_profile(parent);
|
||||
rcu_assign_pointer(ent->new->parent, newest);
|
||||
- } else
|
||||
- aa_put_profile(newest);
|
||||
+ }
|
||||
/* aafs interface uses replacedby */
|
||||
rcu_assign_pointer(ent->new->replacedby->profile,
|
||||
aa_get_profile(ent->new));
|
||||
__list_add_profile(&parent->base.profiles, ent->new);
|
||||
+ aa_put_profile(newest);
|
||||
} else {
|
||||
/* aafs interface uses replacedby */
|
||||
rcu_assign_pointer(ent->new->replacedby->profile,
|
||||
--
|
||||
2.7.4
|
||||
|
@@ -1,38 +0,0 @@
|
||||
From 1224a06778b89dcbf0ca85bd961c2fcdd8765a69 Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Mon, 11 Apr 2016 16:57:19 -0700
|
||||
Subject: [PATCH 03/27] apparmor: fix replacement bug that adds new child to
|
||||
old parent
|
||||
|
||||
When set atomic replacement is used and the parent is updated before the
|
||||
child, and the child did not exist in the old parent so there is no
|
||||
direct replacement then the new child is incorrectly added to the old
|
||||
parent. This results in the new parent not having the child(ren) that
|
||||
it should and the old parent when being destroyed asserting the
|
||||
following error.
|
||||
|
||||
AppArmor: policy_destroy: internal error, policy '<profile/name>' still
|
||||
contains profiles
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
Acked-by: Seth Arnold <seth.arnold@canonical.com>
|
||||
---
|
||||
security/apparmor/policy.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
|
||||
index 222052f..c92a9f6 100644
|
||||
--- a/security/apparmor/policy.c
|
||||
+++ b/security/apparmor/policy.c
|
||||
@@ -1193,7 +1193,7 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
|
||||
/* aafs interface uses replacedby */
|
||||
rcu_assign_pointer(ent->new->replacedby->profile,
|
||||
aa_get_profile(ent->new));
|
||||
- __list_add_profile(&parent->base.profiles, ent->new);
|
||||
+ __list_add_profile(&newest->base.profiles, ent->new);
|
||||
aa_put_profile(newest);
|
||||
} else {
|
||||
/* aafs interface uses replacedby */
|
||||
--
|
||||
2.7.4
|
||||
|
@@ -1,87 +0,0 @@
|
||||
From 15d921647676fdc2c3ee1cf9aa8f578b1012ecff Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Sun, 8 Jun 2014 11:20:54 -0700
|
||||
Subject: [PATCH 04/27] apparmor: fix uninitialized lsm_audit member
|
||||
|
||||
BugLink: http://bugs.launchpad.net/bugs/1268727
|
||||
|
||||
The task field in the lsm_audit struct needs to be initialized if
|
||||
a change_hat fails, otherwise the following oops will occur
|
||||
|
||||
BUG: unable to handle kernel paging request at 0000002fbead7d08
|
||||
IP: [<ffffffff8171153e>] _raw_spin_lock+0xe/0x50
|
||||
PGD 1e3f35067 PUD 0
|
||||
Oops: 0002 [#1] SMP
|
||||
Modules linked in: pppox crc_ccitt p8023 p8022 psnap llc ax25 btrfs raid6_pq xor xfs libcrc32c dm_multipath scsi_dh kvm_amd dcdbas kvm microcode amd64_edac_mod joydev edac_core psmouse edac_mce_amd serio_raw k10temp sp5100_tco i2c_piix4 ipmi_si ipmi_msghandler acpi_power_meter mac_hid lp parport hid_generic usbhid hid pata_acpi mpt2sas ahci raid_class pata_atiixp bnx2 libahci scsi_transport_sas [last unloaded: tipc]
|
||||
CPU: 2 PID: 699 Comm: changehat_twice Tainted: GF O 3.13.0-7-generic #25-Ubuntu
|
||||
Hardware name: Dell Inc. PowerEdge R415/08WNM9, BIOS 1.8.6 12/06/2011
|
||||
task: ffff8802135c6000 ti: ffff880212986000 task.ti: ffff880212986000
|
||||
RIP: 0010:[<ffffffff8171153e>] [<ffffffff8171153e>] _raw_spin_lock+0xe/0x50
|
||||
RSP: 0018:ffff880212987b68 EFLAGS: 00010006
|
||||
RAX: 0000000000020000 RBX: 0000002fbead7500 RCX: 0000000000000000
|
||||
RDX: 0000000000000292 RSI: ffff880212987ba8 RDI: 0000002fbead7d08
|
||||
RBP: ffff880212987b68 R08: 0000000000000246 R09: ffff880216e572a0
|
||||
R10: ffffffff815fd677 R11: ffffea0008469580 R12: ffffffff8130966f
|
||||
R13: ffff880212987ba8 R14: 0000002fbead7d08 R15: ffff8800d8c6b830
|
||||
FS: 00002b5e6c84e7c0(0000) GS:ffff880216e40000(0000) knlGS:0000000055731700
|
||||
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
|
||||
CR2: 0000002fbead7d08 CR3: 000000021270f000 CR4: 00000000000006e0
|
||||
Stack:
|
||||
ffff880212987b98 ffffffff81075f17 ffffffff8130966f 0000000000000009
|
||||
0000000000000000 0000000000000000 ffff880212987bd0 ffffffff81075f7c
|
||||
0000000000000292 ffff880212987c08 ffff8800d8c6b800 0000000000000026
|
||||
Call Trace:
|
||||
[<ffffffff81075f17>] __lock_task_sighand+0x47/0x80
|
||||
[<ffffffff8130966f>] ? apparmor_cred_prepare+0x2f/0x50
|
||||
[<ffffffff81075f7c>] do_send_sig_info+0x2c/0x80
|
||||
[<ffffffff81075fee>] send_sig_info+0x1e/0x30
|
||||
[<ffffffff8130242d>] aa_audit+0x13d/0x190
|
||||
[<ffffffff8130c1dc>] aa_audit_file+0xbc/0x130
|
||||
[<ffffffff8130966f>] ? apparmor_cred_prepare+0x2f/0x50
|
||||
[<ffffffff81304cc2>] aa_change_hat+0x202/0x530
|
||||
[<ffffffff81308fc6>] aa_setprocattr_changehat+0x116/0x1d0
|
||||
[<ffffffff8130a11d>] apparmor_setprocattr+0x25d/0x300
|
||||
[<ffffffff812cee56>] security_setprocattr+0x16/0x20
|
||||
[<ffffffff8121fc87>] proc_pid_attr_write+0x107/0x130
|
||||
[<ffffffff811b7604>] vfs_write+0xb4/0x1f0
|
||||
[<ffffffff811b8039>] SyS_write+0x49/0xa0
|
||||
[<ffffffff8171a1bf>] tracesys+0xe1/0xe6
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
Acked-by: Seth Arnold <seth.arnold@canonical.com>
|
||||
---
|
||||
security/apparmor/audit.c | 3 ++-
|
||||
security/apparmor/file.c | 3 ++-
|
||||
2 files changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
|
||||
index 89c7865..3a7f1da 100644
|
||||
--- a/security/apparmor/audit.c
|
||||
+++ b/security/apparmor/audit.c
|
||||
@@ -200,7 +200,8 @@ int aa_audit(int type, struct aa_profile *profile, gfp_t gfp,
|
||||
|
||||
if (sa->aad->type == AUDIT_APPARMOR_KILL)
|
||||
(void)send_sig_info(SIGKILL, NULL,
|
||||
- sa->u.tsk ? sa->u.tsk : current);
|
||||
+ sa->type == LSM_AUDIT_DATA_TASK && sa->u.tsk ?
|
||||
+ sa->u.tsk : current);
|
||||
|
||||
if (sa->aad->type == AUDIT_APPARMOR_ALLOWED)
|
||||
return complain_error(sa->aad->error);
|
||||
diff --git a/security/apparmor/file.c b/security/apparmor/file.c
|
||||
index 913f377..43d6ae7 100644
|
||||
--- a/security/apparmor/file.c
|
||||
+++ b/security/apparmor/file.c
|
||||
@@ -110,7 +110,8 @@ int aa_audit_file(struct aa_profile *profile, struct file_perms *perms,
|
||||
int type = AUDIT_APPARMOR_AUTO;
|
||||
struct common_audit_data sa;
|
||||
struct apparmor_audit_data aad = {0,};
|
||||
- sa.type = LSM_AUDIT_DATA_NONE;
|
||||
+ sa.type = LSM_AUDIT_DATA_TASK;
|
||||
+ sa.u.tsk = NULL;
|
||||
sa.aad = &aad;
|
||||
aad.op = op,
|
||||
aad.fs.request = request;
|
||||
--
|
||||
2.7.4
|
||||
|
@@ -1,32 +0,0 @@
|
||||
From c1216728b7d644443eef31e4bd9d01b4a0a51d61 Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Fri, 25 Jul 2014 04:02:03 -0700
|
||||
Subject: [PATCH 05/27] apparmor: exec should not be returning ENOENT when it
|
||||
denies
|
||||
|
||||
The current behavior is confusing as it causes exec failures to report
|
||||
the executable is missing instead of identifying that apparmor
|
||||
caused the failure.
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
Acked-by: Seth Arnold <seth.arnold@canonical.com>
|
||||
---
|
||||
security/apparmor/domain.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
|
||||
index dc0027b..67a7418 100644
|
||||
--- a/security/apparmor/domain.c
|
||||
+++ b/security/apparmor/domain.c
|
||||
@@ -433,7 +433,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
|
||||
new_profile = aa_get_newest_profile(ns->unconfined);
|
||||
info = "ux fallback";
|
||||
} else {
|
||||
- error = -ENOENT;
|
||||
+ error = -EACCES;
|
||||
info = "profile not found";
|
||||
/* remove MAY_EXEC to audit as failure */
|
||||
perms.allow &= ~MAY_EXEC;
|
||||
--
|
||||
2.7.4
|
||||
|
@@ -1,28 +0,0 @@
|
||||
From 2d3389de6c8ab6b3ad2cef4ea460c8fce2a226b9 Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Fri, 25 Jul 2014 04:01:56 -0700
|
||||
Subject: [PATCH 06/27] apparmor: fix update the mtime of the profile file on
|
||||
replacement
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
Acked-by: Seth Arnold <seth.arnold@canonical.com>
|
||||
---
|
||||
security/apparmor/apparmorfs.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
|
||||
index ad4fa49..45a6199 100644
|
||||
--- a/security/apparmor/apparmorfs.c
|
||||
+++ b/security/apparmor/apparmorfs.c
|
||||
@@ -379,6 +379,8 @@ void __aa_fs_profile_migrate_dents(struct aa_profile *old,
|
||||
|
||||
for (i = 0; i < AAFS_PROF_SIZEOF; i++) {
|
||||
new->dents[i] = old->dents[i];
|
||||
+ if (new->dents[i])
|
||||
+ new->dents[i]->d_inode->i_mtime = CURRENT_TIME;
|
||||
old->dents[i] = NULL;
|
||||
}
|
||||
}
|
||||
--
|
||||
2.7.4
|
||||
|
@@ -1,36 +0,0 @@
|
||||
From 9caa96e30a1b2bb191a29af872285c8d0b078c10 Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Fri, 25 Jul 2014 04:02:08 -0700
|
||||
Subject: [PATCH 07/27] apparmor: fix disconnected bind mnts reconnection
|
||||
|
||||
Bind mounts can fail to be properly reconnected when PATH_CONNECT is
|
||||
specified. Ensure that when PATH_CONNECT is specified the path has
|
||||
a root.
|
||||
|
||||
BugLink: http://bugs.launchpad.net/bugs/1319984
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
Acked-by: Seth Arnold <seth.arnold@canonical.com>
|
||||
---
|
||||
security/apparmor/path.c | 5 ++++-
|
||||
1 file changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/security/apparmor/path.c b/security/apparmor/path.c
|
||||
index 71e0e3a..bb2f2c6 100644
|
||||
--- a/security/apparmor/path.c
|
||||
+++ b/security/apparmor/path.c
|
||||
@@ -141,7 +141,10 @@ static int d_namespace_path(struct path *path, char *buf, int buflen,
|
||||
error = -EACCES;
|
||||
if (*res == '/')
|
||||
*name = res + 1;
|
||||
- }
|
||||
+ } else if (*res != '/')
|
||||
+ /* CONNECT_PATH with missing root */
|
||||
+ error = prepend(name, *name - buf, "/", 1);
|
||||
+
|
||||
}
|
||||
|
||||
out:
|
||||
--
|
||||
2.7.4
|
||||
|
@@ -1,114 +0,0 @@
|
||||
From 11702a732e149380e05e2ab8ae1b743ac89f892f Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Fri, 25 Jul 2014 04:02:10 -0700
|
||||
Subject: [PATCH 08/27] apparmor: internal paths should be treated as
|
||||
disconnected
|
||||
|
||||
Internal mounts are not mounted anywhere and as such should be treated
|
||||
as disconnected paths.
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
Acked-by: Seth Arnold <seth.arnold@canonical.com>
|
||||
---
|
||||
security/apparmor/path.c | 64 +++++++++++++++++++++++++++---------------------
|
||||
1 file changed, 36 insertions(+), 28 deletions(-)
|
||||
|
||||
diff --git a/security/apparmor/path.c b/security/apparmor/path.c
|
||||
index bb2f2c6..596f799 100644
|
||||
--- a/security/apparmor/path.c
|
||||
+++ b/security/apparmor/path.c
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "include/path.h"
|
||||
#include "include/policy.h"
|
||||
|
||||
-
|
||||
/* modified from dcache.c */
|
||||
static int prepend(char **buffer, int buflen, const char *str, int namelen)
|
||||
{
|
||||
@@ -39,6 +38,38 @@ static int prepend(char **buffer, int buflen, const char *str, int namelen)
|
||||
|
||||
#define CHROOT_NSCONNECT (PATH_CHROOT_REL | PATH_CHROOT_NSCONNECT)
|
||||
|
||||
+/* If the path is not connected to the expected root,
|
||||
+ * check if it is a sysctl and handle specially else remove any
|
||||
+ * leading / that __d_path may have returned.
|
||||
+ * Unless
|
||||
+ * specifically directed to connect the path,
|
||||
+ * OR
|
||||
+ * if in a chroot and doing chroot relative paths and the path
|
||||
+ * resolves to the namespace root (would be connected outside
|
||||
+ * of chroot) and specifically directed to connect paths to
|
||||
+ * namespace root.
|
||||
+ */
|
||||
+static int disconnect(const struct path *path, char *buf, char **name,
|
||||
+ int flags)
|
||||
+{
|
||||
+ int error = 0;
|
||||
+
|
||||
+ if (!(flags & PATH_CONNECT_PATH) &&
|
||||
+ !(((flags & CHROOT_NSCONNECT) == CHROOT_NSCONNECT) &&
|
||||
+ our_mnt(path->mnt))) {
|
||||
+ /* disconnected path, don't return pathname starting
|
||||
+ * with '/'
|
||||
+ */
|
||||
+ error = -EACCES;
|
||||
+ if (**name == '/')
|
||||
+ *name = *name + 1;
|
||||
+ } else if (**name != '/')
|
||||
+ /* CONNECT_PATH with missing root */
|
||||
+ error = prepend(name, *name - buf, "/", 1);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* d_namespace_path - lookup a name associated with a given path
|
||||
* @path: path to lookup (NOT NULL)
|
||||
@@ -74,7 +105,8 @@ static int d_namespace_path(struct path *path, char *buf, int buflen,
|
||||
* control instead of hard coded /proc
|
||||
*/
|
||||
return prepend(name, *name - buf, "/proc", 5);
|
||||
- }
|
||||
+ } else
|
||||
+ return disconnect(path, buf, name, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -120,32 +152,8 @@ static int d_namespace_path(struct path *path, char *buf, int buflen,
|
||||
goto out;
|
||||
}
|
||||
|
||||
- /* If the path is not connected to the expected root,
|
||||
- * check if it is a sysctl and handle specially else remove any
|
||||
- * leading / that __d_path may have returned.
|
||||
- * Unless
|
||||
- * specifically directed to connect the path,
|
||||
- * OR
|
||||
- * if in a chroot and doing chroot relative paths and the path
|
||||
- * resolves to the namespace root (would be connected outside
|
||||
- * of chroot) and specifically directed to connect paths to
|
||||
- * namespace root.
|
||||
- */
|
||||
- if (!connected) {
|
||||
- if (!(flags & PATH_CONNECT_PATH) &&
|
||||
- !(((flags & CHROOT_NSCONNECT) == CHROOT_NSCONNECT) &&
|
||||
- our_mnt(path->mnt))) {
|
||||
- /* disconnected path, don't return pathname starting
|
||||
- * with '/'
|
||||
- */
|
||||
- error = -EACCES;
|
||||
- if (*res == '/')
|
||||
- *name = res + 1;
|
||||
- } else if (*res != '/')
|
||||
- /* CONNECT_PATH with missing root */
|
||||
- error = prepend(name, *name - buf, "/", 1);
|
||||
-
|
||||
- }
|
||||
+ if (!connected)
|
||||
+ error = disconnect(path, buf, name, flags);
|
||||
|
||||
out:
|
||||
return error;
|
||||
--
|
||||
2.7.4
|
||||
|
@@ -1,29 +0,0 @@
|
||||
From c70811d9e6234c96d0ef405cd8ad78b70efb8637 Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Sat, 16 Apr 2016 13:59:02 -0700
|
||||
Subject: [PATCH 09/27] apparmor: fix put() parent ref after updating the
|
||||
active ref
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
Acked-by: Seth Arnold <seth.arnold@canonical.com>
|
||||
---
|
||||
security/apparmor/policy.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
|
||||
index c92a9f6..455c9f8 100644
|
||||
--- a/security/apparmor/policy.c
|
||||
+++ b/security/apparmor/policy.c
|
||||
@@ -1187,8 +1187,8 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
|
||||
/* parent replaced in this atomic set? */
|
||||
if (newest != parent) {
|
||||
aa_get_profile(newest);
|
||||
- aa_put_profile(parent);
|
||||
rcu_assign_pointer(ent->new->parent, newest);
|
||||
+ aa_put_profile(parent);
|
||||
}
|
||||
/* aafs interface uses replacedby */
|
||||
rcu_assign_pointer(ent->new->replacedby->profile,
|
||||
--
|
||||
2.7.4
|
||||
|
@@ -1,87 +0,0 @@
|
||||
From f671b902943f83f0fbc8c8b7bf8bbfb817d124f1 Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Sat, 16 Apr 2016 14:16:50 -0700
|
||||
Subject: [PATCH 10/27] apparmor: fix log failures for all profiles in a set
|
||||
|
||||
currently only the profile that is causing the failure is logged. This
|
||||
makes it more confusing than necessary about which profiles loaded
|
||||
and which didn't. So make sure to log success and failure messages for
|
||||
all profiles in the set being loaded.
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
Acked-by: Seth Arnold <seth.arnold@canonical.com>
|
||||
---
|
||||
security/apparmor/policy.c | 29 +++++++++++++++++++----------
|
||||
1 file changed, 19 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
|
||||
index 455c9f8..db31bc5 100644
|
||||
--- a/security/apparmor/policy.c
|
||||
+++ b/security/apparmor/policy.c
|
||||
@@ -1067,7 +1067,7 @@ static int __lookup_replace(struct aa_namespace *ns, const char *hname,
|
||||
*/
|
||||
ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
|
||||
{
|
||||
- const char *ns_name, *name = NULL, *info = NULL;
|
||||
+ const char *ns_name, *info = NULL;
|
||||
struct aa_namespace *ns = NULL;
|
||||
struct aa_load_ent *ent, *tmp;
|
||||
int op = OP_PROF_REPL;
|
||||
@@ -1082,18 +1082,15 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
|
||||
/* released below */
|
||||
ns = aa_prepare_namespace(ns_name);
|
||||
if (!ns) {
|
||||
- info = "failed to prepare namespace";
|
||||
- error = -ENOMEM;
|
||||
- name = ns_name;
|
||||
- goto fail;
|
||||
+ error = audit_policy(op, GFP_KERNEL, ns_name,
|
||||
+ "failed to prepare namespace", -ENOMEM);
|
||||
+ goto free;
|
||||
}
|
||||
|
||||
mutex_lock(&ns->lock);
|
||||
/* setup parent and ns info */
|
||||
list_for_each_entry(ent, &lh, list) {
|
||||
struct aa_policy *policy;
|
||||
-
|
||||
- name = ent->new->base.hname;
|
||||
error = __lookup_replace(ns, ent->new->base.hname, noreplace,
|
||||
&ent->old, &info);
|
||||
if (error)
|
||||
@@ -1121,7 +1118,6 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
|
||||
if (!p) {
|
||||
error = -ENOENT;
|
||||
info = "parent does not exist";
|
||||
- name = ent->new->base.hname;
|
||||
goto fail_lock;
|
||||
}
|
||||
rcu_assign_pointer(ent->new->parent, aa_get_profile(p));
|
||||
@@ -1214,9 +1210,22 @@ out:
|
||||
|
||||
fail_lock:
|
||||
mutex_unlock(&ns->lock);
|
||||
-fail:
|
||||
- error = audit_policy(op, GFP_KERNEL, name, info, error);
|
||||
|
||||
+ /* audit cause of failure */
|
||||
+ op = (!ent->old) ? OP_PROF_LOAD : OP_PROF_REPL;
|
||||
+ audit_policy(op, GFP_KERNEL, ent->new->base.hname, info, error);
|
||||
+ /* audit status that rest of profiles in the atomic set failed too */
|
||||
+ info = "valid profile in failed atomic policy load";
|
||||
+ list_for_each_entry(tmp, &lh, list) {
|
||||
+ if (tmp == ent) {
|
||||
+ info = "unchecked profile in failed atomic policy load";
|
||||
+ /* skip entry that caused failure */
|
||||
+ continue;
|
||||
+ }
|
||||
+ op = (!ent->old) ? OP_PROF_LOAD : OP_PROF_REPL;
|
||||
+ audit_policy(op, GFP_KERNEL, tmp->new->base.hname, info, error);
|
||||
+ }
|
||||
+free:
|
||||
list_for_each_entry_safe(ent, tmp, &lh, list) {
|
||||
list_del_init(&ent->list);
|
||||
aa_load_ent_free(ent);
|
||||
--
|
||||
2.7.4
|
||||
|
@@ -1,33 +0,0 @@
|
||||
From bc3c7d342bf53afdfdf46bc92dac5c624c89fb91 Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Sat, 16 Apr 2016 14:19:38 -0700
|
||||
Subject: [PATCH 11/27] apparmor: fix audit full profile hname on successful
|
||||
load
|
||||
|
||||
Currently logging of a successful profile load only logs the basename
|
||||
of the profile. This can result in confusion when a child profile has
|
||||
the same name as the another profile in the set. Logging the hname
|
||||
will ensure there is no confusion.
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
Acked-by: Seth Arnold <seth.arnold@canonical.com>
|
||||
---
|
||||
security/apparmor/policy.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
|
||||
index db31bc5..ca402d0 100644
|
||||
--- a/security/apparmor/policy.c
|
||||
+++ b/security/apparmor/policy.c
|
||||
@@ -1159,7 +1159,7 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
|
||||
list_del_init(&ent->list);
|
||||
op = (!ent->old && !ent->rename) ? OP_PROF_LOAD : OP_PROF_REPL;
|
||||
|
||||
- audit_policy(op, GFP_ATOMIC, ent->new->base.name, NULL, error);
|
||||
+ audit_policy(op, GFP_ATOMIC, ent->new->base.hname, NULL, error);
|
||||
|
||||
if (ent->old) {
|
||||
__replace_profile(ent->old, ent->new, 1);
|
||||
--
|
||||
2.7.4
|
||||
|
@@ -1,112 +0,0 @@
|
||||
From 848da0479e5b9da3dc2ae4c64e0cca77a0abf02a Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Wed, 20 Apr 2016 14:18:18 -0700
|
||||
Subject: [PATCH 12/27] apparmor: ensure the target profile name is always
|
||||
audited
|
||||
|
||||
The target profile name was not being correctly audited in a few
|
||||
cases because the target variable was not being set and gotos
|
||||
passed the code to set it at apply:
|
||||
|
||||
Since it is always based on new_profile just drop the target var
|
||||
and conditionally report based on new_profile.
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
Acked-by: Seth Arnold <seth.arnold@canonical.com>
|
||||
---
|
||||
security/apparmor/domain.c | 20 +++++++++-----------
|
||||
1 file changed, 9 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
|
||||
index 67a7418..fc3036b 100644
|
||||
--- a/security/apparmor/domain.c
|
||||
+++ b/security/apparmor/domain.c
|
||||
@@ -346,7 +346,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
|
||||
file_inode(bprm->file)->i_uid,
|
||||
file_inode(bprm->file)->i_mode
|
||||
};
|
||||
- const char *name = NULL, *target = NULL, *info = NULL;
|
||||
+ const char *name = NULL, *info = NULL;
|
||||
int error = 0;
|
||||
|
||||
if (bprm->cred_prepared)
|
||||
@@ -399,6 +399,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
|
||||
if (cxt->onexec) {
|
||||
struct file_perms cp;
|
||||
info = "change_profile onexec";
|
||||
+ new_profile = aa_get_newest_profile(cxt->onexec);
|
||||
if (!(perms.allow & AA_MAY_ONEXEC))
|
||||
goto audit;
|
||||
|
||||
@@ -413,7 +414,6 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
|
||||
|
||||
if (!(cp.allow & AA_MAY_ONEXEC))
|
||||
goto audit;
|
||||
- new_profile = aa_get_newest_profile(cxt->onexec);
|
||||
goto apply;
|
||||
}
|
||||
|
||||
@@ -445,10 +445,8 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
|
||||
if (!new_profile) {
|
||||
error = -ENOMEM;
|
||||
info = "could not create null profile";
|
||||
- } else {
|
||||
+ } else
|
||||
error = -EACCES;
|
||||
- target = new_profile->base.hname;
|
||||
- }
|
||||
perms.xindex |= AA_X_UNSAFE;
|
||||
} else
|
||||
/* fail exec */
|
||||
@@ -459,7 +457,6 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
|
||||
* fail the exec.
|
||||
*/
|
||||
if (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) {
|
||||
- aa_put_profile(new_profile);
|
||||
error = -EPERM;
|
||||
goto cleanup;
|
||||
}
|
||||
@@ -474,10 +471,8 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
|
||||
|
||||
if (bprm->unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
|
||||
error = may_change_ptraced_domain(new_profile);
|
||||
- if (error) {
|
||||
- aa_put_profile(new_profile);
|
||||
+ if (error)
|
||||
goto audit;
|
||||
- }
|
||||
}
|
||||
|
||||
/* Determine if secure exec is needed.
|
||||
@@ -498,7 +493,6 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
|
||||
bprm->unsafe |= AA_SECURE_X_NEEDED;
|
||||
}
|
||||
apply:
|
||||
- target = new_profile->base.hname;
|
||||
/* when transitioning profiles clear unsafe personality bits */
|
||||
bprm->per_clear |= PER_CLEAR_ON_SETID;
|
||||
|
||||
@@ -506,15 +500,19 @@ x_clear:
|
||||
aa_put_profile(cxt->profile);
|
||||
/* transfer new profile reference will be released when cxt is freed */
|
||||
cxt->profile = new_profile;
|
||||
+ new_profile = NULL;
|
||||
|
||||
/* clear out all temporary/transitional state from the context */
|
||||
aa_clear_task_cxt_trans(cxt);
|
||||
|
||||
audit:
|
||||
error = aa_audit_file(profile, &perms, GFP_KERNEL, OP_EXEC, MAY_EXEC,
|
||||
- name, target, cond.uid, info, error);
|
||||
+ name,
|
||||
+ new_profile ? new_profile->base.hname : NULL,
|
||||
+ cond.uid, info, error);
|
||||
|
||||
cleanup:
|
||||
+ aa_put_profile(new_profile);
|
||||
aa_put_profile(profile);
|
||||
kfree(buffer);
|
||||
|
||||
--
|
||||
2.7.4
|
||||
|
@@ -1,27 +0,0 @@
|
||||
From 706473f3ead5cdffe5ad159adfbc090e0fda81d6 Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Thu, 17 Mar 2016 12:02:54 -0700
|
||||
Subject: [PATCH 13/27] apparmor: check that xindex is in trans_table bounds
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
Acked-by: Seth Arnold <seth.arnold@canonical.com>
|
||||
---
|
||||
security/apparmor/policy_unpack.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
|
||||
index a689f10..c841b12 100644
|
||||
--- a/security/apparmor/policy_unpack.c
|
||||
+++ b/security/apparmor/policy_unpack.c
|
||||
@@ -676,7 +676,7 @@ static bool verify_xindex(int xindex, int table_size)
|
||||
int index, xtype;
|
||||
xtype = xindex & AA_X_TYPE_MASK;
|
||||
index = xindex & AA_X_INDEX_MASK;
|
||||
- if (xtype == AA_X_TABLE && index > table_size)
|
||||
+ if (xtype == AA_X_TABLE && index >= table_size)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
--
|
||||
2.7.4
|
||||
|
@@ -1,27 +0,0 @@
|
||||
From 05a64c434466029b298ee1e78a988cd6a7f80c0e Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Wed, 18 Nov 2015 11:41:05 -0800
|
||||
Subject: [PATCH 14/27] apparmor: fix ref count leak when profile sha1 hash is
|
||||
read
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
Acked-by: Seth Arnold <seth.arnold@canonical.com>
|
||||
---
|
||||
security/apparmor/apparmorfs.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
|
||||
index 45a6199..0d8dd71 100644
|
||||
--- a/security/apparmor/apparmorfs.c
|
||||
+++ b/security/apparmor/apparmorfs.c
|
||||
@@ -331,6 +331,7 @@ static int aa_fs_seq_hash_show(struct seq_file *seq, void *v)
|
||||
seq_printf(seq, "%.2x", profile->hash[i]);
|
||||
seq_puts(seq, "\n");
|
||||
}
|
||||
+ aa_put_profile(profile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
--
|
||||
2.7.4
|
||||
|
@@ -1,37 +0,0 @@
|
||||
From 6b0b8b91f454bd021e27abe0e611a6764e4806c1 Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Wed, 16 Dec 2015 18:09:10 -0800
|
||||
Subject: [PATCH 15/27] apparmor: fix refcount race when finding a child
|
||||
profile
|
||||
|
||||
When finding a child profile via an rcu critical section, the profile
|
||||
may be put and scheduled for deletion after the child is found but
|
||||
before its refcount is incremented.
|
||||
|
||||
Protect against this by repeating the lookup if the profiles refcount
|
||||
is 0 and is one its way to deletion.
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
Acked-by: Seth Arnold <seth.arnold@canonical.com>
|
||||
---
|
||||
security/apparmor/policy.c | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
|
||||
index ca402d0..7807125 100644
|
||||
--- a/security/apparmor/policy.c
|
||||
+++ b/security/apparmor/policy.c
|
||||
@@ -766,7 +766,9 @@ struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name)
|
||||
struct aa_profile *profile;
|
||||
|
||||
rcu_read_lock();
|
||||
- profile = aa_get_profile(__find_child(&parent->base.profiles, name));
|
||||
+ do {
|
||||
+ profile = __find_child(&parent->base.profiles, name);
|
||||
+ } while (profile && !aa_get_profile_not0(profile));
|
||||
rcu_read_unlock();
|
||||
|
||||
/* refcount released by caller */
|
||||
--
|
||||
2.7.4
|
||||
|
@@ -1,59 +0,0 @@
|
||||
From 84acc6aa6976e62756e14d3a00c5634724cbaa59 Mon Sep 17 00:00:00 2001
|
||||
From: Geliang Tang <geliangtang@163.com>
|
||||
Date: Mon, 16 Nov 2015 21:46:33 +0800
|
||||
Subject: [PATCH 16/27] apparmor: use list_next_entry instead of
|
||||
list_entry_next
|
||||
|
||||
list_next_entry has been defined in list.h, so I replace list_entry_next
|
||||
with it.
|
||||
|
||||
Signed-off-by: Geliang Tang <geliangtang@163.com>
|
||||
Acked-by: Serge Hallyn <serge.hallyn@canonical.com>
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
---
|
||||
security/apparmor/apparmorfs.c | 8 +++-----
|
||||
1 file changed, 3 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
|
||||
index 0d8dd71..729e595 100644
|
||||
--- a/security/apparmor/apparmorfs.c
|
||||
+++ b/security/apparmor/apparmorfs.c
|
||||
@@ -553,8 +553,6 @@ fail2:
|
||||
}
|
||||
|
||||
|
||||
-#define list_entry_next(pos, member) \
|
||||
- list_entry(pos->member.next, typeof(*pos), member)
|
||||
#define list_entry_is_head(pos, head, member) (&pos->member == (head))
|
||||
|
||||
/**
|
||||
@@ -585,7 +583,7 @@ static struct aa_namespace *__next_namespace(struct aa_namespace *root,
|
||||
parent = ns->parent;
|
||||
while (ns != root) {
|
||||
mutex_unlock(&ns->lock);
|
||||
- next = list_entry_next(ns, base.list);
|
||||
+ next = list_next_entry(ns, base.list);
|
||||
if (!list_entry_is_head(next, &parent->sub_ns, base.list)) {
|
||||
mutex_lock(&next->lock);
|
||||
return next;
|
||||
@@ -639,7 +637,7 @@ static struct aa_profile *__next_profile(struct aa_profile *p)
|
||||
parent = rcu_dereference_protected(p->parent,
|
||||
mutex_is_locked(&p->ns->lock));
|
||||
while (parent) {
|
||||
- p = list_entry_next(p, base.list);
|
||||
+ p = list_next_entry(p, base.list);
|
||||
if (!list_entry_is_head(p, &parent->base.profiles, base.list))
|
||||
return p;
|
||||
p = parent;
|
||||
@@ -648,7 +646,7 @@ static struct aa_profile *__next_profile(struct aa_profile *p)
|
||||
}
|
||||
|
||||
/* is next another profile in the namespace */
|
||||
- p = list_entry_next(p, base.list);
|
||||
+ p = list_next_entry(p, base.list);
|
||||
if (!list_entry_is_head(p, &ns->base.profiles, base.list))
|
||||
return p;
|
||||
|
||||
--
|
||||
2.7.4
|
||||
|
@@ -1,50 +0,0 @@
|
||||
From a3896605318b86d8cf288c122e03604e349d5dd7 Mon Sep 17 00:00:00 2001
|
||||
From: Jeff Mahoney <jeffm@suse.com>
|
||||
Date: Fri, 6 Nov 2015 15:17:30 -0500
|
||||
Subject: [PATCH 17/27] apparmor: allow SYS_CAP_RESOURCE to be sufficient to
|
||||
prlimit another task
|
||||
|
||||
While using AppArmor, SYS_CAP_RESOURCE is insufficient to call prlimit
|
||||
on another task. The only other example of a AppArmor mediating access to
|
||||
another, already running, task (ignoring fork+exec) is ptrace.
|
||||
|
||||
The AppArmor model for ptrace is that one of the following must be true:
|
||||
1) The tracer is unconfined
|
||||
2) The tracer is in complain mode
|
||||
3) The tracer and tracee are confined by the same profile
|
||||
4) The tracer is confined but has SYS_CAP_PTRACE
|
||||
|
||||
1), 2, and 3) are already true for setrlimit.
|
||||
|
||||
We can match the ptrace model just by allowing CAP_SYS_RESOURCE.
|
||||
|
||||
We still test the values of the rlimit since it can always be overridden
|
||||
using a value that means unlimited for a particular resource.
|
||||
|
||||
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
---
|
||||
security/apparmor/resource.c | 6 ++++--
|
||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c
|
||||
index 748bf0c..67a6072 100644
|
||||
--- a/security/apparmor/resource.c
|
||||
+++ b/security/apparmor/resource.c
|
||||
@@ -101,9 +101,11 @@ int aa_task_setrlimit(struct aa_profile *profile, struct task_struct *task,
|
||||
/* TODO: extend resource control to handle other (non current)
|
||||
* profiles. AppArmor rules currently have the implicit assumption
|
||||
* that the task is setting the resource of a task confined with
|
||||
- * the same profile.
|
||||
+ * the same profile or that the task setting the resource of another
|
||||
+ * task has CAP_SYS_RESOURCE.
|
||||
*/
|
||||
- if (profile != task_profile ||
|
||||
+ if ((profile != task_profile &&
|
||||
+ aa_capable(profile, CAP_SYS_RESOURCE, 1)) ||
|
||||
(profile->rlimits.mask & (1 << resource) &&
|
||||
new_rlim->rlim_max > profile->rlimits.limits[resource].rlim_max))
|
||||
error = -EACCES;
|
||||
--
|
||||
2.7.4
|
||||
|
@@ -1,40 +0,0 @@
|
||||
From 6fdcc3cfecd4d89457036627d59ebe5154d094c5 Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Thu, 2 Jun 2016 02:37:02 -0700
|
||||
Subject: [PATCH 18/27] apparmor: add missing id bounds check on dfa
|
||||
verification
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
---
|
||||
security/apparmor/include/match.h | 1 +
|
||||
security/apparmor/match.c | 2 ++
|
||||
2 files changed, 3 insertions(+)
|
||||
|
||||
diff --git a/security/apparmor/include/match.h b/security/apparmor/include/match.h
|
||||
index 001c43a..a1c04fe 100644
|
||||
--- a/security/apparmor/include/match.h
|
||||
+++ b/security/apparmor/include/match.h
|
||||
@@ -62,6 +62,7 @@ struct table_set_header {
|
||||
#define YYTD_ID_ACCEPT2 6
|
||||
#define YYTD_ID_NXT 7
|
||||
#define YYTD_ID_TSIZE 8
|
||||
+#define YYTD_ID_MAX 8
|
||||
|
||||
#define YYTD_DATA8 1
|
||||
#define YYTD_DATA16 2
|
||||
diff --git a/security/apparmor/match.c b/security/apparmor/match.c
|
||||
index 727eb42..f9f57c6 100644
|
||||
--- a/security/apparmor/match.c
|
||||
+++ b/security/apparmor/match.c
|
||||
@@ -47,6 +47,8 @@ static struct table_header *unpack_table(char *blob, size_t bsize)
|
||||
* it every time we use td_id as an index
|
||||
*/
|
||||
th.td_id = be16_to_cpu(*(u16 *) (blob)) - 1;
|
||||
+ if (th.td_id > YYTD_ID_MAX)
|
||||
+ goto out;
|
||||
th.td_flags = be16_to_cpu(*(u16 *) (blob + 2));
|
||||
th.td_lolen = be32_to_cpu(*(u32 *) (blob + 8));
|
||||
blob += sizeof(struct table_header);
|
||||
--
|
||||
2.7.4
|
||||
|
@@ -1,38 +0,0 @@
|
||||
From 95d203cfb59627a86483a279ba82f1aa75297e07 Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Wed, 15 Jun 2016 09:57:55 +0300
|
||||
Subject: [PATCH 19/27] apparmor: don't check for vmalloc_addr if kvzalloc()
|
||||
failed
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
---
|
||||
security/apparmor/match.c | 10 +++++-----
|
||||
1 file changed, 5 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/security/apparmor/match.c b/security/apparmor/match.c
|
||||
index f9f57c6..32b72eb 100644
|
||||
--- a/security/apparmor/match.c
|
||||
+++ b/security/apparmor/match.c
|
||||
@@ -75,14 +75,14 @@ static struct table_header *unpack_table(char *blob, size_t bsize)
|
||||
u32, be32_to_cpu);
|
||||
else
|
||||
goto fail;
|
||||
+ /* if table was vmalloced make sure the page tables are synced
|
||||
+ * before it is used, as it goes live to all cpus.
|
||||
+ */
|
||||
+ if (is_vmalloc_addr(table))
|
||||
+ vm_unmap_aliases();
|
||||
}
|
||||
|
||||
out:
|
||||
- /* if table was vmalloced make sure the page tables are synced
|
||||
- * before it is used, as it goes live to all cpus.
|
||||
- */
|
||||
- if (is_vmalloc_addr(table))
|
||||
- vm_unmap_aliases();
|
||||
return table;
|
||||
fail:
|
||||
kvfree(table);
|
||||
--
|
||||
2.7.4
|
||||
|
@@ -1,33 +0,0 @@
|
||||
From e925f976c7a9c85455f67c360671254bac2d9a91 Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Wed, 15 Jun 2016 10:00:55 +0300
|
||||
Subject: [PATCH 20/27] apparmor: fix oops in profile_unpack() when policy_db
|
||||
is not present
|
||||
|
||||
BugLink: http://bugs.launchpad.net/bugs/1592547
|
||||
|
||||
If unpack_dfa() returns NULL due to the dfa not being present,
|
||||
profile_unpack() is not checking if the dfa is not present (NULL).
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
---
|
||||
security/apparmor/policy_unpack.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
|
||||
index c841b12..dac2121 100644
|
||||
--- a/security/apparmor/policy_unpack.c
|
||||
+++ b/security/apparmor/policy_unpack.c
|
||||
@@ -583,6 +583,9 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
|
||||
error = PTR_ERR(profile->policy.dfa);
|
||||
profile->policy.dfa = NULL;
|
||||
goto fail;
|
||||
+ } else if (!profile->policy.dfa) {
|
||||
+ error = -EPROTO;
|
||||
+ goto fail;
|
||||
}
|
||||
if (!unpack_u32(e, &profile->policy.start[0], "start"))
|
||||
/* default start state */
|
||||
--
|
||||
2.7.4
|
||||
|
@@ -1,162 +0,0 @@
|
||||
From 45774028820fe2ffbbc94667165f04749821d529 Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Wed, 22 Jun 2016 18:01:08 -0700
|
||||
Subject: [PATCH 21/27] apparmor: fix module parameters can be changed after
|
||||
policy is locked
|
||||
|
||||
the policy_lock parameter is a one way switch that prevents policy
|
||||
from being further modified. Unfortunately some of the module parameters
|
||||
can effectively modify policy by turning off enforcement.
|
||||
|
||||
split policy_admin_capable into a view check and a full admin check,
|
||||
and update the admin check to test the policy_lock parameter.
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
---
|
||||
security/apparmor/include/policy.h | 2 ++
|
||||
security/apparmor/lsm.c | 22 ++++++++++------------
|
||||
security/apparmor/policy.c | 18 +++++++++++++++++-
|
||||
3 files changed, 29 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
|
||||
index c28b0f2..52275f0 100644
|
||||
--- a/security/apparmor/include/policy.h
|
||||
+++ b/security/apparmor/include/policy.h
|
||||
@@ -403,6 +403,8 @@ static inline int AUDIT_MODE(struct aa_profile *profile)
|
||||
return profile->audit;
|
||||
}
|
||||
|
||||
+bool policy_view_capable(void);
|
||||
+bool policy_admin_capable(void);
|
||||
bool aa_may_manage_policy(int op);
|
||||
|
||||
#endif /* __AA_POLICY_H */
|
||||
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
|
||||
index 5ee8201..bd40b12 100644
|
||||
--- a/security/apparmor/lsm.c
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -751,51 +751,49 @@ __setup("apparmor=", apparmor_enabled_setup);
|
||||
/* set global flag turning off the ability to load policy */
|
||||
static int param_set_aalockpolicy(const char *val, const struct kernel_param *kp)
|
||||
{
|
||||
- if (!capable(CAP_MAC_ADMIN))
|
||||
+ if (!policy_admin_capable())
|
||||
return -EPERM;
|
||||
- if (aa_g_lock_policy)
|
||||
- return -EACCES;
|
||||
return param_set_bool(val, kp);
|
||||
}
|
||||
|
||||
static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp)
|
||||
{
|
||||
- if (!capable(CAP_MAC_ADMIN))
|
||||
+ if (!policy_view_capable())
|
||||
return -EPERM;
|
||||
return param_get_bool(buffer, kp);
|
||||
}
|
||||
|
||||
static int param_set_aabool(const char *val, const struct kernel_param *kp)
|
||||
{
|
||||
- if (!capable(CAP_MAC_ADMIN))
|
||||
+ if (!policy_admin_capable())
|
||||
return -EPERM;
|
||||
return param_set_bool(val, kp);
|
||||
}
|
||||
|
||||
static int param_get_aabool(char *buffer, const struct kernel_param *kp)
|
||||
{
|
||||
- if (!capable(CAP_MAC_ADMIN))
|
||||
+ if (!policy_view_capable())
|
||||
return -EPERM;
|
||||
return param_get_bool(buffer, kp);
|
||||
}
|
||||
|
||||
static int param_set_aauint(const char *val, const struct kernel_param *kp)
|
||||
{
|
||||
- if (!capable(CAP_MAC_ADMIN))
|
||||
+ if (!policy_admin_capable())
|
||||
return -EPERM;
|
||||
return param_set_uint(val, kp);
|
||||
}
|
||||
|
||||
static int param_get_aauint(char *buffer, const struct kernel_param *kp)
|
||||
{
|
||||
- if (!capable(CAP_MAC_ADMIN))
|
||||
+ if (!policy_view_capable())
|
||||
return -EPERM;
|
||||
return param_get_uint(buffer, kp);
|
||||
}
|
||||
|
||||
static int param_get_audit(char *buffer, struct kernel_param *kp)
|
||||
{
|
||||
- if (!capable(CAP_MAC_ADMIN))
|
||||
+ if (!policy_view_capable())
|
||||
return -EPERM;
|
||||
|
||||
if (!apparmor_enabled)
|
||||
@@ -807,7 +805,7 @@ static int param_get_audit(char *buffer, struct kernel_param *kp)
|
||||
static int param_set_audit(const char *val, struct kernel_param *kp)
|
||||
{
|
||||
int i;
|
||||
- if (!capable(CAP_MAC_ADMIN))
|
||||
+ if (!policy_admin_capable())
|
||||
return -EPERM;
|
||||
|
||||
if (!apparmor_enabled)
|
||||
@@ -828,7 +826,7 @@ static int param_set_audit(const char *val, struct kernel_param *kp)
|
||||
|
||||
static int param_get_mode(char *buffer, struct kernel_param *kp)
|
||||
{
|
||||
- if (!capable(CAP_MAC_ADMIN))
|
||||
+ if (!policy_admin_capable())
|
||||
return -EPERM;
|
||||
|
||||
if (!apparmor_enabled)
|
||||
@@ -840,7 +838,7 @@ static int param_get_mode(char *buffer, struct kernel_param *kp)
|
||||
static int param_set_mode(const char *val, struct kernel_param *kp)
|
||||
{
|
||||
int i;
|
||||
- if (!capable(CAP_MAC_ADMIN))
|
||||
+ if (!policy_admin_capable())
|
||||
return -EPERM;
|
||||
|
||||
if (!apparmor_enabled)
|
||||
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
|
||||
index 7807125..179e68d 100644
|
||||
--- a/security/apparmor/policy.c
|
||||
+++ b/security/apparmor/policy.c
|
||||
@@ -918,6 +918,22 @@ static int audit_policy(int op, gfp_t gfp, const char *name, const char *info,
|
||||
&sa, NULL);
|
||||
}
|
||||
|
||||
+bool policy_view_capable(void)
|
||||
+{
|
||||
+ struct user_namespace *user_ns = current_user_ns();
|
||||
+ bool response = false;
|
||||
+
|
||||
+ if (ns_capable(user_ns, CAP_MAC_ADMIN))
|
||||
+ response = true;
|
||||
+
|
||||
+ return response;
|
||||
+}
|
||||
+
|
||||
+bool policy_admin_capable(void)
|
||||
+{
|
||||
+ return policy_view_capable() && !aa_g_lock_policy;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* aa_may_manage_policy - can the current task manage policy
|
||||
* @op: the policy manipulation operation being done
|
||||
@@ -932,7 +948,7 @@ bool aa_may_manage_policy(int op)
|
||||
return 0;
|
||||
}
|
||||
|
||||
- if (!capable(CAP_MAC_ADMIN)) {
|
||||
+ if (!policy_admin_capable()) {
|
||||
audit_policy(op, GFP_KERNEL, NULL, "not policy admin", -EACCES);
|
||||
return 0;
|
||||
}
|
||||
--
|
||||
2.7.4
|
||||
|
@@ -1,31 +0,0 @@
|
||||
From 7fcfc22cd04261ac35a579c99bcc804db7eb3e83 Mon Sep 17 00:00:00 2001
|
||||
From: Heinrich Schuchardt <xypron.glpk@gmx.de>
|
||||
Date: Fri, 10 Jun 2016 23:34:26 +0200
|
||||
Subject: [PATCH 22/27] apparmor: do not expose kernel stack
|
||||
|
||||
Do not copy uninitalized fields th.td_hilen, th.td_data.
|
||||
|
||||
Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
---
|
||||
security/apparmor/match.c | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/security/apparmor/match.c b/security/apparmor/match.c
|
||||
index 32b72eb..3f900fc 100644
|
||||
--- a/security/apparmor/match.c
|
||||
+++ b/security/apparmor/match.c
|
||||
@@ -63,7 +63,9 @@ static struct table_header *unpack_table(char *blob, size_t bsize)
|
||||
|
||||
table = kvzalloc(tsize);
|
||||
if (table) {
|
||||
- *table = th;
|
||||
+ table->td_id = th.td_id;
|
||||
+ table->td_flags = th.td_flags;
|
||||
+ table->td_lolen = th.td_lolen;
|
||||
if (th.td_flags == YYTD_DATA8)
|
||||
UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
|
||||
u8, byte_to_byte);
|
||||
--
|
||||
2.7.4
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user