mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-31 14:25:52 +00:00
Compare commits
160 Commits
v4.0.0-bet
...
v2.13.2
Author | SHA1 | Date | |
---|---|---|---|
|
af4808b5f6 | ||
|
f811fa9951 | ||
|
a68e6426f4 | ||
|
7356f51425 | ||
|
ef21e9ded7 | ||
|
1a0016ff17 | ||
|
3607865b18 | ||
|
597e17eb67 | ||
|
7dce58987f | ||
|
c044757de9 | ||
|
6249579842 | ||
|
37edb354ff | ||
|
b8dc8d1394 | ||
|
1f2eb0bbbf | ||
|
2296c30af5 | ||
|
aa328cb058 | ||
|
1d183660d5 | ||
|
7b07832459 | ||
|
b6c96f3933 | ||
|
ad236a59b8 | ||
|
f8b95d036d | ||
|
f4d7f8ae57 | ||
|
1b32d764ef | ||
|
dd4c2b05ea | ||
|
314617014a | ||
|
41ff006f3d | ||
|
7fc843d8d0 | ||
|
fc18647fba | ||
|
064521c236 | ||
|
566ad1fefa | ||
|
8def66134d | ||
|
8661ebcb79 | ||
|
3ee32c7ed7 | ||
|
9687b44842 | ||
|
fac1e427f1 | ||
|
37d176e72f | ||
|
6f70502ad1 | ||
|
37e64d99d1 | ||
|
e17d974330 | ||
|
1f884d7612 | ||
|
2e922a9a9b | ||
|
6937123153 | ||
|
5df25d9077 | ||
|
095c9013a5 | ||
|
99f19fdc0f | ||
|
c1dc77347c | ||
|
514cabda19 | ||
|
9987a7ec9c | ||
|
149800201c | ||
|
ddfb5722c0 | ||
|
7b03af8210 | ||
|
f37e9b4e7f | ||
|
f64e0e79f8 | ||
|
bed6986bef | ||
|
a70c80a80f | ||
|
17d3831d2d | ||
|
6ab732ed38 | ||
|
ab91f7bfa3 | ||
|
420aea6262 | ||
|
b672900629 | ||
|
77ebda113e | ||
|
f18c39514c | ||
|
67c1eaff9d | ||
|
ca23b1af45 | ||
|
1742647862 | ||
|
b50888a6de | ||
|
f2a40bb530 | ||
|
803fef6cd9 | ||
|
732ed66f0a | ||
|
f6ee78d5b2 | ||
|
082274c10f | ||
|
734130abad | ||
|
b78e8edee0 | ||
|
fbb8486fe6 | ||
|
25aad109e1 | ||
|
859a16310b | ||
|
052820e648 | ||
|
5e4c68712f | ||
|
ddee796d70 | ||
|
9d841a2291 | ||
|
9cb010f746 | ||
|
645545048c | ||
|
540aa94418 | ||
|
affc7a9fb4 | ||
|
6f5c61e6af | ||
|
b86f313281 | ||
|
4167497738 | ||
|
5cc04694bf | ||
|
b54929b0e0 | ||
|
e0f7594c73 | ||
|
a17775b821 | ||
|
e97b1e732a | ||
|
bc133dd9b5 | ||
|
2f658e2422 | ||
|
730b346fde | ||
|
51a7041f85 | ||
|
d55b94642c | ||
|
8b79ce540c | ||
|
866aaa1687 | ||
|
08412a8a39 | ||
|
1f99202c26 | ||
|
14744e83a6 | ||
|
69800c435a | ||
|
50ae9a1884 | ||
|
e27df656f0 | ||
|
2bef2e23d1 | ||
|
ed1fd20aa9 | ||
|
ffb051db51 | ||
|
e45a46d47d | ||
|
f651633281 | ||
|
02ab39208b | ||
|
fac81098fa | ||
|
2fbb1ed2df | ||
|
65c1a6cae2 | ||
|
529985973d | ||
|
7349a9cb03 | ||
|
fb7a5983bc | ||
|
f4c722c739 | ||
|
267c18e725 | ||
|
41eae89869 | ||
|
e13569fecb | ||
|
1c570118ed | ||
|
ec0c5d470a | ||
|
925cf94cdc | ||
|
090e9986f1 | ||
|
2eb9ab0913 | ||
|
7f0aed7fb8 | ||
|
3abf501527 | ||
|
a5eeed7c63 | ||
|
5070ba61e1 | ||
|
82bd9a390d | ||
|
acb40969b5 | ||
|
7473044d41 | ||
|
56b8e16698 | ||
|
b3dfe3366a | ||
|
249b68c92e | ||
|
749d94297f | ||
|
8a8349d14d | ||
|
7cc2c0dfad | ||
|
bb0a9c76e3 | ||
|
b86917dc95 | ||
|
9d8b6f4dbd | ||
|
40ba8bf047 | ||
|
e24484c42e | ||
|
d9d3cae2aa | ||
|
35522677d3 | ||
|
90c0d2b3c3 | ||
|
0361997506 | ||
|
14f622bc2b | ||
|
a0b77b804b | ||
|
26a3351552 | ||
|
28586f7309 | ||
|
71d089b4fa | ||
|
9179b5cf17 | ||
|
21ffea57f6 | ||
|
313e0b4266 | ||
|
f2914da00a | ||
|
6801c0d0d0 | ||
|
2becda217b | ||
|
8e63137612 |
55
.gitignore
vendored
55
.gitignore
vendored
@@ -4,18 +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-load
|
||||
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
|
||||
@@ -29,10 +21,8 @@ parser/parser_yacc.h
|
||||
parser/pod2htm*.tmp
|
||||
parser/af_rule.o
|
||||
parser/af_unix.o
|
||||
parser/all_rule.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
|
||||
@@ -41,7 +31,6 @@ parser/libapparmor_re/hfa.o
|
||||
parser/libapparmor_re/libapparmor_re.a
|
||||
parser/libapparmor_re/parse.o
|
||||
parser/mount.o
|
||||
parser/mqueue.o
|
||||
parser/network.o
|
||||
parser/parser_alias.o
|
||||
parser/parser_common.o
|
||||
@@ -61,8 +50,6 @@ parser/profile.o
|
||||
parser/ptrace.o
|
||||
parser/rule.o
|
||||
parser/signal.o
|
||||
parser/userns.o
|
||||
parser/io_uring.o
|
||||
parser/*.7
|
||||
parser/*.5
|
||||
parser/*.8
|
||||
@@ -165,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,14 +163,8 @@ libraries/libapparmor/swig/python/test/test-suite.log
|
||||
libraries/libapparmor/swig/python/test/test_python.py
|
||||
libraries/libapparmor/swig/python/test/test_python.py.log
|
||||
libraries/libapparmor/swig/python/test/test_python.py.trs
|
||||
libraries/libapparmor/swig/ruby/LibAppArmor.so
|
||||
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.ruby
|
||||
libraries/libapparmor/swig/ruby/mkmf.log
|
||||
libraries/libapparmor/testsuite/.deps
|
||||
libraries/libapparmor/testsuite/.libs
|
||||
libraries/libapparmor/testsuite/Makefile
|
||||
@@ -210,22 +190,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
|
||||
@@ -240,10 +212,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
|
||||
@@ -254,40 +222,26 @@ 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/io_uring
|
||||
tests/regression/apparmor/link
|
||||
tests/regression/apparmor/link_subset
|
||||
tests/regression/apparmor/mkdir
|
||||
tests/regression/apparmor/mmap
|
||||
tests/regression/apparmor/mount
|
||||
tests/regression/apparmor/move_mount
|
||||
tests/regression/apparmor/named_pipe
|
||||
tests/regression/apparmor/net_finegrained_rcv
|
||||
tests/regression/apparmor/net_finegrained_snd
|
||||
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/posix_mq_rcv
|
||||
tests/regression/apparmor/posix_mq_snd
|
||||
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
|
||||
@@ -298,20 +252,11 @@ tests/regression/apparmor/syscall_setpriority
|
||||
tests/regression/apparmor/syscall_setscheduler
|
||||
tests/regression/apparmor/syscall_sysctl
|
||||
tests/regression/apparmor/sysctl_proc
|
||||
tests/regression/apparmor/sysv_mq_rcv
|
||||
tests/regression/apparmor/sysv_mq_snd
|
||||
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/userns
|
||||
tests/regression/apparmor/userns_setns
|
||||
tests/regression/apparmor/uservars.inc
|
||||
tests/regression/apparmor/xattrs
|
||||
tests/regression/apparmor/xattrs_profile
|
||||
tests/regression/apparmor/coredump
|
||||
**/__pycache__/
|
||||
*.orig
|
||||
|
166
.gitlab-ci.yml
166
.gitlab-ci.yml
@@ -1,166 +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 autoconf-archive 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/*"
|
||||
|
||||
.send-to-coverity: &send-to-coverity
|
||||
- curl https://scan.coverity.com/builds?project=$COVERITY_SCAN_PROJECT_NAME
|
||||
--form token=$COVERITY_SCAN_TOKEN --form email=$GITLAB_USER_EMAIL
|
||||
--form file=@$(ls apparmor-*-cov-int.tar.gz) --form version="$(git describe --tags)"
|
||||
--form description="$(git describe --tags) / $CI_COMMIT_TITLE / $CI_COMMIT_REF_NAME:$CI_PIPELINE_ID"
|
||||
|
||||
coverity:
|
||||
stage: .post
|
||||
extends:
|
||||
- .ubuntu-before_script
|
||||
only:
|
||||
refs:
|
||||
- master
|
||||
script:
|
||||
- apt-get install --no-install-recommends -y curl git texlive-latex-recommended
|
||||
- *install-c-build-deps
|
||||
- curl -o /tmp/cov-analysis-linux64.tgz https://scan.coverity.com/download/linux64
|
||||
--form project=$COVERITY_SCAN_PROJECT_NAME --form token=$COVERITY_SCAN_TOKEN
|
||||
- tar xfz /tmp/cov-analysis-linux64.tgz
|
||||
- COV_VERSION=$(ls -dt cov-analysis-linux64-* | head -1)
|
||||
- PATH=$PATH:$(pwd)/$COV_VERSION/bin
|
||||
- make coverity
|
||||
- *send-to-coverity
|
||||
artifacts:
|
||||
paths:
|
||||
- "apparmor-*.tar.gz"
|
@@ -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
|
8
Makefile
8
Makefile
@@ -19,7 +19,7 @@ DIRS=libraries/libapparmor \
|
||||
|
||||
# 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.13
|
||||
|
||||
COVERITY_DIR=cov-int
|
||||
RELEASE_DIR=apparmor-${VERSION}
|
||||
@@ -54,12 +54,12 @@ snapshot: clean
|
||||
.PHONY: coverity
|
||||
coverity: snapshot
|
||||
cd $(SNAPSHOT_NAME)/libraries/libapparmor && ./configure --with-python
|
||||
$(foreach dir, $(filter-out utils profiles tests, $(DIRS)), \
|
||||
cov-build --dir $(COVERITY_DIR) -- $(MAKE) -C $(SNAPSHOT_NAME)/$(dir); \
|
||||
mv $(COVERITY_DIR)/build-log.txt $(COVERITY_DIR)/build-log-$(subst /,.,$(dir)).txt ;)
|
||||
$(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
|
||||
|
69
README.md
69
README.md
@@ -35,33 +35,16 @@ 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
|
||||
-------------
|
||||
@@ -111,7 +94,7 @@ $ export PYTHON_VERSION=3
|
||||
$ export PYTHON_VERSIONS=python3
|
||||
```
|
||||
|
||||
### libapparmor:
|
||||
libapparmor:
|
||||
|
||||
```
|
||||
$ cd ./libraries/libapparmor
|
||||
@@ -126,7 +109,7 @@ $ make install
|
||||
generate Ruby bindings to libapparmor.]
|
||||
|
||||
|
||||
### Binary Utilities:
|
||||
Binary Utilities:
|
||||
|
||||
```
|
||||
$ cd binutils
|
||||
@@ -135,7 +118,7 @@ $ make check
|
||||
$ make install
|
||||
```
|
||||
|
||||
### Parser:
|
||||
parser:
|
||||
|
||||
```
|
||||
$ cd parser
|
||||
@@ -145,16 +128,16 @@ $ make install
|
||||
```
|
||||
|
||||
|
||||
### Utilities:
|
||||
Utilities:
|
||||
|
||||
```
|
||||
$ cd utils
|
||||
$ make
|
||||
$ make check PYFLAKES=/usr/bin/pyflakes3
|
||||
$ make check
|
||||
$ make install
|
||||
```
|
||||
|
||||
### Apache mod_apparmor:
|
||||
Apache mod_apparmor:
|
||||
|
||||
```
|
||||
$ cd changehat/mod_apparmor
|
||||
@@ -163,7 +146,7 @@ $ make install
|
||||
```
|
||||
|
||||
|
||||
### PAM AppArmor:
|
||||
PAM AppArmor:
|
||||
|
||||
```
|
||||
$ cd changehat/pam_apparmor
|
||||
@@ -172,7 +155,7 @@ $ make install
|
||||
```
|
||||
|
||||
|
||||
### Profiles:
|
||||
Profiles:
|
||||
|
||||
```
|
||||
$ cd profiles
|
||||
@@ -181,9 +164,6 @@ $ make check # depends on the parser having been built first
|
||||
$ make install
|
||||
```
|
||||
|
||||
Note that the empty local/* profile sniplets no longer get created by default.
|
||||
If you want them, run `make local` before running `make check`.
|
||||
|
||||
[Note that for the parser, binutils, and utils, if you only wish 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".]
|
||||
@@ -204,20 +184,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
|
||||
@@ -348,15 +314,10 @@ 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 (deprecated) or Python 3.3.
|
||||
Python 3.x is recommended. Python 2.x support is deprecated since AppArmor 2.11.
|
||||
|
||||
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.
|
||||
|
@@ -19,11 +19,11 @@ 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
|
||||
MANPAGES=aa-enabled.1 aa-exec.1
|
||||
|
||||
WARNINGS = -Wall
|
||||
EXTRA_WARNINGS = -Wsign-compare -Wmissing-field-initializers -Wformat-security -Wunused-parameter
|
||||
CPP_WARNINGS =
|
||||
ifndef CFLAGS
|
||||
CFLAGS = -g -O2 -pipe
|
||||
@@ -36,7 +36,7 @@ CFLAGS = -g -pg -fprofile-arcs -ftest-coverage
|
||||
endif
|
||||
endif #CFLAGS
|
||||
|
||||
EXTRA_CFLAGS = ${CFLAGS} ${CPPFLAGS} ${EXTRA_CXXFLAGS} ${CPP_WARNINGS} $(EXTRA_WARNINGS)
|
||||
EXTRA_CFLAGS = ${CFLAGS} ${CPPFLAGS} ${EXTRA_CXXFLAGS} ${CPP_WARNINGS}
|
||||
|
||||
#INCLUDEDIR = /usr/src/linux/include
|
||||
INCLUDEDIR =
|
||||
@@ -48,17 +48,12 @@ endif
|
||||
# Internationalization support. Define a package and a LOCALEDIR
|
||||
EXTRA_CFLAGS+=-DPACKAGE=\"${NAME}\" -DLOCALEDIR=\"${LOCALEDIR}\"
|
||||
|
||||
SRCS = aa_enabled.c aa_load.c
|
||||
SRCS = aa_enabled.c
|
||||
HDRS =
|
||||
BINTOOLS = aa-enabled aa-exec aa-features-abi
|
||||
SBINTOOLS = aa-status aa-load
|
||||
TOOLS = aa-enabled aa-exec
|
||||
|
||||
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 =
|
||||
@@ -98,7 +93,7 @@ po/%.pot: %.c
|
||||
|
||||
# targets arranged this way so that people who don't want full docs can
|
||||
# pick specific targets they want.
|
||||
arch: $(BINTOOLS) $(SBINTOOLS)
|
||||
arch: $(TOOLS)
|
||||
|
||||
manpages: $(MANPAGES)
|
||||
|
||||
@@ -111,7 +106,7 @@ all: arch indep
|
||||
|
||||
.PHONY: coverage
|
||||
coverage:
|
||||
$(MAKE) clean $(BINTOOLS) $(SBINTOOLS) COVERAGE=1
|
||||
$(MAKE) clean $(TOOLS) COVERAGE=1
|
||||
|
||||
ifndef USE_SYSTEM
|
||||
$(LIBAPPARMOR_A):
|
||||
@@ -123,30 +118,18 @@ $(LIBAPPARMOR_A):
|
||||
fi
|
||||
endif
|
||||
|
||||
aa-features-abi: aa_features_abi.c $(LIBAPPARMOR_A)
|
||||
$(CC) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $< $(LIBS) $(AALIB)
|
||||
|
||||
aa-load: aa_load.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)
|
||||
tests: $(TOOLS) $(TESTS)
|
||||
echo "no tests atm"
|
||||
|
||||
.PHONY: install
|
||||
@@ -155,16 +138,12 @@ 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}
|
||||
install -m 755 ${TOOLS} ${BINDIR}
|
||||
|
||||
.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
|
||||
@@ -173,6 +152,6 @@ endif
|
||||
clean: pod_clean
|
||||
rm -f core core.* *.o *.s *.a *~ *.gcda *.gcno
|
||||
rm -f gmon.out
|
||||
rm -f $(BINTOOLS) $(SBINTOOLS) $(TESTS)
|
||||
rm -f $(TOOLS) $(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
|
||||
@@ -81,10 +76,6 @@ if the AppArmor control files aren't available under /sys/kernel/security/.
|
||||
|
||||
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>
|
||||
|
||||
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
|
||||
|
||||
|
@@ -83,7 +83,7 @@ aa-exec.
|
||||
=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
|
@@ -20,7 +20,6 @@ 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);
|
||||
@@ -31,6 +30,8 @@ void print_help(const char *command)
|
||||
/* Exit statuses and meanings are documented in the aa-enabled.pod file */
|
||||
static void exit_with_error(int saved_errno, int quiet)
|
||||
{
|
||||
int err;
|
||||
|
||||
switch(saved_errno) {
|
||||
case ENOSYS:
|
||||
if (!quiet)
|
||||
@@ -49,11 +50,8 @@ static void exit_with_error(int saved_errno, int quiet)
|
||||
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);
|
||||
@@ -61,27 +59,22 @@ static void exit_with_error(int saved_errno, int quiet)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, enabled;
|
||||
int enabled;
|
||||
int quiet = 0;
|
||||
int require_shared = 0;
|
||||
|
||||
setlocale(LC_MESSAGES, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
if (argc > 3) {
|
||||
if (argc > 2) {
|
||||
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) {
|
||||
} else if (argc == 2) {
|
||||
if (strcmp(argv[1], "--quiet") == 0 ||
|
||||
strcmp(argv[1], "-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) {
|
||||
} else if (strcmp(argv[1], "--help") == 0 ||
|
||||
strcmp(argv[1], "-h") == 0) {
|
||||
print_help(argv[0]);
|
||||
} else {
|
||||
printf(_("unknown option '%s'\n"), argv[1]);
|
||||
@@ -90,10 +83,9 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
enabled = aa_is_enabled();
|
||||
if (!enabled) {
|
||||
if (require_shared || errno != EBUSY)
|
||||
exit_with_error(errno, quiet);
|
||||
}
|
||||
if (!enabled)
|
||||
exit_with_error(errno, quiet);
|
||||
|
||||
if (!quiet)
|
||||
printf(_("Yes\n"));
|
||||
exit(0);
|
||||
|
@@ -25,7 +25,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/apparmor.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#define _(s) gettext(s)
|
||||
|
||||
@@ -34,7 +33,6 @@ 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)
|
||||
{
|
||||
@@ -62,7 +60,7 @@ static void usage(const char *name, bool error)
|
||||
exit(status);
|
||||
}
|
||||
|
||||
#define error(fmt, args...) _error(_("[%ld] aa-exec: ERROR: " fmt "\n"), (long)pid, ## args)
|
||||
#define error(fmt, args...) _error(_("aa-exec: ERROR: " fmt "\n"), ## args)
|
||||
static void _error(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
@@ -73,7 +71,7 @@ static void _error(const char *fmt, ...)
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#define debug(fmt, args...) _debug(_("[%ld] aa-exec: DEBUG: " fmt "\n"), (long)pid, ## args)
|
||||
#define debug(fmt, args...) _debug(_("aa-exec: DEBUG: " fmt "\n"), ## args)
|
||||
static void _debug(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
@@ -86,7 +84,7 @@ static void _debug(const char *fmt, ...)
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
#define verbose(fmt, args...) _verbose(_("[%ld] " fmt "\n"), (long)pid, ## args)
|
||||
#define verbose(fmt, args...) _verbose(_(fmt "\n"), ## args)
|
||||
static void _verbose(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
@@ -104,7 +102,7 @@ static void verbose_print_argv(char **argv)
|
||||
if (!opt_verbose)
|
||||
return;
|
||||
|
||||
fprintf(stderr, _("[%ld] exec"), (long)pid);
|
||||
fprintf(stderr, _("exec"));
|
||||
for (; *argv; argv++)
|
||||
fprintf(stderr, " %s", *argv);
|
||||
fprintf(stderr, "\n");
|
||||
@@ -131,13 +129,9 @@ static char **parse_args(int argc, char **argv)
|
||||
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':
|
||||
@@ -189,11 +183,6 @@ 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)
|
||||
@@ -212,11 +201,8 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
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'",
|
||||
if (errno == ENOENT || errno == EACCES) {
|
||||
error("%s '%s' does not exist\n",
|
||||
opt_profile ? "profile" : "namespace", name);
|
||||
} else if (errno == EINVAL) {
|
||||
error("AppArmor interface not available");
|
||||
|
@@ -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,408 +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 <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <sys/apparmor.h>
|
||||
|
||||
#include <libintl.h>
|
||||
#define _(s) gettext(s)
|
||||
|
||||
/* TODO: implement config locations - value can change */
|
||||
#define DEFAULT_CONFIG_LOCATIONS "/etc/apparmor/parser.conf"
|
||||
#define DEFAULT_POLICY_LOCATIONS "/var/cache/apparmor:/etc/apparmor.d/cache.d:/etc/apparmor.d/cache"
|
||||
#define CACHE_FEATURES_FILE ".features"
|
||||
|
||||
bool opt_debug = false;
|
||||
bool opt_verbose = false;
|
||||
bool opt_dryrun = false;
|
||||
bool opt_force = false;
|
||||
bool opt_config = false;
|
||||
|
||||
#define warning(fmt, args...) _error(_("aa-load: WARN: " fmt "\n"), ## args)
|
||||
#define error(fmt, args...) _error(_("aa-load: ERROR: " fmt "\n"), ## args)
|
||||
static void _error(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
#define verbose(fmt, args...) _debug(opt_verbose, _(fmt "\n"), ## args)
|
||||
#define debug(fmt, args...) _debug(opt_debug, _("aa-load: DEBUG: " fmt "\n"), ## args)
|
||||
static void _debug(bool opt_displayit, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (!opt_displayit)
|
||||
return;
|
||||
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static int have_enough_privilege(const char *command)
|
||||
{
|
||||
uid_t uid, euid;
|
||||
|
||||
uid = getuid();
|
||||
euid = geteuid();
|
||||
|
||||
if (uid != 0 && euid != 0) {
|
||||
error("%s: Sorry. You need root privileges to run this program.\n",
|
||||
command);
|
||||
return EPERM;
|
||||
}
|
||||
|
||||
if (uid != 0 && euid == 0) {
|
||||
error("%s: Aborting! You've set this program setuid root.\n"
|
||||
"Anybody who can run this program can update "
|
||||
"your AppArmor profiles.\n", command);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int load_config(const char *file)
|
||||
{
|
||||
/* TODO */
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* load a single policy cache file to the kernel
|
||||
*/
|
||||
static int load_policy_file(const char *file)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
struct aa_kernel_interface *kernel_interface;
|
||||
|
||||
if (aa_kernel_interface_new(&kernel_interface, NULL, NULL)) {
|
||||
rc = -errno;
|
||||
error("Failed to open kernel interface '%s': %m", file);
|
||||
return rc;
|
||||
}
|
||||
if (!opt_dryrun &&
|
||||
aa_kernel_interface_replace_policy_from_file(kernel_interface,
|
||||
AT_FDCWD, file)) {
|
||||
rc = -errno;
|
||||
error("Failed to load policy into kernel '%s': %m", file);
|
||||
}
|
||||
aa_kernel_interface_unref(kernel_interface);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void validate_features(const char *dir_path)
|
||||
{
|
||||
aa_features *kernel_features;
|
||||
|
||||
if (aa_features_new_from_kernel(&kernel_features) == -1) {
|
||||
error("Failed to obtain features: %m");
|
||||
return;
|
||||
}
|
||||
|
||||
if (aa_features_check(AT_FDCWD, dir_path, kernel_features) == -1) {
|
||||
if (errno == ENOENT) {
|
||||
/* features file does not exist
|
||||
* not an issue when loading cache policies from dir
|
||||
*/
|
||||
}
|
||||
else if (errno == EEXIST) {
|
||||
warning("Overlay features do not match kernel features");
|
||||
}
|
||||
}
|
||||
aa_features_unref(kernel_features);
|
||||
}
|
||||
|
||||
/**
|
||||
* load a directory of policy cache files to the kernel
|
||||
* This does not do a subdir search to find the kernel match but
|
||||
* tries to load the dir regardless of whether its features match
|
||||
*
|
||||
* The hierarchy looks like
|
||||
*
|
||||
* dir/
|
||||
* .features
|
||||
* profile1
|
||||
* ...
|
||||
*/
|
||||
|
||||
static int load_policy_dir(const char *dir_path)
|
||||
{
|
||||
DIR *d;
|
||||
struct dirent *dir;
|
||||
int rc = 0;
|
||||
char *file;
|
||||
size_t len;
|
||||
|
||||
validate_features(dir_path);
|
||||
|
||||
d = opendir(dir_path);
|
||||
if (!d) {
|
||||
rc = -errno;
|
||||
error("Failed to open directory '%s': %m", dir_path);
|
||||
return rc;
|
||||
}
|
||||
|
||||
while ((dir = readdir(d)) != NULL) {
|
||||
/* Only check regular files for now */
|
||||
if (dir->d_type == DT_REG) {
|
||||
len = strnlen(dir->d_name, PATH_MAX);
|
||||
/* Ignores .features */
|
||||
if (strncmp(dir->d_name, CACHE_FEATURES_FILE, len) == 0) {
|
||||
continue;
|
||||
}
|
||||
if (asprintf(&file, "%s/%s", dir_path, dir->d_name) == -1) {
|
||||
error("Failure allocating memory");
|
||||
closedir(d);
|
||||
return -1;
|
||||
}
|
||||
load_policy_file(file);
|
||||
free(file);
|
||||
file = NULL;
|
||||
}
|
||||
}
|
||||
closedir(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* load_hashed_policy - find policy hashed dir and load it
|
||||
*
|
||||
* load/replace all policy from a policy hierarchy directory
|
||||
*
|
||||
* Returns: 0 on success < -errno
|
||||
*
|
||||
* It will find the subdir that matches the kernel and load all
|
||||
* precompiled policy files from it.
|
||||
*
|
||||
* The hierarchy looks something like
|
||||
*
|
||||
* location/
|
||||
* kernel_hash1.0/
|
||||
* .features
|
||||
* profile1
|
||||
* ...
|
||||
* kernel_hash2.0/
|
||||
* .features
|
||||
* profile1
|
||||
* ...
|
||||
*/
|
||||
static int load_policy_by_hash(const char *location)
|
||||
{
|
||||
aa_policy_cache *policy_cache = NULL;
|
||||
int rc;
|
||||
|
||||
if ((rc = aa_policy_cache_new(&policy_cache, NULL, AT_FDCWD, location, 0))) {
|
||||
rc = -errno;
|
||||
error("Failed to open policy cache '%s': %m", location);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (opt_debug) {
|
||||
/* show hash directory under location that matches the
|
||||
* current kernel
|
||||
*/
|
||||
char *cache_loc = aa_policy_cache_dir_path_preview(NULL, AT_FDCWD, location);
|
||||
if (!cache_loc) {
|
||||
rc = -errno;
|
||||
error("Failed to find cache location '%s': %m", location);
|
||||
goto out;
|
||||
}
|
||||
debug("Loading cache from '%s'\n", cache_loc);
|
||||
free(cache_loc);
|
||||
}
|
||||
|
||||
if (!opt_dryrun) {
|
||||
if ((rc = aa_policy_cache_replace_all(policy_cache, NULL)) < 0) {
|
||||
error("Failed to load policy cache '%s': %m", location);
|
||||
} else {
|
||||
verbose("Success - Loaded policy cache '%s'", location);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
aa_policy_cache_unref(policy_cache);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* load_arg - calls specific load functions for files and directories
|
||||
*
|
||||
* load/replace all policy files/dir in arg
|
||||
*
|
||||
* Returns: 0 on success, 1 on failure.
|
||||
*
|
||||
* It will load by hash subtree first, and fallback to a cache dir
|
||||
* If not a directory, it will try to load it as a cache file
|
||||
*/
|
||||
static int load_arg(char *arg)
|
||||
{
|
||||
char **location = NULL;
|
||||
int i, n, rc = 0;
|
||||
|
||||
|
||||
/* arg can specify an overlay of multiple cache locations */
|
||||
if ((n = aa_split_overlay_str(arg, &location, 0, true)) == -1) {
|
||||
error("Failed to parse overlay locations: %m");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
struct stat st;
|
||||
debug("Trying to open %s", location[i]);
|
||||
if (stat(location[i], &st) == -1) {
|
||||
error("Failed stat of '%s': %m", location[i]);
|
||||
rc = 1;
|
||||
continue;
|
||||
}
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
/* try hash dir subtree first */
|
||||
if (load_policy_by_hash(location[i]) < 0) {
|
||||
error("Failed load policy by hash '%s': %m", location[i]);
|
||||
rc = 1;
|
||||
}
|
||||
/* fall back to cache dir */
|
||||
if (load_policy_dir(location[i]) < 0) {
|
||||
error("Failed load policy by directory '%s': %m", location[i]);
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
} else if (load_policy_file(location[i]) < 0) {
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
free(location[i]);
|
||||
free(location);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void print_usage(const char *command)
|
||||
{
|
||||
printf("Usage: %s [OPTIONS] (cache file|cache dir|cache base dir)]*\n"
|
||||
"Load Precompiled AppArmor policy from a cache location or \n"
|
||||
"locations.\n\n"
|
||||
"Options:\n"
|
||||
" -f, --force load policy even if abi does not match the kernel\n"
|
||||
" -d, --debug display debug messages\n"
|
||||
" -v, --verbose display progress and error messages\n"
|
||||
" -n, --dry-run do everything except actual load\n"
|
||||
" -h, --help this message\n",
|
||||
command);
|
||||
}
|
||||
|
||||
static const char *short_options = "c:dfvnh";
|
||||
struct option long_options[] = {
|
||||
{"config", 1, 0, 'c'},
|
||||
{"debug", 0, 0, 'd'},
|
||||
{"force", 0, 0, 'f'},
|
||||
{"verbose", 0, 0, 'v'},
|
||||
{"dry-run", 0, 0, 'n'},
|
||||
{"help", 0, 0, 'h'},
|
||||
{NULL, 0, 0, 0},
|
||||
};
|
||||
|
||||
static int process_args(int argc, char **argv)
|
||||
{
|
||||
int c, o;
|
||||
|
||||
opterr = 1;
|
||||
while ((c = getopt_long(argc, argv, short_options, long_options, &o)) != -1) {
|
||||
switch(c) {
|
||||
case 0:
|
||||
error("error in argument processing\n");
|
||||
exit(1);
|
||||
break;
|
||||
case 'd':
|
||||
opt_debug = true;
|
||||
break;
|
||||
case 'f':
|
||||
opt_force = true;
|
||||
break;
|
||||
case 'v':
|
||||
opt_verbose = true;
|
||||
break;
|
||||
case 'n':
|
||||
opt_dryrun = true;
|
||||
break;
|
||||
case 'h':
|
||||
print_usage(argv[0]);
|
||||
exit(0);
|
||||
break;
|
||||
case 'c':
|
||||
/* TODO: reserved config location,
|
||||
* act as a bad arg for now, when added update usage
|
||||
*/
|
||||
//opt_config = true; uncomment when implemented
|
||||
/* Fall through */
|
||||
default:
|
||||
error("unknown argument: '%s'\n\n", optarg);
|
||||
print_usage(argv[1]);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return optind;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, rc = 0;
|
||||
|
||||
optind = process_args(argc, argv);
|
||||
|
||||
if (!opt_dryrun && have_enough_privilege(argv[0]))
|
||||
return 1;
|
||||
|
||||
/* if no location use the default one */
|
||||
if (optind == argc) {
|
||||
if (!opt_config && load_config(DEFAULT_CONFIG_LOCATIONS) == 0) {
|
||||
verbose("Loaded policy config");
|
||||
}
|
||||
if ((rc = load_arg(DEFAULT_POLICY_LOCATIONS)))
|
||||
verbose("Loading policy from default location '%s'", DEFAULT_POLICY_LOCATIONS);
|
||||
else
|
||||
debug("No policy specified, and no policy config or policy in default locations");
|
||||
}
|
||||
for (i = optind; i < argc; i++) {
|
||||
/* Try to load all policy locations even if one fails
|
||||
* but always return an error if any fail
|
||||
*/
|
||||
|
||||
int tmp = load_arg(argv[i]);
|
||||
if (!rc)
|
||||
rc = tmp;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
1095
binutils/aa_status.c
1095
binutils/aa_status.c
File diff suppressed because it is too large
Load Diff
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,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"
|
@@ -14,8 +14,8 @@ msgstr ""
|
||||
"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"
|
||||
"X-Launchpad-Export-Date: 2018-02-11 05:14+0000\n"
|
||||
"X-Generator: Launchpad (build 18544)\n"
|
||||
"Language: de\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
|
@@ -14,8 +14,8 @@ msgstr ""
|
||||
"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"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: en_GB\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
|
@@ -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"
|
@@ -14,8 +14,8 @@ msgstr ""
|
||||
"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"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: id\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
|
@@ -9,13 +9,13 @@ msgstr ""
|
||||
"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"
|
||||
"Last-Translator: Ivo Xavier <ivoxavier.8@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"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: pt\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
|
@@ -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"
|
@@ -9,13 +9,13 @@ msgstr ""
|
||||
"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"
|
||||
"Last-Translator: Eugene Marshal <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"
|
||||
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 18053)\n"
|
||||
"Language: ru\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
|
@@ -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"
|
@@ -70,8 +70,6 @@ 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)
|
||||
@@ -82,7 +80,7 @@ all: libapparmor_check $(TARGET) docs
|
||||
docs: ${MANPAGES} ${HTMLMANPAGES}
|
||||
|
||||
%.so: %.c
|
||||
${APXS} ${LIBAPPARMOR_FLAGS} ${APXS_CFLAGS} -c $< ${LDLIBS}
|
||||
${APXS} ${LIBAPPARMOR_FLAGS} -c $< ${LDLIBS}
|
||||
mv .libs/$@ .
|
||||
|
||||
.PHONY: install
|
||||
|
@@ -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
|
||||
|
@@ -54,7 +54,7 @@ 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)
|
||||
EXTRA_CFLAGS=$(CFLAGS) $(CPPFLAGS) -fPIC -shared -Wall $(LIBAPPARMOR_INCLUDE)
|
||||
LINK_FLAGS=-Xlinker -x $(AA_LINK_FLAGS) $(LDFLAGS)
|
||||
LIBS=-lpam $(AA_LDLIBS)
|
||||
OBJECTS=${NAME}.o get_options.o
|
||||
|
@@ -67,10 +67,10 @@ to syslog.
|
||||
References
|
||||
----------
|
||||
Project webpage:
|
||||
https://apparmor.net/
|
||||
http://developer.novell.com/wiki/index.php/Novell_AppArmor
|
||||
|
||||
To provide feedback or ask questions please contact the
|
||||
apparmor@lists.ubuntu.com mail list. This is the development list
|
||||
apparmor-dev@forge.novell.com mail list. This is the development list
|
||||
for the AppArmor team.
|
||||
|
||||
See also: change_hat(3), and the Linux-PAM online documentation at
|
||||
|
@@ -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.
|
||||
|
||||
|
||||
@@ -188,9 +188,10 @@ parent context.
|
||||
8. Feedback/Resources
|
||||
-----------------
|
||||
|
||||
Project webpage:
|
||||
https://apparmor.net/
|
||||
To provide feedback or ask questions please contact the
|
||||
apparmor-dev@forge.novell.com mail list. This is the development list for the
|
||||
AppArmor team.
|
||||
|
||||
|
||||
|
||||
|
||||
To provide feedback or ask questions please contact the
|
||||
apparmor@lists.ubuntu.com mail list. This is the development list
|
||||
for the AppArmor team.
|
||||
|
@@ -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.
|
||||
|
||||
|
||||
@@ -188,9 +188,10 @@ parent context.
|
||||
8. Feedback/Resources
|
||||
-----------------
|
||||
|
||||
Project webpage:
|
||||
https://apparmor.net/
|
||||
To provide feedback or ask questions please contact the
|
||||
apparmor-dev@forge.novell.com mail list. This is the development list for the
|
||||
AppArmor team.
|
||||
|
||||
|
||||
|
||||
|
||||
To provide feedback or ask questions please contact the
|
||||
apparmor@lists.ubuntu.com mail list. This is the development list
|
||||
for the AppArmor team.
|
||||
|
@@ -42,13 +42,12 @@ endif
|
||||
|
||||
define nl
|
||||
|
||||
|
||||
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
|
||||
@@ -58,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:
|
||||
@@ -87,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 @@
|
||||
4.0.0~beta2
|
||||
2.13.2
|
||||
|
@@ -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($_);
|
||||
}
|
Binary file not shown.
@@ -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 |
@@ -1,249 +0,0 @@
|
||||
From 02e2bc1b330f7e15dba671547a256a6f900f6e5d Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Sun, 17 Jun 2018 03:56:25 -0700
|
||||
Subject: [PATCH 1/3] apparmor: patch to provide compatibility with v2.x net
|
||||
rules
|
||||
|
||||
The networking rules upstreamed in 4.17 have a deliberate abi break
|
||||
with the older 2.x network rules.
|
||||
|
||||
This patch provides compatibility with the older rules for those
|
||||
still using an apparmor 2.x userspace and still want network rules
|
||||
to work on a newer kernel.
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
---
|
||||
security/apparmor/apparmorfs.c | 1 +
|
||||
security/apparmor/include/apparmor.h | 2 +-
|
||||
security/apparmor/include/net.h | 11 ++++++++
|
||||
security/apparmor/include/policy.h | 2 ++
|
||||
security/apparmor/net.c | 31 ++++++++++++++++-----
|
||||
security/apparmor/policy.c | 1 +
|
||||
security/apparmor/policy_unpack.c | 54 ++++++++++++++++++++++++++++++++++--
|
||||
7 files changed, 92 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
|
||||
index 1fdcc7d5a977..32f0e660ffd0 100644
|
||||
--- a/security/apparmor/apparmorfs.c
|
||||
+++ b/security/apparmor/apparmorfs.c
|
||||
@@ -2272,6 +2272,7 @@ static struct aa_sfs_entry aa_sfs_entry_features[] = {
|
||||
AA_SFS_DIR("domain", aa_sfs_entry_domain),
|
||||
AA_SFS_DIR("file", aa_sfs_entry_file),
|
||||
AA_SFS_DIR("network_v8", aa_sfs_entry_network),
|
||||
+ AA_SFS_DIR("network", aa_sfs_entry_network_compat),
|
||||
AA_SFS_DIR("mount", aa_sfs_entry_mount),
|
||||
AA_SFS_DIR("namespaces", aa_sfs_entry_ns),
|
||||
AA_SFS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
|
||||
diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
|
||||
index 73d63b58d875..17d89f3badc6 100644
|
||||
--- a/security/apparmor/include/apparmor.h
|
||||
+++ b/security/apparmor/include/apparmor.h
|
||||
@@ -24,7 +24,7 @@
|
||||
#define AA_CLASS_UNKNOWN 1
|
||||
#define AA_CLASS_FILE 2
|
||||
#define AA_CLASS_CAP 3
|
||||
-#define AA_CLASS_DEPRECATED 4
|
||||
+#define AA_CLASS_NET_COMPAT 4
|
||||
#define AA_CLASS_RLIMITS 5
|
||||
#define AA_CLASS_DOMAIN 6
|
||||
#define AA_CLASS_MOUNT 7
|
||||
diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
|
||||
index ec7228e857a9..579b59a40ea4 100644
|
||||
--- a/security/apparmor/include/net.h
|
||||
+++ b/security/apparmor/include/net.h
|
||||
@@ -72,6 +72,16 @@ struct aa_sk_ctx {
|
||||
DEFINE_AUDIT_NET(NAME, OP, SK, (SK)->sk_family, (SK)->sk_type, \
|
||||
(SK)->sk_protocol)
|
||||
|
||||
+/* struct aa_net - network confinement data
|
||||
+ * @allow: basic network families permissions
|
||||
+ * @audit: which network permissions to force audit
|
||||
+ * @quiet: which network permissions to quiet rejects
|
||||
+ */
|
||||
+struct aa_net_compat {
|
||||
+ u16 allow[AF_MAX];
|
||||
+ u16 audit[AF_MAX];
|
||||
+ u16 quiet[AF_MAX];
|
||||
+};
|
||||
|
||||
#define af_select(FAMILY, FN, DEF_FN) \
|
||||
({ \
|
||||
@@ -84,6 +94,7 @@ struct aa_sk_ctx {
|
||||
})
|
||||
|
||||
extern struct aa_sfs_entry aa_sfs_entry_network[];
|
||||
+extern struct aa_sfs_entry aa_sfs_entry_network_compat[];
|
||||
|
||||
void audit_net_cb(struct audit_buffer *ab, void *va);
|
||||
int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa,
|
||||
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
|
||||
index 6c93e62383e6..4006fa9fc9f1 100644
|
||||
--- a/security/apparmor/include/policy.h
|
||||
+++ b/security/apparmor/include/policy.h
|
||||
@@ -112,6 +112,7 @@ struct aa_data {
|
||||
* @policy: general match rules governing policy
|
||||
* @file: The set of rules governing basic file access and domain transitions
|
||||
* @caps: capabilities for the profile
|
||||
+ * @net_compat: v2 compat network controls for the profile
|
||||
* @rlimits: rlimits for the profile
|
||||
*
|
||||
* @dents: dentries for the profiles file entries in apparmorfs
|
||||
@@ -149,6 +150,7 @@ struct aa_profile {
|
||||
struct aa_policydb policy;
|
||||
struct aa_file_rules file;
|
||||
struct aa_caps caps;
|
||||
+ struct aa_net_compat *net_compat;
|
||||
|
||||
int xattr_count;
|
||||
char **xattrs;
|
||||
diff --git a/security/apparmor/net.c b/security/apparmor/net.c
|
||||
index bb24cfa0a164..bf6aaefc3a5f 100644
|
||||
--- a/security/apparmor/net.c
|
||||
+++ b/security/apparmor/net.c
|
||||
@@ -27,6 +27,11 @@ struct aa_sfs_entry aa_sfs_entry_network[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
+struct aa_sfs_entry aa_sfs_entry_network_compat[] = {
|
||||
+ AA_SFS_FILE_STRING("af_mask", AA_SFS_AF_MASK),
|
||||
+ { }
|
||||
+};
|
||||
+
|
||||
static const char * const net_mask_names[] = {
|
||||
"unknown",
|
||||
"send",
|
||||
@@ -119,14 +124,26 @@ int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa,
|
||||
if (profile_unconfined(profile))
|
||||
return 0;
|
||||
state = PROFILE_MEDIATES(profile, AA_CLASS_NET);
|
||||
- if (!state)
|
||||
+ if (state) {
|
||||
+ if (!state)
|
||||
+ return 0;
|
||||
+ buffer[0] = cpu_to_be16(family);
|
||||
+ buffer[1] = cpu_to_be16((u16) type);
|
||||
+ state = aa_dfa_match_len(profile->policy.dfa, state,
|
||||
+ (char *) &buffer, 4);
|
||||
+ aa_compute_perms(profile->policy.dfa, state, &perms);
|
||||
+ } else if (profile->net_compat) {
|
||||
+ /* 2.x socket mediation compat */
|
||||
+ perms.allow = (profile->net_compat->allow[family] & (1 << type)) ?
|
||||
+ ALL_PERMS_MASK : 0;
|
||||
+ perms.audit = (profile->net_compat->audit[family] & (1 << type)) ?
|
||||
+ ALL_PERMS_MASK : 0;
|
||||
+ perms.quiet = (profile->net_compat->quiet[family] & (1 << type)) ?
|
||||
+ ALL_PERMS_MASK : 0;
|
||||
+
|
||||
+ } else {
|
||||
return 0;
|
||||
-
|
||||
- buffer[0] = cpu_to_be16(family);
|
||||
- buffer[1] = cpu_to_be16((u16) type);
|
||||
- state = aa_dfa_match_len(profile->policy.dfa, state, (char *) &buffer,
|
||||
- 4);
|
||||
- aa_compute_perms(profile->policy.dfa, state, &perms);
|
||||
+ }
|
||||
aa_apply_modes_to_perms(profile, &perms);
|
||||
|
||||
return aa_check_perms(profile, &perms, request, sa, audit_net_cb);
|
||||
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
|
||||
index c07493ce2376..d1a869699040 100644
|
||||
--- a/security/apparmor/policy.c
|
||||
+++ b/security/apparmor/policy.c
|
||||
@@ -227,6 +227,7 @@ void aa_free_profile(struct aa_profile *profile)
|
||||
aa_free_file_rules(&profile->file);
|
||||
aa_free_cap_rules(&profile->caps);
|
||||
aa_free_rlimit_rules(&profile->rlimits);
|
||||
+ kzfree(profile->net_compat);
|
||||
|
||||
for (i = 0; i < profile->xattr_count; i++)
|
||||
kzfree(profile->xattrs[i]);
|
||||
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
|
||||
index b9e6b2cafa69..a1b07e6c163d 100644
|
||||
--- a/security/apparmor/policy_unpack.c
|
||||
+++ b/security/apparmor/policy_unpack.c
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
#define v5 5 /* base version */
|
||||
#define v6 6 /* per entry policydb mediation check */
|
||||
-#define v7 7
|
||||
+#define v7 7 /* v2 compat networking */
|
||||
#define v8 8 /* full network masking */
|
||||
|
||||
/*
|
||||
@@ -292,6 +292,19 @@ static bool unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name)
|
||||
+{
|
||||
+ if (unpack_nameX(e, AA_U16, name)) {
|
||||
+ if (!inbounds(e, sizeof(u16)))
|
||||
+ return 0;
|
||||
+ if (data)
|
||||
+ *data = le16_to_cpu(get_unaligned((__le16 *) e->pos));
|
||||
+ e->pos += sizeof(u16);
|
||||
+ return 1;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
|
||||
{
|
||||
if (unpack_nameX(e, AA_U32, name)) {
|
||||
@@ -621,7 +634,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
|
||||
struct aa_profile *profile = NULL;
|
||||
const char *tmpname, *tmpns = NULL, *name = NULL;
|
||||
const char *info = "failed to unpack profile";
|
||||
- size_t ns_len;
|
||||
+ size_t size = 0, ns_len;
|
||||
struct rhashtable_params params = { 0 };
|
||||
char *key = NULL;
|
||||
struct aa_data *data;
|
||||
@@ -759,6 +772,43 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
+ size = unpack_array(e, "net_allowed_af");
|
||||
+ if (size || VERSION_LT(e->version, v8)) {
|
||||
+ profile->net_compat = kzalloc(sizeof(struct aa_net_compat), GFP_KERNEL);
|
||||
+ if (!profile->net_compat) {
|
||||
+ info = "out of memory";
|
||||
+ goto fail;
|
||||
+ }
|
||||
+ for (i = 0; i < size; i++) {
|
||||
+ /* discard extraneous rules that this kernel will
|
||||
+ * never request
|
||||
+ */
|
||||
+ if (i >= AF_MAX) {
|
||||
+ u16 tmp;
|
||||
+
|
||||
+ if (!unpack_u16(e, &tmp, NULL) ||
|
||||
+ !unpack_u16(e, &tmp, NULL) ||
|
||||
+ !unpack_u16(e, &tmp, NULL))
|
||||
+ goto fail;
|
||||
+ continue;
|
||||
+ }
|
||||
+ if (!unpack_u16(e, &profile->net_compat->allow[i], NULL))
|
||||
+ goto fail;
|
||||
+ if (!unpack_u16(e, &profile->net_compat->audit[i], NULL))
|
||||
+ goto fail;
|
||||
+ if (!unpack_u16(e, &profile->net_compat->quiet[i], NULL))
|
||||
+ goto fail;
|
||||
+ }
|
||||
+ if (size && !unpack_nameX(e, AA_ARRAYEND, NULL))
|
||||
+ goto fail;
|
||||
+ if (VERSION_LT(e->version, v7)) {
|
||||
+ /* pre v7 policy always allowed these */
|
||||
+ profile->net_compat->allow[AF_UNIX] = 0xffff;
|
||||
+ profile->net_compat->allow[AF_NETLINK] = 0xffff;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+
|
||||
if (unpack_nameX(e, AA_STRUCT, "policydb")) {
|
||||
/* generic policy dfa - optional and may be NULL */
|
||||
info = "failed to unpack policydb";
|
||||
--
|
||||
2.14.1
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,57 +0,0 @@
|
||||
From 45ff74bd5a009ab8f9648531fa11fce55b9a67fd Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Tue, 26 Jun 2018 20:19:19 -0700
|
||||
Subject: [PATCH 3/3] apparmor: fix use after free in sk_peer_label
|
||||
|
||||
BugLink: http://bugs.launchpad.net/bugs/1778646
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
---
|
||||
security/apparmor/lsm.c | 11 +++++++----
|
||||
1 file changed, 7 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
|
||||
index 7a6b1bd8e046..0d2925389947 100644
|
||||
--- a/security/apparmor/lsm.c
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -1125,9 +1125,10 @@ static struct aa_label *sk_peer_label(struct sock *sk)
|
||||
{
|
||||
struct sock *peer_sk;
|
||||
struct aa_sk_ctx *ctx = SK_CTX(sk);
|
||||
+ struct aa_label *label = ERR_PTR(-ENOPROTOOPT);
|
||||
|
||||
if (ctx->peer)
|
||||
- return ctx->peer;
|
||||
+ return aa_get_label(ctx->peer);
|
||||
|
||||
if (sk->sk_family != PF_UNIX)
|
||||
return ERR_PTR(-ENOPROTOOPT);
|
||||
@@ -1135,14 +1136,15 @@ static struct aa_label *sk_peer_label(struct sock *sk)
|
||||
/* check for sockpair peering which does not go through
|
||||
* security_unix_stream_connect
|
||||
*/
|
||||
- peer_sk = unix_peer(sk);
|
||||
+ peer_sk = unix_peer_get(sk);
|
||||
if (peer_sk) {
|
||||
ctx = SK_CTX(peer_sk);
|
||||
if (ctx->label)
|
||||
- return ctx->label;
|
||||
+ label = aa_get_label(ctx->label);
|
||||
+ sock_put(peer_sk);
|
||||
}
|
||||
|
||||
- return ERR_PTR(-ENOPROTOOPT);
|
||||
+ return label;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1186,6 +1188,7 @@ static int apparmor_socket_getpeersec_stream(struct socket *sock,
|
||||
|
||||
}
|
||||
|
||||
+ aa_put_label(peer);
|
||||
done:
|
||||
end_current_label_crit_section(label);
|
||||
|
||||
--
|
||||
2.14.1
|
||||
|
@@ -1,3 +1,3 @@
|
||||
What little documentation exists is in include/aalogparse.h.
|
||||
What little documentation exists is in src/aalogparse.h.
|
||||
|
||||
Please file bugs using https://gitlab.com/apparmor/apparmor/-/issues
|
||||
Please file bugs using https://bugs.launchpad.net/apparmor/+filebug
|
||||
|
@@ -42,11 +42,11 @@ AC_ARG_WITH(python,
|
||||
[AC_MSG_RESULT($withval)], [AC_MSG_RESULT(no)])
|
||||
if test "$with_python" = "yes"; then
|
||||
test -z "$SWIG" && AC_MSG_ERROR([swig is required when enabling python bindings])
|
||||
AC_PATH_PROG(PYTHON, python3)
|
||||
AC_PATH_PROG(PYTHON, python)
|
||||
test -z "$PYTHON" && AC_MSG_ERROR([python is required when enabling python bindings])
|
||||
sinclude(m4/ac_python_devel.m4)
|
||||
AC_PYTHON_DEVEL
|
||||
AM_PATH_PYTHON([3.0])
|
||||
AM_PATH_PYTHON
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([whether perl bindings are enabled])
|
||||
@@ -58,7 +58,7 @@ if test "$with_perl" = "yes"; then
|
||||
AC_PATH_PROG(PERL, perl)
|
||||
test -z "$PERL" && AC_MSG_ERROR([perl is required when enabling perl bindings])
|
||||
perl_includedir="`$PERL -e 'use Config; print $Config{archlib}'`/CORE"
|
||||
AS_IF([test -e "$perl_includedir/perl.h"], enable_perl=yes, enable_perl=no)
|
||||
AC_CHECK_FILE($perl_includedir/perl.h, enable_perl=yes, enable_perl=no)
|
||||
fi
|
||||
|
||||
|
||||
@@ -92,14 +92,6 @@ if test "$ac_cv_prog_cc_c99" = "no"; then
|
||||
AC_MSG_ERROR([C99 mode is required to build libapparmor])
|
||||
fi
|
||||
|
||||
m4_ifndef([AX_CHECK_COMPILE_FLAG], [AC_MSG_ERROR(['autoconf-archive' missing])])
|
||||
EXTRA_CFLAGS="-Wall $(EXTRA_WARNINGS) -fPIC"
|
||||
AX_CHECK_COMPILE_FLAG([-flto-partition=none], , , [-Werror])
|
||||
AS_VAR_IF([ax_cv_check_cflags__Werror__flto_partition_none], [yes],
|
||||
[EXTRA_CFLAGS="$EXTRA_CFLAGS -flto-partition=none"]
|
||||
,)
|
||||
AC_SUBST([AM_CFLAGS], ["$EXTRA_CFLAGS"])
|
||||
|
||||
AC_OUTPUT(
|
||||
Makefile
|
||||
doc/Makefile
|
||||
|
@@ -137,11 +137,11 @@ First, a simple high-level overview of aa_change_hat() use:
|
||||
|
||||
void foo (void) {
|
||||
unsigned long magic_token;
|
||||
|
||||
|
||||
/* get a random magic token value
|
||||
from our huge entropy pool */
|
||||
magic_token = random_function();
|
||||
|
||||
|
||||
/* change into the subprofile while
|
||||
* we do stuff we don't trust */
|
||||
aa_change_hat("stuff_we_dont_trust", magic_token);
|
||||
@@ -166,20 +166,20 @@ aren't accessible after an aa_change_hat() call:
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int fd;
|
||||
unsigned long tok;
|
||||
char buf[10];
|
||||
|
||||
|
||||
/* random() is a poor choice */
|
||||
tok = random();
|
||||
|
||||
|
||||
/* open /etc/passwd outside of any hat */
|
||||
if ((fd=open("/etc/passwd", O_RDONLY)) < 0)
|
||||
perror("Failure opening /etc/passwd");
|
||||
|
||||
|
||||
/* confirm for ourselves that we can really read /etc/passwd */
|
||||
memset(&buf, 0, 10);
|
||||
if (read(fd, &buf, 10) == -1) {
|
||||
@@ -188,7 +188,7 @@ aren't accessible after an aa_change_hat() call:
|
||||
}
|
||||
buf[9] = '\0';
|
||||
printf("/etc/passwd: %s\n", buf);
|
||||
|
||||
|
||||
/* change hat to the "hat" subprofile, which should not have
|
||||
* read access to /etc/passwd -- even though we have a valid
|
||||
* file descriptor at the time of the aa_change_hat() call. */
|
||||
@@ -196,7 +196,7 @@ aren't accessible after an aa_change_hat() call:
|
||||
perror("Failure changing hat -- aborting");
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
|
||||
/* confirm that we cannot read /etc/passwd */
|
||||
lseek(fd,0,SEEK_SET);
|
||||
memset(&buf, 0, 10);
|
||||
@@ -204,7 +204,7 @@ aren't accessible after an aa_change_hat() call:
|
||||
perror("Failure reading /etc/passwd post-hat");
|
||||
buf[9] = '\0';
|
||||
printf("/etc/passwd: %s\n", buf);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -248,7 +248,7 @@ The output when run:
|
||||
=head1 BUGS
|
||||
|
||||
None known. If you find any, please report them at
|
||||
L<https://gitlab.com/apparmor/apparmor/-/issues>. Note that
|
||||
L<https://bugs.launchpad.net/apparmor/+filebug>. Note that
|
||||
aa_change_hat(2) provides no memory barriers between different areas of a
|
||||
program; if address space separation is required, then separate processes
|
||||
should be used.
|
||||
|
@@ -196,7 +196,7 @@ used (in addition to the one for 'i_cant_be_trusted_anymore', above):
|
||||
=head1 BUGS
|
||||
|
||||
None known. If you find any, please report them at
|
||||
L<https://gitlab.com/apparmor/apparmor/-/issues>. Note that using
|
||||
L<https://bugs.launchpad.net/apparmor/+filebug>. Note that using
|
||||
aa_change_profile(2) without execve(2) provides no memory barriers between
|
||||
different areas of a program; if address space separation is required, then
|
||||
separate processes should be used.
|
||||
|
@@ -34,8 +34,6 @@ aa_features_ref - increments the ref count of an aa_features object
|
||||
|
||||
aa_features_unref - decrements the ref count and frees the aa_features object when 0
|
||||
|
||||
aa_features_write_to_fd - write a string representation of an aa_features object to a file descriptor
|
||||
|
||||
aa_features_write_to_file - write a string representation of an aa_features object to a file
|
||||
|
||||
aa_features_is_equal - equality test for two aa_features objects
|
||||
@@ -44,8 +42,6 @@ aa_features_supports - provides aa_features object support status
|
||||
|
||||
aa_features_id - provides unique identifier for an aa_features object
|
||||
|
||||
aa_features_value - the value associated with a given feature.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<#include E<lt>sys/apparmor.hE<gt>>
|
||||
@@ -54,8 +50,6 @@ B<typedef struct aa_features aa_features;>
|
||||
|
||||
B<int aa_features_new(aa_features **features, int dirfd, const char *path);>
|
||||
|
||||
B<int aa_features_new_from_file(aa_features **features, int fd);>
|
||||
|
||||
B<int aa_features_new_from_string(aa_features **features, const char *string, size_t size);>
|
||||
|
||||
B<int aa_features_new_from_kernel(aa_features **features);>
|
||||
@@ -64,8 +58,6 @@ B<aa_features *aa_features_ref(aa_features *features);>
|
||||
|
||||
B<void aa_features_unref(aa_features *features);>
|
||||
|
||||
B<int aa_features_write_to_fd(aa_features *features, int fd);>
|
||||
|
||||
B<int aa_features_write_to_file(aa_features *features, int dirfd, const char *path);>
|
||||
|
||||
B<bool aa_features_is_equal(aa_features *features1, aa_features *features2);>
|
||||
@@ -74,8 +66,6 @@ B<bool aa_features_supports(aa_features *features, const char *str);>
|
||||
|
||||
B<char *aa_features_id(aa_features *features);>
|
||||
|
||||
B<char *aa_features_value(aa_features *features, const char *str, size_t *len);>
|
||||
|
||||
Link with B<-lapparmor> when compiling.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
@@ -92,10 +82,6 @@ directory file descriptor and path. The I<path> can point to a file or
|
||||
directory. See the openat(2) man page for examples of I<dirfd> and I<path>. The
|
||||
allocated I<features> object must be freed using aa_features_unref().
|
||||
|
||||
The aa_features_new_from_file() function is similar except that it
|
||||
accepts an open file as the argument. The allocated I<features> object
|
||||
must be freed using aa_features_unref().
|
||||
|
||||
The aa_features_new_from_string() function is similar except that it accepts a
|
||||
NUL-terminated string representation of the AppArmor features as the I<string>
|
||||
argument. The length of the features string, not counting the NUL-terminator,
|
||||
@@ -111,9 +97,6 @@ aa_features_ref() increments the reference count on the I<features> object.
|
||||
aa_features_unref() decrements the reference count on the I<features> object
|
||||
and releases all corresponding resources when the reference count reaches zero.
|
||||
|
||||
The aa_features_write_to_fd() function writes a string representation of the
|
||||
I<features> object to the file descriptor specified by the I<fd>.
|
||||
|
||||
The aa_features_write_to_file() function writes a string representation of the
|
||||
I<features> object to the file specified by the I<dirfd> and I<path>
|
||||
combination.
|
||||
@@ -157,11 +140,6 @@ aa_features_id() returns a string identifying I<features> which must be
|
||||
freed by the caller. NULL is returned on error, with errno set
|
||||
appropriately.
|
||||
|
||||
aa_features_value() returns a null terminated string with is
|
||||
associated length which must be freed by the caller. NULL is returned
|
||||
on error, with errno set to ENOENT if the feature was not found,
|
||||
ENODIR if the specified feature does not resolve to a leaf feature.
|
||||
|
||||
=head1 ERRORS
|
||||
|
||||
The errno value will be set according to the underlying error in the
|
||||
@@ -179,10 +157,10 @@ before exiting in libapparmor version 2.12 and newer.
|
||||
=head1 BUGS
|
||||
|
||||
None known. If you find any, please report them at
|
||||
L<https://gitlab.com/apparmor/apparmor/-/issues>.
|
||||
L<https://bugs.launchpad.net/apparmor/+filebug>.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
openat(2), aa-features-abi(1) and L<https://wiki.apparmor.net>.
|
||||
openat(2) and L<https://wiki.apparmor.net>.
|
||||
|
||||
=cut
|
||||
|
@@ -70,10 +70,6 @@ AppArmor extensions to the system are not available.
|
||||
|
||||
AppArmor is available on the system but has been disabled at boot.
|
||||
|
||||
=item B<EBUSY>
|
||||
|
||||
AppArmor is available but only via private interfaces.
|
||||
|
||||
=item B<ENOENT>
|
||||
|
||||
AppArmor is available (and maybe even enforcing policy) but the interface is
|
||||
@@ -91,11 +87,6 @@ Did not have sufficient permissions to determine if AppArmor is enabled.
|
||||
|
||||
Did not have sufficient permissions to determine if AppArmor is enabled.
|
||||
|
||||
=item B<EBUSY>
|
||||
|
||||
AppArmor is enabled but does not have access to shared interfaces, and
|
||||
only private interfaces are available.
|
||||
|
||||
=back
|
||||
|
||||
B<aa_find_mountpoint>
|
||||
@@ -119,7 +110,7 @@ The apparmor filesystem mount could not be found
|
||||
=head1 BUGS
|
||||
|
||||
None known. If you find any, please report them at
|
||||
L<https://gitlab.com/apparmor/apparmor/-/issues>.
|
||||
L<https://bugs.launchpad.net/apparmor/+filebug>.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
|
@@ -116,14 +116,6 @@ The specified I<file/task> does not exist or is not visible.
|
||||
|
||||
The confinement data is too large to fit in the supplied buffer.
|
||||
|
||||
=item B<ENOPROTOOPT>
|
||||
|
||||
The kernel doesn't support the SO_PEERLABEL option in sockets. This happens
|
||||
mainly when the kernel lacks 'fine grained unix mediation' support. It also
|
||||
can happen on LSM stacking kernels where another LSM has claimed this
|
||||
interface and decides to return this error, although this is really a
|
||||
corner case.
|
||||
|
||||
=back
|
||||
|
||||
=head1 NOTES
|
||||
@@ -135,7 +127,7 @@ confinement data.
|
||||
=head1 BUGS
|
||||
|
||||
None known. If you find any, please report them at
|
||||
L<https://gitlab.com/apparmor/apparmor/-/issues>.
|
||||
L<https://bugs.launchpad.net/apparmor/+filebug>.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
|
@@ -156,7 +156,7 @@ errno before exiting in libapparmor version 2.12 and newer.
|
||||
=head1 BUGS
|
||||
|
||||
None known. If you find any, please report them at
|
||||
L<https://gitlab.com/apparmor/apparmor/-/issues>.
|
||||
L<https://bugs.launchpad.net/apparmor/+filebug>.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
|
@@ -125,7 +125,7 @@ layer. Binary policy cache files will be located in the directory
|
||||
returned by this function.
|
||||
|
||||
The aa_policy_cache_dir_levels() function provides access to the number
|
||||
of directories that are being overlaid to create the policy cache.
|
||||
of directories that are being overlayed to create the policy cache.
|
||||
|
||||
|
||||
=head1 RETURN VALUE
|
||||
@@ -170,7 +170,7 @@ before exiting in libapparmor version 2.12 and newer.
|
||||
=head1 BUGS
|
||||
|
||||
None known. If you find any, please report them at
|
||||
L<https://gitlab.com/apparmor/apparmor/-/issues>.
|
||||
L<https://bugs.launchpad.net/apparmor/+filebug>.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
|
@@ -123,7 +123,7 @@ query and can change at any point in the future.
|
||||
=head1 BUGS
|
||||
|
||||
None known. If you find any, please report them at
|
||||
L<https://gitlab.com/apparmor/apparmor/-/issues>.
|
||||
L<https://bugs.launchpad.net/apparmor/+filebug>.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
|
@@ -63,7 +63,7 @@ on error.
|
||||
=head1 BUGS
|
||||
|
||||
None known. If you find any, please report them at
|
||||
L<https://gitlab.com/apparmor/apparmor/-/issues>.
|
||||
L<https://bugs.launchpad.net/apparmor/+filebug>.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
|
@@ -109,12 +109,12 @@ To immediately stack a profile named "profile_a", as performed with
|
||||
aa_stack_profile("profile_a"), the equivalent of this shell command can be
|
||||
used:
|
||||
|
||||
$ echo -n "stack profile_a" > /proc/self/attr/current
|
||||
$ echo -n "stackprofile profile_a" > /proc/self/attr/current
|
||||
|
||||
To stack a profile named "profile_a" at the next exec, as performed with
|
||||
aa_stack_onexec("profile_a"), the equivalent of this shell command can be used:
|
||||
|
||||
$ echo -n "stack profile_a" > /proc/self/attr/exec
|
||||
$ echo -n "stackexec profile_a" > /proc/self/attr/exec
|
||||
|
||||
These raw AppArmor filesystem operations must only be used when using
|
||||
libapparmor is not a viable option.
|
||||
@@ -137,12 +137,12 @@ aa_stack_profile().
|
||||
{
|
||||
int fd;
|
||||
char buf[10];
|
||||
|
||||
|
||||
if ((fd=open("/etc/passwd", O_RDONLY)) < 0) {
|
||||
perror("Failure opening /etc/passwd");
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
|
||||
/* Verify that we can read /etc/passwd */
|
||||
memset(&buf, 0, 10);
|
||||
if (read(fd, &buf, 10) == -1) {
|
||||
@@ -153,19 +153,19 @@ aa_stack_profile().
|
||||
printf("/etc/passwd: %s\n", buf);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
printf("Before aa_stack_profile():\n");
|
||||
read_passwd();
|
||||
|
||||
|
||||
/* stack the "i_cant_be_trusted_anymore" profile, which
|
||||
* should not have read access to /etc/passwd. */
|
||||
if (aa_stack_profile("i_cant_be_trusted_anymore") < 0) {
|
||||
perror("Failure changing profile -- aborting");
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
|
||||
printf("After aa_stack_profile():\n");
|
||||
read_passwd();
|
||||
_exit(0);
|
||||
@@ -184,7 +184,6 @@ with apparmor_parser(8):
|
||||
/etc/passwd r,
|
||||
|
||||
# Needed for aa_stack_profile()
|
||||
change-profile -> &i_cant_be_trusted_anymore,
|
||||
/usr/lib/libapparmor*.so* mr,
|
||||
/proc/[0-9]*/attr/current w,
|
||||
}
|
||||
@@ -209,7 +208,7 @@ The output when run:
|
||||
=head1 BUGS
|
||||
|
||||
None known. If you find any, please report them at
|
||||
L<https://gitlab.com/apparmor/apparmor/-/issues>. Note that using
|
||||
L<https://bugs.launchpad.net/apparmor/+filebug>. Note that using
|
||||
aa_stack_profile(2) without execve(2) provides no memory barriers between
|
||||
different areas of a program; if address space separation is required, then
|
||||
separate processes should be used.
|
||||
|
@@ -159,8 +159,6 @@ typedef struct
|
||||
char *fs_type;
|
||||
char *flags;
|
||||
char *src_name;
|
||||
|
||||
char *class;
|
||||
} aa_log_record;
|
||||
|
||||
/**
|
||||
|
@@ -20,8 +20,6 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -95,7 +93,7 @@ extern int aa_getprocattr(pid_t tid, const char *attr, char **label,
|
||||
char **mode);
|
||||
extern int aa_gettaskcon(pid_t target, char **label, char **mode);
|
||||
extern int aa_getcon(char **label, char **mode);
|
||||
extern int aa_getpeercon_raw(int fd, char *buf, socklen_t *len, char **mode);
|
||||
extern int aa_getpeercon_raw(int fd, char *buf, int *len, char **mode);
|
||||
extern int aa_getpeercon(int fd, char **label, char **mode);
|
||||
|
||||
/* A NUL character is used to separate the query command prefix string from the
|
||||
@@ -145,23 +143,18 @@ extern int aa_query_link_path(const char *label, const char *target,
|
||||
|
||||
typedef struct aa_features aa_features;
|
||||
extern int aa_features_new(aa_features **features, int dirfd, const char *path);
|
||||
extern int aa_features_new_from_file(aa_features **features, int file);
|
||||
extern int aa_features_new_from_string(aa_features **features,
|
||||
const char *string, size_t size);
|
||||
extern int aa_features_new_from_kernel(aa_features **features);
|
||||
extern aa_features *aa_features_ref(aa_features *features);
|
||||
extern void aa_features_unref(aa_features *features);
|
||||
|
||||
extern int aa_features_write_to_fd(aa_features *features, int fd);
|
||||
extern int aa_features_write_to_file(aa_features *features,
|
||||
int dirfd, const char *path);
|
||||
extern bool aa_features_is_equal(aa_features *features1,
|
||||
aa_features *features2);
|
||||
extern int aa_features_check(int dirfd, const char *path,
|
||||
aa_features *features);
|
||||
extern bool aa_features_supports(aa_features *features, const char *str);
|
||||
extern char *aa_features_id(aa_features *features);
|
||||
extern char *aa_features_value(aa_features *features, const char *str, size_t *len);
|
||||
|
||||
typedef struct aa_kernel_interface aa_kernel_interface;
|
||||
extern int aa_kernel_interface_new(aa_kernel_interface **kernel_interface,
|
||||
@@ -211,8 +204,6 @@ extern char *aa_policy_cache_filename(aa_policy_cache *policy_cache, const char
|
||||
extern char *aa_policy_cache_dir_path_preview(aa_features *kernel_features,
|
||||
int dirfd, const char *path);
|
||||
|
||||
extern int aa_split_overlay_str(char *str, char ***vec, size_t max_size, bool immutable);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -13,11 +13,6 @@ AC_DEFUN([AC_PYTHON_DEVEL],[
|
||||
PYTHON_VERSION=""
|
||||
fi
|
||||
|
||||
AC_PATH_TOOL([PYTHON_CONFIG],[`basename [$PYTHON]-config`])
|
||||
if test -z "$PYTHON_CONFIG"; then
|
||||
AC_MSG_ERROR([Cannot find python$PYTHON_VERSION-config in your system path])
|
||||
fi
|
||||
|
||||
#
|
||||
# Check for a version of Python >= 2.1.0
|
||||
#
|
||||
@@ -66,17 +61,17 @@ variable to configure. See ``configure --help'' for reference.
|
||||
fi
|
||||
|
||||
#
|
||||
# Check if you have setuptools, else fail
|
||||
# Check if you have distutils, else fail
|
||||
#
|
||||
AC_MSG_CHECKING([for the setuptools Python package])
|
||||
ac_setuptools_result=`$PYTHON -c "import setuptools" 2>&1`
|
||||
if test -z "$ac_setuptools_result"; then
|
||||
AC_MSG_CHECKING([for the distutils Python package])
|
||||
ac_distutils_result=`$PYTHON -c "import distutils" 2>&1`
|
||||
if test -z "$ac_distutils_result"; then
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
AC_MSG_ERROR([cannot import Python module "setuptools".
|
||||
AC_MSG_ERROR([cannot import Python module "distutils".
|
||||
Please check your Python installation. The error was:
|
||||
$ac_setuptools_result])
|
||||
$ac_distutils_result])
|
||||
PYTHON_VERSION=""
|
||||
fi
|
||||
|
||||
@@ -84,12 +79,12 @@ $ac_setuptools_result])
|
||||
# Check for Python include path
|
||||
#
|
||||
AC_MSG_CHECKING([for Python include path])
|
||||
if type $PYTHON_CONFIG; then
|
||||
PYTHON_CPPFLAGS=`$PYTHON_CONFIG --includes`
|
||||
if type $PYTHON-config; then
|
||||
PYTHON_CPPFLAGS=`$PYTHON-config --includes`
|
||||
fi
|
||||
if test -z "$PYTHON_CPPFLAGS"; then
|
||||
python_path=`$PYTHON -c "import sys; import sysconfig;\
|
||||
sys.stdout.write('%s\n' % sysconfig.get_path('include'));"`
|
||||
python_path=`$PYTHON -c "import sys; import distutils.sysconfig;\
|
||||
sys.stdout.write('%s\n' % distutils.sysconfig.get_python_inc());"`
|
||||
if test -n "${python_path}"; then
|
||||
python_path="-I$python_path"
|
||||
fi
|
||||
@@ -102,14 +97,14 @@ sys.stdout.write('%s\n' % sysconfig.get_path('include'));"`
|
||||
# Check for Python library path
|
||||
#
|
||||
AC_MSG_CHECKING([for Python library path])
|
||||
if type $PYTHON_CONFIG; then
|
||||
PYTHON_LDFLAGS=`$PYTHON_CONFIG --ldflags`
|
||||
if type $PYTHON-config; then
|
||||
PYTHON_LDFLAGS=`$PYTHON-config --ldflags`
|
||||
fi
|
||||
if test -z "$PYTHON_LDFLAGS"; then
|
||||
# (makes two attempts to ensure we've got a version number
|
||||
# from the interpreter)
|
||||
py_version=`$PYTHON -c "import sys; import sysconfig; \
|
||||
sys.stdout.write('%s\n' % ''.join(sysconfig.get_config_vars('VERSION')))"`
|
||||
py_version=`$PYTHON -c "import sys; from distutils.sysconfig import *; \
|
||||
sys.stdout.write('%s\n' % ''.join(get_config_vars('VERSION')))"`
|
||||
if test "$py_version" == "[None]"; then
|
||||
if test -n "$PYTHON_VERSION"; then
|
||||
py_version=$PYTHON_VERSION
|
||||
@@ -119,8 +114,8 @@ sys.stdout.write("%s\n" % sys.version[[:3]])"`
|
||||
fi
|
||||
fi
|
||||
|
||||
PYTHON_LDFLAGS=`$PYTHON -c "import sys; import sysconfig; \
|
||||
sys.stdout.write('-L' + sysconfig.get_path('stdlib') + ' -lpython\n')"`$py_version`$PYTHON -c \
|
||||
PYTHON_LDFLAGS=`$PYTHON -c "import sys; from distutils.sysconfig import *; \
|
||||
sys.stdout.write('-L' + get_python_lib(0,1) + ' -lpython\n')"`$py_version`$PYTHON -c \
|
||||
"import sys; sys.stdout.write('%s' % getattr(sys,'abiflags',''))"`
|
||||
fi
|
||||
AC_MSG_RESULT([$PYTHON_LDFLAGS])
|
||||
@@ -131,8 +126,8 @@ sys.stdout.write('-L' + sysconfig.get_path('stdlib') + ' -lpython\n')"`$py_versi
|
||||
#
|
||||
AC_MSG_CHECKING([for Python site-packages path])
|
||||
if test -z "$PYTHON_SITE_PKG"; then
|
||||
PYTHON_SITE_PKG=`$PYTHON -c "import sys; import sysconfig; \
|
||||
sys.stdout.write('%s\n' % sysconfig.get_path('purelib'));"`
|
||||
PYTHON_SITE_PKG=`$PYTHON -c "import sys; import distutils.sysconfig; \
|
||||
sys.stdout.write('%s\n' % distutils.sysconfig.get_python_lib(0,0));"`
|
||||
fi
|
||||
AC_MSG_RESULT([$PYTHON_SITE_PKG])
|
||||
AC_SUBST([PYTHON_SITE_PKG])
|
||||
@@ -141,14 +136,10 @@ sys.stdout.write('%s\n' % sysconfig.get_path('purelib'));"`
|
||||
# libraries which must be linked in when embedding
|
||||
#
|
||||
AC_MSG_CHECKING(python extra libraries)
|
||||
if type $PYTHON_CONFIG; then
|
||||
PYTHON_EXTRA_LIBS=`$PYTHON_CONFIG --libs --embed` || \
|
||||
PYTHON_EXTRA_LIBS=''
|
||||
fi
|
||||
if test -z "$PYTHON_EXTRA_LIBS"; then
|
||||
PYTHON_EXTRA_LIBS=`$PYTHON -c "import sys; import sysconfig; \
|
||||
conf = sysconfig.get_config_var; \
|
||||
sys.stdout.write('%s %s %s\n' % (conf('BLDLIBRARY'), conf('LOCALMODLIBS'), conf('LIBS')))"`
|
||||
PYTHON_EXTRA_LIBS=`$PYTHON -c "import sys; import distutils.sysconfig; \
|
||||
conf = distutils.sysconfig.get_config_var; \
|
||||
sys.stdout.write('%s %s\n' % (conf('LOCALMODLIBS'), conf('LIBS')))"`
|
||||
fi
|
||||
AC_MSG_RESULT([$PYTHON_EXTRA_LIBS])
|
||||
AC_SUBST(PYTHON_EXTRA_LIBS)
|
||||
@@ -157,13 +148,9 @@ sys.stdout.write('%s %s %s\n' % (conf('BLDLIBRARY'), conf('LOCALMODLIBS'), conf(
|
||||
# linking flags needed when embedding
|
||||
#
|
||||
AC_MSG_CHECKING(python extra linking flags)
|
||||
if type $PYTHON_CONFIG; then
|
||||
PYTHON_EXTRA_LDFLAGS=`$PYTHON_CONFIG --ldflags --embed` || \
|
||||
PYTHON_EXTRA_LDFLAGS=''
|
||||
fi
|
||||
if test -z "$PYTHON_EXTRA_LDFLAGS"; then
|
||||
PYTHON_EXTRA_LDFLAGS=`$PYTHON -c "import sys; import sysconfig; \
|
||||
conf = sysconfig.get_config_var; \
|
||||
PYTHON_EXTRA_LDFLAGS=`$PYTHON -c "import sys; import distutils.sysconfig; \
|
||||
conf = distutils.sysconfig.get_config_var; \
|
||||
sys.stdout.write('%s\n' % conf('LINKFORSHARED'))"`
|
||||
fi
|
||||
AC_MSG_RESULT([$PYTHON_EXTRA_LDFLAGS])
|
||||
@@ -177,7 +164,7 @@ sys.stdout.write('%s\n' % conf('LINKFORSHARED'))"`
|
||||
# save current global flags
|
||||
ac_save_LIBS="$LIBS"
|
||||
ac_save_CPPFLAGS="$CPPFLAGS"
|
||||
LIBS="$ac_save_LIBS $PYTHON_EXTRA_LIBS $PYTHON_LDFLAGS"
|
||||
LIBS="$ac_save_LIBS $PYTHON_LDFLAGS"
|
||||
CPPFLAGS="$ac_save_CPPFLAGS $PYTHON_CPPFLAGS"
|
||||
AC_TRY_LINK([
|
||||
#include <Python.h>
|
||||
|
@@ -11,13 +11,9 @@ INCLUDES = $(all_includes)
|
||||
# 3. If any interfaces have been added, removed, or changed since the last
|
||||
# update,
|
||||
# - increment AA_LIB_CURRENT
|
||||
# - by 1 if bugfix release
|
||||
# - by 5 on larger releases. This gives room to fix library interface
|
||||
# problems in the unlikely event where an interface has to break.
|
||||
# - set AA_LIB_REVISION to 0.
|
||||
# 4. If any interfaces have been added since the last public release, then
|
||||
# - increment AA_LIB_AGE by the same amount that AA_LIB_CURRENT was
|
||||
# incremented.
|
||||
# - increment AA_LIB_AGE.
|
||||
# 5. If any interfaces have been removed or changed since the last public
|
||||
# release, then
|
||||
# - set AA_LIB_AGE to 0.
|
||||
@@ -30,21 +26,16 @@ INCLUDES = $(all_includes)
|
||||
# For more information, see:
|
||||
# http://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html
|
||||
#
|
||||
# After changing the AA_LIB_* variables, also update EXPECTED_SO_NAME.
|
||||
|
||||
AA_LIB_CURRENT = 18
|
||||
AA_LIB_REVISION = 1
|
||||
AA_LIB_AGE = 17
|
||||
EXPECTED_SO_NAME = libapparmor.so.1.17.1
|
||||
AA_LIB_CURRENT = 7
|
||||
AA_LIB_REVISION = 0
|
||||
AA_LIB_AGE = 6
|
||||
|
||||
SUFFIXES = .pc.in .pc
|
||||
|
||||
COMMONDIR=$(top_srcdir)/../../common/
|
||||
include $(COMMONDIR)/Make.rules
|
||||
|
||||
BUILT_SOURCES = grammar.h scanner.h af_protos.h
|
||||
AM_LFLAGS = -v
|
||||
AM_YFLAGS = -d -p aalogparse_
|
||||
AM_CFLAGS = -Wall
|
||||
AM_CPPFLAGS = -D_GNU_SOURCE -I$(top_srcdir)/include/
|
||||
scanner.h: scanner.l
|
||||
$(LEX) -v $<
|
||||
@@ -52,13 +43,13 @@ scanner.h: scanner.l
|
||||
scanner.c: scanner.l
|
||||
|
||||
af_protos.h:
|
||||
echo '#include <netinet/in.h>' | $(CC) $(CPPFLAGS) -E -dM - | LC_ALL=C sed -n -e "/IPPROTO_MAX/d" -e "s/^\#define[ \\t]\\+IPPROTO_\\([A-Z0-9_]\\+\\)\\(.*\\)$$/AA_GEN_PROTO_ENT(\\UIPPROTO_\\1, \"\\L\\1\")/p" > $@
|
||||
echo '#include <netinet/in.h>' | $(CC) -E -dM - | LC_ALL=C sed -n -e "/IPPROTO_MAX/d" -e "s/^\#define[ \\t]\\+IPPROTO_\\([A-Z0-9_]\\+\\)\\(.*\\)$$/AA_GEN_PROTO_ENT(\\UIPPROTO_\\1, \"\\L\\1\")/p" > $@
|
||||
|
||||
lib_LTLIBRARIES = libapparmor.la
|
||||
noinst_HEADERS = grammar.h parser.h scanner.h af_protos.h private.h PMurHash.h
|
||||
|
||||
libapparmor_la_SOURCES = grammar.y libaalogparse.c kernel.c scanner.c private.c features.c kernel_interface.c policy_cache.c PMurHash.c
|
||||
libapparmor_la_LDFLAGS = -version-info $(AA_LIB_CURRENT):$(AA_LIB_REVISION):$(AA_LIB_AGE) -XCClinker -Bdynamic -pthread \
|
||||
libapparmor_la_LDFLAGS = -version-info $(AA_LIB_CURRENT):$(AA_LIB_REVISION):$(AA_LIB_AGE) -XCClinker -dynamic -pthread \
|
||||
-Wl,--version-script=$(top_srcdir)/src/libapparmor.map
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
@@ -83,8 +74,4 @@ tst_kernel_LDFLAGS = -pthread
|
||||
check_PROGRAMS = tst_aalogmisc tst_features tst_kernel
|
||||
TESTS = $(check_PROGRAMS)
|
||||
|
||||
.PHONY: check-local
|
||||
check-local:
|
||||
test -f ./.libs/$(EXPECTED_SO_NAME) || { echo '*** unexpected .so name/number for libapparmor (expected $(EXPECTED_SO_NAME), the actual filename is shown below) ***' ; ls -l ./.libs/libapparmor.so.*.* ; exit 1; }
|
||||
|
||||
EXTRA_DIST = grammar.y scanner.l libapparmor.map libapparmor.pc
|
||||
|
@@ -35,7 +35,6 @@
|
||||
#include "PMurHash.h"
|
||||
|
||||
#define FEATURES_FILE "/sys/kernel/security/apparmor/features"
|
||||
#define CACHE_FEATURES_FILE ".features"
|
||||
|
||||
#define HASH_SIZE (8 + 1) /* 32 bits binary to hex + NUL terminator */
|
||||
#define STRING_SIZE 8192
|
||||
@@ -99,8 +98,9 @@ static int features_snprintf(struct features_struct *fst, const char *fmt, ...)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* load_features_file - reads a file into @buffer and then NUL-terminates @buffer
|
||||
* @file: file to read the features from
|
||||
/* load_features_file - opens and reads a file into @buffer and then NUL-terminates @buffer
|
||||
* @dirfd: a directory file descriptory or AT_FDCWD (see openat(2))
|
||||
* @path: name of the file
|
||||
* @buffer: the buffer to read the features file into (will be NUL-terminated on success)
|
||||
* @size: the size of @buffer
|
||||
*
|
||||
@@ -110,11 +110,25 @@ static int features_snprintf(struct features_struct *fst, const char *fmt, ...)
|
||||
* ENOBUFS indicating that @buffer was not large enough to contain all of the
|
||||
* file contents.
|
||||
*/
|
||||
static ssize_t load_features_file(int file, char *buffer, size_t size)
|
||||
static ssize_t load_features_file(int dirfd, const char *path,
|
||||
char *buffer, size_t size)
|
||||
{
|
||||
autoclose int file = -1;
|
||||
char *pos = buffer;
|
||||
ssize_t len;
|
||||
|
||||
file = openat(dirfd, path, O_RDONLY);
|
||||
if (file < 0) {
|
||||
PDEBUG("Could not open '%s'\n", path);
|
||||
return -1;
|
||||
}
|
||||
PDEBUG("Opened features \"%s\"\n", path);
|
||||
|
||||
if (!size) {
|
||||
errno = ENOBUFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Save room for a NUL-terminator at the end of @buffer */
|
||||
size--;
|
||||
|
||||
@@ -137,7 +151,7 @@ static ssize_t load_features_file(int file, char *buffer, size_t size)
|
||||
if (len > 0)
|
||||
errno = ENOBUFS;
|
||||
|
||||
PDEBUG("Error reading features file: %m\n");
|
||||
PDEBUG("Error reading features file '%s': %m\n", path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -147,42 +161,6 @@ static ssize_t load_features_file(int file, char *buffer, size_t size)
|
||||
return pos - buffer;
|
||||
}
|
||||
|
||||
/* open_and_load_features_file - opens and reads a file into @buffer and then NUL-terminates @buffer
|
||||
* @dirfd: a directory file descriptory or AT_FDCWD (see openat(2))
|
||||
* @path: name of the file
|
||||
* @buffer: the buffer to read the features file into (will be NUL-terminated on success)
|
||||
* @size: the size of @buffer
|
||||
*
|
||||
* Returns: The number of bytes copied into @buffer on success (not counting
|
||||
* the NUL-terminator), else -1 and errno is set. Note that @size must be
|
||||
* larger than the size of the file or -1 will be returned with errno set to
|
||||
* ENOBUFS indicating that @buffer was not large enough to contain all of the
|
||||
* file contents.
|
||||
*/
|
||||
static ssize_t open_and_load_features_file(int dirfd, const char *path,
|
||||
char *buffer, size_t size)
|
||||
{
|
||||
autoclose int file = -1;
|
||||
ssize_t rc;
|
||||
|
||||
file = openat(dirfd, path, O_RDONLY);
|
||||
if (file < 0) {
|
||||
PDEBUG("Could not open '%s': %m\n", path);
|
||||
return -1;
|
||||
}
|
||||
PDEBUG("Opened features '%s': %m\n", path);
|
||||
|
||||
if (!size) {
|
||||
errno = ENOBUFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = load_features_file(file, buffer, size);
|
||||
if (rc == -1)
|
||||
PDEBUG("Error failed to load features file '%s': %m\n", path);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int features_dir_cb(int dirfd, const char *name, struct stat *st,
|
||||
void *data)
|
||||
{
|
||||
@@ -195,8 +173,6 @@ static int features_dir_cb(int dirfd, const char *name, struct stat *st,
|
||||
if (features_snprintf(fst, "%s {", name) == -1)
|
||||
return -1;
|
||||
|
||||
/* Handle symlink here. See _aa_dirat_for_each in private.c */
|
||||
|
||||
if (S_ISREG(st->st_mode)) {
|
||||
ssize_t len;
|
||||
size_t remaining;
|
||||
@@ -204,7 +180,7 @@ static int features_dir_cb(int dirfd, const char *name, struct stat *st,
|
||||
if (features_buffer_remaining(fst, &remaining) == -1)
|
||||
return -1;
|
||||
|
||||
len = open_and_load_features_file(dirfd, name, fst->pos, remaining);
|
||||
len = load_features_file(dirfd, name, fst->pos, remaining);
|
||||
if (len < 0)
|
||||
return -1;
|
||||
|
||||
@@ -243,7 +219,7 @@ static int init_features_hash(aa_features *features)
|
||||
/* portable murmur3 hash
|
||||
* https://github.com/aappleby/smhasher/wiki/MurmurHash3
|
||||
*/
|
||||
PMurHash32_Process(&hash, &carry, string, len);
|
||||
PMurHash32_Process(&hash, &carry, features, len);
|
||||
hash = PMurHash32_Result(hash, carry, len);
|
||||
|
||||
if (snprintf(features->hash, HASH_SIZE,
|
||||
@@ -453,7 +429,7 @@ int aa_features_new(aa_features **features, int dirfd, const char *path)
|
||||
|
||||
retval = S_ISDIR(stat_file.st_mode) ?
|
||||
load_features_dir(dirfd, path, f->string, STRING_SIZE) :
|
||||
open_and_load_features_file(dirfd, path, f->string, STRING_SIZE);
|
||||
load_features_file(dirfd, path, f->string, STRING_SIZE);
|
||||
if (retval == -1) {
|
||||
aa_features_unref(f);
|
||||
return -1;
|
||||
@@ -516,48 +492,6 @@ int aa_features_new_from_string(aa_features **features,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* aa_features_new_from_file - create a new aa_features object based on an open file
|
||||
* @features: will point to the address of an allocated and initialized
|
||||
* aa_features object upon success
|
||||
* @file: file to load features from
|
||||
*
|
||||
* Returns: 0 on success, -1 on error with errno set and *@features pointing to
|
||||
* NULL
|
||||
*/
|
||||
int aa_features_new_from_file(aa_features **features, int file)
|
||||
{
|
||||
aa_features *f;
|
||||
ssize_t retval;
|
||||
|
||||
*features = NULL;
|
||||
|
||||
f = calloc(1, sizeof(*f));
|
||||
if (!f) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
aa_features_ref(f);
|
||||
|
||||
retval = load_features_file(file, f->string, STRING_SIZE);
|
||||
if (retval == -1) {
|
||||
aa_features_unref(f);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (init_features_hash(f) == -1) {
|
||||
int save = errno;
|
||||
|
||||
aa_features_unref(f);
|
||||
errno = save;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*features = f;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* aa_features_new_from_kernel - create a new aa_features object based on the current kernel
|
||||
* @features: will point to the address of an allocated and initialized
|
||||
@@ -598,18 +532,27 @@ void aa_features_unref(aa_features *features)
|
||||
}
|
||||
|
||||
/**
|
||||
* aa_features_write_to_fd - write a string representation of an aa_features object to an @fd
|
||||
* aa_features_write_to_file - write a string representation of an aa_features object to a file
|
||||
* @features: the features
|
||||
* @fd: the file descriptor to write to
|
||||
* @dirfd: directory file descriptor or AT_FDCWD (see openat(2))
|
||||
* @path: the path to write to
|
||||
*
|
||||
* Returns: 0 on success, -1 on error with errno set
|
||||
*/
|
||||
int aa_features_write_to_fd(aa_features *features, int fd)
|
||||
int aa_features_write_to_file(aa_features *features,
|
||||
int dirfd, const char *path)
|
||||
{
|
||||
autoclose int fd = -1;
|
||||
size_t size;
|
||||
ssize_t retval;
|
||||
char *string;
|
||||
|
||||
fd = openat(dirfd, path,
|
||||
O_WRONLY | O_CREAT | O_TRUNC | O_SYNC | O_CLOEXEC,
|
||||
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
|
||||
string = features->string;
|
||||
size = strlen(string);
|
||||
do {
|
||||
@@ -624,28 +567,6 @@ int aa_features_write_to_fd(aa_features *features, int fd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* aa_features_write_to_file - write a string representation of an aa_features object to a file
|
||||
* @features: the features
|
||||
* @dirfd: directory file descriptor or AT_FDCWD (see openat(2))
|
||||
* @path: the path to write to
|
||||
*
|
||||
* Returns: 0 on success, -1 on error with errno set
|
||||
*/
|
||||
int aa_features_write_to_file(aa_features *features,
|
||||
int dirfd, const char *path)
|
||||
{
|
||||
autoclose int fd = -1;
|
||||
|
||||
fd = openat(dirfd, path,
|
||||
O_WRONLY | O_CREAT | O_TRUNC | O_SYNC | O_CLOEXEC,
|
||||
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
|
||||
return aa_features_write_to_fd(features, fd);
|
||||
}
|
||||
|
||||
/**
|
||||
* aa_features_is_equal - equality test for two aa_features objects
|
||||
* @features1: the first features (can be NULL)
|
||||
@@ -659,76 +580,6 @@ bool aa_features_is_equal(aa_features *features1, aa_features *features2)
|
||||
strcmp(features1->string, features2->string) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* aa_features_check - check if features from a directory matches an aa_features object
|
||||
* @dirfd: a directory file descriptory or AT_FDCWD (see openat(2))
|
||||
* @path: the path containing the features
|
||||
* @features: features to be matched against
|
||||
*
|
||||
* Returns: 0 on success, -1 on failure. errno is set to EEXIST when there's not a match
|
||||
*/
|
||||
int aa_features_check(int dirfd, const char *path,
|
||||
aa_features *features)
|
||||
{
|
||||
aa_features *local_features = NULL;
|
||||
autofree char *name = NULL;
|
||||
bool rc;
|
||||
int len;
|
||||
|
||||
len = asprintf(&name, "%s/%s", path, CACHE_FEATURES_FILE);
|
||||
if (len == -1) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* verify that path dir .features matches */
|
||||
if (aa_features_new(&local_features, dirfd, name)) {
|
||||
PDEBUG("could not setup new features object for dirfd '%d' '%s'\n", dirfd, name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = aa_features_is_equal(local_features, features);
|
||||
aa_features_unref(local_features);
|
||||
if (!rc) {
|
||||
errno = EEXIST;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *features_lookup(aa_features *features, const char *str)
|
||||
{
|
||||
const char *features_string = features->string;
|
||||
struct component components[32];
|
||||
size_t i, num_components;
|
||||
|
||||
/* Empty strings are not accepted. Neither are leading '/' chars. */
|
||||
if (!str || str[0] == '/')
|
||||
return NULL;
|
||||
|
||||
/**
|
||||
* Break @str into an array of components. For example,
|
||||
* "mount/mask/mount" would turn into { "mount", 5 } as the first
|
||||
* component, { "mask", 4 } as the second, and { "mount", 5 } as the
|
||||
* third
|
||||
*/
|
||||
num_components = tokenize_path_components(str, components,
|
||||
sizeof(components) / sizeof(*components));
|
||||
|
||||
/* At least one valid token is required */
|
||||
if (!num_components)
|
||||
return NULL;
|
||||
|
||||
/* Ensure that all components are valid and found */
|
||||
for (i = 0; i < num_components; i++) {
|
||||
if (!walk_one(&features_string, &components[i], i == 0))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return features_string;
|
||||
}
|
||||
|
||||
/**
|
||||
* aa_features_supports - provides aa_features object support status
|
||||
* @features: the features
|
||||
@@ -741,53 +592,34 @@ static const char *features_lookup(aa_features *features, const char *str)
|
||||
*/
|
||||
bool aa_features_supports(aa_features *features, const char *str)
|
||||
{
|
||||
const char *value = features_lookup(features, str);
|
||||
const char *features_string = features->string;
|
||||
struct component components[32];
|
||||
size_t i, num_components;
|
||||
|
||||
if (!value)
|
||||
/* Empty strings are not accepted. Neither are leading '/' chars. */
|
||||
if (!str || str[0] == '/')
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Break @str into an array of components. For example,
|
||||
* "mount/mask/mount" would turn into { "mount", 5 } as the first
|
||||
* component, { "mask", 4 } as the second, and { "mount", 5 } as the
|
||||
* third
|
||||
*/
|
||||
num_components = tokenize_path_components(str, components,
|
||||
sizeof(components) / sizeof(*components));
|
||||
|
||||
/**
|
||||
* aa_features_value - lookup the value for a give feature
|
||||
* @features: the features
|
||||
* @str: the feature to look up the value for
|
||||
* @len: return: if set length of returned str on success
|
||||
*
|
||||
* Returns: null terminated string or NULL on error with errno set to
|
||||
* ENOENT - @str not found
|
||||
* EISDIR - @str is not a leaf node in the feature tree
|
||||
*/
|
||||
/* At least one valid token is required */
|
||||
if (!num_components)
|
||||
return false;
|
||||
|
||||
char *aa_features_value(aa_features *features, const char *str, size_t *len)
|
||||
{
|
||||
const char *start, *cur = features_lookup(features, str);
|
||||
|
||||
errno = ENOENT;
|
||||
if (!cur)
|
||||
return NULL;
|
||||
|
||||
if (!islbrace(*cur))
|
||||
return NULL;
|
||||
cur++;
|
||||
start = cur;
|
||||
|
||||
while (!isbrace_or_nul(*cur)) {
|
||||
if (!isascii(*cur))
|
||||
return NULL;
|
||||
if (islbrace(*cur)) {
|
||||
/* component is not leaf */
|
||||
errno = EISDIR;
|
||||
return NULL;
|
||||
}
|
||||
cur++;
|
||||
/* Ensure that all components are valid and found */
|
||||
for (i = 0; i < num_components; i++) {
|
||||
if (!walk_one(&features_string, &components[i], i == 0))
|
||||
return false;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
if (len)
|
||||
*len = cur - start;
|
||||
return strndup(start, cur - start);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -19,12 +19,7 @@
|
||||
%{
|
||||
|
||||
/* set the following to non-zero to get bison to emit debugging
|
||||
* information about tokens given and rules matched.
|
||||
* Also:
|
||||
* Uncomment the %defines
|
||||
* parse.error
|
||||
* parse.trace
|
||||
*/
|
||||
* information about tokens given and rules matched. */
|
||||
#define YYDEBUG 0
|
||||
#include <string.h>
|
||||
#include <aalogparse.h>
|
||||
@@ -32,25 +27,14 @@
|
||||
#include "grammar.h"
|
||||
#include "scanner.h"
|
||||
|
||||
#ifndef unused_
|
||||
#define unused_ __attribute__ ((unused))
|
||||
#endif
|
||||
#if (YYDEBUG != 0)
|
||||
#define debug_unused_ /* nothing */
|
||||
#else
|
||||
#define debug_unused_ unused_
|
||||
#endif
|
||||
|
||||
aa_log_record *ret_record;
|
||||
|
||||
/* Since we're a library, on any errors we don't want to print out any
|
||||
* error messages. We should probably add a debug interface that does
|
||||
* emit messages when asked for. */
|
||||
void aalogparse_error(unused_ void *scanner, debug_unused_ char const *s)
|
||||
void aalogparse_error(void *scanner, char const *s)
|
||||
{
|
||||
#if (YYDEBUG != 0)
|
||||
printf("ERROR: %s\n", s);
|
||||
#endif
|
||||
//printf("ERROR: %s\n", s);
|
||||
ret_record->event = AA_RECORD_INVALID;
|
||||
}
|
||||
|
||||
@@ -84,11 +68,6 @@ aa_record_event_type lookup_aa_event(unsigned int type)
|
||||
%}
|
||||
|
||||
%defines
|
||||
/* uncomment for debugging
|
||||
%define parse.error verbose
|
||||
%define parse.trace
|
||||
*/
|
||||
|
||||
%define api.pure
|
||||
%lex-param{void *scanner}
|
||||
%parse-param{void *scanner}
|
||||
@@ -149,8 +128,6 @@ aa_record_event_type lookup_aa_event(unsigned int type)
|
||||
%token TOK_KEY_PEER_PID
|
||||
%token TOK_KEY_PROFILE
|
||||
%token TOK_KEY_PEER_PROFILE
|
||||
%token TOK_KEY_LABEL
|
||||
%token TOK_KEY_PEER_LABEL
|
||||
%token TOK_KEY_PEER
|
||||
%token TOK_AUDIT
|
||||
%token TOK_KEY_FAMILY
|
||||
@@ -159,9 +136,7 @@ aa_record_event_type lookup_aa_event(unsigned int type)
|
||||
%token TOK_KEY_NAMESPACE
|
||||
%token TOK_KEY_ERROR
|
||||
%token TOK_KEY_FSUID
|
||||
%token TOK_KEY_FSUID_UPPER
|
||||
%token TOK_KEY_OUID
|
||||
%token TOK_KEY_OUID_UPPER
|
||||
%token TOK_KEY_UID
|
||||
%token TOK_KEY_AUID
|
||||
%token TOK_KEY_SAUID
|
||||
@@ -187,9 +162,7 @@ aa_record_event_type lookup_aa_event(unsigned int type)
|
||||
%token TOK_KEY_FSTYPE
|
||||
%token TOK_KEY_FLAGS
|
||||
%token TOK_KEY_SRCNAME
|
||||
%token TOK_KEY_CLASS
|
||||
|
||||
%token TOK_SOCKLOGD_KERNEL
|
||||
%token TOK_SYSLOG_KERNEL
|
||||
%token TOK_SYSLOG_USER
|
||||
|
||||
@@ -221,7 +194,7 @@ new_syntax:
|
||||
| TOK_TYPE_AA_ERROR audit_msg key_list { ret_record->event = AA_RECORD_ERROR; }
|
||||
| TOK_TYPE_UNKNOWN audit_msg key_list { ret_record->event = lookup_aa_event($1); }
|
||||
| TOK_TYPE_LSM_AVC audit_msg key_list
|
||||
| TOK_TYPE_USER_AVC audit_user_msg
|
||||
| TOK_TYPE_USER_AVC audit_user_msg TOK_SINGLE_QUOTE key_list TOK_SINGLE_QUOTE
|
||||
;
|
||||
|
||||
other_audit: TOK_TYPE_OTHER audit_msg TOK_MSG_REST
|
||||
@@ -236,28 +209,19 @@ dmesg_type: TOK_DMESG_STAMP TOK_AUDIT TOK_COLON key_type audit_id key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($1); }
|
||||
;
|
||||
|
||||
syslog_id: TOK_ID TOK_SYSLOG_KERNEL { free($1); }
|
||||
| TOK_SOCKLOGD_KERNEL { }
|
||||
;
|
||||
|
||||
syslog_type:
|
||||
syslog_date syslog_id audit_id key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; }
|
||||
| syslog_date syslog_id key_type audit_id key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; }
|
||||
| syslog_date syslog_id TOK_DMESG_STAMP audit_id key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($3); }
|
||||
| syslog_date syslog_id TOK_DMESG_STAMP key_type audit_id key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($3); }
|
||||
/* needs update: hard newline in handling multiline log messages */
|
||||
| syslog_date syslog_id TOK_DMESG_STAMP TOK_AUDIT TOK_COLON key_type audit_id audit_user_msg_partial_tail
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($3); }
|
||||
| syslog_date syslog_id TOK_DMESG_STAMP TOK_AUDIT TOK_COLON key_type audit_id audit_user_msg_tail
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($3); }
|
||||
| syslog_date syslog_id TOK_DMESG_STAMP TOK_AUDIT TOK_COLON key_type audit_id key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($3); }
|
||||
| syslog_date syslog_id TOK_AUDIT TOK_COLON key_type audit_id key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; }
|
||||
syslog_date TOK_ID TOK_SYSLOG_KERNEL audit_id key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($2); }
|
||||
| syslog_date TOK_ID TOK_SYSLOG_KERNEL key_type audit_id key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($2); }
|
||||
| syslog_date TOK_ID TOK_SYSLOG_KERNEL TOK_DMESG_STAMP audit_id key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($2); free($4); }
|
||||
| syslog_date TOK_ID TOK_SYSLOG_KERNEL TOK_DMESG_STAMP key_type audit_id key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($2); free($4); }
|
||||
| syslog_date TOK_ID TOK_SYSLOG_KERNEL TOK_DMESG_STAMP TOK_AUDIT TOK_COLON key_type audit_id key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($2); free($4); }
|
||||
| syslog_date TOK_ID TOK_SYSLOG_KERNEL TOK_AUDIT TOK_COLON key_type audit_id key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($2); }
|
||||
| syslog_date TOK_ID TOK_SYSLOG_USER key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($2); }
|
||||
;
|
||||
@@ -270,13 +234,7 @@ audit_dispatch:
|
||||
audit_msg: TOK_KEY_MSG TOK_EQUALS audit_id
|
||||
;
|
||||
|
||||
audit_user_msg_partial_tail: ignored_pid ignored_uid ignored_auid ignored_ses TOK_KEY_MSG TOK_EQUALS TOK_SINGLE_QUOTE key_list
|
||||
;
|
||||
|
||||
audit_user_msg_tail: audit_user_msg_partial_tail TOK_SINGLE_QUOTE
|
||||
;
|
||||
|
||||
audit_user_msg: TOK_KEY_MSG TOK_EQUALS audit_id audit_user_msg_tail
|
||||
audit_user_msg: TOK_KEY_MSG TOK_EQUALS audit_id ignored_pid ignored_uid ignored_auid ignored_ses TOK_KEY_MSG TOK_EQUALS
|
||||
;
|
||||
|
||||
audit_id: TOK_AUDIT TOK_OPEN_PAREN TOK_AUDIT_DIGITS TOK_PERIOD TOK_AUDIT_DIGITS TOK_COLON TOK_AUDIT_DIGITS TOK_CLOSE_PAREN TOK_COLON
|
||||
@@ -334,10 +292,6 @@ key: TOK_KEY_OPERATION TOK_EQUALS TOK_QUOTED_STRING
|
||||
{ ret_record->profile = $3;}
|
||||
| TOK_KEY_PEER_PROFILE TOK_EQUALS safe_string
|
||||
{ ret_record->peer_profile = $3;}
|
||||
| TOK_KEY_LABEL TOK_EQUALS safe_string
|
||||
{ ret_record->profile = $3;}
|
||||
| TOK_KEY_PEER_LABEL TOK_EQUALS safe_string
|
||||
{ ret_record->peer_profile = $3;}
|
||||
| TOK_KEY_FAMILY TOK_EQUALS TOK_QUOTED_STRING
|
||||
{ ret_record->net_family = $3;}
|
||||
| TOK_KEY_SOCK_TYPE TOK_EQUALS TOK_QUOTED_STRING
|
||||
@@ -354,10 +308,6 @@ key: TOK_KEY_OPERATION TOK_EQUALS TOK_QUOTED_STRING
|
||||
{ ret_record->fsuid = $3;}
|
||||
| TOK_KEY_OUID TOK_EQUALS TOK_DIGITS
|
||||
{ ret_record->ouid = $3;}
|
||||
| TOK_KEY_FSUID_UPPER TOK_EQUALS TOK_QUOTED_STRING
|
||||
{ free($3);} /* Ignore - fsuid username */
|
||||
| TOK_KEY_OUID_UPPER TOK_EQUALS TOK_QUOTED_STRING
|
||||
{ free($3);} /* Ignore - ouid username */
|
||||
| TOK_KEY_SAUID TOK_EQUALS TOK_DIGITS
|
||||
{ /* Ignore - Source audit ID from user AVC messages */ }
|
||||
| TOK_KEY_HOSTNAME TOK_EQUALS safe_string
|
||||
@@ -385,7 +335,7 @@ key: TOK_KEY_OPERATION TOK_EQUALS TOK_QUOTED_STRING
|
||||
| TOK_KEY_CAPABILITY TOK_EQUALS TOK_DIGITS
|
||||
{ /* need to reverse map number to string, need to figure out
|
||||
* how to get auto generation of reverse mapping table into
|
||||
* autotools Makefile. For now just drop assuming capname is
|
||||
* autotools Makefile. For now just drop assumming capname is
|
||||
* present which it should be with current kernels */
|
||||
}
|
||||
| TOK_KEY_CAPNAME TOK_EQUALS TOK_QUOTED_STRING
|
||||
@@ -393,7 +343,7 @@ key: TOK_KEY_OPERATION TOK_EQUALS TOK_QUOTED_STRING
|
||||
ret_record->name = $3;
|
||||
}
|
||||
| TOK_KEY_OFFSET TOK_EQUALS TOK_DIGITS
|
||||
{ /* offset is used for reporting where an error occurred unpacking
|
||||
{ /* offset is used for reporting where an error occured unpacking
|
||||
* loaded policy. We can just drop this currently
|
||||
*/
|
||||
}
|
||||
@@ -432,8 +382,6 @@ key: TOK_KEY_OPERATION TOK_EQUALS TOK_QUOTED_STRING
|
||||
ret_record->event = AA_RECORD_INVALID;
|
||||
ret_record->info = $1;
|
||||
}
|
||||
| TOK_KEY_CLASS TOK_EQUALS TOK_QUOTED_STRING
|
||||
{ ret_record->class = $3; }
|
||||
;
|
||||
|
||||
apparmor_event:
|
||||
|
@@ -43,137 +43,10 @@
|
||||
__asm__ (".symver " #real "," #name "@" #version)
|
||||
#define default_symbol_version(real, name, version) \
|
||||
__asm__ (".symver " #real "," #name "@@" #version)
|
||||
#define DLLEXPORT __attribute__((visibility("default"),externally_visible))
|
||||
|
||||
#define UNCONFINED "unconfined"
|
||||
#define UNCONFINED_SIZE strlen(UNCONFINED)
|
||||
|
||||
/*
|
||||
* AppArmor kernel interfaces. Potentially used by this code to
|
||||
* implement the various library functions.
|
||||
*
|
||||
*
|
||||
* /sys/module/apparmor/parameters/ *
|
||||
*
|
||||
* Available on all kernels, some options may not be available and policy
|
||||
* may block access.
|
||||
* audit - normal,quiet_denied,quiet,noquiet,all
|
||||
* debug (bool) - turn on debug messages if enabled during compile
|
||||
* hash_policy (bool) - provide a hash of loaded policy
|
||||
* logsyscall (bool) - ignored
|
||||
* paranoid_load (bool) - whether full policy checks are done. Should only
|
||||
* be disabled for embedded device kernels
|
||||
* audit_header (bool) - include "apparmor=<mode> in messages"
|
||||
* enabled (bool) - whether apparmor is enabled. This can be
|
||||
* different than whether apparmor is available.
|
||||
* See virtualization and LSM stacking.
|
||||
* lock_policy (bool) - one way trigger. Once set policy can not be
|
||||
* loaded, replace, removed.
|
||||
* mode - global policy namespace control of whether
|
||||
* apparmor is in "enforce", "complain"
|
||||
* path_max - maximum path size. Can always be read but
|
||||
* can only be set on some kernels.
|
||||
*
|
||||
* securityfs/apparmor - usually mounted at /sys/kernel/security/apparmor/ *
|
||||
* .access - transactional interface used to query kernel
|
||||
* .ns_level - RO policy namespace level of current task
|
||||
* .ns_name - RO current policy namespace of current task
|
||||
* .ns_stacked - RO boolean if stacking is in use with the namespace
|
||||
* .null - special device file used to redirect closed fds to
|
||||
* profiles - RO virtualized text list of visible loaded profiles
|
||||
* .remove - WO names of profiles to remove
|
||||
* .replace - WO binary policy to replace (will load if not present)
|
||||
* .load - WO binary policy to load (will fail if already present)
|
||||
* revision - RO unique incrementing revision number for policy
|
||||
* .stacked - RO boolean if label is currently stacked
|
||||
* features/ - RO feature set supported by kernel
|
||||
* policy/ - RO policy loaded into kernel
|
||||
*
|
||||
*
|
||||
* /proc/<tid>/attr/apparmor/ *
|
||||
* New proc attr interface compatible with LSM stacking. Available even
|
||||
* when LSM stacking is not in use.
|
||||
* current - see /proc/<tid>/attr/current
|
||||
* exec - see /proc/<tid>/attr/exec
|
||||
* prev - see /proc/<tid>/attr/prev
|
||||
*
|
||||
* /proc/<tid>/attr/ * Old proc attr interface shared between LSMs goes
|
||||
* to first registered LSM that wants the proc interface, but can be
|
||||
* virtualized by setting the display LSM. So if LSM stacking is in
|
||||
* use this interface may belong to another LSM. Use
|
||||
* /proc/<tid>/attr/apparmor/ *
|
||||
* first if possible, and do NOT use if
|
||||
* /sys/module/apparmor/parameters/enabled=N.
|
||||
* Note: older version of the library only used this interface and did not
|
||||
* check if it was available. Which could lead to weird failures if
|
||||
* another LSM has claimed it. This version of the library tries to
|
||||
* fix this problem, but unfortunately it is impossible to completely
|
||||
* address, because access to interfaces required to determine
|
||||
* whether apparmor owns the interface may be restricted, either
|
||||
* by existing apparmor policy that has not been updated to use the
|
||||
* new interface or by another LSM.
|
||||
* current - current confinement
|
||||
* display - LSM stacking. Which LSM currently owns the interface.
|
||||
* exec - label to switch to at exec
|
||||
* fscreate - unused by apparmor
|
||||
* keycreate - unused by apparmor
|
||||
* prev - when in HAT set to parent label
|
||||
* sockcreate - unused by apparmor
|
||||
*
|
||||
*
|
||||
* Below /proc/ interface combinations are documented on how the library
|
||||
* currently behaves and how it used to behave. This serves to document
|
||||
* known failure points as we can not entirely fix this mess.
|
||||
* Note: userspace applications using the interface directly have all
|
||||
* the issues/failures of AppArmor 2.x unless they have specifically
|
||||
* been updated to deal with this mess.
|
||||
*
|
||||
*
|
||||
* AppArmor 2.x Lib
|
||||
*
|
||||
* LSM AA sys sys proc/ proc/ user
|
||||
* Stk | Blt | LSM | enabl | avail | aa/ | * | space |
|
||||
* ----+-----+-------+-------+-------+-------+-------+-------+--------+
|
||||
* N | N | - | - | - | - | N | AA2.x | - |
|
||||
* N | N | other | - | - | - | N | AA2.x | FAIL |
|
||||
* N | N | other |denied | - | - | N | AA2.x | FAIL |
|
||||
* N | Y | - | N | - | - | N | AA2.x | - |
|
||||
* N | Y | other | - | - | - | N | AA2.x | FAIL |
|
||||
* N | Y | AA | - | - | - | Y | AA2.x | PASS |
|
||||
* Y | N | - | - | - | - | N | AA2.x | - |
|
||||
* Y | N | other | - | - | - | N | AA2.x | FAIL |
|
||||
* Y | Y | - | N | - | - | N | AA2.x | - |
|
||||
* Y | Y | other | - | - | - | N | AA2.x | FAIL |
|
||||
* Y | Y | AA | - | - | - | Y | AA2.x | PASS |
|
||||
* Y | Y | major | - | - | - | Y | AA2.x | PASS |
|
||||
* Y | Y | minor | - | - | - | N | AA2.x | FAIL |
|
||||
*
|
||||
*
|
||||
* AppArmor 3.x Lib - adds stacking support.
|
||||
*
|
||||
* Will FAIL in a few cases because it can not determine if apparmor
|
||||
* is enabled and has control of the old interface. Not failing in these
|
||||
* cases where AppArmor is available will result in regressions where
|
||||
* the library will not work correctly with old kernels. In these
|
||||
* cases its better that apparmor userspace is not used.
|
||||
*
|
||||
* AppArmor 3.x will avoid the failure cases if any of enabled, avail
|
||||
* or the new proc interfaces are available to the task. AppArmor 3.x
|
||||
* will also automatically add permissions to access the new proc
|
||||
* interfaces so change_hat and change_profile won't experience these
|
||||
* failures, it will only happen for confined applications hitting the
|
||||
* interfaces and not using change_hat or change_profile.
|
||||
*
|
||||
* LSM AA sys sys proc/ proc/
|
||||
* Stk | Blt | LSM | enabl | avail | aa/ | * |
|
||||
* ----+-----+-------+-------+-------+-------+-------+-----------------
|
||||
* Y/N | N | other | denied| NA | NA | Y | old interface avail
|
||||
* Y/N | Y | other | denied| NA | NA | Y | old interface avail
|
||||
* Y | Y | minor | denied| NA | NA | Y | old interface avail
|
||||
* Y | Y | minor | denied| NA | denied| Y | old interface avail
|
||||
* Y/N | Y | minor | denied| denied| denied| Y | old interface avail
|
||||
*/
|
||||
|
||||
/**
|
||||
* aa_find_mountpoint - find where the apparmor interface filesystem is mounted
|
||||
* @mnt: returns buffer with the mountpoint string
|
||||
@@ -220,85 +93,6 @@ int aa_find_mountpoint(char **mnt)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* pararm_check_base - return boolean value for PARAM
|
||||
* PARAM: parameter to check
|
||||
*
|
||||
* Returns: 1 == Y
|
||||
* 0 == N
|
||||
* <0 == error
|
||||
*
|
||||
* done as a macro so we can paste the param
|
||||
*/
|
||||
|
||||
#define param_check_base(PARAM) \
|
||||
({ \
|
||||
int rc, fd; \
|
||||
fd = open("/sys/module/apparmor/parameters/" PARAM, O_RDONLY); \
|
||||
if (fd == -1) { \
|
||||
rc = -errno; \
|
||||
} else { \
|
||||
char buffer[2]; \
|
||||
int size = read(fd, &buffer, 2); \
|
||||
rc = -errno; \
|
||||
close(fd); \
|
||||
errno = -rc; \
|
||||
if (size > 0) { \
|
||||
if (buffer[0] == 'Y') \
|
||||
rc = 1; \
|
||||
else \
|
||||
rc = 0; \
|
||||
} \
|
||||
} \
|
||||
(rc); \
|
||||
})
|
||||
|
||||
static pthread_once_t param_enabled_ctl = PTHREAD_ONCE_INIT;
|
||||
static int param_enabled = 0;
|
||||
|
||||
static pthread_once_t param_private_enabled_ctl = PTHREAD_ONCE_INIT;
|
||||
static int param_private_enabled = 0;
|
||||
|
||||
static void param_check_enabled_init_once(void)
|
||||
{
|
||||
param_enabled = param_check_base("enabled");
|
||||
}
|
||||
|
||||
static int param_check_enabled()
|
||||
{
|
||||
if (pthread_once(¶m_enabled_ctl, param_check_enabled_init_once) == 0 && param_enabled >= 0)
|
||||
return param_enabled;
|
||||
/* fallback if not initialized OR we recorded an error when
|
||||
* initializing.
|
||||
*/
|
||||
return param_check_base("enabled");
|
||||
}
|
||||
|
||||
static int is_enabled(void)
|
||||
{
|
||||
return param_check_enabled() == 1;
|
||||
}
|
||||
|
||||
static void param_check_private_enabled_init_once(void)
|
||||
{
|
||||
param_private_enabled = param_check_base("available");
|
||||
}
|
||||
|
||||
static int param_check_private_enabled()
|
||||
{
|
||||
if (pthread_once(¶m_private_enabled_ctl, param_check_private_enabled_init_once) == 0 && param_private_enabled >= 0)
|
||||
return param_private_enabled;
|
||||
/* fallback if not initialized OR we recorded an error when
|
||||
* initializing.
|
||||
*/
|
||||
return param_check_base("available");
|
||||
}
|
||||
|
||||
static int is_private_enabled(void)
|
||||
{
|
||||
return param_check_private_enabled() == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* aa_is_enabled - determine if apparmor is enabled
|
||||
*
|
||||
@@ -311,47 +105,36 @@ static int is_private_enabled(void)
|
||||
*/
|
||||
int aa_is_enabled(void)
|
||||
{
|
||||
int rc;
|
||||
int serrno, fd, rc, size;
|
||||
char buffer[2];
|
||||
char *mnt;
|
||||
bool private = false;
|
||||
|
||||
rc = param_check_enabled();
|
||||
if (rc < 1) {
|
||||
if (!is_private_enabled()) {
|
||||
if (rc == 0)
|
||||
errno = ECANCELED;
|
||||
else if (rc == -ENOENT)
|
||||
errno = ENOSYS;
|
||||
else
|
||||
errno = -rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* actually available but only on private interfaces */
|
||||
private = true;
|
||||
}
|
||||
|
||||
/* if the interface mountpoint is available apparmor may not
|
||||
* be locally enabled for older interfaces but still present
|
||||
* so make sure to check after, checking available status
|
||||
* also we don't cache the enabled status like available
|
||||
* because the mount status can change.
|
||||
*/
|
||||
/* if the interface mountpoint is available apparmor is enabled */
|
||||
rc = aa_find_mountpoint(&mnt);
|
||||
if (rc == 0) {
|
||||
free(mnt);
|
||||
if (!private)
|
||||
return 1;
|
||||
/* provide an error code to indicate apparmor is available
|
||||
* on private interfaces, but we can note that apparmor
|
||||
* is enabled because some applications hit the low level
|
||||
* interfaces directly and don't know about the new
|
||||
* private interfaces
|
||||
*/
|
||||
errno = EBUSY;
|
||||
/* fall through to return 0 */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* determine why the interface mountpoint isn't available */
|
||||
fd = open("/sys/module/apparmor/parameters/enabled", O_RDONLY);
|
||||
if (fd == -1) {
|
||||
if (errno == ENOENT)
|
||||
errno = ENOSYS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size = read(fd, &buffer, 2);
|
||||
serrno = errno;
|
||||
close(fd);
|
||||
errno = serrno;
|
||||
|
||||
if (size > 0) {
|
||||
if (buffer[0] == 'Y')
|
||||
errno = ENOENT;
|
||||
else
|
||||
errno = ECANCELED;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -364,138 +147,14 @@ static inline pid_t aa_gettid(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for the new apparmor proc interface once on the first api call
|
||||
* and then reuse the result on all subsequent api calls. This avoids
|
||||
* a double syscall overhead on each api call if the interface is not
|
||||
* present.
|
||||
*/
|
||||
static pthread_once_t proc_attr_base_ctl = PTHREAD_ONCE_INIT;
|
||||
static const char *proc_attr_base_old = "/proc/%d/attr/%s";
|
||||
static const char *proc_attr_new_dir = "/proc/%d/attr/apparmor/";
|
||||
static const char *proc_attr_base_stacking = "/proc/%d/attr/apparmor/%s";
|
||||
static const char *proc_attr_base_unavailable = "/proc/%d/attr/apparmor/unavailable/%s";
|
||||
static const char *proc_attr_base = NULL;
|
||||
static int proc_stacking_present = -1; /* unknown */
|
||||
|
||||
static void proc_attr_base_init_once(void)
|
||||
{
|
||||
autofree char *tmp;
|
||||
|
||||
/* if we fail we just fall back to the default value */
|
||||
if (asprintf(&tmp, proc_attr_new_dir, aa_gettid()) > 0) {
|
||||
struct stat sb;
|
||||
if (stat(tmp, &sb) == 0) {
|
||||
proc_attr_base = proc_attr_base_stacking;
|
||||
proc_stacking_present = 1;
|
||||
return;
|
||||
} else if (errno == ENOENT) {
|
||||
/* no stacking - try falling back */
|
||||
proc_stacking_present = 0;
|
||||
} else if (errno == EACCES) {
|
||||
/* the dir exists, but access is denied */
|
||||
proc_stacking_present = 1;
|
||||
proc_attr_base = proc_attr_base_stacking;
|
||||
} /* else
|
||||
denied by policy, or other error try falling back */
|
||||
} else {
|
||||
/* failed allocation - proc_attr_base stays NULL */
|
||||
return;
|
||||
}
|
||||
/* check for new interface failed, see if we can fallback */
|
||||
if (param_check_enabled() == 0) {
|
||||
/* definate NO (not just an error) on enabled. Do not fall
|
||||
* back to old shared proc interface
|
||||
*
|
||||
* First try an alternate check for private proc interface
|
||||
*/
|
||||
int enabled = param_check_private_enabled();
|
||||
if (enabled == 1) {
|
||||
/* the private interface exists and we can't
|
||||
* fallback so just keep trying on the new
|
||||
* interface.
|
||||
*/
|
||||
proc_attr_base = proc_attr_base_stacking;
|
||||
} else if (enabled == 0) {
|
||||
/* definite NO - no interface available */
|
||||
proc_attr_base = proc_attr_base_unavailable;
|
||||
} else {
|
||||
/* error can't determine, proc_attr_base stays NULL */
|
||||
}
|
||||
} else if (param_check_enabled() == 1) {
|
||||
/* apparmor is enabled, we can use the old interface */
|
||||
proc_attr_base = proc_attr_base_old;
|
||||
} else if (errno != EACCES) {
|
||||
/* this shouldn't happen unless apparmor is not builtin
|
||||
* or proc isn't mounted
|
||||
*/
|
||||
proc_attr_base = proc_attr_base_unavailable;
|
||||
} /* else
|
||||
denied by policy - proc_attr_base stays NULL */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static char *procattr_path(pid_t pid, const char *attr)
|
||||
{
|
||||
char *path = NULL;
|
||||
const char *tmp;
|
||||
|
||||
/* TODO: rework this with futex or userspace RCU so we can update
|
||||
* the base value instead of continually using the same base
|
||||
* after we have hit an error
|
||||
*/
|
||||
/* ignore failure, we just fallback to the default value */
|
||||
(void) pthread_once(&proc_attr_base_ctl, proc_attr_base_init_once);
|
||||
|
||||
if (proc_attr_base)
|
||||
tmp = proc_attr_base;
|
||||
else if (proc_stacking_present)
|
||||
/* couldn't determine during init */
|
||||
tmp = proc_attr_base_stacking;
|
||||
else
|
||||
/* couldn't determine during init and no stacking */
|
||||
tmp = proc_attr_base_old;
|
||||
if (asprintf(&path, tmp, pid, attr) > 0)
|
||||
if (asprintf(&path, "/proc/%d/attr/%s", pid, attr) > 0)
|
||||
return path;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int procattr_open(pid_t tid, const char *attr, int flags)
|
||||
{
|
||||
autofree char *tmp = NULL;
|
||||
int fd;
|
||||
|
||||
tmp = procattr_path(tid, attr);
|
||||
if (!tmp) {
|
||||
return -1;
|
||||
}
|
||||
fd = open(tmp, flags);
|
||||
|
||||
/* Test is we can fallback to the old interface (this is ugly).
|
||||
* If we haven't tried the old interface already
|
||||
* proc_attr_base == proc_attr_base_old - no fallback
|
||||
* else if is_enabled()
|
||||
* apparmor is available on the old interface
|
||||
* we do NOT use is_private_enabled() as
|
||||
* 1. the new private interface would have been tried first above
|
||||
* 2. that can be true even when another LSM is using the
|
||||
* old interface where is_enabled() is only successful if
|
||||
* the old interface is available to apparmor.
|
||||
*/
|
||||
if (fd == -1 && param_check_enabled() != 0 && strncmp(tmp, proc_attr_base_old, strlen(proc_attr_base_old)) != 0) {
|
||||
free(tmp);
|
||||
if (asprintf(&tmp, proc_attr_base_old, tid, attr) < 0) {
|
||||
/* tmp is undefined, make sure it is null for autofree*/
|
||||
tmp = NULL;
|
||||
return -1;
|
||||
}
|
||||
fd = open(tmp, flags);
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* parse_unconfined - check for the unconfined label
|
||||
* @con: the confinement context
|
||||
@@ -605,7 +264,12 @@ int aa_getprocattr_raw(pid_t tid, const char *attr, char *buf, int len,
|
||||
goto out;
|
||||
}
|
||||
|
||||
fd = procattr_open(tid, attr, O_RDONLY);
|
||||
tmp = procattr_path(tid, attr);
|
||||
if (!tmp)
|
||||
goto out;
|
||||
|
||||
fd = open(tmp, O_RDONLY);
|
||||
free(tmp);
|
||||
if (fd == -1) {
|
||||
goto out;
|
||||
}
|
||||
@@ -716,13 +380,18 @@ static int setprocattr(pid_t tid, const char *attr, const char *buf, int len)
|
||||
{
|
||||
int rc = -1;
|
||||
int fd, ret;
|
||||
char *ctl = NULL;
|
||||
|
||||
if (!buf) {
|
||||
errno = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
fd = procattr_open(tid, attr, O_WRONLY);
|
||||
ctl = procattr_path(tid, attr);
|
||||
if (!ctl)
|
||||
goto out;
|
||||
|
||||
fd = open(ctl, O_WRONLY);
|
||||
if (fd == -1) {
|
||||
goto out;
|
||||
}
|
||||
@@ -743,6 +412,9 @@ static int setprocattr(pid_t tid, const char *attr, const char *buf, int len)
|
||||
(void)close(fd);
|
||||
|
||||
out:
|
||||
if (ctl) {
|
||||
free(ctl);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -828,7 +500,7 @@ int aa_change_onexec(const char *profile)
|
||||
}
|
||||
|
||||
/* create an alias for the old change_hat@IMMUNIX_1.0 symbol */
|
||||
DLLEXPORT extern typeof((__change_hat)) __old_change_hat __attribute__((alias ("__change_hat")));
|
||||
extern typeof((__change_hat)) __old_change_hat __attribute__((alias ("__change_hat")));
|
||||
symbol_version(__old_change_hat, change_hat, IMMUNIX_1.0);
|
||||
default_symbol_version(__change_hat, change_hat, APPARMOR_1.0);
|
||||
|
||||
@@ -1018,24 +690,16 @@ int aa_getcon(char **label, char **mode)
|
||||
* Returns: length of confinement context including null termination or -1 on
|
||||
* error if errno == ERANGE then @len will hold the size needed
|
||||
*/
|
||||
int aa_getpeercon_raw(int fd, char *buf, socklen_t *len, char **mode)
|
||||
int aa_getpeercon_raw(int fd, char *buf, int *len, char **mode)
|
||||
{
|
||||
socklen_t optlen;
|
||||
socklen_t optlen = *len;
|
||||
int rc;
|
||||
|
||||
if (*len <= 0 || buf == NULL) {
|
||||
if (optlen <= 0 || buf == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
optlen = *len;
|
||||
|
||||
if (!is_enabled()) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
/* TODO: add check for private_enabled when alternate interface
|
||||
* is approved
|
||||
*/
|
||||
rc = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, buf, &optlen);
|
||||
if (rc == -1 || optlen <= 0)
|
||||
goto out;
|
||||
@@ -1083,8 +747,7 @@ out:
|
||||
*/
|
||||
int aa_getpeercon(int fd, char **label, char **mode)
|
||||
{
|
||||
socklen_t last_size, size = INITIAL_GUESS_SIZE;
|
||||
int rc;
|
||||
int rc, last_size, size = INITIAL_GUESS_SIZE;
|
||||
char *buffer = NULL;
|
||||
|
||||
if (!label) {
|
||||
@@ -1186,7 +849,7 @@ int query_label(uint32_t mask, char *query, size_t size, int *allowed,
|
||||
memcpy(query, AA_QUERY_CMD_LABEL, AA_QUERY_CMD_LABEL_SIZE);
|
||||
errno = 0;
|
||||
ret = write(fd, query, size);
|
||||
if (ret < 0 || ((size_t) ret != size)) {
|
||||
if (ret != size) {
|
||||
if (ret >= 0)
|
||||
errno = EPROTO;
|
||||
/* IMPORTANT: This is the only valid error path that can have
|
||||
@@ -1226,7 +889,7 @@ int query_label(uint32_t mask, char *query, size_t size, int *allowed,
|
||||
|
||||
/* export multiple aa_query_label symbols to compensate for downstream
|
||||
* releases with differing symbol versions. */
|
||||
DLLEXPORT extern typeof((query_label)) __aa_query_label __attribute__((alias ("query_label")));
|
||||
extern typeof((query_label)) __aa_query_label __attribute__((alias ("query_label")));
|
||||
symbol_version(__aa_query_label, aa_query_label, APPARMOR_1.1);
|
||||
default_symbol_version(query_label, aa_query_label, APPARMOR_2.9);
|
||||
|
||||
@@ -1322,9 +985,9 @@ int aa_query_link_path_len(const char *label, size_t label_len,
|
||||
query[pos] = 0;
|
||||
query[++pos] = AA_CLASS_FILE;
|
||||
memcpy(query + pos + 1, link, link_len);
|
||||
/* The kernel does the query in two parts; we could simulate this
|
||||
/* The kernel does the query in two parts we could similate this
|
||||
* doing the following, however as long as policy is compiled
|
||||
* correctly this isn't required, and it requires an extra round
|
||||
* correctly this isn't requied, and it requires and extra round
|
||||
* trip to the kernel and adds a race on policy replacement between
|
||||
* the two queries.
|
||||
*
|
||||
@@ -1358,121 +1021,3 @@ int aa_query_link_path(const char *label, const char *target, const char *link,
|
||||
strlen(target), link, strlen(link),
|
||||
allowed, audited);
|
||||
}
|
||||
|
||||
static int alloc_substring(char ***v, char *s, char *p,
|
||||
size_t max_size, size_t n, bool immutable)
|
||||
{
|
||||
if (max_size) {
|
||||
if (n >= max_size) {
|
||||
errno = E2BIG;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
char ** tmpv;
|
||||
tmpv = (char **) realloc(*v, (n + 1) * sizeof(char *));
|
||||
if (tmpv == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
*v = tmpv;
|
||||
}
|
||||
if (immutable) {
|
||||
char *tmp;
|
||||
tmp = (char *) malloc(p - s + 1);
|
||||
if (tmp == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
memcpy(tmp, s, p - s);
|
||||
tmp[p - s] = 0;
|
||||
(*v)[n] = tmp;
|
||||
} else {
|
||||
(*v)[n] = s;
|
||||
if (*p)
|
||||
*p = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* aa_split_overlay_str - split a string into potentially multiple strings
|
||||
* @str: the string to split
|
||||
* @vec: vector to put string pointers into, IF null will be allocated
|
||||
* @max_size: maximum number of ents to put in @vec, IF 0 dynamic
|
||||
* @immutable: true if @str should not be modified.
|
||||
*
|
||||
* Returns: the number of entries in vec on success. -1 on error and errno set.
|
||||
*
|
||||
* Split a comma or colon separated string into substrings.
|
||||
*
|
||||
* IF @vec == NULL
|
||||
* the vec will be dynamically allocated
|
||||
* ELSE
|
||||
* passed in @vec will be used, and NOT updated/extended
|
||||
*
|
||||
* IF @max_size == 0 && @vec == NULL
|
||||
* @vec will be dynamically resized
|
||||
* ELSE
|
||||
* @vec will be fixed at @max_size
|
||||
*
|
||||
* IF @immutable is true
|
||||
* the substrings placed in @vec will be allocated copies.
|
||||
* ELSE
|
||||
* @str will be updated in place and @vec[x] will point into @str
|
||||
*/
|
||||
int aa_split_overlay_str(char *str, char ***vec, size_t max_size, bool immutable)
|
||||
{
|
||||
char *s = str;
|
||||
char *p = str;
|
||||
int rc, n = 0;
|
||||
char **v = *vec;
|
||||
|
||||
if (!*vec) {
|
||||
if (max_size) {
|
||||
v = (char **) malloc(max_size * sizeof(char *));
|
||||
if (v == NULL) {
|
||||
rc = ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (*p) {
|
||||
if (*p == '\\') {
|
||||
if (*(p + 1) != 0)
|
||||
p++;
|
||||
} else if (*p == ',' || *p == ':') {
|
||||
if (p != s) {
|
||||
if (alloc_substring(&v, s, p, max_size, n, immutable) == -1) {
|
||||
rc = errno;
|
||||
goto err;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
p++;
|
||||
s = p;
|
||||
} else
|
||||
p++;
|
||||
}
|
||||
if (p != s) {
|
||||
if (alloc_substring(&v, s, p, max_size, n, immutable) == -1) {
|
||||
rc = errno;
|
||||
goto err;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
|
||||
*vec = v;
|
||||
return n;
|
||||
err:
|
||||
if (immutable) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
free(v[i]);
|
||||
}
|
||||
}
|
||||
if (!*vec)
|
||||
free(v);
|
||||
errno = rc;
|
||||
return -1;
|
||||
}
|
||||
|
@@ -90,7 +90,7 @@ static int write_buffer(int fd, const char *buffer, int size)
|
||||
|
||||
/**
|
||||
* write_policy_buffer - load compiled policy into the kernel
|
||||
* @fd: kernel interface to write to
|
||||
* @fd: kernel iterface to write to
|
||||
* @atomic: whether to load all policy in buffer atomically (true)
|
||||
* @buffer: buffer of policy to load
|
||||
* @size: the size of the data in the buffer
|
||||
@@ -205,7 +205,7 @@ static int write_policy_file_to_iface(aa_kernel_interface *kernel_interface,
|
||||
* @apparmorfs: path to the apparmor directory of the mounted securityfs (can
|
||||
* be NULL and the path will be auto discovered)
|
||||
*
|
||||
* Returns: 0 on success, -1 on error with errno set and *@kernel_interface
|
||||
* Returns: 0 on success, -1 on error with errnot set and *@kernel_interface
|
||||
* pointing to NULL
|
||||
*/
|
||||
int aa_kernel_interface_new(aa_kernel_interface **kernel_interface,
|
||||
|
@@ -103,8 +103,6 @@ void free_record(aa_log_record *record)
|
||||
free(record->flags);
|
||||
if (record->src_name != NULL)
|
||||
free(record->src_name);
|
||||
if (record->class != NULL)
|
||||
free(record->class);
|
||||
|
||||
free(record);
|
||||
}
|
||||
@@ -133,7 +131,7 @@ char *hex_to_string(char *hexstring)
|
||||
char *ret = NULL;
|
||||
char buf[3], *endptr;
|
||||
size_t len;
|
||||
size_t i;
|
||||
int i;
|
||||
|
||||
if (!hexstring)
|
||||
goto out;
|
||||
|
@@ -6,14 +6,14 @@
|
||||
|
||||
IMMUNIX_1.0 {
|
||||
global:
|
||||
change_hat; __old_change_hat;
|
||||
change_hat;
|
||||
local:
|
||||
*;
|
||||
};
|
||||
|
||||
APPARMOR_1.0 {
|
||||
global:
|
||||
change_hat; __change_hat;
|
||||
change_hat;
|
||||
parse_record;
|
||||
free_record;
|
||||
local:
|
||||
@@ -24,7 +24,7 @@ APPARMOR_1.1 {
|
||||
global:
|
||||
aa_is_enabled;
|
||||
aa_find_mountpoint;
|
||||
aa_change_hat; __old_change_hat;
|
||||
aa_change_hat;
|
||||
aa_change_hatv;
|
||||
aa_change_hat_vargs;
|
||||
aa_change_profile;
|
||||
@@ -37,7 +37,7 @@ APPARMOR_1.1 {
|
||||
free_record;
|
||||
aa_getprocattr_raw;
|
||||
aa_getprocattr;
|
||||
aa_query_label; __aa_query_label;
|
||||
aa_query_label;
|
||||
|
||||
# no more symbols here, please
|
||||
|
||||
@@ -47,7 +47,7 @@ APPARMOR_1.1 {
|
||||
|
||||
APPARMOR_2.9 {
|
||||
global:
|
||||
aa_query_label; query_label;
|
||||
aa_query_label;
|
||||
local:
|
||||
*;
|
||||
} APPARMOR_1.1;
|
||||
@@ -115,26 +115,9 @@ APPARMOR_2.13.1 {
|
||||
*;
|
||||
} APPARMOR_2.13;
|
||||
|
||||
APPARMOR_3.0 {
|
||||
global:
|
||||
aa_features_new_from_file;
|
||||
aa_features_write_to_fd;
|
||||
aa_features_value;
|
||||
local:
|
||||
*;
|
||||
} APPARMOR_2.13.1;
|
||||
|
||||
APPARMOR_3.1 {
|
||||
global:
|
||||
aa_features_check;
|
||||
local:
|
||||
*;
|
||||
} APPARMOR_3.0;
|
||||
|
||||
PRIVATE {
|
||||
global:
|
||||
_aa_is_blacklisted;
|
||||
_aa_asprintf;
|
||||
_aa_autofree;
|
||||
_aa_autoclose;
|
||||
_aa_autofclose;
|
||||
|
@@ -45,8 +45,6 @@ struct aa_policy_cache {
|
||||
static int clear_cache_cb(int dirfd, const char *path, struct stat *st,
|
||||
void *data unused)
|
||||
{
|
||||
/* Handle symlink here. See _aa_dirat_for_each in private.c */
|
||||
|
||||
if (S_ISREG(st->st_mode)) {
|
||||
/* remove regular files */
|
||||
return unlinkat(dirfd, path, 0);
|
||||
@@ -147,6 +145,36 @@ repeat:
|
||||
return path;
|
||||
}
|
||||
|
||||
static int cache_check_features(int dirfd, const char *cache_name,
|
||||
aa_features *features)
|
||||
{
|
||||
aa_features *local_features = NULL;
|
||||
autofree char *name = NULL;
|
||||
bool rc;
|
||||
int len;
|
||||
|
||||
len = asprintf(&name, "%s/%s", cache_name, CACHE_FEATURES_FILE);
|
||||
if (len == -1) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* verify that cache dir .features matches */
|
||||
if (aa_features_new(&local_features, dirfd, name)) {
|
||||
PDEBUG("could not setup new features object for dirfd '%d' '%s'\n", dirfd, name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = aa_features_is_equal(local_features, features);
|
||||
aa_features_unref(local_features);
|
||||
if (!rc) {
|
||||
errno = EEXIST;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int create_cache(aa_policy_cache *policy_cache, aa_features *features)
|
||||
{
|
||||
if (aa_policy_cache_remove(policy_cache->dirfd[0], "."))
|
||||
@@ -164,8 +192,8 @@ static int create_cache(aa_policy_cache *policy_cache, aa_features *features)
|
||||
static int init_cache_features(aa_policy_cache *policy_cache,
|
||||
aa_features *kernel_features, bool create)
|
||||
{
|
||||
if (aa_features_check(policy_cache->dirfd[0], ".",
|
||||
kernel_features)) {
|
||||
if (cache_check_features(policy_cache->dirfd[0], ".",
|
||||
kernel_features)) {
|
||||
/* EEXIST must come before ENOENT for short circuit eval */
|
||||
if (!create || errno == EEXIST || errno != ENOENT)
|
||||
return -1;
|
||||
@@ -201,13 +229,13 @@ static int cache_miss_cb(int dirfd, const struct dirent *ent, void *arg)
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
if (!aa_features_check(dirfd, cache_name, data->features) || errno == ENOENT) {
|
||||
if (!cache_check_features(dirfd, cache_name, data->features) || errno == ENOENT) {
|
||||
/* found cache dir matching pattern */
|
||||
data->cache_name = cache_name;
|
||||
/* return 1 to stop iteration and signal dir found */
|
||||
return 1;
|
||||
} else if (errno != EEXIST) {
|
||||
PDEBUG("aa_features_check() failed for dirfd '%d' '%s'\n", dirfd, cache_name);
|
||||
PDEBUG("cache_check_features() failed for dirfd '%d' '%s'\n", dirfd, cache_name);
|
||||
free(cache_name);
|
||||
return -1;
|
||||
}
|
||||
@@ -232,7 +260,7 @@ static int cache_dir_from_path_and_features(char **cache_path,
|
||||
{
|
||||
autofree const char *features_id = NULL;
|
||||
char *cache_dir;
|
||||
ssize_t len;
|
||||
size_t len;
|
||||
int rc;
|
||||
|
||||
features_id = aa_features_id(features);
|
||||
@@ -243,12 +271,12 @@ static int cache_dir_from_path_and_features(char **cache_path,
|
||||
if (len == -1)
|
||||
return -1;
|
||||
|
||||
if (!aa_features_check(dirfd, cache_dir, features) || errno == ENOENT) {
|
||||
if (!cache_check_features(dirfd, cache_dir, features) || errno == ENOENT) {
|
||||
PDEBUG("cache_dir_from_path_and_features() found '%s'\n", cache_dir);
|
||||
*cache_path = cache_dir;
|
||||
return 0;
|
||||
} else if (errno != EEXIST) {
|
||||
PDEBUG("aa_features_check() failed for dirfd '%d' %s\n", dirfd, cache_dir);
|
||||
PDEBUG("cache_check_features() failed for dirfd '%d' %s\n", dirfd, cache_dir);
|
||||
free(cache_dir);
|
||||
return -1;
|
||||
}
|
||||
@@ -660,8 +688,8 @@ char *aa_policy_cache_dir_path_preview(aa_features *kernel_features,
|
||||
|
||||
aa_features_unref(kernel_features);
|
||||
|
||||
if (asprintf(&dir_path, "%s%s%s", cache_loc ? cache_loc : "",
|
||||
cache_loc ? "/" : "", cache_dir) == -1) {
|
||||
if (asprintf(&dir_path, "%s%s%s",
|
||||
cache_loc ? : "", cache_loc ? "/" : "", cache_dir) == -1) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
@@ -49,7 +49,7 @@
|
||||
* Allow libapparmor to build on older glibcs and other libcs that do
|
||||
* not support reallocarray.
|
||||
*/
|
||||
#ifndef HAVE_REALLOCARRAY
|
||||
#ifndef HAVE_REALLOCARRY
|
||||
void *reallocarray(void *ptr, size_t nmemb, size_t size)
|
||||
{
|
||||
return realloc(ptr, nmemb * size);
|
||||
@@ -63,7 +63,7 @@ struct ignored_suffix_t {
|
||||
};
|
||||
|
||||
static struct ignored_suffix_t ignored_suffixes[] = {
|
||||
/* Debian packaging files, which are in flux during install
|
||||
/* Debian packging files, which are in flux during install
|
||||
should be silently ignored. */
|
||||
{ ".dpkg-new", 9, 1 },
|
||||
{ ".dpkg-old", 9, 1 },
|
||||
@@ -126,7 +126,7 @@ bool atomic_dec_and_test(unsigned int *v)
|
||||
|
||||
int _aa_is_blacklisted(const char *name)
|
||||
{
|
||||
ssize_t name_len = strlen(name);
|
||||
size_t name_len = strlen(name);
|
||||
struct ignored_suffix_t *suffix;
|
||||
|
||||
/* skip dot files and files with no name */
|
||||
@@ -147,7 +147,7 @@ int _aa_is_blacklisted(const char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* automatically free allocated variables tagged with autofree on fn exit */
|
||||
/* automaticly free allocated variables tagged with autofree on fn exit */
|
||||
void _aa_autofree(void *p)
|
||||
{
|
||||
void **_p = (void**)p;
|
||||
@@ -278,33 +278,33 @@ static int insert(struct overlaydir **overlayptr, int *max_size, int *size,
|
||||
|
||||
#define merge(overlay, n_overlay, max_size, list, n_list, dirfd) \
|
||||
({ \
|
||||
int y, z; \
|
||||
int i, j; \
|
||||
int rc = 0; \
|
||||
\
|
||||
for (y = 0, z = 0; y < n_overlay && z < n_list; ) { \
|
||||
int res = strcmp(overlay[y].dent->d_name, list[z]->d_name);\
|
||||
for (i = 0, j = 0; i < n_overlay && j < n_list; ) { \
|
||||
int res = strcmp(overlay[i].dent->d_name, list[j]->d_name);\
|
||||
if (res < 0) { \
|
||||
y++; \
|
||||
i++; \
|
||||
continue; \
|
||||
} else if (res == 0) { \
|
||||
free(list[z]); \
|
||||
list[z] = NULL; \
|
||||
y++; \
|
||||
z++; \
|
||||
free(list[j]); \
|
||||
list[j] = NULL; \
|
||||
i++; \
|
||||
j++; \
|
||||
} else { \
|
||||
if ((rc = insert(&overlay, &max_size, &n_overlay, y,\
|
||||
n_list - z, dirfd, list[z]))) \
|
||||
if ((rc = insert(&overlay, &max_size, &n_overlay, i,\
|
||||
n_list - j, dirfd, list[j]))) \
|
||||
goto fail; \
|
||||
y++; \
|
||||
list[z++] = NULL; \
|
||||
i++; \
|
||||
list[j++] = NULL; \
|
||||
} \
|
||||
} \
|
||||
while (z < n_list) { \
|
||||
if ((rc = insert(&overlay, &max_size, &n_overlay, y, \
|
||||
n_list - z, dirfd,list[z]))) \
|
||||
while (j < n_list) { \
|
||||
if ((rc = insert(&overlay, &max_size, &n_overlay, i, \
|
||||
n_list - j, dirfd,list[j]))) \
|
||||
goto fail; \
|
||||
y++; \
|
||||
list[z++] = NULL; \
|
||||
i++; \
|
||||
list[j++] = NULL; \
|
||||
} \
|
||||
\
|
||||
fail: \
|
||||
@@ -315,7 +315,8 @@ static ssize_t readdirfd(int dirfd, struct dirent ***out,
|
||||
int (*dircmp)(const struct dirent **, const struct dirent **))
|
||||
{
|
||||
struct dirent **dents = NULL, *dent;
|
||||
ssize_t n = 0, i;
|
||||
ssize_t n = 0;
|
||||
size_t i;
|
||||
int save;
|
||||
DIR *dir;
|
||||
|
||||
@@ -365,7 +366,7 @@ static ssize_t readdirfd(int dirfd, struct dirent ***out,
|
||||
}
|
||||
|
||||
if (dircmp)
|
||||
qsort(dents, n, sizeof(struct dirent *), (int (*)(const void *, const void *))dircmp);
|
||||
qsort(dents, n, sizeof(*dent), (int (*)(const void *, const void *))dircmp);
|
||||
|
||||
*out = dents;
|
||||
closedir(dir);
|
||||
@@ -388,7 +389,7 @@ int _aa_overlaydirat_for_each(int dirfd[], int n, void *data,
|
||||
{
|
||||
autofree struct dirent **list = NULL;
|
||||
autofree struct overlaydir *overlay = NULL;
|
||||
int i;
|
||||
int i, k;
|
||||
int n_list, size = 0, max_size = 0;
|
||||
int rc = 0;
|
||||
|
||||
@@ -399,10 +400,10 @@ int _aa_overlaydirat_for_each(int dirfd[], int n, void *data,
|
||||
return -1;
|
||||
}
|
||||
if (merge(overlay, size, max_size, list, n_list, dirfd[i])) {
|
||||
for (i = 0; i < n_list; i++)
|
||||
for (k = 0; k < n_list; k++)
|
||||
free(list[i]);
|
||||
for (i = 0; i < size; i++)
|
||||
free(overlay[i].dent);
|
||||
for (k = 0; k < size; k++)
|
||||
free(overlay[k].dent);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -452,8 +453,7 @@ int _aa_overlaydirat_for_each(int dirfd[], int n, void *data,
|
||||
*
|
||||
* The cb function is called with the DIR in use and the name of the
|
||||
* file in that directory. If the file is to be opened it should
|
||||
* use the openat, fstatat, and related fns. If the file is a symlink
|
||||
* _aa_dirat_for_each currently tries to traverse it for the caller
|
||||
* use the openat, fstatat, and related fns.
|
||||
*
|
||||
* Returns: 0 on success, else -1 and errno is set to the error code
|
||||
*/
|
||||
@@ -475,7 +475,7 @@ int _aa_dirat_for_each(int dirfd, const char *name, void *data,
|
||||
return -1;
|
||||
}
|
||||
|
||||
num_dirs = readdirfd(cb_dirfd, &namelist, alphasort);
|
||||
num_dirs = readdirfd(cb_dirfd, &namelist, NULL);
|
||||
if (num_dirs == -1) {
|
||||
PDEBUG("scandirat of directory '%s' failed: %m\n", name);
|
||||
return -1;
|
||||
@@ -486,34 +486,14 @@ int _aa_dirat_for_each(int dirfd, const char *name, void *data,
|
||||
autofree struct dirent *dir = namelist[i];
|
||||
struct stat my_stat;
|
||||
|
||||
if (fstatat(cb_dirfd, dir->d_name, &my_stat, AT_SYMLINK_NOFOLLOW)) {
|
||||
if (rc)
|
||||
continue;
|
||||
|
||||
if (fstatat(cb_dirfd, dir->d_name, &my_stat, 0)) {
|
||||
PDEBUG("stat failed for '%s': %m\n", dir->d_name);
|
||||
rc = -1;
|
||||
continue;
|
||||
}
|
||||
/* currently none of the callers handle symlinks, and this
|
||||
* same basic code was applied to each. So for this patch
|
||||
* just drop it here.
|
||||
*
|
||||
* Going forward we need to start handling symlinks as
|
||||
* they have meaning.
|
||||
* In the case of
|
||||
* cache: they act as a place holder for files that have been
|
||||
* combined into a single binary. This enables the
|
||||
* file based cache lookup time find that relation
|
||||
* and dedup, so multiple loads aren't done.
|
||||
* profiles: just a profile in an alternate location, but
|
||||
* should do dedup detection when doing dir reads
|
||||
* so we don't double process.
|
||||
*/
|
||||
if (S_ISLNK(my_stat.st_mode)) {
|
||||
/* just traverse the symlink */
|
||||
if (fstatat(cb_dirfd, dir->d_name, &my_stat, 0)) {
|
||||
PDEBUG("symlink target stat failed for '%s': %m\n", dir->d_name);
|
||||
rc = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (cb(cb_dirfd, dir->d_name, &my_stat, data)) {
|
||||
PDEBUG("dir_for_each callback failed for '%s'\n",
|
||||
|
@@ -72,7 +72,7 @@ void string_buf_append(unsigned int length, char *text)
|
||||
|
||||
%}
|
||||
|
||||
ws [ \t\r\n\x1d]
|
||||
ws [ \t\r\n]
|
||||
|
||||
equals "="
|
||||
digit [[:digit:]]
|
||||
@@ -121,8 +121,6 @@ key_namespace "namespace"
|
||||
key_mask "mask"
|
||||
key_denied_mask "denied_mask"
|
||||
key_requested_mask "requested_mask"
|
||||
key_denied "denied"
|
||||
key_requested "requested"
|
||||
key_attribute "attribute"
|
||||
key_task "task"
|
||||
key_parent "parent"
|
||||
@@ -133,16 +131,12 @@ key_pid "pid"
|
||||
key_peer_pid "peer_pid"
|
||||
key_profile "profile"
|
||||
key_peer_profile "peer_profile"
|
||||
key_label "label"
|
||||
key_peer_label "peer_label"
|
||||
key_family "family"
|
||||
key_sock_type "sock_type"
|
||||
key_protocol "protocol"
|
||||
key_error "error"
|
||||
key_fsuid "fsuid"
|
||||
key_fsuid_upper "FSUID"
|
||||
key_ouid "ouid"
|
||||
key_ouid_upper "OUID"
|
||||
key_uid "uid"
|
||||
key_auid "auid"
|
||||
key_sauid "sauid"
|
||||
@@ -165,21 +159,17 @@ key_dest "dest"
|
||||
key_path "path"
|
||||
key_interface "interface"
|
||||
key_member "member"
|
||||
key_method "method"
|
||||
key_signal "signal"
|
||||
key_peer "peer"
|
||||
key_fstype "fstype"
|
||||
key_flags "flags"
|
||||
key_srcname "srcname"
|
||||
key_class "class"
|
||||
key_tcontext "tcontext"
|
||||
audit "audit"
|
||||
|
||||
/* network addrs */
|
||||
ip_addr [a-f[:digit:].:]{3,}
|
||||
|
||||
/* syslog tokens */
|
||||
socklogd_kernel kern.notice{colon}
|
||||
syslog_kernel kernel{colon}
|
||||
syslog_user [[:alnum:]_-]+\[[[:digit:]]+\]{colon}
|
||||
syslog_yyyymmdd {digit}{4}{minus}{digit}{2}{minus}{digit}{2}
|
||||
@@ -314,8 +304,6 @@ yy_flex_debug = 0;
|
||||
{key_mask} { return(TOK_KEY_MASK); }
|
||||
{key_denied_mask} { return(TOK_KEY_DENIED_MASK); }
|
||||
{key_requested_mask} { return(TOK_KEY_REQUESTED_MASK); }
|
||||
{key_denied} { return(TOK_KEY_DENIED_MASK); }
|
||||
{key_requested} { return(TOK_KEY_REQUESTED_MASK); }
|
||||
{key_attribute} { BEGIN(sub_id); return(TOK_KEY_ATTRIBUTE); }
|
||||
{key_task} { return(TOK_KEY_TASK); }
|
||||
{key_parent} { return(TOK_KEY_PARENT); }
|
||||
@@ -326,17 +314,12 @@ yy_flex_debug = 0;
|
||||
{key_peer_pid} { return(TOK_KEY_PEER_PID); }
|
||||
{key_profile} { BEGIN(safe_string); return(TOK_KEY_PROFILE); }
|
||||
{key_peer_profile} { BEGIN(safe_string); return(TOK_KEY_PEER_PROFILE); }
|
||||
{key_label} { BEGIN(safe_string); return(TOK_KEY_LABEL); }
|
||||
{key_peer_label} { BEGIN(safe_string); return(TOK_KEY_PEER_LABEL); }
|
||||
{key_tcontext} { BEGIN(safe_string); return(TOK_KEY_PEER_LABEL); }
|
||||
{key_family} { return(TOK_KEY_FAMILY); }
|
||||
{key_sock_type} { return(TOK_KEY_SOCK_TYPE); }
|
||||
{key_protocol} { return(TOK_KEY_PROTOCOL); }
|
||||
{key_error} { return(TOK_KEY_ERROR); }
|
||||
{key_fsuid} { return(TOK_KEY_FSUID); }
|
||||
{key_fsuid_upper} { return(TOK_KEY_FSUID_UPPER); }
|
||||
{key_ouid} { return(TOK_KEY_OUID); }
|
||||
{key_ouid_upper} { return(TOK_KEY_OUID_UPPER); }
|
||||
{key_uid} { return(TOK_KEY_UID); }
|
||||
{key_auid} { return(TOK_KEY_AUID); }
|
||||
{key_sauid} { return(TOK_KEY_SAUID); }
|
||||
@@ -358,15 +341,12 @@ yy_flex_debug = 0;
|
||||
{key_path} { return(TOK_KEY_PATH); }
|
||||
{key_interface} { return(TOK_KEY_INTERFACE); }
|
||||
{key_member} { return(TOK_KEY_MEMBER); }
|
||||
{key_method} { return(TOK_KEY_MEMBER); }
|
||||
{key_signal} { BEGIN(sub_id); return(TOK_KEY_SIGNAL); }
|
||||
{key_peer} { BEGIN(safe_string); return(TOK_KEY_PEER); }
|
||||
{key_fstype} { return(TOK_KEY_FSTYPE); }
|
||||
{key_flags} { BEGIN(safe_string); return(TOK_KEY_FLAGS); }
|
||||
{key_srcname} { BEGIN(safe_string); return(TOK_KEY_SRCNAME); }
|
||||
{key_class} { BEGIN(safe_string); return(TOK_KEY_CLASS); }
|
||||
|
||||
{socklogd_kernel} { BEGIN(dmesg_timestamp); return(TOK_SOCKLOGD_KERNEL); }
|
||||
{syslog_kernel} { BEGIN(dmesg_timestamp); return(TOK_SYSLOG_KERNEL); }
|
||||
{syslog_user} { return(TOK_SYSLOG_USER); }
|
||||
{syslog_month} { yylval->t_str = strdup(yytext); return(TOK_DATE_MONTH); }
|
||||
@@ -381,7 +361,6 @@ yy_flex_debug = 0;
|
||||
|
||||
<hostname>{
|
||||
{ws}+ { /* eat whitespace */ }
|
||||
{socklogd_kernel} { BEGIN(dmesg_timestamp); return(TOK_SOCKLOGD_KERNEL); }
|
||||
{syslog_hostname} { yylval->t_str = strdup(yytext); BEGIN(INITIAL); return(TOK_ID); }
|
||||
}
|
||||
|
||||
|
@@ -1,8 +1,5 @@
|
||||
if HAVE_PYTHON
|
||||
|
||||
COMMONDIR = $(top_srcdir)/../../common/
|
||||
include $(COMMONDIR)/Make.rules
|
||||
|
||||
EXTRA_DIST = libapparmor_wrap.c
|
||||
|
||||
SUBDIRS = test
|
||||
@@ -14,14 +11,14 @@ MOSTLYCLEANFILES=libapparmor_wrap.c LibAppArmor.py
|
||||
|
||||
all-local: libapparmor_wrap.c setup.py
|
||||
if test ! -f libapparmor_wrap.c; then cp $(srcdir)/libapparmor_wrap.c . ; fi
|
||||
CC="$(CC)" CFLAGS="$(PYTHON_CPPFLAGS) $(EXTRA_WARNINGS)" LDSHARED="$(CC) -shared" LDFLAGS="$(PYTHON_LDFLAGS) $(LDFLAGS)" $(PYTHON) setup.py build
|
||||
$(PYTHON) setup.py build
|
||||
|
||||
install-exec-local:
|
||||
$(PYTHON) setup.py install --root="/$(DESTDIR)" --prefix="$(prefix)"
|
||||
|
||||
clean-local:
|
||||
if test -x "$(PYTHON)"; then $(PYTHON) setup.py clean; fi
|
||||
rm -rf build LibAppArmor.egg-info
|
||||
rm -rf build
|
||||
if test $(top_srcdir) != $(top_builddir) ; then rm -f libapparmor_wrap.c ; fi
|
||||
|
||||
endif
|
||||
|
@@ -1 +1,6 @@
|
||||
from LibAppArmor.LibAppArmor import *
|
||||
import sys
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
from LibAppArmor.LibAppArmor import *
|
||||
else:
|
||||
from .LibAppArmor import *
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user