mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-09-01 06:45:38 +00:00
Compare commits
29 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
8b81fe065f | ||
|
a8f5b8f0db | ||
|
878ebd4b33 | ||
|
bc5634f2af | ||
|
7c217b7413 | ||
|
86037e0a23 | ||
|
1f82a98029 | ||
|
7adbc4b3ee | ||
|
5199e44ef0 | ||
|
32e76985c9 | ||
|
54bdfd3565 | ||
|
bd68cd2d69 | ||
|
f076497f89 | ||
|
5089a941c8 | ||
|
3b490f9450 | ||
|
66928660f5 | ||
|
d2fc6ff1cc | ||
|
39fc9dc40f | ||
|
a90238e7c6 | ||
|
5246203c9e | ||
|
4b99f16b49 | ||
|
7777b1418e | ||
|
9d5934f5ff | ||
|
962d4afb3d | ||
|
eb8acf4b45 | ||
|
8217eb04af | ||
|
26e1200324 | ||
|
4181b187c3 | ||
|
485798c4f8 |
@@ -1,34 +1,7 @@
|
||||
apparmor-*
|
||||
cscope.*
|
||||
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-load.8
|
||||
binutils/aa-status
|
||||
binutils/aa-status.8
|
||||
binutils/cJSON.o
|
||||
binutils/po/*.mo
|
||||
changehat/mod_apparmor/.libs
|
||||
changehat/mod_apparmor/mod_apparmor.8
|
||||
changehat/mod_apparmor/mod_apparmor.8.html
|
||||
changehat/mod_apparmor/mod_apparmor.la
|
||||
changehat/mod_apparmor/mod_apparmor.lo
|
||||
changehat/mod_apparmor/mod_apparmor.slo
|
||||
changehat/mod_apparmor/mod_apparmor.so
|
||||
changehat/mod_apparmor/pod2htmd.tmp
|
||||
changehat/pam_apparmor/get_options.o
|
||||
changehat/pam_apparmor/pam_apparmor.o
|
||||
changehat/pam_apparmor/pam_apparmor.so
|
||||
parser/po/*.mo
|
||||
parser/af_names.h
|
||||
parser/cap_names.h
|
||||
parser/generated_cap_names.h
|
||||
parser/generated_af_names.h
|
||||
parser/errnos.h
|
||||
parser/tst_lib
|
||||
parser/tst_misc
|
||||
parser/tst_regex
|
||||
@@ -40,9 +13,6 @@ parser/parser_version.h
|
||||
parser/parser_yacc.c
|
||||
parser/parser_yacc.h
|
||||
parser/pod2htm*.tmp
|
||||
parser/libapparmor_re/*.o
|
||||
parser/libapparmor_re/libapparmor_re.a
|
||||
parser/*.o
|
||||
parser/*.7
|
||||
parser/*.5
|
||||
parser/*.8
|
||||
@@ -56,8 +26,7 @@ parser/techdoc.aux
|
||||
parser/techdoc.log
|
||||
parser/techdoc.pdf
|
||||
parser/techdoc.toc
|
||||
profiles/apparmor.d/local/*
|
||||
!profiles/apparmor.d/local/README
|
||||
profiles/apparmor.d/local/*.*
|
||||
libraries/libapparmor/Makefile
|
||||
libraries/libapparmor/Makefile.in
|
||||
libraries/libapparmor/aclocal.m4
|
||||
@@ -88,27 +57,17 @@ libraries/libapparmor/src/.deps
|
||||
libraries/libapparmor/src/.libs
|
||||
libraries/libapparmor/src/Makefile
|
||||
libraries/libapparmor/src/Makefile.in
|
||||
libraries/libapparmor/src/PMurHash.lo
|
||||
libraries/libapparmor/src/PMurHash.o
|
||||
libraries/libapparmor/src/af_protos.h
|
||||
libraries/libapparmor/src/change_hat.lo
|
||||
libraries/libapparmor/src/features.lo
|
||||
libraries/libapparmor/src/features.o
|
||||
libraries/libapparmor/src/grammar.lo
|
||||
libraries/libapparmor/src/grammar.o
|
||||
libraries/libapparmor/src/kernel.lo
|
||||
libraries/libapparmor/src/kernel.o
|
||||
libraries/libapparmor/src/kernel_interface.lo
|
||||
libraries/libapparmor/src/kernel_interface.o
|
||||
libraries/libapparmor/src/libaalogparse.lo
|
||||
libraries/libapparmor/src/libaalogparse.o
|
||||
libraries/libapparmor/src/libimmunix_warning.lo
|
||||
libraries/libapparmor/src/policy_cache.lo
|
||||
libraries/libapparmor/src/policy_cache.o
|
||||
libraries/libapparmor/src/private.lo
|
||||
libraries/libapparmor/src/private.o
|
||||
libraries/libapparmor/src/scanner.lo
|
||||
libraries/libapparmor/src/scanner.o
|
||||
libraries/libapparmor/src/libapparmor.pc
|
||||
libraries/libapparmor/src/libapparmor.la
|
||||
libraries/libapparmor/src/libimmunix.la
|
||||
@@ -116,31 +75,7 @@ libraries/libapparmor/src/grammar.c
|
||||
libraries/libapparmor/src/grammar.h
|
||||
libraries/libapparmor/src/scanner.c
|
||||
libraries/libapparmor/src/scanner.h
|
||||
libraries/libapparmor/src/test-suite.log
|
||||
libraries/libapparmor/src/tst_aalogmisc
|
||||
libraries/libapparmor/src/tst_aalogmisc.log
|
||||
libraries/libapparmor/src/tst_aalogmisc.o
|
||||
libraries/libapparmor/src/tst_aalogmisc.trs
|
||||
libraries/libapparmor/src/tst_aalogparse_cpp
|
||||
libraries/libapparmor/src/tst_aalogparse_cpp.log
|
||||
libraries/libapparmor/src/tst_aalogparse_cpp.o
|
||||
libraries/libapparmor/src/tst_aalogparse_cpp.trs
|
||||
libraries/libapparmor/src/tst_aalogparse_reentrancy
|
||||
libraries/libapparmor/src/tst_aalogparse_reentrancy.log
|
||||
libraries/libapparmor/src/tst_aalogparse_reentrancy.o
|
||||
libraries/libapparmor/src/tst_aalogparse_reentrancy.trs
|
||||
libraries/libapparmor/src/tst_aalogparse_oldname
|
||||
libraries/libapparmor/src/tst_aalogparse_oldname.log
|
||||
libraries/libapparmor/src/tst_aalogparse_oldname.o
|
||||
libraries/libapparmor/src/tst_aalogparse_oldname.trs
|
||||
libraries/libapparmor/src/tst_features
|
||||
libraries/libapparmor/src/tst_features.log
|
||||
libraries/libapparmor/src/tst_features.o
|
||||
libraries/libapparmor/src/tst_features.trs
|
||||
libraries/libapparmor/src/tst_kernel
|
||||
libraries/libapparmor/src/tst_kernel.log
|
||||
libraries/libapparmor/src/tst_kernel.o
|
||||
libraries/libapparmor/src/tst_kernel.trs
|
||||
libraries/libapparmor/swig/Makefile
|
||||
libraries/libapparmor/swig/Makefile.in
|
||||
libraries/libapparmor/swig/perl/LibAppArmor.bs
|
||||
@@ -154,10 +89,8 @@ libraries/libapparmor/swig/perl/MYMETA.json
|
||||
libraries/libapparmor/swig/perl/MYMETA.yml
|
||||
libraries/libapparmor/swig/perl/blib
|
||||
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
|
||||
@@ -165,18 +98,8 @@ libraries/libapparmor/swig/python/Makefile.in
|
||||
libraries/libapparmor/swig/python/setup.py
|
||||
libraries/libapparmor/swig/python/test/Makefile
|
||||
libraries/libapparmor/swig/python/test/Makefile.in
|
||||
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
|
||||
@@ -192,31 +115,14 @@ libraries/libapparmor/testsuite/lib/Makefile.in
|
||||
libraries/libapparmor/testsuite/libaalogparse.test/Makefile
|
||||
libraries/libapparmor/testsuite/libaalogparse.test/Makefile.in
|
||||
libraries/libapparmor/testsuite/test_multi/out
|
||||
libraries/libapparmor/testsuite/test_multi_multi-test_multi.o
|
||||
changehat/mod_apparmor/.libs
|
||||
utils/*.8
|
||||
utils/*.8.html
|
||||
utils/*.5
|
||||
utils/*.5.html
|
||||
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
|
||||
@@ -231,13 +137,7 @@ tests/regression/apparmor/chgrp
|
||||
tests/regression/apparmor/chmod
|
||||
tests/regression/apparmor/chown
|
||||
tests/regression/apparmor/clone
|
||||
tests/regression/apparmor/complain
|
||||
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/disconnected_mount_complain
|
||||
tests/regression/apparmor/env_check
|
||||
tests/regression/apparmor/environ
|
||||
tests/regression/apparmor/exec
|
||||
@@ -247,42 +147,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/getcon_verify
|
||||
tests/regression/apparmor/introspect
|
||||
tests/regression/apparmor/io_uring
|
||||
tests/regression/apparmor/link
|
||||
tests/regression/apparmor/link_subset
|
||||
tests/regression/apparmor/linkat_tmpfile
|
||||
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_inet_rcv
|
||||
tests/regression/apparmor/net_inet_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
|
||||
@@ -293,32 +177,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
|
||||
|
||||
# Patterns related to spread integration tests
|
||||
*.img
|
||||
*.iso
|
||||
*.lock
|
||||
*.log
|
||||
*.qcow2
|
||||
*.run
|
||||
.spread-reuse.yaml
|
||||
.spread-reuse.*.yaml
|
||||
spread-artifacts/
|
||||
spread-logs/
|
337
.gitlab-ci.yml
337
.gitlab-ci.yml
@@ -1,337 +0,0 @@
|
||||
spec:
|
||||
inputs:
|
||||
build-test-images:
|
||||
default: false
|
||||
type: boolean
|
||||
description: Explicitly build virtual machine images used by integration tests.
|
||||
---
|
||||
image: ubuntu:latest
|
||||
|
||||
# XXX - add a deploy stage to publish man pages, docs, and coverage
|
||||
# reports
|
||||
|
||||
workflow:
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
|
||||
- if: $CI_COMMIT_TAG
|
||||
- if: $CI_COMMIT_BRANCH
|
||||
|
||||
stages:
|
||||
- build
|
||||
- test
|
||||
- spread
|
||||
|
||||
.ubuntu-common:
|
||||
interruptible: true
|
||||
before_script:
|
||||
# Install build-dependencies by loading the package list from the ubuntu/debian cloud-init profile.
|
||||
- printf '\e[0K%s:%s:%s[collapsed=true]\r\e[0K%s\n' section_start "$(date +%s)" install_deps "Installing dependencies..."
|
||||
- apt-get update -qq
|
||||
- apt-get install --yes yq make lsb-release
|
||||
- |
|
||||
printf 'include .image-garden.mk\n$(info $(UBUNTU_CLOUD_INIT_USER_DATA_TEMPLATE))\n.PHONY: nothing\nnothing:\n' \
|
||||
| make -f - nothing \
|
||||
| yq '.packages | .[]' \
|
||||
| xargs apt-get install --yes --no-install-recommends
|
||||
- printf '\e[0K%s:%s:%s\r\e[0K\n' section_end "$(date +%s)" install_deps
|
||||
after_script:
|
||||
# Inspect the kernel and lsb-release.
|
||||
- lsb_release -a
|
||||
- uname -a
|
||||
|
||||
build-all:
|
||||
stage: build
|
||||
extends:
|
||||
- .ubuntu-common
|
||||
script:
|
||||
# Run the spread prepare section to build everything.
|
||||
- yq -r '.prepare' <spread.yaml | SPREAD_PATH=. bash -xeu
|
||||
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/
|
||||
|
||||
test-libapparmor:
|
||||
stage: test
|
||||
needs: ["build-all"]
|
||||
extends:
|
||||
- .ubuntu-common
|
||||
script:
|
||||
# This is to touch the built files in the test stage to avoid needless rebuilding
|
||||
- make -C libraries/libapparmor --touch
|
||||
- make -C libraries/libapparmor check
|
||||
|
||||
test-parser:
|
||||
stage: test
|
||||
needs: ["build-all"]
|
||||
extends:
|
||||
- .ubuntu-common
|
||||
script:
|
||||
# This is to touch the built files in the test stage to avoid needless rebuilding
|
||||
- make -C parser --touch
|
||||
- make -C parser -j $(nproc) tst_binaries
|
||||
- make -C parser check
|
||||
|
||||
test-binutils:
|
||||
stage: test
|
||||
needs: ["build-all"]
|
||||
extends:
|
||||
- .ubuntu-common
|
||||
script:
|
||||
- make -C binutils check
|
||||
|
||||
test-utils:
|
||||
stage: test
|
||||
needs: ["build-all"]
|
||||
extends:
|
||||
- .ubuntu-common
|
||||
script:
|
||||
# This is to touch the built files in the test stage to avoid needless rebuilding
|
||||
- make -C utils --touch
|
||||
|
||||
# TODO: move those to cloud-init list?
|
||||
- printf '\e[0K%s:%s:%s[collapsed=true]\r\e[0K%s\n' section_start "$(date +%s)" install_extra_deps "Installing additional dependencies..."
|
||||
- apt-get install --no-install-recommends -y libc6-dev libjs-jquery libjs-jquery-throttle-debounce libjs-jquery-isonscreen libjs-jquery-tablesorter flake8 python3-coverage python3-notify2 python3-psutil python3-setuptools python3-tk python3-ttkthemes python3-gi
|
||||
- printf '\e[0K%s:%s:%s\r\e[0K\n' section_end "$(date +%s)" install_extra_deps
|
||||
|
||||
# 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-common
|
||||
script:
|
||||
# This is to touch the built files in the test stage to avoid needless rebuilding
|
||||
- make -C changehat/mod_apparmor --touch
|
||||
- make -C changehat/mod_apparmor check
|
||||
|
||||
test-profiles:
|
||||
stage: test
|
||||
needs: ["build-all"]
|
||||
extends:
|
||||
- .ubuntu-common
|
||||
script:
|
||||
# This is to touch the built files in the test stage to avoid needless rebuilding
|
||||
- make -C profiles --touch
|
||||
- make -C profiles check-parser
|
||||
- make -C profiles check-abstractions.d
|
||||
- make -C profiles check-local
|
||||
|
||||
shellcheck:
|
||||
stage: test
|
||||
needs: []
|
||||
extends:
|
||||
- .ubuntu-common
|
||||
script:
|
||||
- printf '\e[0K%s:%s:%s[collapsed=true]\r\e[0K%s\n' section_start "$(date +%s)" install_extra_deps "Installing additional dependencies..."
|
||||
- apt-get install --no-install-recommends -y python3-minimal file shellcheck xmlstarlet
|
||||
- printf '\e[0K%s:%s:%s\r\e[0K\n' section_end "$(date +%s)" install_extra_deps
|
||||
- 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/*"
|
||||
|
||||
coverity:
|
||||
stage: .post
|
||||
interruptible: true
|
||||
extends:
|
||||
- .ubuntu-common
|
||||
script:
|
||||
- printf '\e[0K%s:%s:%s[collapsed=true]\r\e[0K%s\n' section_start "$(date +%s)" install_extra_deps "Installing additional dependencies..."
|
||||
- apt-get install --no-install-recommends -y curl git texlive-latex-recommended
|
||||
- printf '\e[0K%s:%s:%s\r\e[0K\n' section_end "$(date +%s)" install_extra_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
|
||||
- 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"
|
||||
artifacts:
|
||||
paths:
|
||||
- "apparmor-*.tar.gz"
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_PROJECT_PATH == "apparmor/apparmor"
|
||||
|
||||
.image-garden-x86_64:
|
||||
stage: spread
|
||||
interruptible: true
|
||||
# TODO: use tagged release once container tagging is improved upstream.
|
||||
image: registry.gitlab.com/zygoon/image-garden:latest
|
||||
tags:
|
||||
- linux
|
||||
- x86_64
|
||||
- kvm
|
||||
variables:
|
||||
ARCH: x86_64
|
||||
GARDEN_DL_DIR: dl
|
||||
CACHE_POLICY: pull-push
|
||||
CACHE_COMPRESSION_LEVEL: fastest
|
||||
before_script:
|
||||
# Restore the mtime of the .image-garden.mk file. This helps make determine
|
||||
# if there's actually something to do correctly. Git does not preserve the
|
||||
# mtime of files during checkout.
|
||||
- git restore-mtime .image-garden.mk
|
||||
# Prepare the image in dry-run mode. This helps in debugging cache misses
|
||||
# when files are not cached correctly by the runner, causing the build section
|
||||
# below to always do hevy-duty work.
|
||||
- printf '\e[0K%s:%s:%s[collapsed=true]\r\e[0K%s\n' section_start "$(date +%s)" prepare_image_dry_run "Prepare image (dry run)"
|
||||
- image-garden make --dry-run --debug "$GARDEN_SYSTEM.$ARCH.run" "$GARDEN_SYSTEM.$ARCH.qcow2" "$GARDEN_SYSTEM.seed.iso" "$GARDEN_SYSTEM.user-data" "$GARDEN_SYSTEM.meta-data"
|
||||
- printf '\e[0K%s:%s:%s\r\e[0K\n' section_end "$(date +%s)" prepare_image_dry_run
|
||||
script:
|
||||
# Prepare the image, for real.
|
||||
- printf '\e[0K%s:%s:%s[collapsed=true]\r\e[0K%s\n' section_start "$(date +%s)" prepare_image "Prepare image"
|
||||
# If there's nothing to do then remove all the files that we would normally
|
||||
# cache so that GitLab skips the cache upload step. This saves significant
|
||||
# time required to re-compress and upload unchanged content.
|
||||
# The idea for how to do is is documented at
|
||||
# https://olex.biz/2025/04/gitlab-ci-prevent-cache-reupload-without-changes/
|
||||
# The GitLab issue requesting a proper feature is
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/226068
|
||||
- |
|
||||
if image-garden make --question "$GARDEN_SYSTEM.$ARCH.run" "$GARDEN_SYSTEM.$ARCH.qcow2" "$GARDEN_SYSTEM.seed.iso" "$GARDEN_SYSTEM.user-data" "$GARDEN_SYSTEM.meta-data"; then
|
||||
rm -f "$GARDEN_SYSTEM".* efi-code.*.img efi-vars.*.img
|
||||
rm -rf "$GARDEN_DL_DIR"
|
||||
else
|
||||
image-garden make "$GARDEN_SYSTEM.$ARCH.run" "$GARDEN_SYSTEM.$ARCH.qcow2" "$GARDEN_SYSTEM.seed.iso" "$GARDEN_SYSTEM.user-data" "$GARDEN_SYSTEM.meta-data"
|
||||
fi
|
||||
- printf '\e[0K%s:%s:%s\r\e[0K\n' section_end "$(date +%s)" prepare_image
|
||||
cache:
|
||||
# Cache the base image (pre-customization).
|
||||
- key: image-garden-base-${GARDEN_SYSTEM}.${ARCH}
|
||||
policy: $CACHE_POLICY
|
||||
when: always
|
||||
paths:
|
||||
- $GARDEN_DL_DIR
|
||||
# Those are never mutated so they are safe to share.
|
||||
- efi-code.*.img
|
||||
- efi-vars.*.img
|
||||
# Cache the customized system. This cache depends on .image-garden.mk file
|
||||
# so that any customization updates are immediately acted upon.
|
||||
- key:
|
||||
prefix: image-garden-custom-${GARDEN_SYSTEM}.${ARCH}-
|
||||
files:
|
||||
- .image-garden.mk
|
||||
policy: $CACHE_POLICY
|
||||
when: always
|
||||
paths:
|
||||
- $GARDEN_SYSTEM.*
|
||||
- $GARDEN_SYSTEM.seed.iso
|
||||
- $GARDEN_SYSTEM.meta-data
|
||||
- $GARDEN_SYSTEM.user-data
|
||||
|
||||
# This job builds and caches the image that the job below looks at.
|
||||
image-ubuntu-cloud-24.04-x86_64:
|
||||
extends: .image-garden-x86_64
|
||||
variables:
|
||||
GARDEN_SYSTEM: ubuntu-cloud-24.04
|
||||
needs: []
|
||||
dependencies: []
|
||||
rules:
|
||||
- if: $CI_COMMIT_TAG
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
changes:
|
||||
paths:
|
||||
- .image-garden.mk
|
||||
- .gitlab-ci.yml
|
||||
compare_to: "refs/heads/master"
|
||||
- if: $CI_COMMIT_BRANCH && "$[[ inputs.build-test-images ]]" == "true"
|
||||
|
||||
.spread-x86_64:
|
||||
extends: .image-garden-x86_64
|
||||
variables:
|
||||
# GitLab project identifier of zygoon/spread-dist can be seen on
|
||||
# https://gitlab.com/zygoon/spread-dist, under the three-dot menu on
|
||||
# top-right.
|
||||
SPREAD_GITLAB_PROJECT_ID: "65375371"
|
||||
# Git revision of spread to install.
|
||||
# This must have been built via spread-dist.
|
||||
# TODO: switch to upstream 1.0 release when available.
|
||||
SPREAD_REV: 413817eda7bec07a3885e0717c178b965f8924e1
|
||||
# Run all the tasks for a given system.
|
||||
SPREAD_ARGS: "garden:$GARDEN_SYSTEM:"
|
||||
SPREAD_GOARCH: amd64
|
||||
before_script:
|
||||
# Restore the mtime of the .image-garden.mk file. This helps make determine
|
||||
# if there's actually something to do correctly. Git does not preserve the
|
||||
# mtime of files during checkout.
|
||||
- git restore-mtime .image-garden.mk
|
||||
# Prepare the image in dry-run mode. This helps in debugging cache misses
|
||||
# when files are not cached correctly by the runner, causing the build section
|
||||
# below to always do hevy-duty work.
|
||||
- printf '\e[0K%s:%s:%s[collapsed=true]\r\e[0K%s\n' section_start "$(date +%s)" prepare_image_dry_run "Prepare image (dry run)"
|
||||
- image-garden make --dry-run --debug "$GARDEN_SYSTEM.$ARCH.run" "$GARDEN_SYSTEM.$ARCH.qcow2" "$GARDEN_SYSTEM.seed.iso" "$GARDEN_SYSTEM.user-data" "$GARDEN_SYSTEM.meta-data"
|
||||
- stat .image-garden.mk "$GARDEN_SYSTEM".* || true
|
||||
- printf '\e[0K%s:%s:%s\r\e[0K\n' section_end "$(date +%s)" prepare_image_dry_run
|
||||
# Install the selected revision of spread.
|
||||
- printf '\e[0K%s:%s:%s[collapsed=true]\r\e[0K%s\n' section_start "$(date +%s)" install_spread "Installing spread..."
|
||||
# Install pre-built spread from https://gitlab.com/zygoon/spread-dist generic package repository.
|
||||
- |
|
||||
curl --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --location --output spread "${CI_API_V4_URL}/projects/${SPREAD_GITLAB_PROJECT_ID}/packages/generic/spread/${SPREAD_REV}/spread.${SPREAD_GOARCH}"
|
||||
- chmod +x spread
|
||||
- printf '\e[0K%s:%s:%s\r\e[0K\n' section_end "$(date +%s)" install_spread
|
||||
script:
|
||||
- printf '\e[0K%s:%s:%s\r\e[0K%s\n' section_start "$(date +%s)" run_spread "Running spread for $GARDEN_SYSTEM..."
|
||||
# TODO: transform to inject ^...$ to properly select jobs to run.
|
||||
- mkdir -p spread-logs spread-artifacts
|
||||
- ./spread -list $SPREAD_ARGS |
|
||||
split --number=l/"${CI_NODE_INDEX:-1}"/"${CI_NODE_TOTAL:-1}" |
|
||||
xargs --verbose ./spread -v -artifacts ./spread-artifacts -v | tee spread-logs/"$GARDEN_SYSTEM".log
|
||||
- printf '\e[0K%s:%s:%s\r\e[0K\n' section_end "$(date +%s)" run_spread
|
||||
artifacts:
|
||||
paths:
|
||||
- spread-logs
|
||||
- spread-artifacts
|
||||
when: always
|
||||
|
||||
spread-ubuntu-cloud-24.04-x86_64:
|
||||
extends: .spread-x86_64
|
||||
variables:
|
||||
GARDEN_SYSTEM: ubuntu-cloud-24.04
|
||||
SPREAD_ARGS: garden:$GARDEN_SYSTEM:tests/regression/ garden:$GARDEN_SYSTEM:tests/profiles/
|
||||
CACHE_POLICY: pull
|
||||
dependencies: []
|
||||
needs:
|
||||
- job: image-ubuntu-cloud-24.04-x86_64
|
||||
optional: true
|
||||
parallel: 4
|
129
.image-garden.mk
129
.image-garden.mk
@@ -1,129 +0,0 @@
|
||||
# This file is read by image-garden when spread is allocating test machines.
|
||||
# All the package installation happens through cloud-init profiles defined
|
||||
# below.
|
||||
|
||||
# NOTE: Should the kernel be out of date, just increment this value. Make will
|
||||
# re-create the image whenever the .image-garden.mk file is more recent than
|
||||
# the image itself. In reality all you need is touch(1), but this is more apt.
|
||||
unused=1
|
||||
|
||||
# This is the cloud-init user-data profile for all Debian systems. Note that it
|
||||
# is an extension of the default profile necessary for operation of
|
||||
# image-garden.
|
||||
define DEBIAN_CLOUD_INIT_USER_DATA_TEMPLATE
|
||||
$(CLOUD_INIT_USER_DATA_TEMPLATE)
|
||||
packages:
|
||||
- apache2-dev
|
||||
- attr
|
||||
- autoconf
|
||||
- autoconf-archive
|
||||
- automake
|
||||
- bison
|
||||
- build-essential
|
||||
- dejagnu
|
||||
- dosfstools
|
||||
- flake8
|
||||
- flex
|
||||
- fuse-overlayfs
|
||||
- gdb
|
||||
- gettext
|
||||
- libdbus-1-dev
|
||||
- libpam0g-dev
|
||||
- libtool
|
||||
- liburing-dev
|
||||
- pkg-config
|
||||
- proftpd-core
|
||||
- python3-all-dev
|
||||
- python3-gi
|
||||
- python3-notify2
|
||||
- python3-psutil
|
||||
- python3-setuptools
|
||||
- python3-tk
|
||||
- python3-ttkthemes
|
||||
- swig
|
||||
- tinyproxy
|
||||
# Update all the packages. This allows us to be on the up-to-date kernel
|
||||
# version that we cannot otherwise easily select with cloud init alone. Note
|
||||
# that we do not need to reboot the system as image garden shuts down the image
|
||||
# after first boot. On subsequent boot we will be running the latest kernel.
|
||||
package_upgrade: true
|
||||
package_update: true
|
||||
endef
|
||||
|
||||
# Ubuntu shares cloud-init profile with Debian.
|
||||
UBUNTU_CLOUD_INIT_USER_DATA_TEMPLATE=$(DEBIAN_CLOUD_INIT_USER_DATA_TEMPLATE)
|
||||
|
||||
# This is the cloud-init user-data profile for openSUSE Tumbleweed.
|
||||
define OPENSUSE_tumbleweed_CLOUD_INIT_USER_DATA_TEMPLATE
|
||||
$(CLOUD_INIT_USER_DATA_TEMPLATE)
|
||||
- sed -i -e 's/security=selinux/security=apparmor/g' /etc/default/grub
|
||||
- update-bootloader
|
||||
packages:
|
||||
- apache2-devel
|
||||
- attr
|
||||
- autoconf
|
||||
- autoconf-archive
|
||||
- automake
|
||||
- bison
|
||||
- dbus-1-devel
|
||||
- dejagnu
|
||||
- dosfstools
|
||||
- flex
|
||||
- fuse-overlayfs
|
||||
- gcc
|
||||
- gcc-c++
|
||||
- gdb
|
||||
- gettext
|
||||
- gobject-introspection
|
||||
- libtool
|
||||
- liburing2-devel
|
||||
- make
|
||||
- pam-devel
|
||||
- pkg-config
|
||||
- python3-devel
|
||||
- python3-flake8
|
||||
- python3-notify2
|
||||
- python3-psutil
|
||||
- python3-setuptools
|
||||
- python3-setuptools
|
||||
- python3-tk
|
||||
- python311
|
||||
- python311-devel
|
||||
- swig
|
||||
- which
|
||||
# See above for rationale.
|
||||
package_upgrade: true
|
||||
package_update: true
|
||||
endef
|
||||
|
||||
define FEDORA_CLOUD_INIT_USER_DATA_TEMPLATE
|
||||
$(CLOUD_INIT_USER_DATA_TEMPLATE)
|
||||
packages:
|
||||
- attr
|
||||
- autoconf
|
||||
- autoconf-archive
|
||||
- automake
|
||||
- bison
|
||||
- dbus-devel
|
||||
- dejagnu
|
||||
- dosfstools
|
||||
- flex
|
||||
- gdb
|
||||
- gettext
|
||||
- httpd-devel
|
||||
- libstdc++-static
|
||||
- libtool
|
||||
- liburing-devel
|
||||
- pam-devel
|
||||
- perl
|
||||
- pkg-config
|
||||
- python3-devel
|
||||
- python3-flake8
|
||||
- python3-gobject-base
|
||||
- python3-notify2
|
||||
- python3-tkinter
|
||||
- swig
|
||||
# See above for rationale.
|
||||
package_upgrade: true
|
||||
package_update: true
|
||||
endef
|
@@ -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
|
41
Makefile
41
Makefile
@@ -17,9 +17,12 @@ DIRS=libraries/libapparmor \
|
||||
profiles \
|
||||
tests
|
||||
|
||||
# with conversion to git, we don't export from the remote
|
||||
REPO_URL?=git@gitlab.com:apparmor/apparmor.git
|
||||
REPO_BRANCH?=master
|
||||
#REPO_URL?=lp:apparmor
|
||||
# --per-file-timestamps is failing over SSH, https://bugs.launchpad.net/bzr/+bug/1257078
|
||||
REPO_URL?=https://code.launchpad.net/~apparmor-dev/apparmor/2.11
|
||||
# alternate possibilities to export from
|
||||
#REPO_URL=.
|
||||
#REPO_URL="bzr+ssh://bazaar.launchpad.net/~sbeattie/+junk/apparmor-dev/"
|
||||
|
||||
COVERITY_DIR=cov-int
|
||||
RELEASE_DIR=apparmor-${VERSION}
|
||||
@@ -28,9 +31,7 @@ __SETUP_DIR?=.
|
||||
# We create a separate version for tags because git can't handle tags
|
||||
# with embedded ~s in them. No spaces around '-' or they'll get
|
||||
# embedded in ${VERSION}
|
||||
# apparmor version tag format 'vX.Y.ZZ'
|
||||
# apparmor branch name format 'apparmor-X.Y'
|
||||
TAG_VERSION="v$(subst ~,-,${VERSION})"
|
||||
TAG_VERSION=$(subst ~,-,${VERSION})
|
||||
|
||||
# Add exclusion entries arguments for tar here, of the form:
|
||||
# --exclude dir_to_exclude --exclude other_dir
|
||||
@@ -39,49 +40,49 @@ TAR_EXCLUSIONS=
|
||||
.PHONY: tarball
|
||||
tarball: clean
|
||||
REPO_VERSION=`$(value REPO_VERSION_CMD)` && \
|
||||
$(MAKE) export_dir __EXPORT_DIR=${RELEASE_DIR} __REPO_VERSION=$${REPO_VERSION} && \
|
||||
$(MAKE) setup __SETUP_DIR=${RELEASE_DIR} && \
|
||||
make export_dir __EXPORT_DIR=${RELEASE_DIR} __REPO_VERSION=$${REPO_VERSION} && \
|
||||
make setup __SETUP_DIR=${RELEASE_DIR} && \
|
||||
tar ${TAR_EXCLUSIONS} -cvzf ${RELEASE_DIR}.tar.gz ${RELEASE_DIR}
|
||||
|
||||
.PHONY: snapshot
|
||||
snapshot: clean
|
||||
$(eval REPO_VERSION:=$(shell $(value REPO_VERSION_CMD)))
|
||||
$(eval SNAPSHOT_NAME=apparmor-$(VERSION)~$(shell echo $(REPO_VERSION) | cut -d '-' -f 2-))
|
||||
$(MAKE) export_dir __EXPORT_DIR=${SNAPSHOT_NAME} __REPO_VERSION=${REPO_VERSION} && \
|
||||
$(MAKE) setup __SETUP_DIR=${SNAPSHOT_NAME} && \
|
||||
$(eval SNAPSHOT_NAME=apparmor-$(VERSION)~$(REPO_VERSION))
|
||||
make export_dir __EXPORT_DIR=${SNAPSHOT_NAME} __REPO_VERSION=${REPO_VERSION} && \
|
||||
make setup __SETUP_DIR=${SNAPSHOT_NAME} && \
|
||||
tar ${TAR_EXCLUSIONS} -cvzf ${SNAPSHOT_NAME}.tar.gz ${SNAPSHOT_NAME}
|
||||
|
||||
.PHONY: coverity
|
||||
coverity: snapshot
|
||||
cd $(SNAPSHOT_NAME)/libraries/libapparmor && ./configure --with-python
|
||||
cov-build --dir $(COVERITY_DIR) -- sh -c \
|
||||
"$(foreach dir, $(filter-out utils profiles tests, $(DIRS)), \
|
||||
$(MAKE) -j $$(nproc) -C $(SNAPSHOT_NAME)/$(dir);) "
|
||||
$(foreach dir, $(filter-out utils profiles tests, $(DIRS)), \
|
||||
cov-build --dir $(COVERITY_DIR) -- make -C $(SNAPSHOT_NAME)/$(dir);)
|
||||
tar -cvzf $(SNAPSHOT_NAME)-$(COVERITY_DIR).tar.gz $(COVERITY_DIR)
|
||||
|
||||
.PHONY: export_dir
|
||||
export_dir:
|
||||
mkdir $(__EXPORT_DIR)
|
||||
/usr/bin/git archive --prefix=$(__EXPORT_DIR)/ --format tar $(__REPO_VERSION) | tar xv
|
||||
echo "$(REPO_URL) $(REPO_BRANCH) $(__REPO_VERSION)" > $(__EXPORT_DIR)/common/.stamp_rev
|
||||
/usr/bin/bzr export --per-file-timestamps -r $(__REPO_VERSION) $(__EXPORT_DIR) $(REPO_URL)
|
||||
echo "$(REPO_URL) $(__REPO_VERSION)" > $(__EXPORT_DIR)/common/.stamp_rev
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
-rm -rf ${RELEASE_DIR} ./apparmor-${VERSION}~* ${COVERITY_DIR}
|
||||
for dir in $(DIRS); do \
|
||||
$(MAKE) -C $$dir clean; \
|
||||
make -C $$dir clean; \
|
||||
done
|
||||
|
||||
.PHONY: setup
|
||||
setup:
|
||||
cd $(__SETUP_DIR)/libraries/libapparmor && ./autogen.sh
|
||||
# parser has an extra doc to build
|
||||
$(MAKE) -C $(__SETUP_DIR)/parser extra_docs
|
||||
make -C $(__SETUP_DIR)/parser extra_docs
|
||||
# libraries/libapparmor needs configure to have run before
|
||||
# building docs
|
||||
$(foreach dir, $(filter-out libraries/libapparmor tests, $(DIRS)), \
|
||||
$(MAKE) -C $(__SETUP_DIR)/$(dir) docs;)
|
||||
make -C $(__SETUP_DIR)/$(dir) docs;)
|
||||
|
||||
.PHONY: tag
|
||||
tag:
|
||||
git tag -m 'AppArmor $(VERSION)' -s $(TAG_VERSION)
|
||||
bzr tag apparmor_${TAG_VERSION}
|
||||
|
||||
|
241
README
Normal file
241
README
Normal file
@@ -0,0 +1,241 @@
|
||||
------------
|
||||
Introduction
|
||||
------------
|
||||
AppArmor protects systems from insecure or untrusted processes by
|
||||
running them in restricted confinement, while still allowing processes
|
||||
to share files, exercise privilege and communicate with other processes.
|
||||
AppArmor is a Mandatory Access Control (MAC) mechanism which uses the
|
||||
Linux Security Module (LSM) framework. The confinement's restrictions
|
||||
are mandatory and are not bound to identity, group membership, or object
|
||||
ownership. The protections provided are in addition to the kernel's
|
||||
regular access control mechanisms (including DAC) and can be used to
|
||||
restrict the superuser.
|
||||
|
||||
The AppArmor kernel module and accompanying user-space tools are
|
||||
available under the GPL license (the exception is the libapparmor
|
||||
library, available under the LGPL license, which allows change_hat(2)
|
||||
and change_profile(2) to be used by non-GPL binaries).
|
||||
|
||||
For more information, you can read the techdoc.pdf (available after
|
||||
building the parser) and by visiting the http://apparmor.net/ web
|
||||
site.
|
||||
|
||||
|
||||
-------------
|
||||
Source Layout
|
||||
-------------
|
||||
|
||||
AppArmor consists of several different parts:
|
||||
|
||||
binutils/ source for basic utilities written in compiled languages
|
||||
changehat/ source for using changehat with Apache, PAM and Tomcat
|
||||
common/ common makefile rules
|
||||
desktop/ empty
|
||||
kernel-patches/ compatibility patches for various kernel versions
|
||||
libraries/ libapparmor source and language bindings
|
||||
parser/ source for parser/loader and corresponding documentation
|
||||
profiles/ configuration files, reference profiles and abstractions
|
||||
tests/ regression and stress testsuites
|
||||
utils/ high-level utilities for working with AppArmor
|
||||
|
||||
--------------------------------------
|
||||
Important note on AppArmor kernel code
|
||||
--------------------------------------
|
||||
|
||||
While most of the kernel AppArmor code has been accepted in the
|
||||
upstream Linux kernel, a few important pieces were not included. These
|
||||
missing pieces unfortunately are important bits for AppArmor userspace
|
||||
and kernel interaction; therefore we have included compatibility
|
||||
patches in the kernel-patches/ subdirectory, versioned by upstream
|
||||
kernel (2.6.37 patches should apply cleanly to 2.6.38 source).
|
||||
|
||||
Without these patches applied to the kernel, the AppArmor userspace
|
||||
will not function correctly.
|
||||
|
||||
------------------------------------------
|
||||
Building and Installing AppArmor Userspace
|
||||
------------------------------------------
|
||||
|
||||
To build and install AppArmor userspace on your system, build and install in
|
||||
the following order.
|
||||
|
||||
|
||||
libapparmor:
|
||||
$ cd ./libraries/libapparmor
|
||||
$ sh ./autogen.sh
|
||||
$ sh ./configure --prefix=/usr --with-perl --with-python # see below
|
||||
$ make
|
||||
$ make check
|
||||
$ make install
|
||||
|
||||
[an additional optional argument to libapparmor's configure is --with-ruby, to
|
||||
generate Ruby bindings to libapparmor.]
|
||||
|
||||
|
||||
Binary Utilities:
|
||||
$ cd binutils
|
||||
$ make
|
||||
$ make check
|
||||
$ make install
|
||||
|
||||
|
||||
Utilities:
|
||||
$ cd utils
|
||||
$ make
|
||||
$ make check
|
||||
$ make install
|
||||
|
||||
|
||||
parser:
|
||||
$ cd parser
|
||||
$ make # depends on libapparmor having been built first
|
||||
$ make check
|
||||
$ make install
|
||||
|
||||
|
||||
Apache mod_apparmor:
|
||||
$ cd changehat/mod_apparmor
|
||||
$ make # depends on libapparmor having been built first
|
||||
$ make install
|
||||
|
||||
|
||||
PAM AppArmor:
|
||||
$ cd changehat/pam_apparmor
|
||||
$ make # depends on libapparmor having been built first
|
||||
$ make install
|
||||
|
||||
|
||||
Profiles:
|
||||
$ cd profiles
|
||||
$ make
|
||||
$ make check # depends on the parser having been built first
|
||||
$ make install
|
||||
|
||||
|
||||
[Note that for the parser, binutils, and utils, if you only wish to build/use
|
||||
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".]
|
||||
|
||||
-------------------
|
||||
AppArmor Testsuites
|
||||
-------------------
|
||||
|
||||
A number of testsuites are in the AppArmor sources. Most have documentation on
|
||||
usage and how to update and add tests. Below is a quick overview of their
|
||||
location and how to run them.
|
||||
|
||||
|
||||
Regression tests
|
||||
----------------
|
||||
For details on structure and adding tests, see
|
||||
tests/regression/apparmor/README.
|
||||
|
||||
To run:
|
||||
$ cd tests/regression/apparmor (requires root)
|
||||
$ make
|
||||
$ sudo make tests
|
||||
$ sudo bash open.sh -r # runs and saves the last testcase from open.sh
|
||||
|
||||
|
||||
Parser tests
|
||||
------------
|
||||
For details on structure and adding tests, see parser/tst/README.
|
||||
|
||||
To run:
|
||||
$ cd parser/tst
|
||||
$ make
|
||||
$ make tests
|
||||
|
||||
|
||||
Libapparmor
|
||||
-----------
|
||||
For details on structure and adding tests, see libraries/libapparmor/README.
|
||||
$ cd libraries/libapparmor
|
||||
$ make check
|
||||
|
||||
Utils
|
||||
-----
|
||||
Tests for the Python utilities exist in the test/ subdirectory.
|
||||
$ cd utils
|
||||
$ make check
|
||||
|
||||
The aa-decode utility to be tested can be overridden by
|
||||
setting up environment variable APPARMOR_DECODE; e.g.:
|
||||
|
||||
$ APPARMOR_DECODE=/usr/bin/aa-decode make check
|
||||
|
||||
Profile checks
|
||||
--------------
|
||||
A basic consistency check to ensure that the parser and aa-logprof parse
|
||||
successfully the current set of shipped profiles. The system or other
|
||||
parser and logprof can be passed in by overriding the PARSER and LOGPROF
|
||||
variables.
|
||||
$ cd profiles
|
||||
$ make && make check
|
||||
|
||||
Stress Tests
|
||||
------------
|
||||
To run AppArmor stress tests:
|
||||
$ make all
|
||||
|
||||
Use these:
|
||||
$ ./change_hat
|
||||
$ ./child
|
||||
$ ./kill.sh
|
||||
$ ./open
|
||||
$ ./s.sh
|
||||
|
||||
Or run all at once:
|
||||
$ ./stress.sh
|
||||
|
||||
Please note that the above will stress the system so much it may end up
|
||||
invoking the OOM killer.
|
||||
|
||||
To run parser stress tests (requires /usr/bin/ruby):
|
||||
$ ./stress.sh
|
||||
|
||||
(see stress.sh -h for options)
|
||||
|
||||
Coverity Support
|
||||
----------------
|
||||
Coverity scans are available to AppArmor developers at
|
||||
https://scan.coverity.com/projects/apparmor.
|
||||
|
||||
In order to submit a Coverity build for analysis, the cov-build binary
|
||||
must be discoverable from your PATH. See the "To Setup" section of
|
||||
https://scan.coverity.com/download?tab=cxx to obtain a pre-built copy of
|
||||
cov-build.
|
||||
|
||||
To generate a compressed tarball of an intermediate Coverity directory:
|
||||
$ make coverity
|
||||
|
||||
The compressed tarball is written to
|
||||
apparmor-<SNAPSHOT_VERSION>-cov-int.tar.gz, where <SNAPSHOT_VERSION>
|
||||
is something like 2.10.90~3328, and must be uploaded to
|
||||
https://scan.coverity.com/projects/apparmor/builds/new for analysis. You must
|
||||
include the snapshot version in Coverity's project build submission form, in
|
||||
the "Project Version" field, so that it is quickly obvious to all AppArmor
|
||||
developers what snapshot of the AppArmor repository was used for the analysis.
|
||||
|
||||
-----------------------------------------------
|
||||
Building and Installing AppArmor Kernel Patches
|
||||
-----------------------------------------------
|
||||
|
||||
TODO
|
||||
|
||||
|
||||
-----------------
|
||||
Required versions
|
||||
-----------------
|
||||
|
||||
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 2.7 (deprecated) or Python 3.3.
|
||||
Python 3.x is recommended. Python 2.x support is deprecated since AppArmor 2.11.
|
||||
|
||||
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.
|
415
README.md
415
README.md
@@ -1,415 +0,0 @@
|
||||
# AppArmor
|
||||
|
||||
[](https://gitlab.com/apparmor/apparmor/commits/master)
|
||||
[](https://gitlab.com/apparmor/apparmor/pipelines)
|
||||
[](https://bestpractices.coreinfrastructure.org/projects/1699)
|
||||
|
||||
------------
|
||||
Introduction
|
||||
------------
|
||||
AppArmor protects systems from insecure or untrusted processes by
|
||||
running them in restricted confinement, while still allowing processes
|
||||
to share files, exercise privilege and communicate with other processes.
|
||||
AppArmor is a Mandatory Access Control (MAC) mechanism which uses the
|
||||
Linux Security Module (LSM) framework. The confinement's restrictions
|
||||
are mandatory and are not bound to identity, group membership, or object
|
||||
ownership. The protections provided are in addition to the kernel's
|
||||
regular access control mechanisms (including DAC) and can be used to
|
||||
restrict the superuser.
|
||||
|
||||
The AppArmor kernel module and accompanying user-space tools are
|
||||
available under the GPL license (the exception is the libapparmor
|
||||
library, available under the LGPL license, which allows change_hat(2)
|
||||
and change_profile(2) to be used by non-GPL binaries).
|
||||
|
||||
For more information, you can read the techdoc.pdf (available after
|
||||
building the parser) and by visiting the https://apparmor.net/ web
|
||||
site.
|
||||
|
||||
----------------
|
||||
Getting in Touch
|
||||
----------------
|
||||
|
||||
Please send all complaints, feature requests, rants about the software,
|
||||
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
|
||||
list directly for those who wish not to register for an account on
|
||||
GitLab. 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
|
||||
in the [wiki](https://gitlab.com/apparmor/apparmor/wikis/home#reporting-security-vulnerabilities).
|
||||
|
||||
|
||||
--------------
|
||||
Privacy Policy
|
||||
--------------
|
||||
|
||||
The AppArmor security project respects users privacy and data and does not collect data from or on its users beyond what is required for a given component to function.
|
||||
|
||||
The AppArmor kernel security module will log violations to the audit subsystem, and those will be logged/forwarded/recorded on the user's system(s) according to how the administrator has logging configured. Again this is not forwarded to or collected by the AppArmor project.
|
||||
|
||||
The AppArmor userspace tools do not collect information on the system user beyond the logs and information needed to interact with the user. This is not forwarded to, nor collected by the AppArmor project.
|
||||
|
||||
Users may submit information as part of an email, bug report or merge request, etc. and that will be recorded as part of the mailing list, bug/issue tracker, or code repository but only as part of a user initiated action.
|
||||
|
||||
The AppArmor project does not collect information from contributors beyond their interactions with the AppArmor project, code, and community. However contributors are subject to the terms and conditions and privacy policy of the individual platforms (currently GitLab) should they choose to contribute through those platforms. And those platforms may collect data on the user that the AppArmor project does not.
|
||||
|
||||
Currently GitLab requires a user account to submit patches or report bugs and issues. If a contributor does not wish to create an account for these platforms the mailing list is available. Membership in the list is not required. Content from non-list members will be sent to moderation, to ensure that it is on topic, so there may be a delay in choosing to interact in this way.
|
||||
|
||||
|
||||
-------------
|
||||
Source Layout
|
||||
-------------
|
||||
|
||||
AppArmor consists of several different parts:
|
||||
|
||||
```
|
||||
binutils/ source for basic utilities written in compiled languages
|
||||
changehat/ source for using changehat with Apache, PAM and Tomcat
|
||||
common/ common makefile rules
|
||||
desktop/ empty
|
||||
kernel-patches/ compatibility patches for various kernel versions
|
||||
libraries/ libapparmor source and language bindings
|
||||
parser/ source for parser/loader and corresponding documentation
|
||||
profiles/ configuration files, reference profiles and abstractions
|
||||
tests/ regression and stress testsuites
|
||||
utils/ high-level utilities for working with AppArmor
|
||||
```
|
||||
|
||||
--------------------------------------
|
||||
Important note on AppArmor kernel code
|
||||
--------------------------------------
|
||||
|
||||
While most of the kernel AppArmor code has been accepted in the
|
||||
upstream Linux kernel, a few important pieces were not included. These
|
||||
missing pieces unfortunately are important bits for AppArmor userspace
|
||||
and kernel interaction; therefore we have included compatibility
|
||||
patches in the kernel-patches/ subdirectory, versioned by upstream
|
||||
kernel (2.6.37 patches should apply cleanly to 2.6.38 source).
|
||||
|
||||
Without these patches applied to the kernel, the AppArmor userspace
|
||||
will not function correctly.
|
||||
|
||||
------------------------------------------
|
||||
Building and Installing AppArmor Userspace
|
||||
------------------------------------------
|
||||
|
||||
To build and install AppArmor userspace on your system, build and install in
|
||||
the following order. Some systems may need to export various python-related
|
||||
environment variables to complete the build. For example, before building
|
||||
anything on these systems, use something along the lines of:
|
||||
|
||||
```
|
||||
$ export PYTHONPATH=$(realpath libraries/libapparmor/swig/python)
|
||||
$ export PYTHON=/usr/bin/python3
|
||||
$ export PYTHON_VERSION=3
|
||||
$ export PYTHON_VERSIONS=python3
|
||||
```
|
||||
|
||||
Note that, in general, the build steps can be run in parallel, while the test
|
||||
steps do not gain much speedup from being run in parallel. This is because the
|
||||
test steps spawn a handful of long-lived test runner processes that mostly
|
||||
run their tests sequentially and do not use `make`'s jobserver. Moreover,
|
||||
process spawning overhead constitutes a significant part of test runtime, so
|
||||
reworking the test harnesses to add parallelism (which would be a major undertaking
|
||||
for the harnesses that do not have it already) would not produce much of a speedup.
|
||||
|
||||
### libapparmor:
|
||||
|
||||
```
|
||||
$ cd ./libraries/libapparmor
|
||||
$ sh ./autogen.sh
|
||||
$ sh ./configure --prefix=/usr --with-perl --with-python # see below
|
||||
$ make -j $(nproc)
|
||||
$ make check
|
||||
$ make install
|
||||
```
|
||||
|
||||
[an additional optional argument to libapparmor's configure is --with-ruby, to
|
||||
generate Ruby bindings to libapparmor.]
|
||||
|
||||
|
||||
### Binary Utilities:
|
||||
|
||||
```
|
||||
$ cd binutils
|
||||
$ make -j $(nproc)
|
||||
$ make check
|
||||
$ make install
|
||||
```
|
||||
|
||||
### Parser:
|
||||
|
||||
```
|
||||
$ cd parser
|
||||
$ make -j $(nproc) # depends on libapparmor having been built first
|
||||
$ make -j $(nproc) tst_binaries # a build step of make check that can be parallelized
|
||||
$ make check
|
||||
$ make install
|
||||
```
|
||||
|
||||
|
||||
### Utilities:
|
||||
|
||||
```
|
||||
$ cd utils
|
||||
$ make -j $(nproc)
|
||||
$ make check PYFLAKES=/usr/bin/pyflakes3
|
||||
$ make install
|
||||
```
|
||||
|
||||
### Apache mod_apparmor:
|
||||
|
||||
```
|
||||
$ cd changehat/mod_apparmor
|
||||
$ make -j $(nproc) # depends on libapparmor having been built first
|
||||
$ make install
|
||||
```
|
||||
|
||||
|
||||
### PAM AppArmor:
|
||||
|
||||
```
|
||||
$ cd changehat/pam_apparmor
|
||||
$ make -j $(nproc) # depends on libapparmor having been built first
|
||||
$ make install
|
||||
```
|
||||
|
||||
|
||||
### Profiles:
|
||||
|
||||
```
|
||||
$ cd profiles
|
||||
$ make
|
||||
$ 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".]
|
||||
|
||||
-------------------
|
||||
AppArmor Testsuites
|
||||
-------------------
|
||||
|
||||
A number of testsuites are in the AppArmor sources. Most have documentation on
|
||||
usage and how to update and add tests. Below is a quick overview of their
|
||||
location and how to run them.
|
||||
|
||||
|
||||
Using spread with local virtual machines
|
||||
----------------------------------------
|
||||
|
||||
It may be convenient to use the spread tool to provision and run the test suite
|
||||
in an ephemeral virtual machine. This allows testing in isolation from the
|
||||
host, as well as testing across different commonly used distributions and their
|
||||
real kernels.
|
||||
|
||||
Image Garden is available as a snap. If you wish to use it this way then snap
|
||||
then install the snap with:
|
||||
|
||||
```sh
|
||||
sudo snap install image-garden
|
||||
```
|
||||
|
||||
If you need to install snapd first, see https://snapcraft.io/docs/installing-snapd
|
||||
|
||||
Alternatively you may build image-garden and spread from source, and install
|
||||
dependencies manually.
|
||||
|
||||
```sh
|
||||
sudo apt install git golang whois ovmf genisoimage qemu-utils qemu-system
|
||||
go install github.com/snapcore/spread/cmd/spread@latest
|
||||
git clone https://gitlab.com/zygoon/image-garden
|
||||
make -C image-garden
|
||||
sudo make -C image-garden install
|
||||
image-garden make ubuntu-cloud-24.10.x86_64.run
|
||||
cd $APPARMOR_PATH
|
||||
git clean -xdf
|
||||
~/go/bin/spread -artifacts ./spread-artifacts -v ubuntu-cloud-24.10
|
||||
# or ~/go/bin/spread -v garden:ubuntu-cloud-24.04:tests/regression/apparmor:at_secure
|
||||
```
|
||||
|
||||
Running the `run_spread.sh` script, with `image-garden` snap installed or with
|
||||
`spread` on `PATH` will run all the tests across several supported systems
|
||||
(Debian, Ubuntu and openSUSE).
|
||||
|
||||
If you include a `bzImage` file in the root of the repository then that kernel
|
||||
will be used in the integration test. Please look at `spread.yaml` for details.
|
||||
|
||||
Regression tests
|
||||
----------------
|
||||
For details on structure and adding tests, see
|
||||
tests/regression/apparmor/README.
|
||||
|
||||
To run:
|
||||
|
||||
### Regression tests - using apparmor userspace installed on host
|
||||
```
|
||||
$ cd tests/regression/apparmor (requires root)
|
||||
$ make -j $(nproc) 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 -j $(nproc)
|
||||
$ sudo make tests
|
||||
$ sudo bash open.sh -r # runs and saves the last testcase from open.sh
|
||||
```
|
||||
|
||||
Parser tests
|
||||
------------
|
||||
For details on structure and adding tests, see parser/tst/README.
|
||||
|
||||
To run:
|
||||
|
||||
```
|
||||
$ cd parser/tst
|
||||
$ make
|
||||
$ make tests
|
||||
```
|
||||
|
||||
Libapparmor
|
||||
-----------
|
||||
For details on structure and adding tests, see libraries/libapparmor/README.
|
||||
|
||||
```
|
||||
$ cd libraries/libapparmor
|
||||
$ make check
|
||||
```
|
||||
|
||||
Utils
|
||||
-----
|
||||
Tests for the Python utilities exist in the test/ subdirectory.
|
||||
|
||||
```
|
||||
$ cd utils
|
||||
$ make check
|
||||
```
|
||||
|
||||
The aa-decode utility to be tested can be overridden by
|
||||
setting up environment variable APPARMOR_DECODE; e.g.:
|
||||
|
||||
```
|
||||
$ APPARMOR_DECODE=/usr/bin/aa-decode make check
|
||||
```
|
||||
|
||||
Profile checks
|
||||
--------------
|
||||
A basic consistency check to ensure that the parser and aa-logprof parse
|
||||
successfully the current set of shipped profiles. The system or other
|
||||
parser and logprof can be passed in by overriding the PARSER and LOGPROF
|
||||
variables.
|
||||
|
||||
```
|
||||
$ cd profiles
|
||||
$ make && make check
|
||||
```
|
||||
|
||||
Stress Tests
|
||||
------------
|
||||
To run AppArmor stress tests:
|
||||
|
||||
```
|
||||
$ make all
|
||||
```
|
||||
|
||||
Use these:
|
||||
|
||||
```
|
||||
$ ./change_hat
|
||||
$ ./child
|
||||
$ ./kill.sh
|
||||
$ ./open
|
||||
$ ./s.sh
|
||||
```
|
||||
|
||||
Or run all at once:
|
||||
|
||||
```
|
||||
$ ./stress.sh
|
||||
```
|
||||
|
||||
Please note that the above will stress the system so much it may end up
|
||||
invoking the OOM killer.
|
||||
|
||||
To run parser stress tests (requires /usr/bin/ruby):
|
||||
|
||||
```
|
||||
$ ./stress.sh
|
||||
```
|
||||
|
||||
(see stress.sh -h for options)
|
||||
|
||||
Coverity Support
|
||||
----------------
|
||||
Coverity scans are available to AppArmor developers at
|
||||
https://scan.coverity.com/projects/apparmor.
|
||||
|
||||
In order to submit a Coverity build for analysis, the cov-build binary
|
||||
must be discoverable from your PATH. See the "To Setup" section of
|
||||
https://scan.coverity.com/download?tab=cxx to obtain a pre-built copy of
|
||||
cov-build.
|
||||
|
||||
To generate a compressed tarball of an intermediate Coverity directory:
|
||||
|
||||
```
|
||||
$ make coverity
|
||||
```
|
||||
|
||||
The compressed tarball is written to
|
||||
apparmor-<SNAPSHOT_VERSION>-cov-int.tar.gz, where <SNAPSHOT_VERSION>
|
||||
is something like 2.10.90~3328, and must be uploaded to
|
||||
https://scan.coverity.com/projects/apparmor/builds/new for analysis. You must
|
||||
include the snapshot version in Coverity's project build submission form, in
|
||||
the "Project Version" field, so that it is quickly obvious to all AppArmor
|
||||
developers what snapshot of the AppArmor repository was used for the analysis.
|
||||
|
||||
-----------------------------------------------
|
||||
Building and Installing AppArmor Kernel Patches
|
||||
-----------------------------------------------
|
||||
|
||||
TODO
|
||||
|
||||
|
||||
-----------------
|
||||
Required versions
|
||||
-----------------
|
||||
|
||||
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 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
|
||||
* python3-sqlite (part of the python3.NN-stdlib package)
|
||||
* python3-tk
|
||||
* python3-ttkthemes
|
||||
* python3-gi
|
||||
|
||||
Perl is no longer needed since none of the utilities shipped to end users depend
|
||||
on it anymore.
|
||||
|
||||
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-load.8 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 = ${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):
|
||||
@@ -119,34 +114,22 @@ $(LIBAPPARMOR_A):
|
||||
echo "error: $@ is missing. Pick one of these possible solutions:" 1>&2; \
|
||||
echo " 1) Build against the in-tree libapparmor by building it first and then trying again. See the top-level README for help." 1>&2; \
|
||||
echo " 2) Build against the system libapparmor by adding USE_SYSTEM=1 to your make command." 1>&2;\
|
||||
exit 1; \
|
||||
return 1; \
|
||||
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
|
||||
@@ -61,31 +56,27 @@ Upon exiting, B<aa-enabled> will set its exit status to the following values:
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<0>
|
||||
=item 0:
|
||||
|
||||
if AppArmor is enabled.
|
||||
|
||||
=item B<1>
|
||||
=item 1:
|
||||
|
||||
if AppArmor is not enabled/loaded.
|
||||
|
||||
=item B<2>
|
||||
=item 2:
|
||||
|
||||
intentionally not used as an B<aa-enabled> exit status.
|
||||
|
||||
=item B<3>
|
||||
=item 3:
|
||||
|
||||
if the AppArmor control files aren't available under /sys/kernel/security/.
|
||||
|
||||
=item B<4>
|
||||
=item 4:
|
||||
|
||||
if B<aa-enabled> doesn't have enough privileges to read the apparmor control files.
|
||||
|
||||
=item B<10>
|
||||
|
||||
AppArmor is enabled but does not have access to shared LSM interfaces.
|
||||
|
||||
=item B<64>
|
||||
=item 64:
|
||||
|
||||
if any unexpected error or condition is encountered.
|
||||
|
||||
@@ -94,10 +85,10 @@ 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
|
||||
|
||||
apparmor(7), apparmor.d(5), aa_is_enabled(2), and L<https://wiki.apparmor.net>.
|
||||
apparmor(7), apparmor.d(5), aa_is_enabled(2), and L<http://wiki.apparmor.net>.
|
||||
|
||||
=cut
|
||||
|
@@ -80,117 +80,14 @@ aa-exec.
|
||||
|
||||
=back
|
||||
|
||||
=head1 RESTRICTIONS
|
||||
|
||||
aa-exec uses I<aa_change_profile(3)> to change application confinement.
|
||||
The use of I<aa_change_profile(3)> may be restricted by policy in ways
|
||||
that will cause failure or results different than expected.
|
||||
|
||||
Even when using I<aa-exec> from unconfined restrictions in policy can
|
||||
causes failure or the confinement entered to be different than requested
|
||||
|
||||
See the unpriviled unconfined restriction documentation for more detail.
|
||||
https://gitlab.com/apparmor/apparmor/-/wikis/unprivileged_unconfined_restriction
|
||||
|
||||
=head1 STACKING
|
||||
|
||||
aa-exec can be used to setup a stack of profiles as confinement. When an
|
||||
application is confined by a stack, all profiles in the stack are checked
|
||||
as if they were the profile confining the application. The resulting
|
||||
mediation is the intersection of what is allowed by each profile in the
|
||||
stack.
|
||||
|
||||
The profiles in a stack are treated independently. Each profile can have
|
||||
its own flags and profile transitions. During an exec each profile gets
|
||||
to specify its transition and the results brought together to form a
|
||||
new canonicalized stack.
|
||||
|
||||
The profile separator indicating a stack is the character sequence I<//&>.
|
||||
Thus a stack can be expressed using
|
||||
|
||||
=over 4
|
||||
|
||||
$ aa-exec -p "unconfined//&firefox" -- bash
|
||||
$ ps -Z
|
||||
LABEL PID TTY TIME CMD
|
||||
unconfined 30714 pts/12 00:00:00 bash
|
||||
firefox//&unconfined (unconfined) 31160 pts/12 00:00:00 bash
|
||||
firefox//&unconfined (unconfined) 31171 pts/12 00:00:00 ps
|
||||
|
||||
=back
|
||||
|
||||
=head1 NAMESPACES
|
||||
|
||||
aa-exec can be used to enter confinement in another policy namespace
|
||||
if the policy namespaces exists, is visible, and the profile exists in
|
||||
the namespace. Note applications launched within the namespace will
|
||||
not be able to exit the namespace, and may be restricted by additional
|
||||
confinement around namespacing. Files and resources visible to the
|
||||
parent that launches the application may not be visible in the policy
|
||||
namespace resulting in access denials.
|
||||
|
||||
To enter a policy namespace the profile is prefixed with the namespace's
|
||||
name, using a I<:> prefix and suffix.
|
||||
|
||||
Eg.
|
||||
|
||||
=over 4
|
||||
|
||||
$ aa-exec -p :ex1:unconfined -- bash
|
||||
$ ps -Z
|
||||
LABEL PID TTY TIME CMD
|
||||
- 30714 pts/12 00:00:00 bash
|
||||
unconfined 34372 pts/12 00:00:00 bash
|
||||
unconfined 34379 pts/12 00:00:00 ps
|
||||
|
||||
=back
|
||||
|
||||
Confinement of processes outside of the namespace may not be visible
|
||||
in which case the confinement will be represented with a -. If policy
|
||||
is stacked only part of the confinement might be visible. However
|
||||
confinement is usually fully visible from the parent policy namespace.
|
||||
|
||||
Eg. the confinement of the child can be queried in the parent to see
|
||||
|
||||
=over 4
|
||||
|
||||
$ ps -Z 34372
|
||||
LABEL PID TTY STAT TIME COMMAND
|
||||
:ex1:unconfined 34372 pts/12 S+ 0:00 bash
|
||||
|
||||
=back
|
||||
|
||||
And in the case of stacking with namespaces
|
||||
|
||||
=over 4
|
||||
|
||||
$ aa-exec -p "unconfined//&:ex1:unconfined" -- bash
|
||||
$ ps -Z
|
||||
LABEL PID TTY TIME CMD
|
||||
- 30714 pts/12 00:00:00 bash
|
||||
unconfined 36298 pts/12 00:00:00 bash
|
||||
unconfined 36305 pts/12 00:00:00 ps
|
||||
|
||||
=back
|
||||
|
||||
while from the parent namespace the full confinement can be seen
|
||||
|
||||
=over 4
|
||||
|
||||
$ ps -Z 36298
|
||||
LABEL PID TTY STAT TIME COMMAND
|
||||
unconfined//&:ex1:unconfined 36298 pts/12 S+ 0:00 bash
|
||||
|
||||
=back
|
||||
|
||||
=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
|
||||
|
||||
apparmor(7), apparmor.d(5), aa_change_profile(3),
|
||||
aa_change_onexec(3) and L<https://wiki.apparmor.net>.
|
||||
aa-stack(8), aa-namespace(8), apparmor(7), apparmor.d(5), aa_change_profile(3),
|
||||
aa_change_onexec(3) and L<http://wiki.apparmor.net>.
|
||||
|
||||
=cut
|
||||
|
@@ -1,97 +0,0 @@
|
||||
# This publication is intellectual property of Canonical Ltd. Its contents
|
||||
# can be duplicated, either in part or in whole, provided that a copyright
|
||||
# label is visibly located on each copy.
|
||||
#
|
||||
# All information found in this book has been compiled with utmost
|
||||
# attention to detail. However, this does not guarantee complete accuracy.
|
||||
# Neither Canonical Ltd, the authors, nor the translators shall be held
|
||||
# liable for possible errors or the consequences thereof.
|
||||
#
|
||||
# Many of the software and hardware descriptions cited in this book
|
||||
# are registered trademarks. All trade names are subject to copyright
|
||||
# restrictions and may be registered trade marks. Canonical Ltd
|
||||
# essentially adheres to the manufacturer's spelling.
|
||||
#
|
||||
# Names of products and trademarks appearing in this book (with or without
|
||||
# specific notation) are likewise subject to trademark and trade protection
|
||||
# laws and may thus fall under copyright restrictions.
|
||||
#
|
||||
|
||||
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
aa-features-abi - Extract, validate and manipulate AppArmor feature abis
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<aa-features-abi> [OPTIONS] <SOURCE> [OUTPUT OPTIONS]
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
B<aa-features-abi> is used to extract a features abi and output to
|
||||
either stdout or a specified file. A SOURCE_OPTION must be specified.
|
||||
If an output option is not specified the features abi is written to
|
||||
stdout.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
B<aa-features-abi> accepts the following arguments:
|
||||
|
||||
=over 4
|
||||
|
||||
=item -h, --help
|
||||
|
||||
Display a brief usage guide.
|
||||
|
||||
=item -d, --debug
|
||||
|
||||
show messages with debugging information
|
||||
|
||||
=item -v, --verbose
|
||||
|
||||
show messages with stats
|
||||
|
||||
=back
|
||||
|
||||
=head1 SOURCE
|
||||
|
||||
=over 4
|
||||
|
||||
=item -x, --extract
|
||||
|
||||
Extract the features abi for the kernel
|
||||
|
||||
=item -f FILE, --file=FILE
|
||||
|
||||
Load the features abi from FILE and send it to OUTPUT OPTIONS.
|
||||
|
||||
=back
|
||||
|
||||
=head1 OUTPUT OPTIONS
|
||||
|
||||
=over 4
|
||||
|
||||
=item --stdout
|
||||
|
||||
Write the features abi to I<stdout>, this is the default if no output option
|
||||
is specified.
|
||||
|
||||
=item -w FILE, --write FILE
|
||||
|
||||
Write the features abi to I<FILE>.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
If you find any bugs, please report them at
|
||||
L<https://gitlab.com/apparmor/apparmor/-/issues>.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
apparmor(7), apparmor.d(5), aa_features(3), and L<https://wiki.apparmor.net>.
|
||||
|
||||
=cut
|
@@ -1,77 +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-load - load precompiled AppArmor policy from cache location(s)
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<aa-load> [options] (cache file|cache dir|cache base dir)+
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
B<aa-load> loads precompiled AppArmor policy from the specified locations.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
B<aa-load> accepts the following arguments:
|
||||
|
||||
=over 4
|
||||
|
||||
=item -f, --force
|
||||
|
||||
Force B<aa-load> to load a policy even if its abi does not match the kernel abi.
|
||||
|
||||
=item -d, --debug
|
||||
|
||||
Display debug messages.
|
||||
|
||||
=item -v, --verbose
|
||||
|
||||
Display progress and error messages.
|
||||
|
||||
=item -n, --dry-run
|
||||
|
||||
Do not actually load the specified policy/policies into the kernel.
|
||||
|
||||
=item -h, --help
|
||||
|
||||
Display a brief usage guide.
|
||||
|
||||
=back
|
||||
|
||||
=head1 EXIT STATUS
|
||||
|
||||
Upon exiting, B<aa-load> returns 0 upon success and 1 upon an error loading
|
||||
the precompiled policy.
|
||||
|
||||
=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), apparmor_parser(8), 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,409 +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 <limits.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) {
|
||||
/* As per POSIX dir->d_name has at most NAME_MAX characters */
|
||||
len = strnlen(dir->d_name, NAME_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 cache location(s)\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;
|
||||
}
|
1120
binutils/aa_status.c
1120
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 @@
|
||||
# Translations for aa_enabled
|
||||
# Copyright (C) 2024 Canonical Ltd
|
||||
# This file is distributed under the same license as the AppArmor package.
|
||||
# John Johansen <john.johansen@canonical.com>, 2020.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: apparmor@lists.ubuntu.com\n"
|
||||
"POT-Creation-Date: 2024-08-31 15:59-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 @@
|
||||
# Translations for aa_exec
|
||||
# Copyright (C) 2024 Canonical Ltd
|
||||
# This file is distributed under the same license as the AppArmor package.
|
||||
# John Johansen <john.johansen@canonical.com>, 2020.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: apparmor@lists.ubuntu.com\n"
|
||||
"POT-Creation-Date: 2024-08-31 15:59-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 @@
|
||||
# Translations for aa_features_abi
|
||||
# Copyright (C) 2024 Canonical Ltd
|
||||
# This file is distributed under the same license as the AppArmor package.
|
||||
# John Johansen <john.johansen@canonical.com>, 2011.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: apparmor@lists.ubuntu.com\n"
|
||||
"POT-Creation-Date: 2024-08-31 15:59-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,34 +0,0 @@
|
||||
# Translations for aa_load
|
||||
# Copyright (C) 2024 Canonical Ltd
|
||||
# This file is distributed under the same license as the AppArmor package.
|
||||
# John Johansen <john.johansen@canonical.com>, 2020.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: apparmor@lists.ubuntu.com\n"
|
||||
"POT-Creation-Date: 2024-08-31 15:59-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_load.c:40
|
||||
msgid "aa-load: WARN: "
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_load.c:41
|
||||
msgid "aa-load: ERROR: "
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_load.c:51
|
||||
msgid "\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_load.c:52
|
||||
msgid "aa-load: DEBUG: "
|
||||
msgstr ""
|
@@ -1,179 +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: 2025-04-26 11:12-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_status.c:161
|
||||
msgid "apparmor not present.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:164
|
||||
msgid "apparmor module is loaded.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:168
|
||||
msgid "apparmor filesystem is not mounted.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:181
|
||||
msgid "You do not have enough privilege to read the profile set.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:183
|
||||
#, c-format
|
||||
msgid "Could not open %s: %s"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:356 ../aa_status.c:379
|
||||
msgid "ERROR: Failed to allocate memory\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:587 ../aa_status.c:653 ../aa_status.c:603 ../aa_status.c:669
|
||||
#, c-format
|
||||
msgid "Error: failed to compile sub filter '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:715 ../aa_status.c:731
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Usage: %s [OPTIONS]\n"
|
||||
"Legacy options and their equivalent command\n"
|
||||
" --profiled --count --profiles\n"
|
||||
" --enforced --count --profiles --mode=enforced\n"
|
||||
" --complaining --count --profiles --mode=complain\n"
|
||||
" --kill --count --profiles --mode=kill\n"
|
||||
" --prompt --count --profiles --mode=prompt\n"
|
||||
" --special-unconfined --count --profiles --mode=unconfined\n"
|
||||
" --process-mixed --count --ps --mode=mixed\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:734 ../aa_status.c:750
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Usage of filters\n"
|
||||
"Filters are used to reduce the output of information to only\n"
|
||||
"those entries that will match the filter. Filters use posix\n"
|
||||
"regular expression syntax. The possible values for exes that\n"
|
||||
"support filters are below\n"
|
||||
"\n"
|
||||
" --filter.mode: regular expression to match the profile "
|
||||
"mode modes: enforce, complain, kill, unconfined, mixed\n"
|
||||
" --filter.profiles: regular expression to match displayed profile names\n"
|
||||
" --filter.pid: regular expression to match displayed processes pids\n"
|
||||
" --filter.exe: regular expression to match executable\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:762 ../aa_status.c:778
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Usage: %s [OPTIONS]\n"
|
||||
"Displays various information about the currently loaded AppArmor policy.\n"
|
||||
"Default if no options given\n"
|
||||
" --show=all\n"
|
||||
"\n"
|
||||
"OPTIONS (one only):\n"
|
||||
" --enabled returns error code if AppArmor not enabled\n"
|
||||
" --show=X What information to show. {profiles,processes,all}\n"
|
||||
" --count print the number of entries. Implies --quiet\n"
|
||||
" --filter.mode=filter see filters\n"
|
||||
" --filter.profiles=filter see filters\n"
|
||||
" --filter.pid=filter see filters\n"
|
||||
" --filter.exe=filter see filters\n"
|
||||
" --json displays multiple data points in machine-readable JSON "
|
||||
"format\n"
|
||||
" --pretty-json same data as --json, formatted for human consumption as "
|
||||
"well\n"
|
||||
" --verbose (default) displays data points about loaded policy set\n"
|
||||
" --quiet don't output error messages\n"
|
||||
" -h[(legacy|filters)] this message, or info on the specified option\n"
|
||||
" --help[=(legacy|filters)] this message, or info on the specified option\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:856 ../aa_status.c:872
|
||||
#, c-format
|
||||
msgid "Error: Invalid --help option '%s'.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:924 ../aa_status.c:940
|
||||
#, c-format
|
||||
msgid "Error: Invalid --show option '%s'.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:946 ../aa_status.c:962
|
||||
msgid "Error: Invalid command.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:971 ../aa_status.c:987
|
||||
msgid "Error: Unknown options.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:983 ../aa_status.c:999
|
||||
#, c-format
|
||||
msgid "Error: failed to compile mode filter '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:988 ../aa_status.c:1004
|
||||
#, c-format
|
||||
msgid "Error: failed to compile profiles filter '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:994 ../aa_status.c:1010
|
||||
#, c-format
|
||||
msgid "Error: failed to compile ps filter '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:1000 ../aa_status.c:1016
|
||||
#, c-format
|
||||
msgid "Error: failed to compile exe filter '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:1015 ../aa_status.c:1031
|
||||
#, c-format
|
||||
msgid "Failed to open memstream: %m\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:1026
|
||||
#, c-format
|
||||
msgid "Failed to get profiles: %d....\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:1050
|
||||
#, c-format
|
||||
msgid "Failed to get processes: %d....\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:1076 ../aa_status.c:1099
|
||||
msgid "Failed to parse json output"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:1083 ../aa_status.c:1106
|
||||
msgid "Failed to print pretty json"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:1044
|
||||
#, c-format
|
||||
msgid "Failed to retrieve profiles from kernel: %d....\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:1073
|
||||
#, c-format
|
||||
msgid "Failed to get confinement information from processes: %d....\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_status.c:1042
|
||||
msgid "No policy loaded into the kernel\n"
|
||||
msgstr ""
|
@@ -1,71 +0,0 @@
|
||||
# Afrikaans translation for apparmor
|
||||
# Copyright (c) 2020 Rosetta Contributors and Canonical Ltd 2020
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2020-03-04 17:55+0000\n"
|
||||
"Last-Translator: bernard stafford <Unknown>\n"
|
||||
"Language-Team: Afrikaans <af@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2020-03-05 05:40+0000\n"
|
||||
"X-Generator: Launchpad (build e0878392dc799b267dea80578fa65500a5d74155)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [opsies]\n"
|
||||
" opsies:\n"
|
||||
" -q | --quiet Moenie druk uit enige boodskappe\n"
|
||||
" -h | --help Afdruk hulp\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "onbekende of onversoenbare opsies\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "onbekende opsie '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Ja\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "Geen - nie beskikbaar op hierdie stelsel.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "Nee - gestremde by stewel.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Miskien - beleid koppelvlak nie beskikbaar.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "Miskien - onvoldoende toestemmings om beskikbaarheid te bepaal.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Fout - '%s'\n"
|
@@ -1,67 +0,0 @@
|
||||
# Belarusian 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-05-05 21:55+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Belarusian <be@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-05-06 05:41+0000\n"
|
||||
"X-Generator: Launchpad (build fbdff7602bd10fb883bf7e2ddcc7fd5a16f60398)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr ""
|
@@ -1,71 +0,0 @@
|
||||
# Catalan translation for apparmor
|
||||
# Copyright (c) 2024 Rosetta Contributors and Canonical Ltd 2024
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2024.
|
||||
#
|
||||
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: 2024-09-14 10:17+0000\n"
|
||||
"Last-Translator: Walter Garcia-Fontes <walter.garcia@upf.edu>\n"
|
||||
"Language-Team: Catalan <ca@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: 2024-09-15 07:16+0000\n"
|
||||
"X-Generator: Launchpad (build 1b1ed1ad2dbfc71ee62b5c5491c975135a771bf0)\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: [opcions]\n"
|
||||
" opcions:\n"
|
||||
" -q | --quiet No imprimeixis cap missatge\n"
|
||||
" -h | --help Imprimeix l'ajuda\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "opcions desconegudes o incompatibles\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "opció desconeguda «%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 esta disponible a aquest sistema\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "No - desactivat a l'inici.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Potser - la interfície de política no està disponible.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "Potser - permisos insuficient per determinar la disponibilitat.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Error - '%s'\n"
|
@@ -1,67 +0,0 @@
|
||||
# Czech translation for apparmor
|
||||
# Copyright (c) 2022 Rosetta Contributors and Canonical Ltd 2022
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
|
||||
#
|
||||
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: 2022-01-09 11:59+0000\n"
|
||||
"Last-Translator: Marek Hladík <mhladik@seznam.cz>\n"
|
||||
"Language-Team: Czech <cs@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: 2022-01-10 06:32+0000\n"
|
||||
"X-Generator: Launchpad (build 1682fd44eec4f62371f0bed122a83482daf08e23)\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 "neznámé nebo nekompatibilní volby\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "neznámá volba '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Ano\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "Ne - není v tomto systému k dispozici.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "Ne - zakázáno při startu.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Možná - rozhraní zásad není k dispozici.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "Možná - nedostatečná oprávnění k určení dostupnosti.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Chyba - '%s'\n"
|
@@ -8,14 +8,14 @@ msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: AppArmor list <apparmor@lists.ubuntu.com>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2018-02-09 23:55+0000\n"
|
||||
"Last-Translator: Tobias Bannert <tobannert@gmail.com>\n"
|
||||
"PO-Revision-Date: 2016-03-20 01:58+0000\n"
|
||||
"Last-Translator: Tobias Bannert <Unknown>\n"
|
||||
"Language-Team: German <de@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2019-04-18 05:33+0000\n"
|
||||
"X-Generator: Launchpad (build 18928)\n"
|
||||
"X-Launchpad-Export-Date: 2016-03-21 05:15+0000\n"
|
||||
"X-Generator: Launchpad (build 17947)\n"
|
||||
"Language: de\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
@@ -26,20 +26,16 @@ msgid ""
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [Optionen]\n"
|
||||
" Optionen:\n"
|
||||
" -q | --quiet Keine Nachrichten anzeigen\n"
|
||||
" -h | --help Hilfetext anzeigen\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "unbekannte oder nicht kompatible Optionen\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "unbekannte Option »%s«\n"
|
||||
msgstr "Unbekannte Option »%s«\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
@@ -59,15 +55,14 @@ msgstr "Nein – beim Start deaktiviert.\n"
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Vielleicht – Richtlinienschnittstelle nicht verfügbar.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
"Vielleicht – ungenügende Berechtigungen, um die Verfügbarkeit zu prüfen\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Fehler – »%s«\n"
|
||||
msgstr "Fehler - »%s«\n"
|
||||
|
@@ -1,67 +0,0 @@
|
||||
# English (Australia) 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-11-28 04:45+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: English (Australia) <en_AU@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-11-29 06:26+0000\n"
|
||||
"X-Generator: Launchpad (build 12d09381f8e8eee3115395875b132e165fa96574)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr ""
|
@@ -1,67 +0,0 @@
|
||||
# English (Canada) translation for apparmor
|
||||
# Copyright (c) 2021 Rosetta Contributors and Canonical Ltd 2021
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2021.
|
||||
#
|
||||
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: 2021-10-01 04:55+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: English (Canada) <en_CA@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: 2021-10-02 06:17+0000\n"
|
||||
"X-Generator: Launchpad (build 1ce78163f6a09ed42b4201fe7d3f0e3a2eba7d02)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr ""
|
@@ -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-02-19 05:10+0000\n"
|
||||
"X-Generator: Launchpad (build 17925)\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,71 +0,0 @@
|
||||
# Estonian translation for apparmor
|
||||
# Copyright (c) 2023 Rosetta Contributors and Canonical Ltd 2023
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2023.
|
||||
#
|
||||
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: 2023-07-04 08:52+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Estonian <et@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: 2023-07-05 04:31+0000\n"
|
||||
"X-Generator: Launchpad (build beda0e9dd2b131780db60fe479d4b43618b27243)\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: [valikud]\n"
|
||||
" valikud:\n"
|
||||
" -q | --quiet Ärge printige sõnumeid välja\n"
|
||||
" -h | --help Prindi abiinfo\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "tundmatud või ühildumatud valikud\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "tundmatu valik '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Jah\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "Ei – pole selles süsteemis saadaval.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "Ei – käivitamisel keelatud.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Võib-olla – poliisiliides pole saadaval.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "Võib-olla - kättesaadavuse määramiseks pole piisavalt õigusi.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Viga – '%s'\n"
|
@@ -1,67 +0,0 @@
|
||||
# Persian translation for apparmor
|
||||
# Copyright (c) 2019 Rosetta Contributors and Canonical Ltd 2019
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2019.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2019-12-27 08:16+0000\n"
|
||||
"Last-Translator: VahidNameni <Unknown>\n"
|
||||
"Language-Team: Persian <fa@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2019-12-28 05:38+0000\n"
|
||||
"X-Generator: Launchpad (build bceb5ef013b87ef7aafe0755545ceb689ca7ac60)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "تنظیم نامعلوم یا ناسازگار\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "تنظیم '%s' ناشناخته است\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "بله\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "خیر- در این سیستم موجود نیست.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "خیر - غیرفعال در زمان boot.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "شاید - رابط سیاست گذاری در دسترس نیست.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "شاید - دسترسی ناکافی جهت شناسایی در دسترس پذیری.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "خطا - '%s'\n"
|
@@ -1,67 +0,0 @@
|
||||
# Finnish translation for apparmor
|
||||
# Copyright (c) 2020 Rosetta Contributors and Canonical Ltd 2020
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2020-01-29 07:44+0000\n"
|
||||
"Last-Translator: Jiri Grönroos <Unknown>\n"
|
||||
"Language-Team: Finnish <fi@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2020-01-30 05:40+0000\n"
|
||||
"X-Generator: Launchpad (build b8d1327fd820d6bf500589d6da587d5037c7d88e)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "tuntemattomat tai yhteensopimattomat valinnat\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "tuntematon valinta '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Kyllä\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "Ei - ei käytettävissä tässä järjestelmässä.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "Ei - poistettu käytöstä käynnistyksen yhteydessä.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Virhe - '%s'\n"
|
@@ -1,67 +0,0 @@
|
||||
# Galician 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-04-21 14:59+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Galician <gl@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-04-22 06:10+0000\n"
|
||||
"X-Generator: Launchpad (build aad6b57d58e2f621954298e262c1cc904860f5d2)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr ""
|
@@ -1,71 +0,0 @@
|
||||
# Hebrew translation for apparmor
|
||||
# Copyright (c) 2023 Rosetta Contributors and Canonical Ltd 2023
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2023.
|
||||
#
|
||||
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: 2023-10-05 05:12+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Hebrew <he@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: 2023-10-06 08:32+0000\n"
|
||||
"X-Generator: Launchpad (build bd6cfd0cfc024dbe1dcd7d5d91165fb4f6a6c596)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [אפשרויות]\n"
|
||||
" אפשרויות:\n"
|
||||
" -q | --quiet לא להציג הודעות\n"
|
||||
" -h | --help הצגת עזרה\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "אפשרויות לא ידועות או לא נתמכות\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "האפשרות ‚%s’ לא מוכרת\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "כן\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "לא - לא זמין במערכת הזאת.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "לא - מושבת בעלייה.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "אולי - מנשק המדיניות לא זמין.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "אולי - אין מספיק הרשאות לקבוע זמינות.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "שגיאה - ‚%s’\n"
|
@@ -1,67 +0,0 @@
|
||||
# Hindi translation for apparmor
|
||||
# Copyright (c) 2023 Rosetta Contributors and Canonical Ltd 2023
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2023.
|
||||
#
|
||||
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: 2023-01-09 07:39+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Hindi <hi@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: 2023-01-10 06:22+0000\n"
|
||||
"X-Generator: Launchpad (build 87bfee1fd14ea3245297d63eeec1e4c8a1d203a8)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr ""
|
@@ -1,71 +0,0 @@
|
||||
# Croatian 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: 2021-10-03 10:17+0000\n"
|
||||
"Last-Translator: gogo <trebelnik2@gmail.com>\n"
|
||||
"Language-Team: Croatian <hr@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: 2021-10-04 06:23+0000\n"
|
||||
"X-Generator: Launchpad (build 1ce78163f6a09ed42b4201fe7d3f0e3a2eba7d02)\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: [mogućnosti]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Ne prikazuj poruke\n"
|
||||
" -h | --help Prikaži pomoć\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "nepoznata ili nepotpuna mogućnost\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "nepoznata mogućnost '%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 "Ne - nedostupno na ovom sustavu.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "Ne - onemogućeno pri pokretanju.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Možda - pravilo sučelja nedostupno.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "Možda - nedovoljna dozvola za određivanje dostupnosti.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Greška - '%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-02-02 05:11+0000\n"
|
||||
"X-Generator: Launchpad (build 17908)\n"
|
||||
"Language: id\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
|
@@ -1,72 +0,0 @@
|
||||
# Italian translation for apparmor
|
||||
# Copyright (c) 2022 Rosetta Contributors and Canonical Ltd 2022
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
|
||||
#
|
||||
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: 2022-06-30 17:54+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Italian <it@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: 2022-07-01 04:30+0000\n"
|
||||
"X-Generator: Launchpad (build f48158886a49da429840bcd298f0c7ed60f9ad7b)\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: [opzioni]\n"
|
||||
" opzioni:\n"
|
||||
" -q | --quiet Non stampa nessun messaggio\n"
|
||||
" -h | --help Stampa la guida\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "opzioni sconosciute o incompatibili\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "opzione sconosciuta '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Si\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "No - non disponibile su questo sistema.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "No - disabilitato all'avvio.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Forse - interfaccia dei criteri non disponibile.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
"Forse - autorizzazioni insufficienti per determinare la disponibilità.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Errore - '%s'\n"
|
@@ -1,72 +0,0 @@
|
||||
# Georgian translation for apparmor
|
||||
# Copyright (c) 2023 Rosetta Contributors and Canonical Ltd 2023
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2023.
|
||||
#
|
||||
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: 2023-06-26 15:06+0000\n"
|
||||
"Last-Translator: NorwayFun <temuri.doghonadze@gmail.com>\n"
|
||||
"Language-Team: Georgian <ka@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: 2023-06-27 04:31+0000\n"
|
||||
"X-Generator: Launchpad (build aedf8597c50c1abc5fb7f9e871e686dfcb381fde)\n"
|
||||
"Language: aa\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [პარამეტრები]\n"
|
||||
" პარამეტრები:\n"
|
||||
" -q | --quiet შეტყობინებები გამოტანილი არ იქნება\n"
|
||||
" -h | --help დახმარების გამოტანა\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "უცნობი ან შეუთავსებელი პარამეტრები\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "უცნობი პარამეტრი \"%s\"-სთვის\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "დიახ\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "არა - მიუწვდომელია ამ სისტემაზე\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "არა - გამორთულია ჩატვირთვისას\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "შეიძლება - პოლიტიკის ინტერფეისი ხელმისაწვდომი არაა.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "შეიძლება - არასაკმარისი წვდომები ხელმისაწვდომობის დასადგენად.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "შეცდომა - \"%s\"\n"
|
@@ -1,67 +0,0 @@
|
||||
# Kabyle 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-04-29 14:31+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Kabyle <kab@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-04-30 05:44+0000\n"
|
||||
"X-Generator: Launchpad (build fbdff7602bd10fb883bf7e2ddcc7fd5a16f60398)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr ""
|
@@ -1,73 +0,0 @@
|
||||
# Burmese translation for apparmor
|
||||
# Copyright (c) 2022 Rosetta Contributors and Canonical Ltd 2022
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
|
||||
#
|
||||
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: 2022-06-26 11:50+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Burmese <my@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: 2022-06-27 04:30+0000\n"
|
||||
"X-Generator: Launchpad (build 51a2e4fa2e9b8e45f00904ad7f53546f45ac48a5)\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"
|
||||
" ရွေးချယ်စရာများ-\n"
|
||||
" -q | --quiet မည်သည့်စာတိုကိုမှ ပရင့်မထုတ်ပါနှင့်။\n"
|
||||
" -h | --help ပရင့်အကူအညီ\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "အမည်မသိ သို့မဟုတ် သဟဇာတမဖြစ်သော ရွေးချယ်စရာများ\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "အမည်မသိရွေးချယ်မှု '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "ဟုတ်\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "မဟုတ်ပါ - ဤစနစ်တွင် မရနိုင်ပါ။\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "မဟုတ်ပါ - boot တွင် ပိတ်ထားပါသည်။\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "ဖြစ်နိုင်ပါသည် - မူဝါဒ interface ကို မရနိုင်ပါ။\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 @@
|
||||
# Occitan (post 1500) translation for apparmor
|
||||
# Copyright (c) 2021 Rosetta Contributors and Canonical Ltd 2021
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2021.
|
||||
#
|
||||
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: 2021-01-14 18:26+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Occitan (post 1500) <oc@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: 2021-01-15 07:59+0000\n"
|
||||
"X-Generator: Launchpad (build 511b4a3b6512aa3d421c5f7d74f3527e78bff26e)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr ""
|
@@ -1,71 +0,0 @@
|
||||
# Polish translation for apparmor
|
||||
# Copyright (c) 2021 Rosetta Contributors and Canonical Ltd 2021
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2021.
|
||||
#
|
||||
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: 2021-07-22 20:10+0000\n"
|
||||
"Last-Translator: Marek Adamski <Unknown>\n"
|
||||
"Language-Team: Polish <pl@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: 2021-07-23 06:03+0000\n"
|
||||
"X-Generator: Launchpad (build 7edebbcd0516593cf020aaa3c59299732a7c73cc)\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: [opcje]\n"
|
||||
" opcje:\n"
|
||||
" -q | --quiet Nie wyświetlaj żadnych komunikatów\n"
|
||||
" -h | --help Wyświetl pomoc\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "nieznane lub niekompatybilne opcje\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "nieznana opcja '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Tak\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "Nie - nie jest dostępne w tym systemie.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "Nie - wyłączone podczas rozruchu.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Może - interfejs zasad nie jest dostępny.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "Może - brak wystarczających uprawnień do określenia dostępności.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Błąd - '%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-03-04 04:35+0000\n"
|
||||
"X-Generator: Launchpad (build 17936)\n"
|
||||
"Language: pt\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
|
@@ -1,71 +0,0 @@
|
||||
# Brazilian Portuguese 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-04-27 20:32+0000\n"
|
||||
"Last-Translator: Rodrigo Farias <Unknown>\n"
|
||||
"Language-Team: Brazilian Portuguese <pt_BR@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-04-28 05:52+0000\n"
|
||||
"X-Generator: Launchpad (build d1105341713c5be348effe2a5142c4a210ce4cde)\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"
|
||||
" opções:\n"
|
||||
" -q | --quiet Não imprimir nenhum mensagem\n"
|
||||
" -h | --help Assistente de impressão\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "opções incompatíveis ou desconhecidas\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "opção desconhecida '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Sim\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "Não - não disponível neste sistema.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "Não - desabilitado na inicialização.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Talvez - interface de política não disponível.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "Talvez - permissões insuficientes para determinar disponibilidade.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Erro - '%s'\n"
|
@@ -1,78 +0,0 @@
|
||||
# Romanian translation for apparmor, "apparmor-binutils" component.
|
||||
# Mesajele în limba română pentru pachetul „apparmor”, componenta „apparmor-binutils”.
|
||||
# Copyright © 2020 Rosetta Contributors and Canonical Ltd.
|
||||
# Copyright © 2024 Canonical Ltd.
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
#
|
||||
# Daniel Slavu <Unknown>, feb-2020.
|
||||
# Remus-Gabriel Chelu <remusgabriel.chelu@disroot.org>, sep-2024.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor-binutils\n"
|
||||
"Report-Msgid-Bugs-To: <apparmor@lists.ubuntu.com>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2024-09-23 22:45+0000\n"
|
||||
"Last-Translator: Remus-Gabriel Chelu <Unknown>\n"
|
||||
"Language-Team: Romanian <debian-l10n-romanian@lists.debian.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2024-09-25 04:33+0000\n"
|
||||
"X-Generator: Launchpad (build 1b1ed1ad2dbfc71ee62b5c5491c975135a771bf0)\n"
|
||||
"Language: ro\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 | --quiet nu afișează niciun mesaj\n"
|
||||
" -h | --help imprimă ajutorul\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ă (de directive politice) 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-03-30 05:13+0000\n"
|
||||
"X-Generator: Launchpad (build 17967)\n"
|
||||
"Language: ru\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
|
@@ -1,67 +0,0 @@
|
||||
# Serbian 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-11-23 18:06+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Serbian <sr@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-11-24 05:55+0000\n"
|
||||
"X-Generator: Launchpad (build c35ff22711d15549e2303ae18ae521fd91f6bf00)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr ""
|
@@ -1,72 +0,0 @@
|
||||
# Swedish translation for apparmor
|
||||
# Copyright (c) 2018 Rosetta Contributors and Canonical Ltd 2018
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2018.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2018-09-08 03:51+0000\n"
|
||||
"Last-Translator: Jonatan Nyberg <Unknown>\n"
|
||||
"Language-Team: Swedish <sv@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2019-04-18 05:33+0000\n"
|
||||
"X-Generator: Launchpad (build 18928)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [options]\n"
|
||||
" flaggor:\n"
|
||||
" -q | --quiet Skriv inte ut några meddelanden\n"
|
||||
" -h | --help Skriv ut hjälp\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "okända eller inkompatibla flaggor\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "okänd flagga '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Ja\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "Nej - inte tillgänglig på detta system.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "Nej - inaktiverad vid uppstart.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Kanske - policy gränssnitt inte tillgängliga.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
"Kanske - otillräckliga behörigheter för att bestämma tillgängligheten.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Fel - '%s'\n"
|
@@ -1,71 +0,0 @@
|
||||
# Swahili translation for apparmor
|
||||
# Copyright (c) 2019 Rosetta Contributors and Canonical Ltd 2019
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2019.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2019-11-14 12:33+0000\n"
|
||||
"Last-Translator: Swahilinux Administration <admin@swahilinux.org>\n"
|
||||
"Language-Team: Swahili <sw@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2019-11-15 04:30+0000\n"
|
||||
"X-Generator: Launchpad (build c597c3229eb023b1e626162d5947141bf7befb13)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [chaguzi]\n"
|
||||
" chaguzi:\n"
|
||||
" -q | --quiet Usichapishe jumbe yoyote\n"
|
||||
" -h | --help Chapisha msaada\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "chaguo lisilojulikana au lisilofaa\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "chaguo lisilojulikana '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Ndio\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "La - haipo kwenye mfumo huu.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "La - ilizimwa kwenye washi.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Labda - kiolesura cha faragha hakipo.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "Labda - hamna ruhusa ya kutosha ili kuamua kama ipo.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Dosari - '%s'\n"
|
@@ -1,72 +0,0 @@
|
||||
# Turkish translation for apparmor
|
||||
# Copyright (c) 2018 Rosetta Contributors and Canonical Ltd 2018
|
||||
# This file is distributed under the same license as the apparmor package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2018.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: apparmor\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: 2018-05-19 23:10+0000\n"
|
||||
"Last-Translator: Kudret EMRE <kudretemre@hotmail.com>\n"
|
||||
"Language-Team: Turkish <tr@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2019-04-18 05:33+0000\n"
|
||||
"X-Generator: Launchpad (build 18928)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [seçenekler]\n"
|
||||
" seçenekler:\n"
|
||||
" -q | --quiet Hiçbir mesajı gösterme\n"
|
||||
" -h | --help Yardımı görüntüler\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "bilinmeyen veya uyumsuz seçenekler\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "bilinmeyen seçenek '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Evet\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "Hayır - Bu sistemde kullanılabilir değil.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "Hayır - önyüklemede devredışı bırakıldı.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Belki - policy arayüzü kullanılabilir değil.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
"Belki - kullanılabilir olup olmadığını denetlemek için yetersiz yetki.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Hata - '%s'\n"
|
@@ -1,71 +0,0 @@
|
||||
# Ukrainian 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-05-19 21:48+0000\n"
|
||||
"Last-Translator: Nazarii Ritter <nazariy.ritter@gmail.com>\n"
|
||||
"Language-Team: Ukrainian <uk@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-05-20 05:42+0000\n"
|
||||
"X-Generator: Launchpad (build 0385b538081bc4718df6fb844a3afc89729c94ce)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [опції]\n"
|
||||
" опції:\n"
|
||||
" -q | --quiet Не виводити жодних повідомлень\n"
|
||||
" -h | --help Вивести довідку\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "невідомі або несумісні опції\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "невідомий параметр «%s»\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "Так\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "Ні – недоступно на цій системі.\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "Ні – вимкнено під час завантаження.\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "Можливо – інтерфейс політики недоступний.\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "Можливо – недостатньо дозволів для визначення наявності.\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "Помилка - '%s'\n"
|
@@ -1,71 +0,0 @@
|
||||
# Chinese (Simplified) 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-05-14 09:16+0000\n"
|
||||
"Last-Translator: 玉堂白鹤 <yjwork@qq.com>\n"
|
||||
"Language-Team: Chinese (Simplified) <zh_CN@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-05-15 05:51+0000\n"
|
||||
"X-Generator: Launchpad (build 0385b538081bc4718df6fb844a3afc89729c94ce)\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
"%s: [选项]\n"
|
||||
" 选项:\n"
|
||||
" -q | --quiet 不要打印任何消息\n"
|
||||
" -h | --help 打印帮助\n"
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr "未知或不兼容的选项\n"
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr "未知选项 '%s'\n"
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr "是\n"
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr "否 - 在此系统上不可用。\n"
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr "否 - 引导时被禁用。\n"
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr "也许 - 策略界面不可用\n"
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr "也许 - 没有足够的权限确定可用性。\n"
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr "错误 - '%s'\n"
|
@@ -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,14 +80,14 @@ 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
|
||||
install: ${TARGET} ${MANPAGES}
|
||||
mkdir -p ${DESTDIR}/${APXS_INSTALL_DIR}
|
||||
install -m 755 $< ${DESTDIR}/${APXS_INSTALL_DIR}
|
||||
$(MAKE) install_manpages DESTDIR=${DESTDIR}
|
||||
make install_manpages DESTDIR=${DESTDIR}
|
||||
|
||||
.PHONY: clean
|
||||
clean: pod_clean
|
||||
|
@@ -30,10 +30,6 @@
|
||||
|
||||
/* #define DEBUG */
|
||||
|
||||
#ifndef unused_
|
||||
#define unused_ __attribute__ ((unused))
|
||||
#endif
|
||||
|
||||
/* should the following be configurable? */
|
||||
#define DEFAULT_HAT "HANDLING_UNTRUSTED_INPUT"
|
||||
#define DEFAULT_URI_HAT "DEFAULT_URI"
|
||||
@@ -69,7 +65,7 @@ typedef struct {
|
||||
* memory will be wiped out, and the magic_token will be lost, so apache
|
||||
* wouldn't be able to change_hat back out. */
|
||||
static int
|
||||
aa_init(apr_pool_t *p, unused_ apr_pool_t *plog, unused_ apr_pool_t *ptemp, unused_ server_rec *s)
|
||||
aa_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
|
||||
{
|
||||
apr_file_t *file;
|
||||
apr_size_t size = sizeof(magic_token);
|
||||
@@ -93,7 +89,7 @@ aa_init(apr_pool_t *p, unused_ apr_pool_t *plog, unused_ apr_pool_t *ptemp, unus
|
||||
* to protect ourselves from bugs in parsing network input, but before
|
||||
* we change_hat to the uri specific hat. */
|
||||
static void
|
||||
aa_child_init(unused_ apr_pool_t *p, unused_ server_rec *s)
|
||||
aa_child_init(apr_pool_t *p, server_rec *s)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -264,7 +260,7 @@ aa_exit_hat(request_rec *r)
|
||||
}
|
||||
|
||||
static const char *
|
||||
aa_cmd_ch_path(unused_ cmd_parms *cmd, unused_ void *mconfig, const char *parm1)
|
||||
aa_cmd_ch_path(cmd_parms *cmd, void *mconfig, const char *parm1)
|
||||
{
|
||||
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, "directory config change hat %s",
|
||||
parm1 ? parm1 : "DEFAULT");
|
||||
@@ -291,7 +287,7 @@ immunix_cmd_ch_path(cmd_parms *cmd, void *mconfig, const char *parm1)
|
||||
}
|
||||
|
||||
static const char *
|
||||
aa_cmd_ch_srv(cmd_parms *cmd, unused_ void *mconfig, const char *parm1)
|
||||
aa_cmd_ch_srv(cmd_parms *cmd, void *mconfig, const char *parm1)
|
||||
{
|
||||
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, "server config change hat %s",
|
||||
parm1 ? parm1 : "DEFAULT");
|
||||
@@ -351,7 +347,7 @@ aa_merge_dir_config(apr_pool_t *p, void *parent, void *child)
|
||||
*/
|
||||
|
||||
static void *
|
||||
aa_create_srv_config(apr_pool_t *p, unused_ server_rec *srv)
|
||||
aa_create_srv_config(apr_pool_t *p, server_rec *srv)
|
||||
{
|
||||
apparmor_srv_cfg *newcfg = (apparmor_srv_cfg *) apr_pcalloc(p, sizeof(*newcfg));
|
||||
|
||||
@@ -401,7 +397,7 @@ static const command_rec mod_apparmor_cmds[] = {
|
||||
};
|
||||
|
||||
static void
|
||||
register_hooks(unused_ apr_pool_t *p)
|
||||
register_hooks(apr_pool_t *p)
|
||||
{
|
||||
ap_hook_post_config(aa_init, NULL, NULL, APR_HOOK_MIDDLE);
|
||||
ap_hook_child_init(aa_child_init, NULL, NULL, APR_HOOK_MIDDLE);
|
||||
@@ -412,7 +408,7 @@ register_hooks(unused_ apr_pool_t *p)
|
||||
|
||||
module AP_MODULE_DECLARE_DATA apparmor_module = {
|
||||
STANDARD20_MODULE_STUFF,
|
||||
aa_create_dir_config, /* dir config creator */
|
||||
aa_create_dir_config, /* dir config creater */
|
||||
NULL, /* dir merger --- default is to override */
|
||||
/* immunix_merge_dir_config, */ /* dir merger --- default is to override */
|
||||
aa_create_srv_config, /* server config */
|
||||
|
@@ -135,11 +135,11 @@ may not work correctly. For Apache 2.4 users, you should enable the mpm_prefork
|
||||
module.
|
||||
|
||||
There are likely other bugs lurking about; if you find any, please report
|
||||
them at L<https://gitlab.com/apparmor/apparmor/-/issues>.
|
||||
them at L<https://bugs.launchpad.net/apparmor/+filebug>.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
apparmor(7), apparmor_parser(8), aa_change_hat(2) and
|
||||
L<https://wiki.apparmor.net>.
|
||||
apparmor(7), subdomain.conf(5), apparmor_parser(8), aa_change_hat(2) and
|
||||
L<http://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
|
||||
@@ -82,7 +82,7 @@ SECDIR ?= ${DESTDIR}/lib/security
|
||||
.PHONY: install
|
||||
install: $(NAME).so
|
||||
install -m 755 -d $(SECDIR)
|
||||
install -m 755 $(NAME).so $(SECDIR)/
|
||||
install -m 555 $(NAME).so $(SECDIR)/
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
|
@@ -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.
|
||||
|
@@ -35,17 +35,20 @@ VERSION=$(shell cat $(COMMONDIR)/Version)
|
||||
pathsearch = $(firstword $(wildcard $(addsuffix /$(1),$(subst :, ,$(PATH)))))
|
||||
map = $(foreach a,$(2),$(call $(1),$(a)))
|
||||
|
||||
AWK?=$(or $(shell which awk),$(error awk utility required for build but not available))
|
||||
AWK:=$(shell which awk)
|
||||
ifndef AWK
|
||||
$(error awk utility required for build but not available)
|
||||
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
|
||||
REPO_VERSION_CMD=[ -x /usr/bin/bzr ] && /usr/bin/bzr version-info --custom --template="{revno}" . 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
|
||||
@@ -55,18 +58,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:
|
||||
@@ -84,6 +75,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 @@
|
||||
5.0.0~alpha1
|
||||
2.11.1
|
||||
|
@@ -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:\nhttp://wiki.apparmor.net/index.php/Profiles"));
|
||||
|
||||
UI_Important(gettext("Please start the application to be profiled in \nanother window and exercise its functionality now.\n\nOnce completed, select the \"Scan\" button below in \norder to scan the system logs for AppArmor events. \n\nFor each AppArmor event, you will be given the \nopportunity to choose whether the access should be \nallowed or denied."));
|
||||
|
||||
my $syslog = 1;
|
||||
my $logmark = "";
|
||||
my $done_profiling = 0;
|
||||
|
||||
$syslog = 0 if (-e "/var/log/audit/audit.log");
|
||||
|
||||
while (not $done_profiling) {
|
||||
if ($syslog) {
|
||||
$logmark = `date | md5sum`;
|
||||
chomp $logmark;
|
||||
$logmark = $1 if $logmark =~ /^([0-9a-f]+)/;
|
||||
system("$logger -p kern.warn 'GenProf: $logmark'");
|
||||
} else {
|
||||
$logmark = last_audit_entry_time();
|
||||
}
|
||||
eval {
|
||||
|
||||
my $q = {};
|
||||
$q->{headers} = [ gettext("Profiling"), $fqdbin ];
|
||||
$q->{functions} = [ "CMD_SCAN", "CMD_FINISHED" ];
|
||||
$q->{default} = "CMD_SCAN";
|
||||
|
||||
my ($ans, $arg) = UI_PromptUser($q);
|
||||
|
||||
if ($ans eq "CMD_SCAN") {
|
||||
|
||||
my $lp_ret = do_logprof_pass($logmark);
|
||||
|
||||
$done_profiling = 1 if $lp_ret eq "FINISHED";
|
||||
|
||||
} else {
|
||||
|
||||
$done_profiling = 1;
|
||||
|
||||
}
|
||||
};
|
||||
if ($@) {
|
||||
if ($@ =~ /FINISHING/) {
|
||||
$done_profiling = 1;
|
||||
} else {
|
||||
die $@;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for my $p (sort keys %helpers) {
|
||||
if ($helpers{$p} eq "enforce") {
|
||||
enforce($p);
|
||||
reload($p);
|
||||
}
|
||||
}
|
||||
|
||||
UI_Info(gettext("Reloaded AppArmor profiles in enforce mode."));
|
||||
UI_Info(gettext("\nPlease consider contributing your new profile! See\nthe following wiki page for more information:\nhttp://wiki.apparmor.net/index.php/Profiles\n"));
|
||||
UI_Info(sprintf(gettext('Finished generating profile for %s.'), $fqdbin));
|
||||
exit 0;
|
||||
|
||||
sub usage {
|
||||
UI_Info(sprintf(gettext("usage: \%s [ -d /path/to/profiles ] [ -f /path/to/logfile ] [ program to profile ]"), $0));
|
||||
exit 0;
|
||||
}
|
||||
|
||||
sub last_audit_entry_time {
|
||||
local $_ = `tail -1 /var/log/audit/audit.log`;
|
||||
my $logmark;
|
||||
if (/^*msg\=audit\((\d+\.\d+\:\d+).*\).*$/) {
|
||||
$logmark = $1;
|
||||
} else {
|
||||
$logmark = "";
|
||||
}
|
||||
return $logmark;
|
||||
}
|
72
deprecated/utils/aa-logprof
Executable file
72
deprecated/utils/aa-logprof
Executable file
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/perl
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2005 Novell, Inc. All Rights Reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Novell, Inc.
|
||||
#
|
||||
# To contact Novell about this file by physical or electronic mail,
|
||||
# you may find current contact information at www.novell.com.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
use strict;
|
||||
use Data::Dumper;
|
||||
use Getopt::Long;
|
||||
use Locale::gettext;
|
||||
use POSIX;
|
||||
|
||||
use Immunix::AppArmor;
|
||||
|
||||
# force $PATH to be sane
|
||||
$ENV{PATH} = "/bin:/sbin:/usr/bin:/usr/sbin";
|
||||
|
||||
# initialize the local poo
|
||||
setlocale(LC_MESSAGES, "");
|
||||
textdomain("apparmor-utils");
|
||||
|
||||
setup_yast();
|
||||
|
||||
# options variables
|
||||
my $help = '';
|
||||
my $logmark;
|
||||
|
||||
GetOptions(
|
||||
'file|f=s' => \$filename,
|
||||
'dir|d=s' => \$profiledir,
|
||||
'logmark|m=s' => \$logmark,
|
||||
'help|h' => \$help,
|
||||
);
|
||||
|
||||
# tell 'em how to use it...
|
||||
&usage && exit if $help;
|
||||
|
||||
# let's convert it to full path...
|
||||
$profiledir = get_full_path($profiledir);
|
||||
|
||||
unless (-d $profiledir) {
|
||||
fatal_error "Can't find AppArmor profiles in $profiledir.";
|
||||
}
|
||||
|
||||
# load all the include files
|
||||
loadincludes();
|
||||
|
||||
do_logprof_pass($logmark);
|
||||
|
||||
shutdown_yast();
|
||||
|
||||
exit 0;
|
||||
|
||||
sub usage {
|
||||
UI_Info(sprintf(gettext("usage: \%s [ -d /path/to/profiles ] [ -f /path/to/logfile ] [ -m \"mark in log to start processing after\""), $0));
|
||||
exit 0;
|
||||
}
|
||||
|
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 |
Binary file not shown.
Before Width: | Height: | Size: 50 KiB |
@@ -1,605 +0,0 @@
|
||||
From 97b3200925ba627346432edf521d49de8bb018a3 Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Mon, 4 Oct 2010 15:03:36 -0700
|
||||
Subject: [PATCH 1/3] UBUNTU: SAUCE: AppArmor: basic networking rules
|
||||
|
||||
Base support for network mediation.
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
---
|
||||
security/apparmor/.gitignore | 1 +
|
||||
security/apparmor/Makefile | 42 ++++++++++-
|
||||
security/apparmor/apparmorfs.c | 1 +
|
||||
security/apparmor/include/audit.h | 4 +
|
||||
security/apparmor/include/net.h | 59 +++++++++++++++
|
||||
security/apparmor/include/policy.h | 3 +
|
||||
security/apparmor/lsm.c | 112 ++++++++++++++++++++++++++++
|
||||
security/apparmor/net.c | 148 +++++++++++++++++++++++++++++++++++++
|
||||
security/apparmor/policy.c | 1 +
|
||||
security/apparmor/policy_unpack.c | 47 +++++++++++-
|
||||
10 files changed, 415 insertions(+), 3 deletions(-)
|
||||
create mode 100644 security/apparmor/include/net.h
|
||||
create mode 100644 security/apparmor/net.c
|
||||
|
||||
diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore
|
||||
index 9cdec70d72b8..d5b291e94264 100644
|
||||
--- a/security/apparmor/.gitignore
|
||||
+++ b/security/apparmor/.gitignore
|
||||
@@ -1,5 +1,6 @@
|
||||
#
|
||||
# Generated include files
|
||||
#
|
||||
+net_names.h
|
||||
capability_names.h
|
||||
rlim_names.h
|
||||
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
|
||||
index ad369a7aac24..a7dc10be232d 100644
|
||||
--- a/security/apparmor/Makefile
|
||||
+++ b/security/apparmor/Makefile
|
||||
@@ -4,10 +4,10 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
|
||||
|
||||
apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
|
||||
path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
|
||||
- resource.o secid.o file.o policy_ns.o
|
||||
+ resource.o secid.o file.o policy_ns.o net.o
|
||||
apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
|
||||
|
||||
-clean-files := capability_names.h rlim_names.h
|
||||
+clean-files := capability_names.h rlim_names.h net_names.h
|
||||
|
||||
|
||||
# Build a lower case string table of capability names
|
||||
@@ -25,6 +25,38 @@ cmd_make-caps = echo "static const char *const capability_names[] = {" > $@ ;\
|
||||
-e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/\L\1/p' | \
|
||||
tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
|
||||
|
||||
+# Build a lower case string table of address family names
|
||||
+# Transform lines from
|
||||
+# define AF_LOCAL 1 /* POSIX name for AF_UNIX */
|
||||
+# #define AF_INET 2 /* Internet IP Protocol */
|
||||
+# to
|
||||
+# [1] = "local",
|
||||
+# [2] = "inet",
|
||||
+#
|
||||
+# and build the securityfs entries for the mapping.
|
||||
+# Transforms lines from
|
||||
+# #define AF_INET 2 /* Internet IP Protocol */
|
||||
+# to
|
||||
+# #define AA_FS_AF_MASK "local inet"
|
||||
+quiet_cmd_make-af = GEN $@
|
||||
+cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\
|
||||
+ sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e \
|
||||
+ 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
|
||||
+ echo "};" >> $@ ;\
|
||||
+ echo -n '\#define AA_FS_AF_MASK "' >> $@ ;\
|
||||
+ sed -r -n 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/\L\1/p'\
|
||||
+ $< | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
|
||||
+
|
||||
+# Build a lower case string table of sock type names
|
||||
+# Transform lines from
|
||||
+# SOCK_STREAM = 1,
|
||||
+# to
|
||||
+# [1] = "stream",
|
||||
+quiet_cmd_make-sock = GEN $@
|
||||
+cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\
|
||||
+ sed $^ >>$@ -r -n \
|
||||
+ -e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
|
||||
+ echo "};" >> $@
|
||||
|
||||
# Build a lower case string table of rlimit names.
|
||||
# Transforms lines from
|
||||
@@ -61,6 +93,7 @@ cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \
|
||||
tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
|
||||
|
||||
$(obj)/capability.o : $(obj)/capability_names.h
|
||||
+$(obj)/net.o : $(obj)/net_names.h
|
||||
$(obj)/resource.o : $(obj)/rlim_names.h
|
||||
$(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
|
||||
$(src)/Makefile
|
||||
@@ -68,3 +101,8 @@ $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
|
||||
$(obj)/rlim_names.h : $(srctree)/include/uapi/asm-generic/resource.h \
|
||||
$(src)/Makefile
|
||||
$(call cmd,make-rlim)
|
||||
+$(obj)/net_names.h : $(srctree)/include/linux/socket.h \
|
||||
+ $(srctree)/include/linux/net.h \
|
||||
+ $(src)/Makefile
|
||||
+ $(call cmd,make-af)
|
||||
+ $(call cmd,make-sock)
|
||||
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
|
||||
index 41073f70eb41..4d236736cfb8 100644
|
||||
--- a/security/apparmor/apparmorfs.c
|
||||
+++ b/security/apparmor/apparmorfs.c
|
||||
@@ -1209,6 +1209,7 @@ static struct aa_fs_entry aa_fs_entry_features[] = {
|
||||
AA_FS_DIR("policy", aa_fs_entry_policy),
|
||||
AA_FS_DIR("domain", aa_fs_entry_domain),
|
||||
AA_FS_DIR("file", aa_fs_entry_file),
|
||||
+ AA_FS_DIR("network", aa_fs_entry_network),
|
||||
AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
|
||||
AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
|
||||
AA_FS_DIR("caps", aa_fs_entry_caps),
|
||||
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
|
||||
index fdc4774318ba..0df708e8748b 100644
|
||||
--- a/security/apparmor/include/audit.h
|
||||
+++ b/security/apparmor/include/audit.h
|
||||
@@ -127,6 +127,10 @@ struct apparmor_audit_data {
|
||||
int rlim;
|
||||
unsigned long max;
|
||||
} rlim;
|
||||
+ struct {
|
||||
+ int type, protocol;
|
||||
+ struct sock *sk;
|
||||
+ } net;
|
||||
};
|
||||
};
|
||||
|
||||
diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
|
||||
new file mode 100644
|
||||
index 000000000000..55da1dad8720
|
||||
--- /dev/null
|
||||
+++ b/security/apparmor/include/net.h
|
||||
@@ -0,0 +1,59 @@
|
||||
+/*
|
||||
+ * AppArmor security module
|
||||
+ *
|
||||
+ * This file contains AppArmor network mediation definitions.
|
||||
+ *
|
||||
+ * Copyright (C) 1998-2008 Novell/SUSE
|
||||
+ * Copyright 2009-2012 Canonical Ltd.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation, version 2 of the
|
||||
+ * License.
|
||||
+ */
|
||||
+
|
||||
+#ifndef __AA_NET_H
|
||||
+#define __AA_NET_H
|
||||
+
|
||||
+#include <net/sock.h>
|
||||
+
|
||||
+#include "apparmorfs.h"
|
||||
+
|
||||
+/* struct aa_net - network confinement data
|
||||
+ * @allowed: basic network families permissions
|
||||
+ * @audit_network: which network permissions to force audit
|
||||
+ * @quiet_network: which network permissions to quiet rejects
|
||||
+ */
|
||||
+struct aa_net {
|
||||
+ u16 allow[AF_MAX];
|
||||
+ u16 audit[AF_MAX];
|
||||
+ u16 quiet[AF_MAX];
|
||||
+};
|
||||
+
|
||||
+extern struct aa_fs_entry aa_fs_entry_network[];
|
||||
+
|
||||
+#define DEFINE_AUDIT_NET(NAME, OP, SK, F, T, P) \
|
||||
+ struct lsm_network_audit NAME ## _net = { .sk = (SK), \
|
||||
+ .family = (F)}; \
|
||||
+ DEFINE_AUDIT_DATA(NAME, \
|
||||
+ ((SK) && (F) != AF_UNIX) ? LSM_AUDIT_DATA_NET : \
|
||||
+ LSM_AUDIT_DATA_NONE, \
|
||||
+ OP); \
|
||||
+ NAME.u.net = &(NAME ## _net); \
|
||||
+ aad(&NAME)->net.type = (T); \
|
||||
+ aad(&NAME)->net.protocol = (P)
|
||||
+
|
||||
+#define DEFINE_AUDIT_SK(NAME, OP, SK) \
|
||||
+ DEFINE_AUDIT_NET(NAME, OP, SK, (SK)->sk_family, (SK)->sk_type, \
|
||||
+ (SK)->sk_protocol)
|
||||
+
|
||||
+extern int aa_net_perm(const char *op, struct aa_profile *profile, u16 family,
|
||||
+ int type, int protocol, struct sock *sk);
|
||||
+extern int aa_revalidate_sk(const char *op, struct sock *sk);
|
||||
+
|
||||
+static inline void aa_free_net_rules(struct aa_net *new)
|
||||
+{
|
||||
+ /* NOP */
|
||||
+}
|
||||
+
|
||||
+#endif /* __AA_NET_H */
|
||||
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
|
||||
index 67bc96afe541..a3d18ea8d730 100644
|
||||
--- a/security/apparmor/include/policy.h
|
||||
+++ b/security/apparmor/include/policy.h
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "capability.h"
|
||||
#include "domain.h"
|
||||
#include "file.h"
|
||||
+#include "net.h"
|
||||
#include "lib.h"
|
||||
#include "resource.h"
|
||||
|
||||
@@ -132,6 +133,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: network controls for the profile
|
||||
* @rlimits: rlimits for the profile
|
||||
*
|
||||
* @dents: dentries for the profiles file entries in apparmorfs
|
||||
@@ -174,6 +176,7 @@ struct aa_profile {
|
||||
struct aa_policydb policy;
|
||||
struct aa_file_rules file;
|
||||
struct aa_caps caps;
|
||||
+ struct aa_net net;
|
||||
struct aa_rlimit rlimits;
|
||||
|
||||
struct aa_loaddata *rawdata;
|
||||
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
|
||||
index 709eacd23909..e3017129a404 100644
|
||||
--- a/security/apparmor/lsm.c
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "include/context.h"
|
||||
#include "include/file.h"
|
||||
#include "include/ipc.h"
|
||||
+#include "include/net.h"
|
||||
#include "include/path.h"
|
||||
#include "include/policy.h"
|
||||
#include "include/policy_ns.h"
|
||||
@@ -587,6 +588,104 @@ static int apparmor_task_setrlimit(struct task_struct *task,
|
||||
return error;
|
||||
}
|
||||
|
||||
+static int apparmor_socket_create(int family, int type, int protocol, int kern)
|
||||
+{
|
||||
+ struct aa_profile *profile;
|
||||
+ int error = 0;
|
||||
+
|
||||
+ if (kern)
|
||||
+ return 0;
|
||||
+
|
||||
+ profile = __aa_current_profile();
|
||||
+ if (!unconfined(profile))
|
||||
+ error = aa_net_perm(OP_CREATE, profile, family, type, protocol,
|
||||
+ NULL);
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_bind(struct socket *sock,
|
||||
+ struct sockaddr *address, int addrlen)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_BIND, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_connect(struct socket *sock,
|
||||
+ struct sockaddr *address, int addrlen)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_CONNECT, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_listen(struct socket *sock, int backlog)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_LISTEN, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_accept(struct socket *sock, struct socket *newsock)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_ACCEPT, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_sendmsg(struct socket *sock,
|
||||
+ struct msghdr *msg, int size)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_SENDMSG, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_recvmsg(struct socket *sock,
|
||||
+ struct msghdr *msg, int size, int flags)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_RECVMSG, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_getsockname(struct socket *sock)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_GETSOCKNAME, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_getpeername(struct socket *sock)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_GETPEERNAME, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_getsockopt(struct socket *sock, int level,
|
||||
+ int optname)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_GETSOCKOPT, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_setsockopt(struct socket *sock, int level,
|
||||
+ int optname)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_SETSOCKOPT, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_shutdown(struct socket *sock, int how)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_SHUTDOWN, sk);
|
||||
+}
|
||||
+
|
||||
static struct security_hook_list apparmor_hooks[] = {
|
||||
LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
|
||||
LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
|
||||
@@ -616,6 +715,19 @@ static struct security_hook_list apparmor_hooks[] = {
|
||||
LSM_HOOK_INIT(getprocattr, apparmor_getprocattr),
|
||||
LSM_HOOK_INIT(setprocattr, apparmor_setprocattr),
|
||||
|
||||
+ LSM_HOOK_INIT(socket_create, apparmor_socket_create),
|
||||
+ LSM_HOOK_INIT(socket_bind, apparmor_socket_bind),
|
||||
+ LSM_HOOK_INIT(socket_connect, apparmor_socket_connect),
|
||||
+ LSM_HOOK_INIT(socket_listen, apparmor_socket_listen),
|
||||
+ LSM_HOOK_INIT(socket_accept, apparmor_socket_accept),
|
||||
+ LSM_HOOK_INIT(socket_sendmsg, apparmor_socket_sendmsg),
|
||||
+ LSM_HOOK_INIT(socket_recvmsg, apparmor_socket_recvmsg),
|
||||
+ LSM_HOOK_INIT(socket_getsockname, apparmor_socket_getsockname),
|
||||
+ LSM_HOOK_INIT(socket_getpeername, apparmor_socket_getpeername),
|
||||
+ LSM_HOOK_INIT(socket_getsockopt, apparmor_socket_getsockopt),
|
||||
+ LSM_HOOK_INIT(socket_setsockopt, apparmor_socket_setsockopt),
|
||||
+ LSM_HOOK_INIT(socket_shutdown, apparmor_socket_shutdown),
|
||||
+
|
||||
LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank),
|
||||
LSM_HOOK_INIT(cred_free, apparmor_cred_free),
|
||||
LSM_HOOK_INIT(cred_prepare, apparmor_cred_prepare),
|
||||
diff --git a/security/apparmor/net.c b/security/apparmor/net.c
|
||||
new file mode 100644
|
||||
index 000000000000..b9c8cd0e882e
|
||||
--- /dev/null
|
||||
+++ b/security/apparmor/net.c
|
||||
@@ -0,0 +1,148 @@
|
||||
+/*
|
||||
+ * AppArmor security module
|
||||
+ *
|
||||
+ * This file contains AppArmor network mediation
|
||||
+ *
|
||||
+ * Copyright (C) 1998-2008 Novell/SUSE
|
||||
+ * Copyright 2009-2012 Canonical Ltd.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation, version 2 of the
|
||||
+ * License.
|
||||
+ */
|
||||
+
|
||||
+#include "include/apparmor.h"
|
||||
+#include "include/audit.h"
|
||||
+#include "include/context.h"
|
||||
+#include "include/net.h"
|
||||
+#include "include/policy.h"
|
||||
+
|
||||
+#include "net_names.h"
|
||||
+
|
||||
+struct aa_fs_entry aa_fs_entry_network[] = {
|
||||
+ AA_FS_FILE_STRING("af_mask", AA_FS_AF_MASK),
|
||||
+ { }
|
||||
+};
|
||||
+
|
||||
+/* audit callback for net specific fields */
|
||||
+static void audit_cb(struct audit_buffer *ab, void *va)
|
||||
+{
|
||||
+ struct common_audit_data *sa = va;
|
||||
+
|
||||
+ audit_log_format(ab, " family=");
|
||||
+ if (address_family_names[sa->u.net->family]) {
|
||||
+ audit_log_string(ab, address_family_names[sa->u.net->family]);
|
||||
+ } else {
|
||||
+ audit_log_format(ab, "\"unknown(%d)\"", sa->u.net->family);
|
||||
+ }
|
||||
+ audit_log_format(ab, " sock_type=");
|
||||
+ if (sock_type_names[aad(sa)->net.type]) {
|
||||
+ audit_log_string(ab, sock_type_names[aad(sa)->net.type]);
|
||||
+ } else {
|
||||
+ audit_log_format(ab, "\"unknown(%d)\"", aad(sa)->net.type);
|
||||
+ }
|
||||
+ audit_log_format(ab, " protocol=%d", aad(sa)->net.protocol);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * audit_net - audit network access
|
||||
+ * @profile: profile being enforced (NOT NULL)
|
||||
+ * @op: operation being checked
|
||||
+ * @family: network family
|
||||
+ * @type: network type
|
||||
+ * @protocol: network protocol
|
||||
+ * @sk: socket auditing is being applied to
|
||||
+ * @error: error code for failure else 0
|
||||
+ *
|
||||
+ * Returns: %0 or sa->error else other errorcode on failure
|
||||
+ */
|
||||
+static int audit_net(struct aa_profile *profile, const char *op, u16 family,
|
||||
+ int type, int protocol, struct sock *sk, int error)
|
||||
+{
|
||||
+ int audit_type = AUDIT_APPARMOR_AUTO;
|
||||
+ DEFINE_AUDIT_NET(sa, op, sk, family, type, protocol);
|
||||
+
|
||||
+ aad(&sa)->error = error;
|
||||
+
|
||||
+ if (likely(!aad(&sa)->error)) {
|
||||
+ u16 audit_mask = profile->net.audit[sa.u.net->family];
|
||||
+ if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
|
||||
+ !(1 << aad(&sa)->net.type & audit_mask)))
|
||||
+ return 0;
|
||||
+ audit_type = AUDIT_APPARMOR_AUDIT;
|
||||
+ } else {
|
||||
+ u16 quiet_mask = profile->net.quiet[sa.u.net->family];
|
||||
+ u16 kill_mask = 0;
|
||||
+ u16 denied = (1 << aad(&sa)->net.type) & ~quiet_mask;
|
||||
+
|
||||
+ if (denied & kill_mask)
|
||||
+ audit_type = AUDIT_APPARMOR_KILL;
|
||||
+
|
||||
+ if ((denied & quiet_mask) &&
|
||||
+ AUDIT_MODE(profile) != AUDIT_NOQUIET &&
|
||||
+ AUDIT_MODE(profile) != AUDIT_ALL)
|
||||
+ return COMPLAIN_MODE(profile) ? 0 : aad(&sa)->error;
|
||||
+ }
|
||||
+
|
||||
+ return aa_audit(audit_type, profile, &sa, audit_cb);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * aa_net_perm - very course network access check
|
||||
+ * @op: operation being checked
|
||||
+ * @profile: profile being enforced (NOT NULL)
|
||||
+ * @family: network family
|
||||
+ * @type: network type
|
||||
+ * @protocol: network protocol
|
||||
+ *
|
||||
+ * Returns: %0 else error if permission denied
|
||||
+ */
|
||||
+int aa_net_perm(const char *op, struct aa_profile *profile, u16 family,
|
||||
+ int type, int protocol, struct sock *sk)
|
||||
+{
|
||||
+ u16 family_mask;
|
||||
+ int error;
|
||||
+
|
||||
+ if ((family < 0) || (family >= AF_MAX))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if ((type < 0) || (type >= SOCK_MAX))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ /* unix domain and netlink sockets are handled by ipc */
|
||||
+ if (family == AF_UNIX || family == AF_NETLINK)
|
||||
+ return 0;
|
||||
+
|
||||
+ family_mask = profile->net.allow[family];
|
||||
+
|
||||
+ error = (family_mask & (1 << type)) ? 0 : -EACCES;
|
||||
+
|
||||
+ return audit_net(profile, op, family, type, protocol, sk, error);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * aa_revalidate_sk - Revalidate access to a sock
|
||||
+ * @op: operation being checked
|
||||
+ * @sk: sock being revalidated (NOT NULL)
|
||||
+ *
|
||||
+ * Returns: %0 else error if permission denied
|
||||
+ */
|
||||
+int aa_revalidate_sk(const char *op, struct sock *sk)
|
||||
+{
|
||||
+ struct aa_profile *profile;
|
||||
+ int error = 0;
|
||||
+
|
||||
+ /* aa_revalidate_sk should not be called from interrupt context
|
||||
+ * don't mediate these calls as they are not task related
|
||||
+ */
|
||||
+ if (in_interrupt())
|
||||
+ return 0;
|
||||
+
|
||||
+ profile = __aa_current_profile();
|
||||
+ if (!unconfined(profile))
|
||||
+ error = aa_net_perm(op, profile, sk->sk_family, sk->sk_type,
|
||||
+ sk->sk_protocol, sk);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
|
||||
index def1fbd6bdfd..9fe7b9d4500f 100644
|
||||
--- a/security/apparmor/policy.c
|
||||
+++ b/security/apparmor/policy.c
|
||||
@@ -237,6 +237,7 @@ void aa_free_profile(struct aa_profile *profile)
|
||||
|
||||
aa_free_file_rules(&profile->file);
|
||||
aa_free_cap_rules(&profile->caps);
|
||||
+ aa_free_net_rules(&profile->net);
|
||||
aa_free_rlimit_rules(&profile->rlimits);
|
||||
|
||||
kzfree(profile->dirname);
|
||||
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
|
||||
index 2e37c9c26bbd..bc23a5b3b113 100644
|
||||
--- a/security/apparmor/policy_unpack.c
|
||||
+++ b/security/apparmor/policy_unpack.c
|
||||
@@ -217,6 +217,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((u16 *) 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)) {
|
||||
@@ -519,7 +532,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;
|
||||
- size_t ns_len;
|
||||
+ size_t ns_len, size = 0;
|
||||
struct rhashtable_params params = { 0 };
|
||||
char *key = NULL;
|
||||
struct aa_data *data;
|
||||
@@ -635,6 +648,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
|
||||
if (!unpack_rlimits(e, profile))
|
||||
goto fail;
|
||||
|
||||
+ size = unpack_array(e, "net_allowed_af");
|
||||
+ if (size) {
|
||||
+
|
||||
+ 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.allow[i], NULL))
|
||||
+ goto fail;
|
||||
+ if (!unpack_u16(e, &profile->net.audit[i], NULL))
|
||||
+ goto fail;
|
||||
+ if (!unpack_u16(e, &profile->net.quiet[i], NULL))
|
||||
+ goto fail;
|
||||
+ }
|
||||
+ if (!unpack_nameX(e, AA_ARRAYEND, NULL))
|
||||
+ goto fail;
|
||||
+ }
|
||||
+ /*
|
||||
+ * allow unix domain and netlink sockets they are handled
|
||||
+ * by IPC
|
||||
+ */
|
||||
+ profile->net.allow[AF_UNIX] = 0xffff;
|
||||
+ profile->net.allow[AF_NETLINK] = 0xffff;
|
||||
+
|
||||
if (unpack_nameX(e, AA_STRUCT, "policydb")) {
|
||||
/* generic policy dfa - optional and may be NULL */
|
||||
profile->policy.dfa = unpack_dfa(e);
|
||||
--
|
||||
2.11.0
|
||||
|
@@ -1,38 +0,0 @@
|
||||
From b866a43c2897f5469c9d787426144074a3713f6a Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Fri, 29 Jun 2012 17:34:00 -0700
|
||||
Subject: [PATCH 2/3] apparmor: Fix quieting of audit messages for network
|
||||
mediation
|
||||
|
||||
If a profile specified a quieting of network denials for a given rule by
|
||||
either the quiet or deny rule qualifiers, the resultant quiet mask for
|
||||
denied requests was applied incorrectly, resulting in two potential bugs.
|
||||
1. The misapplied quiet mask would prevent denials from being correctly
|
||||
tested against the kill mask/mode. Thus network access requests that
|
||||
should have resulted in the application being killed did not.
|
||||
|
||||
2. The actual quieting of the denied network request was not being applied.
|
||||
This would result in network rejections always being logged even when
|
||||
they had been specifically marked as quieted.
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
---
|
||||
security/apparmor/net.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/security/apparmor/net.c b/security/apparmor/net.c
|
||||
index b9c8cd0e882e..5ba19ad1d65c 100644
|
||||
--- a/security/apparmor/net.c
|
||||
+++ b/security/apparmor/net.c
|
||||
@@ -74,7 +74,7 @@ static int audit_net(struct aa_profile *profile, const char *op, u16 family,
|
||||
} else {
|
||||
u16 quiet_mask = profile->net.quiet[sa.u.net->family];
|
||||
u16 kill_mask = 0;
|
||||
- u16 denied = (1 << aad(&sa)->net.type) & ~quiet_mask;
|
||||
+ u16 denied = (1 << aad(&sa)->net.type);
|
||||
|
||||
if (denied & kill_mask)
|
||||
audit_type = AUDIT_APPARMOR_KILL;
|
||||
--
|
||||
2.11.0
|
||||
|
@@ -1,938 +0,0 @@
|
||||
From 4429c3f9522b608300cfe1ae148dc6cdadf3d76c Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Wed, 16 May 2012 10:58:05 -0700
|
||||
Subject: [PATCH 3/3] UBUNTU: SAUCE: apparmor: Add the ability to mediate mount
|
||||
|
||||
Add the ability for apparmor to do mediation of mount operations. Mount
|
||||
rules require an updated apparmor_parser (2.8 series) for policy compilation.
|
||||
|
||||
The basic form of the rules are.
|
||||
|
||||
[audit] [deny] mount [conds]* [device] [ -> [conds] path],
|
||||
[audit] [deny] remount [conds]* [path],
|
||||
[audit] [deny] umount [conds]* [path],
|
||||
[audit] [deny] pivotroot [oldroot=<value>] <path>
|
||||
|
||||
remount is just a short cut for mount options=remount
|
||||
|
||||
where [conds] can be
|
||||
fstype=<expr>
|
||||
options=<expr>
|
||||
|
||||
Example mount commands
|
||||
mount, # allow all mounts, but not umount or pivotroot
|
||||
|
||||
mount fstype=procfs, # allow mounting procfs anywhere
|
||||
|
||||
mount options=(bind, ro) /foo -> /bar, # readonly bind mount
|
||||
|
||||
mount /dev/sda -> /mnt,
|
||||
|
||||
mount /dev/sd** -> /mnt/**,
|
||||
|
||||
mount fstype=overlayfs options=(rw,upperdir=/tmp/upper/,lowerdir=/) -> /mnt/
|
||||
|
||||
umount,
|
||||
|
||||
umount /m*,
|
||||
|
||||
See the apparmor userspace for full documentation
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
Acked-by: Kees Cook <kees@ubuntu.com>
|
||||
---
|
||||
security/apparmor/Makefile | 2 +-
|
||||
security/apparmor/apparmorfs.c | 13 +
|
||||
security/apparmor/domain.c | 2 +-
|
||||
security/apparmor/include/apparmor.h | 3 +-
|
||||
security/apparmor/include/audit.h | 11 +
|
||||
security/apparmor/include/domain.h | 2 +
|
||||
security/apparmor/include/mount.h | 54 +++
|
||||
security/apparmor/lsm.c | 60 ++++
|
||||
security/apparmor/mount.c | 616 +++++++++++++++++++++++++++++++++++
|
||||
9 files changed, 760 insertions(+), 3 deletions(-)
|
||||
create mode 100644 security/apparmor/include/mount.h
|
||||
create mode 100644 security/apparmor/mount.c
|
||||
|
||||
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
|
||||
index a7dc10be232d..01368441f230 100644
|
||||
--- a/security/apparmor/Makefile
|
||||
+++ b/security/apparmor/Makefile
|
||||
@@ -4,7 +4,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
|
||||
|
||||
apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
|
||||
path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
|
||||
- resource.o secid.o file.o policy_ns.o net.o
|
||||
+ resource.o secid.o file.o policy_ns.o net.o mount.o
|
||||
apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
|
||||
|
||||
clean-files := capability_names.h rlim_names.h net_names.h
|
||||
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
|
||||
index 4d236736cfb8..2e8d09e2368b 100644
|
||||
--- a/security/apparmor/apparmorfs.c
|
||||
+++ b/security/apparmor/apparmorfs.c
|
||||
@@ -1205,11 +1205,24 @@ static struct aa_fs_entry aa_fs_entry_policy[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
+static struct aa_fs_entry aa_fs_entry_mount[] = {
|
||||
+ AA_FS_FILE_STRING("mask", "mount umount"),
|
||||
+ { }
|
||||
+};
|
||||
+
|
||||
+static struct aa_fs_entry aa_fs_entry_namespaces[] = {
|
||||
+ AA_FS_FILE_BOOLEAN("profile", 1),
|
||||
+ AA_FS_FILE_BOOLEAN("pivot_root", 1),
|
||||
+ { }
|
||||
+};
|
||||
+
|
||||
static struct aa_fs_entry aa_fs_entry_features[] = {
|
||||
AA_FS_DIR("policy", aa_fs_entry_policy),
|
||||
AA_FS_DIR("domain", aa_fs_entry_domain),
|
||||
AA_FS_DIR("file", aa_fs_entry_file),
|
||||
AA_FS_DIR("network", aa_fs_entry_network),
|
||||
+ AA_FS_DIR("mount", aa_fs_entry_mount),
|
||||
+ AA_FS_DIR("namespaces", aa_fs_entry_namespaces),
|
||||
AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
|
||||
AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
|
||||
AA_FS_DIR("caps", aa_fs_entry_caps),
|
||||
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
|
||||
index 001e133a3c8c..708b7e22b9b5 100644
|
||||
--- a/security/apparmor/domain.c
|
||||
+++ b/security/apparmor/domain.c
|
||||
@@ -237,7 +237,7 @@ static const char *next_name(int xtype, const char *name)
|
||||
*
|
||||
* Returns: refcounted profile, or NULL on failure (MAYBE NULL)
|
||||
*/
|
||||
-static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
|
||||
+struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
|
||||
{
|
||||
struct aa_profile *new_profile = NULL;
|
||||
struct aa_ns *ns = profile->ns;
|
||||
diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
|
||||
index 1750cc0721c1..3383dc66f30f 100644
|
||||
--- a/security/apparmor/include/apparmor.h
|
||||
+++ b/security/apparmor/include/apparmor.h
|
||||
@@ -27,8 +27,9 @@
|
||||
#define AA_CLASS_NET 4
|
||||
#define AA_CLASS_RLIMITS 5
|
||||
#define AA_CLASS_DOMAIN 6
|
||||
+#define AA_CLASS_MOUNT 7
|
||||
|
||||
-#define AA_CLASS_LAST AA_CLASS_DOMAIN
|
||||
+#define AA_CLASS_LAST AA_CLASS_MOUNT
|
||||
|
||||
/* Control parameters settable through module/boot flags */
|
||||
extern enum audit_mode aa_g_audit;
|
||||
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
|
||||
index 0df708e8748b..41374ad89547 100644
|
||||
--- a/security/apparmor/include/audit.h
|
||||
+++ b/security/apparmor/include/audit.h
|
||||
@@ -70,6 +70,10 @@ enum audit_type {
|
||||
#define OP_FMMAP "file_mmap"
|
||||
#define OP_FMPROT "file_mprotect"
|
||||
|
||||
+#define OP_PIVOTROOT "pivotroot"
|
||||
+#define OP_MOUNT "mount"
|
||||
+#define OP_UMOUNT "umount"
|
||||
+
|
||||
#define OP_CREATE "create"
|
||||
#define OP_POST_CREATE "post_create"
|
||||
#define OP_BIND "bind"
|
||||
@@ -127,6 +131,13 @@ struct apparmor_audit_data {
|
||||
int rlim;
|
||||
unsigned long max;
|
||||
} rlim;
|
||||
+ struct {
|
||||
+ const char *src_name;
|
||||
+ const char *type;
|
||||
+ const char *trans;
|
||||
+ const char *data;
|
||||
+ unsigned long flags;
|
||||
+ } mnt;
|
||||
struct {
|
||||
int type, protocol;
|
||||
struct sock *sk;
|
||||
diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h
|
||||
index 30544729878a..7bd21d20a2bd 100644
|
||||
--- a/security/apparmor/include/domain.h
|
||||
+++ b/security/apparmor/include/domain.h
|
||||
@@ -23,6 +23,8 @@ struct aa_domain {
|
||||
char **table;
|
||||
};
|
||||
|
||||
+struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex);
|
||||
+
|
||||
int apparmor_bprm_set_creds(struct linux_binprm *bprm);
|
||||
int apparmor_bprm_secureexec(struct linux_binprm *bprm);
|
||||
void apparmor_bprm_committing_creds(struct linux_binprm *bprm);
|
||||
diff --git a/security/apparmor/include/mount.h b/security/apparmor/include/mount.h
|
||||
new file mode 100644
|
||||
index 000000000000..a43b1d62e428
|
||||
--- /dev/null
|
||||
+++ b/security/apparmor/include/mount.h
|
||||
@@ -0,0 +1,54 @@
|
||||
+/*
|
||||
+ * AppArmor security module
|
||||
+ *
|
||||
+ * This file contains AppArmor file mediation function definitions.
|
||||
+ *
|
||||
+ * Copyright 2012 Canonical Ltd.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation, version 2 of the
|
||||
+ * License.
|
||||
+ */
|
||||
+
|
||||
+#ifndef __AA_MOUNT_H
|
||||
+#define __AA_MOUNT_H
|
||||
+
|
||||
+#include <linux/fs.h>
|
||||
+#include <linux/path.h>
|
||||
+
|
||||
+#include "domain.h"
|
||||
+#include "policy.h"
|
||||
+
|
||||
+/* mount perms */
|
||||
+#define AA_MAY_PIVOTROOT 0x01
|
||||
+#define AA_MAY_MOUNT 0x02
|
||||
+#define AA_MAY_UMOUNT 0x04
|
||||
+#define AA_AUDIT_DATA 0x40
|
||||
+#define AA_CONT_MATCH 0x40
|
||||
+
|
||||
+#define AA_MS_IGNORE_MASK (MS_KERNMOUNT | MS_NOSEC | MS_ACTIVE | MS_BORN)
|
||||
+
|
||||
+int aa_remount(struct aa_profile *profile, const struct path *path,
|
||||
+ unsigned long flags, void *data);
|
||||
+
|
||||
+int aa_bind_mount(struct aa_profile *profile, const struct path *path,
|
||||
+ const char *old_name, unsigned long flags);
|
||||
+
|
||||
+
|
||||
+int aa_mount_change_type(struct aa_profile *profile, const struct path *path,
|
||||
+ unsigned long flags);
|
||||
+
|
||||
+int aa_move_mount(struct aa_profile *profile, const struct path *path,
|
||||
+ const char *old_name);
|
||||
+
|
||||
+int aa_new_mount(struct aa_profile *profile, const char *dev_name,
|
||||
+ const struct path *path, const char *type, unsigned long flags,
|
||||
+ void *data);
|
||||
+
|
||||
+int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags);
|
||||
+
|
||||
+int aa_pivotroot(struct aa_profile *profile, const struct path *old_path,
|
||||
+ const struct path *new_path);
|
||||
+
|
||||
+#endif /* __AA_MOUNT_H */
|
||||
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
|
||||
index e3017129a404..ee58a2cca74f 100644
|
||||
--- a/security/apparmor/lsm.c
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "include/policy.h"
|
||||
#include "include/policy_ns.h"
|
||||
#include "include/procattr.h"
|
||||
+#include "include/mount.h"
|
||||
|
||||
/* Flag indicating whether initialization completed */
|
||||
int apparmor_initialized __initdata;
|
||||
@@ -479,6 +480,61 @@ static int apparmor_file_mprotect(struct vm_area_struct *vma,
|
||||
!(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
|
||||
}
|
||||
|
||||
+static int apparmor_sb_mount(const char *dev_name, const struct path *path,
|
||||
+ const char *type, unsigned long flags, void *data)
|
||||
+{
|
||||
+ struct aa_profile *profile;
|
||||
+ int error = 0;
|
||||
+
|
||||
+ /* Discard magic */
|
||||
+ if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
|
||||
+ flags &= ~MS_MGC_MSK;
|
||||
+
|
||||
+ flags &= ~AA_MS_IGNORE_MASK;
|
||||
+
|
||||
+ profile = __aa_current_profile();
|
||||
+ if (!unconfined(profile)) {
|
||||
+ if (flags & MS_REMOUNT)
|
||||
+ error = aa_remount(profile, path, flags, data);
|
||||
+ else if (flags & MS_BIND)
|
||||
+ error = aa_bind_mount(profile, path, dev_name, flags);
|
||||
+ else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE |
|
||||
+ MS_UNBINDABLE))
|
||||
+ error = aa_mount_change_type(profile, path, flags);
|
||||
+ else if (flags & MS_MOVE)
|
||||
+ error = aa_move_mount(profile, path, dev_name);
|
||||
+ else
|
||||
+ error = aa_new_mount(profile, dev_name, path, type,
|
||||
+ flags, data);
|
||||
+ }
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int apparmor_sb_umount(struct vfsmount *mnt, int flags)
|
||||
+{
|
||||
+ struct aa_profile *profile;
|
||||
+ int error = 0;
|
||||
+
|
||||
+ profile = __aa_current_profile();
|
||||
+ if (!unconfined(profile))
|
||||
+ error = aa_umount(profile, mnt, flags);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int apparmor_sb_pivotroot(const struct path *old_path,
|
||||
+ const struct path *new_path)
|
||||
+{
|
||||
+ struct aa_profile *profile;
|
||||
+ int error = 0;
|
||||
+
|
||||
+ profile = __aa_current_profile();
|
||||
+ if (!unconfined(profile))
|
||||
+ error = aa_pivotroot(profile, old_path, new_path);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
static int apparmor_getprocattr(struct task_struct *task, char *name,
|
||||
char **value)
|
||||
{
|
||||
@@ -692,6 +748,10 @@ static struct security_hook_list apparmor_hooks[] = {
|
||||
LSM_HOOK_INIT(capget, apparmor_capget),
|
||||
LSM_HOOK_INIT(capable, apparmor_capable),
|
||||
|
||||
+ LSM_HOOK_INIT(sb_mount, apparmor_sb_mount),
|
||||
+ LSM_HOOK_INIT(sb_umount, apparmor_sb_umount),
|
||||
+ LSM_HOOK_INIT(sb_pivotroot, apparmor_sb_pivotroot),
|
||||
+
|
||||
LSM_HOOK_INIT(path_link, apparmor_path_link),
|
||||
LSM_HOOK_INIT(path_unlink, apparmor_path_unlink),
|
||||
LSM_HOOK_INIT(path_symlink, apparmor_path_symlink),
|
||||
diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c
|
||||
new file mode 100644
|
||||
index 000000000000..9e95a41c015c
|
||||
--- /dev/null
|
||||
+++ b/security/apparmor/mount.c
|
||||
@@ -0,0 +1,616 @@
|
||||
+/*
|
||||
+ * AppArmor security module
|
||||
+ *
|
||||
+ * This file contains AppArmor mediation of files
|
||||
+ *
|
||||
+ * Copyright (C) 1998-2008 Novell/SUSE
|
||||
+ * Copyright 2009-2012 Canonical Ltd.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation, version 2 of the
|
||||
+ * License.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/fs.h>
|
||||
+#include <linux/mount.h>
|
||||
+#include <linux/namei.h>
|
||||
+
|
||||
+#include "include/apparmor.h"
|
||||
+#include "include/audit.h"
|
||||
+#include "include/context.h"
|
||||
+#include "include/domain.h"
|
||||
+#include "include/file.h"
|
||||
+#include "include/match.h"
|
||||
+#include "include/mount.h"
|
||||
+#include "include/path.h"
|
||||
+#include "include/policy.h"
|
||||
+
|
||||
+
|
||||
+static void audit_mnt_flags(struct audit_buffer *ab, unsigned long flags)
|
||||
+{
|
||||
+ if (flags & MS_RDONLY)
|
||||
+ audit_log_format(ab, "ro");
|
||||
+ else
|
||||
+ audit_log_format(ab, "rw");
|
||||
+ if (flags & MS_NOSUID)
|
||||
+ audit_log_format(ab, ", nosuid");
|
||||
+ if (flags & MS_NODEV)
|
||||
+ audit_log_format(ab, ", nodev");
|
||||
+ if (flags & MS_NOEXEC)
|
||||
+ audit_log_format(ab, ", noexec");
|
||||
+ if (flags & MS_SYNCHRONOUS)
|
||||
+ audit_log_format(ab, ", sync");
|
||||
+ if (flags & MS_REMOUNT)
|
||||
+ audit_log_format(ab, ", remount");
|
||||
+ if (flags & MS_MANDLOCK)
|
||||
+ audit_log_format(ab, ", mand");
|
||||
+ if (flags & MS_DIRSYNC)
|
||||
+ audit_log_format(ab, ", dirsync");
|
||||
+ if (flags & MS_NOATIME)
|
||||
+ audit_log_format(ab, ", noatime");
|
||||
+ if (flags & MS_NODIRATIME)
|
||||
+ audit_log_format(ab, ", nodiratime");
|
||||
+ if (flags & MS_BIND)
|
||||
+ audit_log_format(ab, flags & MS_REC ? ", rbind" : ", bind");
|
||||
+ if (flags & MS_MOVE)
|
||||
+ audit_log_format(ab, ", move");
|
||||
+ if (flags & MS_SILENT)
|
||||
+ audit_log_format(ab, ", silent");
|
||||
+ if (flags & MS_POSIXACL)
|
||||
+ audit_log_format(ab, ", acl");
|
||||
+ if (flags & MS_UNBINDABLE)
|
||||
+ audit_log_format(ab, flags & MS_REC ? ", runbindable" :
|
||||
+ ", unbindable");
|
||||
+ if (flags & MS_PRIVATE)
|
||||
+ audit_log_format(ab, flags & MS_REC ? ", rprivate" :
|
||||
+ ", private");
|
||||
+ if (flags & MS_SLAVE)
|
||||
+ audit_log_format(ab, flags & MS_REC ? ", rslave" :
|
||||
+ ", slave");
|
||||
+ if (flags & MS_SHARED)
|
||||
+ audit_log_format(ab, flags & MS_REC ? ", rshared" :
|
||||
+ ", shared");
|
||||
+ if (flags & MS_RELATIME)
|
||||
+ audit_log_format(ab, ", relatime");
|
||||
+ if (flags & MS_I_VERSION)
|
||||
+ audit_log_format(ab, ", iversion");
|
||||
+ if (flags & MS_STRICTATIME)
|
||||
+ audit_log_format(ab, ", strictatime");
|
||||
+ if (flags & MS_NOUSER)
|
||||
+ audit_log_format(ab, ", nouser");
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * audit_cb - call back for mount specific audit fields
|
||||
+ * @ab: audit_buffer (NOT NULL)
|
||||
+ * @va: audit struct to audit values of (NOT NULL)
|
||||
+ */
|
||||
+static void audit_cb(struct audit_buffer *ab, void *va)
|
||||
+{
|
||||
+ struct common_audit_data *sa = va;
|
||||
+
|
||||
+ if (aad(sa)->mnt.type) {
|
||||
+ audit_log_format(ab, " fstype=");
|
||||
+ audit_log_untrustedstring(ab, aad(sa)->mnt.type);
|
||||
+ }
|
||||
+ if (aad(sa)->mnt.src_name) {
|
||||
+ audit_log_format(ab, " srcname=");
|
||||
+ audit_log_untrustedstring(ab, aad(sa)->mnt.src_name);
|
||||
+ }
|
||||
+ if (aad(sa)->mnt.trans) {
|
||||
+ audit_log_format(ab, " trans=");
|
||||
+ audit_log_untrustedstring(ab, aad(sa)->mnt.trans);
|
||||
+ }
|
||||
+ if (aad(sa)->mnt.flags) {
|
||||
+ audit_log_format(ab, " flags=\"");
|
||||
+ audit_mnt_flags(ab, aad(sa)->mnt.flags);
|
||||
+ audit_log_format(ab, "\"");
|
||||
+ }
|
||||
+ if (aad(sa)->mnt.data) {
|
||||
+ audit_log_format(ab, " options=");
|
||||
+ audit_log_untrustedstring(ab, aad(sa)->mnt.data);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * audit_mount - handle the auditing of mount operations
|
||||
+ * @profile: the profile being enforced (NOT NULL)
|
||||
+ * @gfp: allocation flags
|
||||
+ * @op: operation being mediated (NOT NULL)
|
||||
+ * @name: name of object being mediated (MAYBE NULL)
|
||||
+ * @src_name: src_name of object being mediated (MAYBE_NULL)
|
||||
+ * @type: type of filesystem (MAYBE_NULL)
|
||||
+ * @trans: name of trans (MAYBE NULL)
|
||||
+ * @flags: filesystem idependent mount flags
|
||||
+ * @data: filesystem mount flags
|
||||
+ * @request: permissions requested
|
||||
+ * @perms: the permissions computed for the request (NOT NULL)
|
||||
+ * @info: extra information message (MAYBE NULL)
|
||||
+ * @error: 0 if operation allowed else failure error code
|
||||
+ *
|
||||
+ * Returns: %0 or error on failure
|
||||
+ */
|
||||
+static int audit_mount(struct aa_profile *profile, gfp_t gfp, const char *op,
|
||||
+ const char *name, const char *src_name,
|
||||
+ const char *type, const char *trans,
|
||||
+ unsigned long flags, const void *data, u32 request,
|
||||
+ struct file_perms *perms, const char *info, int error)
|
||||
+{
|
||||
+ int audit_type = AUDIT_APPARMOR_AUTO;
|
||||
+ DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, op);
|
||||
+
|
||||
+ if (likely(!error)) {
|
||||
+ u32 mask = perms->audit;
|
||||
+
|
||||
+ if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
|
||||
+ mask = 0xffff;
|
||||
+
|
||||
+ /* mask off perms that are not being force audited */
|
||||
+ request &= mask;
|
||||
+
|
||||
+ if (likely(!request))
|
||||
+ return 0;
|
||||
+ audit_type = AUDIT_APPARMOR_AUDIT;
|
||||
+ } else {
|
||||
+ /* only report permissions that were denied */
|
||||
+ request = request & ~perms->allow;
|
||||
+
|
||||
+ if (request & perms->kill)
|
||||
+ audit_type = AUDIT_APPARMOR_KILL;
|
||||
+
|
||||
+ /* quiet known rejects, assumes quiet and kill do not overlap */
|
||||
+ if ((request & perms->quiet) &&
|
||||
+ AUDIT_MODE(profile) != AUDIT_NOQUIET &&
|
||||
+ AUDIT_MODE(profile) != AUDIT_ALL)
|
||||
+ request &= ~perms->quiet;
|
||||
+
|
||||
+ if (!request)
|
||||
+ return COMPLAIN_MODE(profile) ?
|
||||
+ complain_error(error) : error;
|
||||
+ }
|
||||
+
|
||||
+ aad(&sa)->name = name;
|
||||
+ aad(&sa)->mnt.src_name = src_name;
|
||||
+ aad(&sa)->mnt.type = type;
|
||||
+ aad(&sa)->mnt.trans = trans;
|
||||
+ aad(&sa)->mnt.flags = flags;
|
||||
+ if (data && (perms->audit & AA_AUDIT_DATA))
|
||||
+ aad(&sa)->mnt.data = data;
|
||||
+ aad(&sa)->info = info;
|
||||
+ aad(&sa)->error = error;
|
||||
+
|
||||
+ return aa_audit(audit_type, profile, &sa, audit_cb);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * match_mnt_flags - Do an ordered match on mount flags
|
||||
+ * @dfa: dfa to match against
|
||||
+ * @state: state to start in
|
||||
+ * @flags: mount flags to match against
|
||||
+ *
|
||||
+ * Mount flags are encoded as an ordered match. This is done instead of
|
||||
+ * checking against a simple bitmask, to allow for logical operations
|
||||
+ * on the flags.
|
||||
+ *
|
||||
+ * Returns: next state after flags match
|
||||
+ */
|
||||
+static unsigned int match_mnt_flags(struct aa_dfa *dfa, unsigned int state,
|
||||
+ unsigned long flags)
|
||||
+{
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ for (i = 0; i <= 31 ; ++i) {
|
||||
+ if ((1 << i) & flags)
|
||||
+ state = aa_dfa_next(dfa, state, i + 1);
|
||||
+ }
|
||||
+
|
||||
+ return state;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * compute_mnt_perms - compute mount permission associated with @state
|
||||
+ * @dfa: dfa to match against (NOT NULL)
|
||||
+ * @state: state match finished in
|
||||
+ *
|
||||
+ * Returns: mount permissions
|
||||
+ */
|
||||
+static struct file_perms compute_mnt_perms(struct aa_dfa *dfa,
|
||||
+ unsigned int state)
|
||||
+{
|
||||
+ struct file_perms perms;
|
||||
+
|
||||
+ perms.kill = 0;
|
||||
+ perms.allow = dfa_user_allow(dfa, state);
|
||||
+ perms.audit = dfa_user_audit(dfa, state);
|
||||
+ perms.quiet = dfa_user_quiet(dfa, state);
|
||||
+ perms.xindex = dfa_user_xindex(dfa, state);
|
||||
+
|
||||
+ return perms;
|
||||
+}
|
||||
+
|
||||
+static const char *mnt_info_table[] = {
|
||||
+ "match succeeded",
|
||||
+ "failed mntpnt match",
|
||||
+ "failed srcname match",
|
||||
+ "failed type match",
|
||||
+ "failed flags match",
|
||||
+ "failed data match"
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * Returns 0 on success else element that match failed in, this is the
|
||||
+ * index into the mnt_info_table above
|
||||
+ */
|
||||
+static int do_match_mnt(struct aa_dfa *dfa, unsigned int start,
|
||||
+ const char *mntpnt, const char *devname,
|
||||
+ const char *type, unsigned long flags,
|
||||
+ void *data, bool binary, struct file_perms *perms)
|
||||
+{
|
||||
+ unsigned int state;
|
||||
+
|
||||
+ state = aa_dfa_match(dfa, start, mntpnt);
|
||||
+ state = aa_dfa_null_transition(dfa, state);
|
||||
+ if (!state)
|
||||
+ return 1;
|
||||
+
|
||||
+ if (devname)
|
||||
+ state = aa_dfa_match(dfa, state, devname);
|
||||
+ state = aa_dfa_null_transition(dfa, state);
|
||||
+ if (!state)
|
||||
+ return 2;
|
||||
+
|
||||
+ if (type)
|
||||
+ state = aa_dfa_match(dfa, state, type);
|
||||
+ state = aa_dfa_null_transition(dfa, state);
|
||||
+ if (!state)
|
||||
+ return 3;
|
||||
+
|
||||
+ state = match_mnt_flags(dfa, state, flags);
|
||||
+ if (!state)
|
||||
+ return 4;
|
||||
+ *perms = compute_mnt_perms(dfa, state);
|
||||
+ if (perms->allow & AA_MAY_MOUNT)
|
||||
+ return 0;
|
||||
+
|
||||
+ /* only match data if not binary and the DFA flags data is expected */
|
||||
+ if (data && !binary && (perms->allow & AA_CONT_MATCH)) {
|
||||
+ state = aa_dfa_null_transition(dfa, state);
|
||||
+ if (!state)
|
||||
+ return 4;
|
||||
+
|
||||
+ state = aa_dfa_match(dfa, state, data);
|
||||
+ if (!state)
|
||||
+ return 5;
|
||||
+ *perms = compute_mnt_perms(dfa, state);
|
||||
+ if (perms->allow & AA_MAY_MOUNT)
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ /* failed at end of flags match */
|
||||
+ return 4;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * match_mnt - handle path matching for mount
|
||||
+ * @profile: the confining profile
|
||||
+ * @mntpnt: string for the mntpnt (NOT NULL)
|
||||
+ * @devname: string for the devname/src_name (MAYBE NULL)
|
||||
+ * @type: string for the dev type (MAYBE NULL)
|
||||
+ * @flags: mount flags to match
|
||||
+ * @data: fs mount data (MAYBE NULL)
|
||||
+ * @binary: whether @data is binary
|
||||
+ * @perms: Returns: permission found by the match
|
||||
+ * @info: Returns: infomation string about the match for logging
|
||||
+ *
|
||||
+ * Returns: 0 on success else error
|
||||
+ */
|
||||
+static int match_mnt(struct aa_profile *profile, const char *mntpnt,
|
||||
+ const char *devname, const char *type,
|
||||
+ unsigned long flags, void *data, bool binary,
|
||||
+ struct file_perms *perms, const char **info)
|
||||
+{
|
||||
+ int pos;
|
||||
+
|
||||
+ if (!profile->policy.dfa)
|
||||
+ return -EACCES;
|
||||
+
|
||||
+ pos = do_match_mnt(profile->policy.dfa,
|
||||
+ profile->policy.start[AA_CLASS_MOUNT],
|
||||
+ mntpnt, devname, type, flags, data, binary, perms);
|
||||
+ if (pos) {
|
||||
+ *info = mnt_info_table[pos];
|
||||
+ return -EACCES;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int path_flags(struct aa_profile *profile, const struct path *path)
|
||||
+{
|
||||
+ return profile->path_flags |
|
||||
+ S_ISDIR(path->dentry->d_inode->i_mode) ? PATH_IS_DIR : 0;
|
||||
+}
|
||||
+
|
||||
+int aa_remount(struct aa_profile *profile, const struct path *path,
|
||||
+ unsigned long flags, void *data)
|
||||
+{
|
||||
+ struct file_perms perms = { };
|
||||
+ const char *name, *info = NULL;
|
||||
+ char *buffer = NULL;
|
||||
+ int binary, error;
|
||||
+
|
||||
+ binary = path->dentry->d_sb->s_type->fs_flags & FS_BINARY_MOUNTDATA;
|
||||
+
|
||||
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
|
||||
+ &info);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = match_mnt(profile, name, NULL, NULL, flags, data, binary,
|
||||
+ &perms, &info);
|
||||
+
|
||||
+audit:
|
||||
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
|
||||
+ NULL, flags, data, AA_MAY_MOUNT, &perms, info,
|
||||
+ error);
|
||||
+ kfree(buffer);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+int aa_bind_mount(struct aa_profile *profile, const struct path *path,
|
||||
+ const char *dev_name, unsigned long flags)
|
||||
+{
|
||||
+ struct file_perms perms = { };
|
||||
+ char *buffer = NULL, *old_buffer = NULL;
|
||||
+ const char *name, *old_name = NULL, *info = NULL;
|
||||
+ struct path old_path;
|
||||
+ int error;
|
||||
+
|
||||
+ if (!dev_name || !*dev_name)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ flags &= MS_REC | MS_BIND;
|
||||
+
|
||||
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
|
||||
+ &info);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = kern_path(dev_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = aa_path_name(&old_path, path_flags(profile, &old_path),
|
||||
+ &old_buffer, &old_name, &info);
|
||||
+ path_put(&old_path);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = match_mnt(profile, name, old_name, NULL, flags, NULL, 0,
|
||||
+ &perms, &info);
|
||||
+
|
||||
+audit:
|
||||
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
|
||||
+ NULL, NULL, flags, NULL, AA_MAY_MOUNT, &perms,
|
||||
+ info, error);
|
||||
+ kfree(buffer);
|
||||
+ kfree(old_buffer);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+int aa_mount_change_type(struct aa_profile *profile, const struct path *path,
|
||||
+ unsigned long flags)
|
||||
+{
|
||||
+ struct file_perms perms = { };
|
||||
+ char *buffer = NULL;
|
||||
+ const char *name, *info = NULL;
|
||||
+ int error;
|
||||
+
|
||||
+ /* These are the flags allowed by do_change_type() */
|
||||
+ flags &= (MS_REC | MS_SILENT | MS_SHARED | MS_PRIVATE | MS_SLAVE |
|
||||
+ MS_UNBINDABLE);
|
||||
+
|
||||
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
|
||||
+ &info);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = match_mnt(profile, name, NULL, NULL, flags, NULL, 0, &perms,
|
||||
+ &info);
|
||||
+
|
||||
+audit:
|
||||
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
|
||||
+ NULL, flags, NULL, AA_MAY_MOUNT, &perms, info,
|
||||
+ error);
|
||||
+ kfree(buffer);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+int aa_move_mount(struct aa_profile *profile, const struct path *path,
|
||||
+ const char *orig_name)
|
||||
+{
|
||||
+ struct file_perms perms = { };
|
||||
+ char *buffer = NULL, *old_buffer = NULL;
|
||||
+ const char *name, *old_name = NULL, *info = NULL;
|
||||
+ struct path old_path;
|
||||
+ int error;
|
||||
+
|
||||
+ if (!orig_name || !*orig_name)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
|
||||
+ &info);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = kern_path(orig_name, LOOKUP_FOLLOW, &old_path);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = aa_path_name(&old_path, path_flags(profile, &old_path),
|
||||
+ &old_buffer, &old_name, &info);
|
||||
+ path_put(&old_path);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = match_mnt(profile, name, old_name, NULL, MS_MOVE, NULL, 0,
|
||||
+ &perms, &info);
|
||||
+
|
||||
+audit:
|
||||
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
|
||||
+ NULL, NULL, MS_MOVE, NULL, AA_MAY_MOUNT, &perms,
|
||||
+ info, error);
|
||||
+ kfree(buffer);
|
||||
+ kfree(old_buffer);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+int aa_new_mount(struct aa_profile *profile, const char *orig_dev_name,
|
||||
+ const struct path *path, const char *type, unsigned long flags,
|
||||
+ void *data)
|
||||
+{
|
||||
+ struct file_perms perms = { };
|
||||
+ char *buffer = NULL, *dev_buffer = NULL;
|
||||
+ const char *name = NULL, *dev_name = NULL, *info = NULL;
|
||||
+ int binary = 1;
|
||||
+ int error;
|
||||
+
|
||||
+ dev_name = orig_dev_name;
|
||||
+ if (type) {
|
||||
+ int requires_dev;
|
||||
+ struct file_system_type *fstype = get_fs_type(type);
|
||||
+ if (!fstype)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ binary = fstype->fs_flags & FS_BINARY_MOUNTDATA;
|
||||
+ requires_dev = fstype->fs_flags & FS_REQUIRES_DEV;
|
||||
+ put_filesystem(fstype);
|
||||
+
|
||||
+ if (requires_dev) {
|
||||
+ struct path dev_path;
|
||||
+
|
||||
+ if (!dev_name || !*dev_name) {
|
||||
+ error = -ENOENT;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ error = kern_path(dev_name, LOOKUP_FOLLOW, &dev_path);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = aa_path_name(&dev_path,
|
||||
+ path_flags(profile, &dev_path),
|
||||
+ &dev_buffer, &dev_name, &info);
|
||||
+ path_put(&dev_path);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
|
||||
+ &info);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = match_mnt(profile, name, dev_name, type, flags, data, binary,
|
||||
+ &perms, &info);
|
||||
+
|
||||
+audit:
|
||||
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, dev_name,
|
||||
+ type, NULL, flags, data, AA_MAY_MOUNT, &perms, info,
|
||||
+ error);
|
||||
+ kfree(buffer);
|
||||
+ kfree(dev_buffer);
|
||||
+
|
||||
+out:
|
||||
+ return error;
|
||||
+
|
||||
+}
|
||||
+
|
||||
+int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags)
|
||||
+{
|
||||
+ struct file_perms perms = { };
|
||||
+ char *buffer = NULL;
|
||||
+ const char *name, *info = NULL;
|
||||
+ int error;
|
||||
+
|
||||
+ struct path path = { mnt, mnt->mnt_root };
|
||||
+ error = aa_path_name(&path, path_flags(profile, &path), &buffer, &name,
|
||||
+ &info);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ if (!error && profile->policy.dfa) {
|
||||
+ unsigned int state;
|
||||
+ state = aa_dfa_match(profile->policy.dfa,
|
||||
+ profile->policy.start[AA_CLASS_MOUNT],
|
||||
+ name);
|
||||
+ perms = compute_mnt_perms(profile->policy.dfa, state);
|
||||
+ }
|
||||
+
|
||||
+ if (AA_MAY_UMOUNT & ~perms.allow)
|
||||
+ error = -EACCES;
|
||||
+
|
||||
+audit:
|
||||
+ error = audit_mount(profile, GFP_KERNEL, OP_UMOUNT, name, NULL, NULL,
|
||||
+ NULL, 0, NULL, AA_MAY_UMOUNT, &perms, info, error);
|
||||
+ kfree(buffer);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+int aa_pivotroot(struct aa_profile *profile, const struct path *old_path,
|
||||
+ const struct path *new_path)
|
||||
+{
|
||||
+ struct file_perms perms = { };
|
||||
+ struct aa_profile *target = NULL;
|
||||
+ char *old_buffer = NULL, *new_buffer = NULL;
|
||||
+ const char *old_name, *new_name = NULL, *info = NULL;
|
||||
+ int error;
|
||||
+
|
||||
+ error = aa_path_name(old_path, path_flags(profile, old_path),
|
||||
+ &old_buffer, &old_name, &info);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ error = aa_path_name(new_path, path_flags(profile, new_path),
|
||||
+ &new_buffer, &new_name, &info);
|
||||
+ if (error)
|
||||
+ goto audit;
|
||||
+
|
||||
+ if (profile->policy.dfa) {
|
||||
+ unsigned int state;
|
||||
+ state = aa_dfa_match(profile->policy.dfa,
|
||||
+ profile->policy.start[AA_CLASS_MOUNT],
|
||||
+ new_name);
|
||||
+ state = aa_dfa_null_transition(profile->policy.dfa, state);
|
||||
+ state = aa_dfa_match(profile->policy.dfa, state, old_name);
|
||||
+ perms = compute_mnt_perms(profile->policy.dfa, state);
|
||||
+ }
|
||||
+
|
||||
+ if (AA_MAY_PIVOTROOT & perms.allow) {
|
||||
+ if ((perms.xindex & AA_X_TYPE_MASK) == AA_X_TABLE) {
|
||||
+ target = x_table_lookup(profile, perms.xindex);
|
||||
+ if (!target)
|
||||
+ error = -ENOENT;
|
||||
+ else
|
||||
+ error = aa_replace_current_profile(target);
|
||||
+ }
|
||||
+ } else
|
||||
+ error = -EACCES;
|
||||
+
|
||||
+audit:
|
||||
+ error = audit_mount(profile, GFP_KERNEL, OP_PIVOTROOT, new_name,
|
||||
+ old_name, NULL, target ? target->base.name : NULL,
|
||||
+ 0, NULL, AA_MAY_PIVOTROOT, &perms, info, error);
|
||||
+ aa_put_profile(target);
|
||||
+ kfree(old_buffer);
|
||||
+ kfree(new_buffer);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
--
|
||||
2.11.0
|
||||
|
@@ -1,605 +0,0 @@
|
||||
From adbeb027cbafd78a76d5786e082d7c7abb19a591 Mon Sep 17 00:00:00 2001
|
||||
From: John Johansen <john.johansen@canonical.com>
|
||||
Date: Mon, 4 Oct 2010 15:03:36 -0700
|
||||
Subject: [PATCH 1/3] UBUNTU: SAUCE: AppArmor: basic networking rules
|
||||
|
||||
Base support for network mediation.
|
||||
|
||||
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
||||
---
|
||||
security/apparmor/.gitignore | 1 +
|
||||
security/apparmor/Makefile | 42 ++++++++++-
|
||||
security/apparmor/apparmorfs.c | 1 +
|
||||
security/apparmor/include/audit.h | 4 +
|
||||
security/apparmor/include/net.h | 59 +++++++++++++++
|
||||
security/apparmor/include/policy.h | 3 +
|
||||
security/apparmor/lsm.c | 112 ++++++++++++++++++++++++++++
|
||||
security/apparmor/net.c | 148 +++++++++++++++++++++++++++++++++++++
|
||||
security/apparmor/policy.c | 1 +
|
||||
security/apparmor/policy_unpack.c | 47 +++++++++++-
|
||||
10 files changed, 415 insertions(+), 3 deletions(-)
|
||||
create mode 100644 security/apparmor/include/net.h
|
||||
create mode 100644 security/apparmor/net.c
|
||||
|
||||
diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore
|
||||
index 9cdec70d72b8..d5b291e94264 100644
|
||||
--- a/security/apparmor/.gitignore
|
||||
+++ b/security/apparmor/.gitignore
|
||||
@@ -1,5 +1,6 @@
|
||||
#
|
||||
# Generated include files
|
||||
#
|
||||
+net_names.h
|
||||
capability_names.h
|
||||
rlim_names.h
|
||||
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
|
||||
index ad369a7aac24..a7dc10be232d 100644
|
||||
--- a/security/apparmor/Makefile
|
||||
+++ b/security/apparmor/Makefile
|
||||
@@ -4,10 +4,10 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
|
||||
|
||||
apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
|
||||
path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
|
||||
- resource.o secid.o file.o policy_ns.o
|
||||
+ resource.o secid.o file.o policy_ns.o net.o
|
||||
apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
|
||||
|
||||
-clean-files := capability_names.h rlim_names.h
|
||||
+clean-files := capability_names.h rlim_names.h net_names.h
|
||||
|
||||
|
||||
# Build a lower case string table of capability names
|
||||
@@ -25,6 +25,38 @@ cmd_make-caps = echo "static const char *const capability_names[] = {" > $@ ;\
|
||||
-e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/\L\1/p' | \
|
||||
tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
|
||||
|
||||
+# Build a lower case string table of address family names
|
||||
+# Transform lines from
|
||||
+# define AF_LOCAL 1 /* POSIX name for AF_UNIX */
|
||||
+# #define AF_INET 2 /* Internet IP Protocol */
|
||||
+# to
|
||||
+# [1] = "local",
|
||||
+# [2] = "inet",
|
||||
+#
|
||||
+# and build the securityfs entries for the mapping.
|
||||
+# Transforms lines from
|
||||
+# #define AF_INET 2 /* Internet IP Protocol */
|
||||
+# to
|
||||
+# #define AA_FS_AF_MASK "local inet"
|
||||
+quiet_cmd_make-af = GEN $@
|
||||
+cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\
|
||||
+ sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e \
|
||||
+ 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
|
||||
+ echo "};" >> $@ ;\
|
||||
+ echo -n '\#define AA_FS_AF_MASK "' >> $@ ;\
|
||||
+ sed -r -n 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/\L\1/p'\
|
||||
+ $< | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
|
||||
+
|
||||
+# Build a lower case string table of sock type names
|
||||
+# Transform lines from
|
||||
+# SOCK_STREAM = 1,
|
||||
+# to
|
||||
+# [1] = "stream",
|
||||
+quiet_cmd_make-sock = GEN $@
|
||||
+cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\
|
||||
+ sed $^ >>$@ -r -n \
|
||||
+ -e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
|
||||
+ echo "};" >> $@
|
||||
|
||||
# Build a lower case string table of rlimit names.
|
||||
# Transforms lines from
|
||||
@@ -61,6 +93,7 @@ cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \
|
||||
tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
|
||||
|
||||
$(obj)/capability.o : $(obj)/capability_names.h
|
||||
+$(obj)/net.o : $(obj)/net_names.h
|
||||
$(obj)/resource.o : $(obj)/rlim_names.h
|
||||
$(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
|
||||
$(src)/Makefile
|
||||
@@ -68,3 +101,8 @@ $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
|
||||
$(obj)/rlim_names.h : $(srctree)/include/uapi/asm-generic/resource.h \
|
||||
$(src)/Makefile
|
||||
$(call cmd,make-rlim)
|
||||
+$(obj)/net_names.h : $(srctree)/include/linux/socket.h \
|
||||
+ $(srctree)/include/linux/net.h \
|
||||
+ $(src)/Makefile
|
||||
+ $(call cmd,make-af)
|
||||
+ $(call cmd,make-sock)
|
||||
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
|
||||
index 4f6ac9dbc65d..4b121211e5e7 100644
|
||||
--- a/security/apparmor/apparmorfs.c
|
||||
+++ b/security/apparmor/apparmorfs.c
|
||||
@@ -1209,6 +1209,7 @@ static struct aa_fs_entry aa_fs_entry_features[] = {
|
||||
AA_FS_DIR("policy", aa_fs_entry_policy),
|
||||
AA_FS_DIR("domain", aa_fs_entry_domain),
|
||||
AA_FS_DIR("file", aa_fs_entry_file),
|
||||
+ AA_FS_DIR("network", aa_fs_entry_network),
|
||||
AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
|
||||
AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
|
||||
AA_FS_DIR("caps", aa_fs_entry_caps),
|
||||
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
|
||||
index fdc4774318ba..0df708e8748b 100644
|
||||
--- a/security/apparmor/include/audit.h
|
||||
+++ b/security/apparmor/include/audit.h
|
||||
@@ -127,6 +127,10 @@ struct apparmor_audit_data {
|
||||
int rlim;
|
||||
unsigned long max;
|
||||
} rlim;
|
||||
+ struct {
|
||||
+ int type, protocol;
|
||||
+ struct sock *sk;
|
||||
+ } net;
|
||||
};
|
||||
};
|
||||
|
||||
diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
|
||||
new file mode 100644
|
||||
index 000000000000..55da1dad8720
|
||||
--- /dev/null
|
||||
+++ b/security/apparmor/include/net.h
|
||||
@@ -0,0 +1,59 @@
|
||||
+/*
|
||||
+ * AppArmor security module
|
||||
+ *
|
||||
+ * This file contains AppArmor network mediation definitions.
|
||||
+ *
|
||||
+ * Copyright (C) 1998-2008 Novell/SUSE
|
||||
+ * Copyright 2009-2012 Canonical Ltd.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation, version 2 of the
|
||||
+ * License.
|
||||
+ */
|
||||
+
|
||||
+#ifndef __AA_NET_H
|
||||
+#define __AA_NET_H
|
||||
+
|
||||
+#include <net/sock.h>
|
||||
+
|
||||
+#include "apparmorfs.h"
|
||||
+
|
||||
+/* struct aa_net - network confinement data
|
||||
+ * @allowed: basic network families permissions
|
||||
+ * @audit_network: which network permissions to force audit
|
||||
+ * @quiet_network: which network permissions to quiet rejects
|
||||
+ */
|
||||
+struct aa_net {
|
||||
+ u16 allow[AF_MAX];
|
||||
+ u16 audit[AF_MAX];
|
||||
+ u16 quiet[AF_MAX];
|
||||
+};
|
||||
+
|
||||
+extern struct aa_fs_entry aa_fs_entry_network[];
|
||||
+
|
||||
+#define DEFINE_AUDIT_NET(NAME, OP, SK, F, T, P) \
|
||||
+ struct lsm_network_audit NAME ## _net = { .sk = (SK), \
|
||||
+ .family = (F)}; \
|
||||
+ DEFINE_AUDIT_DATA(NAME, \
|
||||
+ ((SK) && (F) != AF_UNIX) ? LSM_AUDIT_DATA_NET : \
|
||||
+ LSM_AUDIT_DATA_NONE, \
|
||||
+ OP); \
|
||||
+ NAME.u.net = &(NAME ## _net); \
|
||||
+ aad(&NAME)->net.type = (T); \
|
||||
+ aad(&NAME)->net.protocol = (P)
|
||||
+
|
||||
+#define DEFINE_AUDIT_SK(NAME, OP, SK) \
|
||||
+ DEFINE_AUDIT_NET(NAME, OP, SK, (SK)->sk_family, (SK)->sk_type, \
|
||||
+ (SK)->sk_protocol)
|
||||
+
|
||||
+extern int aa_net_perm(const char *op, struct aa_profile *profile, u16 family,
|
||||
+ int type, int protocol, struct sock *sk);
|
||||
+extern int aa_revalidate_sk(const char *op, struct sock *sk);
|
||||
+
|
||||
+static inline void aa_free_net_rules(struct aa_net *new)
|
||||
+{
|
||||
+ /* NOP */
|
||||
+}
|
||||
+
|
||||
+#endif /* __AA_NET_H */
|
||||
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
|
||||
index 67bc96afe541..a3d18ea8d730 100644
|
||||
--- a/security/apparmor/include/policy.h
|
||||
+++ b/security/apparmor/include/policy.h
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "capability.h"
|
||||
#include "domain.h"
|
||||
#include "file.h"
|
||||
+#include "net.h"
|
||||
#include "lib.h"
|
||||
#include "resource.h"
|
||||
|
||||
@@ -132,6 +133,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: network controls for the profile
|
||||
* @rlimits: rlimits for the profile
|
||||
*
|
||||
* @dents: dentries for the profiles file entries in apparmorfs
|
||||
@@ -174,6 +176,7 @@ struct aa_profile {
|
||||
struct aa_policydb policy;
|
||||
struct aa_file_rules file;
|
||||
struct aa_caps caps;
|
||||
+ struct aa_net net;
|
||||
struct aa_rlimit rlimits;
|
||||
|
||||
struct aa_loaddata *rawdata;
|
||||
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
|
||||
index 8f3c0f7aca5a..758ddf4a0791 100644
|
||||
--- a/security/apparmor/lsm.c
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "include/context.h"
|
||||
#include "include/file.h"
|
||||
#include "include/ipc.h"
|
||||
+#include "include/net.h"
|
||||
#include "include/path.h"
|
||||
#include "include/policy.h"
|
||||
#include "include/policy_ns.h"
|
||||
@@ -587,6 +588,104 @@ static int apparmor_task_setrlimit(struct task_struct *task,
|
||||
return error;
|
||||
}
|
||||
|
||||
+static int apparmor_socket_create(int family, int type, int protocol, int kern)
|
||||
+{
|
||||
+ struct aa_profile *profile;
|
||||
+ int error = 0;
|
||||
+
|
||||
+ if (kern)
|
||||
+ return 0;
|
||||
+
|
||||
+ profile = __aa_current_profile();
|
||||
+ if (!unconfined(profile))
|
||||
+ error = aa_net_perm(OP_CREATE, profile, family, type, protocol,
|
||||
+ NULL);
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_bind(struct socket *sock,
|
||||
+ struct sockaddr *address, int addrlen)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_BIND, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_connect(struct socket *sock,
|
||||
+ struct sockaddr *address, int addrlen)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_CONNECT, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_listen(struct socket *sock, int backlog)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_LISTEN, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_accept(struct socket *sock, struct socket *newsock)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_ACCEPT, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_sendmsg(struct socket *sock,
|
||||
+ struct msghdr *msg, int size)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_SENDMSG, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_recvmsg(struct socket *sock,
|
||||
+ struct msghdr *msg, int size, int flags)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_RECVMSG, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_getsockname(struct socket *sock)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_GETSOCKNAME, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_getpeername(struct socket *sock)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_GETPEERNAME, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_getsockopt(struct socket *sock, int level,
|
||||
+ int optname)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_GETSOCKOPT, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_setsockopt(struct socket *sock, int level,
|
||||
+ int optname)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_SETSOCKOPT, sk);
|
||||
+}
|
||||
+
|
||||
+static int apparmor_socket_shutdown(struct socket *sock, int how)
|
||||
+{
|
||||
+ struct sock *sk = sock->sk;
|
||||
+
|
||||
+ return aa_revalidate_sk(OP_SHUTDOWN, sk);
|
||||
+}
|
||||
+
|
||||
static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
|
||||
LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
|
||||
LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
|
||||
@@ -616,6 +715,19 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
|
||||
LSM_HOOK_INIT(getprocattr, apparmor_getprocattr),
|
||||
LSM_HOOK_INIT(setprocattr, apparmor_setprocattr),
|
||||
|
||||
+ LSM_HOOK_INIT(socket_create, apparmor_socket_create),
|
||||
+ LSM_HOOK_INIT(socket_bind, apparmor_socket_bind),
|
||||
+ LSM_HOOK_INIT(socket_connect, apparmor_socket_connect),
|
||||
+ LSM_HOOK_INIT(socket_listen, apparmor_socket_listen),
|
||||
+ LSM_HOOK_INIT(socket_accept, apparmor_socket_accept),
|
||||
+ LSM_HOOK_INIT(socket_sendmsg, apparmor_socket_sendmsg),
|
||||
+ LSM_HOOK_INIT(socket_recvmsg, apparmor_socket_recvmsg),
|
||||
+ LSM_HOOK_INIT(socket_getsockname, apparmor_socket_getsockname),
|
||||
+ LSM_HOOK_INIT(socket_getpeername, apparmor_socket_getpeername),
|
||||
+ LSM_HOOK_INIT(socket_getsockopt, apparmor_socket_getsockopt),
|
||||
+ LSM_HOOK_INIT(socket_setsockopt, apparmor_socket_setsockopt),
|
||||
+ LSM_HOOK_INIT(socket_shutdown, apparmor_socket_shutdown),
|
||||
+
|
||||
LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank),
|
||||
LSM_HOOK_INIT(cred_free, apparmor_cred_free),
|
||||
LSM_HOOK_INIT(cred_prepare, apparmor_cred_prepare),
|
||||
diff --git a/security/apparmor/net.c b/security/apparmor/net.c
|
||||
new file mode 100644
|
||||
index 000000000000..b9c8cd0e882e
|
||||
--- /dev/null
|
||||
+++ b/security/apparmor/net.c
|
||||
@@ -0,0 +1,148 @@
|
||||
+/*
|
||||
+ * AppArmor security module
|
||||
+ *
|
||||
+ * This file contains AppArmor network mediation
|
||||
+ *
|
||||
+ * Copyright (C) 1998-2008 Novell/SUSE
|
||||
+ * Copyright 2009-2012 Canonical Ltd.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation, version 2 of the
|
||||
+ * License.
|
||||
+ */
|
||||
+
|
||||
+#include "include/apparmor.h"
|
||||
+#include "include/audit.h"
|
||||
+#include "include/context.h"
|
||||
+#include "include/net.h"
|
||||
+#include "include/policy.h"
|
||||
+
|
||||
+#include "net_names.h"
|
||||
+
|
||||
+struct aa_fs_entry aa_fs_entry_network[] = {
|
||||
+ AA_FS_FILE_STRING("af_mask", AA_FS_AF_MASK),
|
||||
+ { }
|
||||
+};
|
||||
+
|
||||
+/* audit callback for net specific fields */
|
||||
+static void audit_cb(struct audit_buffer *ab, void *va)
|
||||
+{
|
||||
+ struct common_audit_data *sa = va;
|
||||
+
|
||||
+ audit_log_format(ab, " family=");
|
||||
+ if (address_family_names[sa->u.net->family]) {
|
||||
+ audit_log_string(ab, address_family_names[sa->u.net->family]);
|
||||
+ } else {
|
||||
+ audit_log_format(ab, "\"unknown(%d)\"", sa->u.net->family);
|
||||
+ }
|
||||
+ audit_log_format(ab, " sock_type=");
|
||||
+ if (sock_type_names[aad(sa)->net.type]) {
|
||||
+ audit_log_string(ab, sock_type_names[aad(sa)->net.type]);
|
||||
+ } else {
|
||||
+ audit_log_format(ab, "\"unknown(%d)\"", aad(sa)->net.type);
|
||||
+ }
|
||||
+ audit_log_format(ab, " protocol=%d", aad(sa)->net.protocol);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * audit_net - audit network access
|
||||
+ * @profile: profile being enforced (NOT NULL)
|
||||
+ * @op: operation being checked
|
||||
+ * @family: network family
|
||||
+ * @type: network type
|
||||
+ * @protocol: network protocol
|
||||
+ * @sk: socket auditing is being applied to
|
||||
+ * @error: error code for failure else 0
|
||||
+ *
|
||||
+ * Returns: %0 or sa->error else other errorcode on failure
|
||||
+ */
|
||||
+static int audit_net(struct aa_profile *profile, const char *op, u16 family,
|
||||
+ int type, int protocol, struct sock *sk, int error)
|
||||
+{
|
||||
+ int audit_type = AUDIT_APPARMOR_AUTO;
|
||||
+ DEFINE_AUDIT_NET(sa, op, sk, family, type, protocol);
|
||||
+
|
||||
+ aad(&sa)->error = error;
|
||||
+
|
||||
+ if (likely(!aad(&sa)->error)) {
|
||||
+ u16 audit_mask = profile->net.audit[sa.u.net->family];
|
||||
+ if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
|
||||
+ !(1 << aad(&sa)->net.type & audit_mask)))
|
||||
+ return 0;
|
||||
+ audit_type = AUDIT_APPARMOR_AUDIT;
|
||||
+ } else {
|
||||
+ u16 quiet_mask = profile->net.quiet[sa.u.net->family];
|
||||
+ u16 kill_mask = 0;
|
||||
+ u16 denied = (1 << aad(&sa)->net.type) & ~quiet_mask;
|
||||
+
|
||||
+ if (denied & kill_mask)
|
||||
+ audit_type = AUDIT_APPARMOR_KILL;
|
||||
+
|
||||
+ if ((denied & quiet_mask) &&
|
||||
+ AUDIT_MODE(profile) != AUDIT_NOQUIET &&
|
||||
+ AUDIT_MODE(profile) != AUDIT_ALL)
|
||||
+ return COMPLAIN_MODE(profile) ? 0 : aad(&sa)->error;
|
||||
+ }
|
||||
+
|
||||
+ return aa_audit(audit_type, profile, &sa, audit_cb);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * aa_net_perm - very course network access check
|
||||
+ * @op: operation being checked
|
||||
+ * @profile: profile being enforced (NOT NULL)
|
||||
+ * @family: network family
|
||||
+ * @type: network type
|
||||
+ * @protocol: network protocol
|
||||
+ *
|
||||
+ * Returns: %0 else error if permission denied
|
||||
+ */
|
||||
+int aa_net_perm(const char *op, struct aa_profile *profile, u16 family,
|
||||
+ int type, int protocol, struct sock *sk)
|
||||
+{
|
||||
+ u16 family_mask;
|
||||
+ int error;
|
||||
+
|
||||
+ if ((family < 0) || (family >= AF_MAX))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if ((type < 0) || (type >= SOCK_MAX))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ /* unix domain and netlink sockets are handled by ipc */
|
||||
+ if (family == AF_UNIX || family == AF_NETLINK)
|
||||
+ return 0;
|
||||
+
|
||||
+ family_mask = profile->net.allow[family];
|
||||
+
|
||||
+ error = (family_mask & (1 << type)) ? 0 : -EACCES;
|
||||
+
|
||||
+ return audit_net(profile, op, family, type, protocol, sk, error);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * aa_revalidate_sk - Revalidate access to a sock
|
||||
+ * @op: operation being checked
|
||||
+ * @sk: sock being revalidated (NOT NULL)
|
||||
+ *
|
||||
+ * Returns: %0 else error if permission denied
|
||||
+ */
|
||||
+int aa_revalidate_sk(const char *op, struct sock *sk)
|
||||
+{
|
||||
+ struct aa_profile *profile;
|
||||
+ int error = 0;
|
||||
+
|
||||
+ /* aa_revalidate_sk should not be called from interrupt context
|
||||
+ * don't mediate these calls as they are not task related
|
||||
+ */
|
||||
+ if (in_interrupt())
|
||||
+ return 0;
|
||||
+
|
||||
+ profile = __aa_current_profile();
|
||||
+ if (!unconfined(profile))
|
||||
+ error = aa_net_perm(op, profile, sk->sk_family, sk->sk_type,
|
||||
+ sk->sk_protocol, sk);
|
||||
+
|
||||
+ return error;
|
||||
+}
|
||||
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
|
||||
index cf9d670dca94..0eea92aeb02d 100644
|
||||
--- a/security/apparmor/policy.c
|
||||
+++ b/security/apparmor/policy.c
|
||||
@@ -237,6 +237,7 @@ void aa_free_profile(struct aa_profile *profile)
|
||||
|
||||
aa_free_file_rules(&profile->file);
|
||||
aa_free_cap_rules(&profile->caps);
|
||||
+ aa_free_net_rules(&profile->net);
|
||||
aa_free_rlimit_rules(&profile->rlimits);
|
||||
|
||||
kzfree(profile->dirname);
|
||||
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
|
||||
index f3422a91353c..89a1bd78f765 100644
|
||||
--- a/security/apparmor/policy_unpack.c
|
||||
+++ b/security/apparmor/policy_unpack.c
|
||||
@@ -217,6 +217,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((u16 *) 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)) {
|
||||
@@ -519,7 +532,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;
|
||||
- size_t ns_len;
|
||||
+ size_t ns_len, size = 0;
|
||||
struct rhashtable_params params = { 0 };
|
||||
char *key = NULL;
|
||||
struct aa_data *data;
|
||||
@@ -635,6 +648,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
|
||||
if (!unpack_rlimits(e, profile))
|
||||
goto fail;
|
||||
|
||||
+ size = unpack_array(e, "net_allowed_af");
|
||||
+ if (size) {
|
||||
+
|
||||
+ 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.allow[i], NULL))
|
||||
+ goto fail;
|
||||
+ if (!unpack_u16(e, &profile->net.audit[i], NULL))
|
||||
+ goto fail;
|
||||
+ if (!unpack_u16(e, &profile->net.quiet[i], NULL))
|
||||
+ goto fail;
|
||||
+ }
|
||||
+ if (!unpack_nameX(e, AA_ARRAYEND, NULL))
|
||||
+ goto fail;
|
||||
+ }
|
||||
+ /*
|
||||
+ * allow unix domain and netlink sockets they are handled
|
||||
+ * by IPC
|
||||
+ */
|
||||
+ profile->net.allow[AF_UNIX] = 0xffff;
|
||||
+ profile->net.allow[AF_NETLINK] = 0xffff;
|
||||
+
|
||||
if (unpack_nameX(e, AA_STRUCT, "policydb")) {
|
||||
/* generic policy dfa - optional and may be NULL */
|
||||
profile->policy.dfa = unpack_dfa(e);
|
||||
--
|
||||
2.11.0
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user