2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-09-01 06:45:38 +00:00

Compare commits

..

29 Commits

Author SHA1 Message Date
John Johansen
8b81fe065f bump release version to 2.11.1 2017-10-19 02:13:37 -07:00
Steve Beattie
a8f5b8f0db libapparmor: fix swig test_apparmor.py for zero length ptrace records
Merge from trunk revision 3715

The added testcase for a ptrace target with an empty string
(ptrace_garbage_lp1689667_1.in) was causing the swig python test script
to fail. The generated python swig record for libapparmor ends up
setting a number of fields to None or other values that indicate the
value is unset, and the test script was checking if the value in the
field didn't evaluate to False in a python 'if' test.

Unfortunately, python evaluates the empty string '' as False in 'if'
tests, resulting in the specific field that contained the empty string
to be dropped from the returned record. This commit fixes that by
special case checking for the empty string.

Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: John Johansen <john.johansen@canonical.com>
2017-10-18 17:06:28 -07:00
John Johansen
878ebd4b33 Fix af_unix downgrade of network rules
with unix rules we output a downgraded rule compatible with network rules
so that policy will work on kernels that support network socket controls
but not the extended af_unix rules

however this is currently broken if the socket type is left unspecified
(initialized to -1), resulting in denials for kernels that don't support
the extended af_unix rules.

cherry-pick: lp:apparmor r3700
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: timeout
2017-10-18 14:31:16 -07:00
Christian Boltz
bc5634f2af Fix save_profiles() for YaST
YaST has two issues in the "save changed profiles" dialog:
- when using "save selected", the list of profiles doesn't get updated.
  Update q.options inside the loop to fix this.
- the list of profiles is displayed as "["/usr/bin/foo", true]" instead
  of just "/usr/bin/foo". Use changed.keys() instead of changed to fix
  this. (text-mode aa-logprof doesn't change, it always displayed
  "/usr/bin/foo" and continues to do so.)

References: https://bugzilla.opensuse.org/show_bug.cgi?id=1062667 part a)


Acked-by: Seth Arnold <seth.arnold@canonical.com> for trunk and 2.11.

Note that 2.11 needs a slightly different patch (whitespace diff).
2017-10-12 13:28:51 +02:00
Christian Boltz
7c217b7413 Allow /var/run/dovecot/login-master-notify* in dovecot imap-login profiles
Acked-by: Seth Arnold <seth.arnold@canonical.com> for trunk, 2.11, 2.10 and 2.9.
2017-09-28 17:48:13 +02:00
Christian Boltz
86037e0a23 abstractions/freedesktop.org: support /usr/local/applications; support subdirs of applications folder
Merge request by Cameron Norman 2015-06-07
https://code.launchpad.net/~cameronnemo/apparmor/abstraction-fdo-applications-fixups/+merge/261336

Acked-by: Christian Boltz <apparmor@cboltz.de> for trunk, 2.11, 2.10 and 2.9
2017-09-10 12:28:30 +02:00
Christian Boltz
1f82a98029 Add network 'smc' keyword in NetworkRule and apparmor.d manpage
'smc' seems to be new in kernel 4.12.


Note that the 2.10 apparmor.d manpage also misses the 'kcm' keyword, so
the patch also adds it there.


Acked-by: Seth Arnold <seth.arnold@canonical.com> for trunk, 2.11 and 2.10.
2017-08-30 11:06:56 +02:00
Christian Boltz
7adbc4b3ee Samba profile updates for ActiveDirectory / Kerberos
The Samba package used by the INVIS server (based on openSUSE) needs
some additional Samba permissions for the added ActiveDirectory /
Kerberos support.

As discussed with Seth, add /var/lib/sss/mc/initgroups read permissions
to abstractions/nameservice instead of only to the smbd profile because
it's probably needed by more than just Samba if someone uses sss.


Acked-by: Seth Arnold <seth.arnold@canonical.com> for 2.9, 2.10, 2.11 and trunk.
2017-08-29 13:32:03 +02:00
Christian Boltz
5199e44ef0 update some Postfix profiles
- change abstractions/postfix-common to allow /etc/postfix/*.db k
- add several permissions to postfix/error, postfix/lmtp and postfix/pipe
- remove superfluous abstractions/kerberosclient from all postfix
  profiles - it's included via abstractions/nameservice


Acked-by: Seth Arnold <seth.arnold@canonical.com> for 2.9, 2.10, 2.11 and trunk
2017-08-22 12:43:52 +02:00
Steve Beattie
32e76985c9 libapparmor: fix ptrace regression test failure
Merge from trunk revision 3692

In http://bazaar.launchpad.net/~apparmor-dev/apparmor/master/revision/3659,
a testcase was added that where the expected output file did not match
the input source name, cause libapparmor's regression tests to fail:

  Output doesn't match expected data:
  --- ./test_multi/ptrace_no_denied_mask.out    2017-08-18 16:35:30.000000000 -0700
  +++ ./test_multi/out/ptrace_no_denied_mask.out  2017-08-18 16:35:38.985863094 -0700
  @@ -1,5 +1,5 @@
   START
  -File: ptrace_1.in
  +File: ptrace_no_denied_mask.in
   Event type: AA_RECORD_DENIED
   Audit ID: 1495217772.047:4471
   Operation: ptrace
  FAIL: ptrace_no_denied_mask

This patch corrects the issue.

Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
2017-08-18 17:16:27 -07:00
Steve Beattie
54bdfd3565 user abstractions: fix for non-latin file/directory names
Merge from trunk commit 3691
Merge from Vincas Dargis, approved by intrigeri
Fix user-write and user-download abstractions for non-latin file names.

Acked-by: Steve Beattie <steve@nxnw.org>
2017-08-09 12:48:18 -07:00
Steve Beattie
bd68cd2d69 traceroute profile: support TCP SYN for probes, quite net_admin request
Merge from trunk revision 3690
Merge from Vincas Dargis, approved by intrigeri.
fix traceroute denies in tcp mode

Acked-by: Steve Beattie <steve@nxnw.org>
2017-08-09 09:35:34 -07:00
Steve Beattie
f076497f89 abstractions/gnome: allow reading GLib schemas.
Merge from trunk revision 3687

Merge from intrigeri based on original work by Cameron Norman.

Acked-by: Steve Beattie <steve@nxnw.org>
2017-08-07 10:40:35 -07:00
Steve Beattie
5089a941c8 wayland abstraction: allow wayland-cursor-shared-*
Merge from trunk revision 3686

Merge from intrigeri.

Bug: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=870807
Acked-by: Steve Beattie <steve@nxnw.org>
2017-08-07 10:28:30 -07:00
Christian Boltz
3b490f9450 Prevent 'wa' conflicts for file rules
get_file_perms() and propose_file_rules() happily collect all file
permissions. This could lead to proposing 'wa' permissions in
aa-logprof, which then errored out because of conflicting permissions.

This patch adds a check to both functions that removes 'a' if 'w' is
present, and extends the tests to check this.


Acked-by: Seth Arnold <seth.arnold@canonical.com> for trunk and 2.11.

Note: Both functions (including this bug) were introduced together with
FileRule, so older releases are not affected.
2017-08-04 22:27:16 +02:00
Christian Boltz
66928660f5 Carry over all autodep-generated rules in handle_children()
When creating a new child profile, handle_children() did only copy over
include and path rules. While this was correct in the past, path rules
got changed to FileRule in the meantime and were therefore lost.
(In practise, this means the "$binary mr," rule wasn't added to the new
child profile, causing a "superfluous" question in aa-logprof.)

This patch changes handle_children() to carry over the complete new
child profile instead of only cherry-picking include and path rules.


Acked-by: Steve Beattie <steve@nxnw.org> for trunk and 2.11.

Older versions (with path as hasher) are not affected.
2017-08-02 13:26:49 +02:00
Jamie Strandboge
d2fc6ff1cc update aa-status.pod for updated podchecker
Bug-Ubuntu: https://launchpad.net/bugs/1707614

Signed-Off-By: Jamie Strandboge <jamie@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de>
2017-07-31 10:22:33 -05:00
Jamie Strandboge
39fc9dc40f Adjust python abstraction for python3.6
Signed-Off-By: Jamie Strandboge <jamie@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de>
2017-07-26 15:10:24 -05:00
Christian Boltz
a90238e7c6 Add --no-reload to various utils manpages
This option exists in several aa-* tools since 2.9, but isn't mentioned
in the manpage.

Also drop some trailing whitespace in the manpages.


Acked-by: John Johansen <john.johansen@canonical.com>
for 2.9, 2.10, 2.11 and trunk.
2017-07-23 21:30:56 +02:00
Christian Boltz
5246203c9e dovecot profile: add the attach_disconnected flag
Reported by pfak on IRC

[...] apparmor="DENIED" operation="sendmsg" info="Failed name lookup - disconnected path" error=-13 profile="/usr/sbin/dovecot" name="run/systemd/journal/dev-log" pid=20313 comm="dovecot" requested_mask="w" denied_mask="w" fsuid=0 ouid=0


Acked-by <timeout> for 2.9, 2.10, 2.11 and trunk.
2017-06-29 22:54:17 +02:00
Jamie Strandboge
4b99f16b49 Origin: r3669 from trunk
Description: adjust the multiarch alternation rule in the perl abstraction for
 modern Debian and Ubuntu systems which store some modules under the
 architecture-specific perl-base directory instead of perl or perl5.

Signed-Off-By: Jamie Strandboge <jamie@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
2017-06-26 14:43:13 -05:00
Christian Boltz
7777b1418e Ignore ptrace log events without denied_mask
This fixes a crash in the tools.

Reported by peetaur on IRC.


Acked-by: John Johansen <john.johansen@canonical.com> for trunk and 2.11.
2017-05-20 01:06:39 +02:00
Christian Boltz
9d5934f5ff Add two parser files to .bzrignore
- parser/libapparmor_re/parse.cc is autogenerated during build
- parser/tst_lib gets compiled during "make check"

Both files get deleted by make clean.


Acked-by: John Johansen <john.johansen@canonical.com> for trunk and 2.11.
2017-05-20 01:04:10 +02:00
Christian Boltz
962d4afb3d Fix aa-logprof crash on ptrace garbage log events
(garbage) ptrace events like
    ... apparmor="DENIED" operation="ptrace" profile="/bin/netstat" pid=1962 comm="netstat" target=""
cause an empty name2 field, which leads to a crash in the tools.

This patch lets logparser.py ignore such garbage log events, which also
avoids the crash.

As usual, add some testcases.

test-libapparmor-test_multi.py needs some special handling to ignore the
empty name2 field in one of the testcases.


References: https://bugs.launchpad.net/apparmor/+bug/1689667


Acked-by: Seth Arnold <seth.arnold@canonical.com> for trunk and 2.11.

Older releases can't handle ptrace log events and therefore can't crash ;-)
2017-05-19 22:47:36 +02:00
Tyler Hicks
eb8acf4b45 libapparmor: Don't print shell commands that check for test failures
Error messages should only show up in build logs when the error has been
encountered. This patch silences these shell commands from being printed
before they're interpreted.

Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: John Johansen <john.johansen@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de>
2017-04-21 13:52:44 +00:00
Tyler Hicks
8217eb04af libapparmor: Fix parallel make dependency issue in testsuite
A multi job `make check` command could fail due to check-local running
before the check-DEJAGNU target, which is automatically generated by
automake, would complete. This would result in a build failure due to
libaalogparse.log not yet existing.

Fix the issue by depending on the check-DEJAGNU target.

Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: John Johansen <john.johansen@canonical.com>
2017-04-21 13:52:42 +00:00
Christian Boltz
26e1200324 Ignore test failures about duplicated conditionals in dbus rules
Since r3634, the tools allow any order of dbus conditionals.

Quoting the r3634 patch description:

  This patch eases the restriction on the ordering at the expense of the
  utils no longer being able to detect and reject a single attribute that
  is repeated multiple times. In that situation, only the last occurrence
  of the attribute will be honored by the utils.

It seems nobody tested with all test profiles generated ;-) so we have to
add some exceptions to the "does not raise an exception" list now.



Acked-by <timeout> for trunk and 2.11

Bug: https://launchpad.net/bugs/1658239
2017-04-20 13:07:06 +02:00
Steve Beattie
4181b187c3 profiles: abstractions/base - Allow sysconf(_SC_NPROCESSORS_CONF)
Merge Simon McVittie's patch to allow querying the number of configured
processors in the base abstraction.

Acked-by: Steve Beattie <steve@nxnw.org>
2017-04-14 16:08:03 -07:00
John Johansen
485798c4f8 Update REPO_URL to 2.11 branch 2017-04-13 13:56:20 -07:00
2312 changed files with 44504 additions and 124494 deletions

View File

@@ -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/

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
View 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
View File

@@ -1,415 +0,0 @@
# AppArmor
[![Build status](https://gitlab.com/apparmor/apparmor/badges/master/build.svg)](https://gitlab.com/apparmor/apparmor/commits/master)
[![Overall test coverage](https://gitlab.com/apparmor/apparmor/badges/master/coverage.svg)](https://gitlab.com/apparmor/apparmor/pipelines)
[![Core Infrastructure Initiative Best Practices](https://bestpractices.coreinfrastructure.org/projects/1699/badge)](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.

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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");

View File

@@ -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;
}

View File

@@ -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;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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 ""

View File

@@ -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 ""

View File

@@ -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 ""

View File

@@ -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 ""

View File

@@ -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 ""

View File

@@ -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"

View File

@@ -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 ""

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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 ""

View File

@@ -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 ""

View File

@@ -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

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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 ""

View File

@@ -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"

View File

@@ -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 ""

View File

@@ -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"

View File

@@ -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

View File

@@ -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"

View File

@@ -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"

View File

@@ -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 ""

View File

@@ -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"

View File

@@ -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 ""

View File

@@ -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"

View File

@@ -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

View File

@@ -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"

View File

@@ -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"

View File

@@ -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

View File

@@ -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 ""

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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

View File

@@ -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 */

View File

@@ -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

View File

@@ -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:

View File

@@ -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

View File

@@ -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;

View File

@@ -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.

View File

@@ -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.

View File

@@ -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
# =====================

View File

@@ -1 +1 @@
5.0.0~alpha1
2.11.1

View File

@@ -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

View File

@@ -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

View 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
View 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

File diff suppressed because it is too large Load Diff

View 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;

File diff suppressed because it is too large Load Diff

View 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;

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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";
}
}
}

View 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

View 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($_);
}

View File

@@ -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/>.

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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