1 === modified file 'libraries/libapparmor/swig/perl/Makefile.am'
2 --- libraries/libapparmor/swig/perl/Makefile.am 2009-05-12 21:56:56 +0000
3 +++ libraries/libapparmor/swig/perl/Makefile.am 2010-03-16 22:00:26 +0000
5 EXTRA_DIST =Makefile.PL libapparmor_wrap.c LibAppArmor.pm examples/*.pl
8 noinst_DATA =LibAppArmor.so
11 libapparmor_wrap.c: $(srcdir)/../SWIG/libapparmor.i
12 $(SWIG) -perl -I$(srcdir)/../../src -module LibAppArmor -o $@ $(srcdir)/../SWIG/libapparmor.i
15 #rm -f Makefile.perl Makefile.perl.old
19 \ No newline at end of file
22 === modified file 'parser/Makefile'
23 --- parser/Makefile 2009-11-11 18:58:57 +0000
24 +++ parser/Makefile 2010-03-16 22:18:55 +0000
26 techdoc.txt: techdoc/index.html
29 -all: $(TOOLS) $(MANPAGES) ${HTMLMANPAGES} techdoc.pdf
30 +# targets arranged this way so that people who don't want full docs can
31 +# pick specific targets they want.
36 +manpages: $(MANPAGES)
38 +htmlmanpages: $(HTMLMANPAGES)
42 +docs: manpages htmlmanpages pdf
46 apparmor_parser: $(OBJECTS) $(PCREOBJECTS) $(AAREOBJECTS)
49 af_names.h: /usr/include/bits/socket.h
50 LC_ALL=C sed -n -e '/$(__FILTER)/d' -e "s/^\#define[ \\t]\\+PF_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\\(.*\\)\$$/#ifndef AF_\\1\\n# define AF_\\1 \\2\\n#endif\\nAA_GEN_NET_ENT(\"\\L\\1\", \\UAF_\\1)\\n/p" $< > $@
51 LC_ALL=C sed -n -e "s/^\#define[ \\t]\\+PF_MAX[ \\t]\\+\\([0-9]\\+\\)[ \\t]\\+.*/#define AA_AF_MAX \\1\n/p" $< >> $@
55 cap_names.h: /usr/include/linux/capability.h
56 LC_ALL=C sed -n -e "/CAP_EMPTY_SET/d" -e "s/^\#define[ \\t]\\+CAP_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9xa-f]\\+\\)\\(.*\\)\$$/\{\"\\L\\1\", \\UCAP_\\1\},/p" $< > $@
61 - for test in ${TESTS} ; do echo "*** running $${test}" && ./$${test} $(BUILD_OUTPUT) ; done
62 + sh -e -c 'for test in ${TESTS} ; do echo "*** running $${test}" && ./$${test} $(BUILD_OUTPUT) ; done'
63 $(Q)make -s -C tst tests
67 === modified file 'parser/apparmor_parser.pod'
68 --- parser/apparmor_parser.pod 2010-01-07 18:03:49 +0000
69 +++ parser/apparmor_parser.pod 2010-04-03 23:24:06 +0000
71 Given once, only checks the profiles to ensure syntactic correctness.
72 Given twice, dumps its interpretation of the profile for checking.
76 +Debug flag for dumping various structures and passes of policy compilation.
77 +A single dump flag can be specified per --dump option, but the dump flag
78 +can be passed multiple times. Note progress flags tend to also imply
79 +the matching stats flag.
81 + apparmor_parser --dump=dfa-stats --dump=trans-stats <file>
83 +Use --help=dump to see a full list of which dump flags are supported
85 +=item -O n, --optimize=n
87 +Set the optimization flags used by policy compilation. A sinlge optimization
88 +flag can be toggled per -O option, but the optimize flag can be passed
89 +multiple times. Turning off some phases of the optimization can make
90 +it so that policy can't complete compilation due to size constraints
91 +(it is entirely possible to create a dfa with millions of states that will
92 +take days or longer to compile).
94 +Note: The parser is set to use a balanced default set of flags, that
95 +will result in resonable compression but not take excessive amounts
98 +Use --help=optimize to see a full list of which optimization flags are
103 Give a quick reference guide.
105 === modified file 'parser/libapparmor_re/regexp.y'
106 --- parser/libapparmor_re/regexp.y 2010-02-01 07:21:00 +0000
107 +++ parser/libapparmor_re/regexp.y 2010-03-13 10:23:23 +0000
108 @@ -1715,7 +1715,9 @@
109 Trans::iterator j = trans.find(*i);
110 if (j != trans.end())
119 === modified file 'parser/parser.h'
120 --- parser/parser.h 2010-02-17 20:21:52 +0000
121 +++ parser/parser.h 2010-03-12 23:26:32 +0000
123 * Copyright (c) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007
124 * NOVELL (All rights reserved)
126 + * Copyright (c) 2010
127 + * Canonical, Ltd. (All rights reserved)
129 * This program is free software; you can redistribute it and/or
130 * modify it under the terms of version 2 of the GNU General Public
131 * License published by the Free Software Foundation.
133 * GNU General Public License for more details.
135 * You should have received a copy of the GNU General Public License
136 - * along with this program; if not, contact Novell, Inc.
137 + * along with this program; if not, contact Novell, Inc. or Canonical
141 #include <netinet/in.h>
142 @@ -280,12 +284,16 @@
143 extern void free_cod_entries(struct cod_entry *list);
145 /* parser_symtab.c */
148 + struct set_value *next;
150 extern int add_boolean_var(const char *var, int boolean);
151 extern int get_boolean_var(const char *var);
152 extern int new_set_var(const char *var, const char *value);
153 extern int add_set_value(const char *var, const char *value);
154 -extern void *get_set_var(const char *var);
155 -extern char *get_next_set_value(void **context);
156 +extern struct set_value *get_set_var(const char *var);
157 +extern char *get_next_set_value(struct set_value **context);
158 extern void dump_symtab(void);
159 extern void dump_expanded_symtab(void);
160 void free_symtabs(void);
162 extern void add_hat_to_policy(struct codomain *policy, struct codomain *hat);
163 extern void add_entry_to_policy(struct codomain *policy, struct cod_entry *entry);
164 extern void post_process_nt_entries(struct codomain *cod);
165 -extern int post_process_policy(void);
166 +extern int post_process_policy(int debug_only);
167 extern int process_hat_regex(struct codomain *cod);
168 extern int process_hat_variables(struct codomain *cod);
169 extern int post_merge_rules(void);
171 === modified file 'parser/parser_lex.l'
172 --- parser/parser_lex.l 2010-03-09 05:49:16 +0000
173 +++ parser/parser_lex.l 2010-03-12 09:50:26 +0000
179 yypop_buffer_state();
180 if ( !YY_CURRENT_BUFFER ) yyterminate();
183 === modified file 'parser/parser_main.c'
184 --- parser/parser_main.c 2010-01-28 01:20:13 +0000
185 +++ parser/parser_main.c 2010-04-03 22:41:40 +0000
187 * Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
188 * NOVELL (All rights reserved)
190 + * Copyright (c) 2010
191 + * Canonical, Ltd. (All rights reserved)
193 * This program is free software; you can redistribute it and/or
194 * modify it under the terms of version 2 of the GNU General Public
195 * License published by the Free Software Foundation.
197 * GNU General Public License for more details.
199 * You should have received a copy of the GNU General Public License
200 - * along with this program; if not, contact Novell, Inc.
201 + * along with this program; if not, contact Novell, Inc. or Canonical,
211 + skip_read_cache = 1;
216 subdomainbase = strndup(optarg, PATH_MAX);
220 + skip_read_cache = 1;
223 } else if (strcmp(optarg, "variables") == 0) {
229 + skip_read_cache = 1;
230 if (strcmp(optarg, "0") == 0) {
231 dfaflags |= DFA_CONTROL_NO_TREE_NORMAL |
232 DFA_CONTROL_NO_TREE_SIMPLE |
237 - retval = post_process_policy();
238 + retval = post_process_policy(debug);
240 PERROR(_("%s: Errors found in file. Aborting.\n"), progname);
243 === modified file 'parser/parser_policy.c'
244 --- parser/parser_policy.c 2009-08-20 15:27:12 +0000
245 +++ parser/parser_policy.c 2010-03-12 23:26:32 +0000
247 * Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
248 * NOVELL (All rights reserved)
250 + * Copyright (c) 2010
251 + * Canonical, Ltd. (All rights reserved)
253 * This program is free software; you can redistribute it and/or
254 * modify it under the terms of version 2 of the GNU General Public
255 * License published by the Free Software Foundation.
257 * GNU General Public License for more details.
259 * You should have received a copy of the GNU General Public License
260 - * along with this program; if not, contact Novell, Inc.
261 + * along with this program; if not, contact Novell, Inc. or Canonical,
270 -int post_process_policy(void)
271 +int post_process_policy(int debug_only)
275 @@ -696,11 +700,13 @@
279 - retval = post_process_regex();
281 - PERROR(_("%s: Errors found during regex postprocess. Aborting.\n"),
285 + retval = post_process_regex();
287 + PERROR(_("%s: Errors found during regex postprocess. Aborting.\n"),
295 === modified file 'parser/parser_symtab.c'
296 --- parser/parser_symtab.c 2009-07-24 13:24:53 +0000
297 +++ parser/parser_symtab.c 2010-03-12 22:41:58 +0000
304 - struct set_value *next;
312 /* returns a pointer to the value list, which should be used as the
313 * argument to the get_next_set_value() function. */
314 -void *get_set_var(const char *var)
315 +struct set_value *get_set_var(const char *var)
317 struct symtab *result;
318 struct set_value *valuelist = NULL;
319 @@ -321,16 +316,17 @@
322 /* iterator to walk the list of set values */
323 -char *get_next_set_value(void **list)
324 +char *get_next_set_value(struct set_value **list)
326 - struct set_value **valuelist = (struct set_value **) list;
327 + struct set_value *next;
330 - if (!valuelist || !(*valuelist))
331 + if (!list || !(*list))
334 - ret = (*valuelist)->val;
335 - (*valuelist) = (*valuelist)->next;
336 + ret = (*list)->val;
337 + next = (*list)->next;
347 + struct set_value *retptr;
348 struct symtab *a, *b;
350 a = new_symtab_entry("blah");
352 === modified file 'parser/parser_variable.c'
353 --- parser/parser_variable.c 2009-07-24 23:47:46 +0000
354 +++ parser/parser_variable.c 2010-03-12 23:20:22 +0000
357 static int expand_entry_variables(struct cod_entry *entry)
360 + struct set_value *valuelist;
363 struct var_string *split_var;
365 === added file 'profiles/apparmor.d/abstractions/dbus-session'
366 --- profiles/apparmor.d/abstractions/dbus-session 1970-01-01 00:00:00 +0000
367 +++ profiles/apparmor.d/abstractions/dbus-session 2010-04-19 17:38:17 +0000
369 +# vim:syntax=apparmor
371 +# ------------------------------------------------------------------
373 +# Copyright (C) 2010 Canonical Ltd.
375 +# This program is free software; you can redistribute it and/or
376 +# modify it under the terms of version 2 of the GNU General Public
377 +# License published by the Free Software Foundation.
379 +# ------------------------------------------------------------------
381 + #include <abstractions/dbus>
382 + /usr/bin/dbus-launch Uxr,
384 === modified file 'profiles/apparmor.d/abstractions/php5'
385 --- profiles/apparmor.d/abstractions/php5 2010-01-03 21:16:38 +0000
386 +++ profiles/apparmor.d/abstractions/php5 2010-03-30 17:34:32 +0000
388 # ------------------------------------------------------------------
390 # Copyright (C) 2002-2006 Novell/SUSE
391 -# Copyright (C) 2009 Canonical, Ltd.
392 +# Copyright (C) 2009-2010 Canonical Ltd.
394 # This program is free software; you can redistribute it and/or
395 # modify it under the terms of version 2 of the GNU General Public
397 # ------------------------------------------------------------------
399 # shared snippets for config files
400 - /etc/php5/{conf.d,apache2,cli,fastcgi}/ r,
401 - /etc/php5/{conf.d,apache2,cli,fastcgi}/*.ini r,
402 + /etc/php5/{conf.d,apache2,cli,fastcgi,cgi}/ r,
403 + /etc/php5/{conf.d,apache2,cli,fastcgi,cgi}/*.ini r,
406 /usr/X11R6/lib{,32,64}/lib*.so* mr,
408 - /usr/lib{64,}/php5/{libexec,extensions}/*.so mr,
409 + /usr/lib{64,}/php5/*/*.so mr,
411 # php5 session mmap socket
412 /var/lib/php5/session_mm_* rwlk,
414 === modified file 'profiles/apparmor.d/abstractions/samba'
415 --- profiles/apparmor.d/abstractions/samba 2009-11-04 20:25:42 +0000
416 +++ profiles/apparmor.d/abstractions/samba 2010-03-25 23:13:00 +0000
419 # ------------------------------------------------------------------
421 -# Copyright (C) 2009 Canonical Ltd.
422 +# Copyright (C) 2009-2010 Canonical Ltd.
424 # This program is free software; you can redistribute it and/or
425 # modify it under the terms of version 2 of the GNU General Public
428 /etc/samba/smb.conf r,
429 /usr/share/samba/*.dat r,
430 - /var/lib/samba/**.tdb rw,
431 + /var/lib/samba/**.tdb rwk,
432 /var/log/samba/cores/* w,
433 /var/log/samba/log.* w,
434 /var/run/samba/*.tdb rw,
436 === modified file 'profiles/apparmor.d/abstractions/user-tmp'
437 --- profiles/apparmor.d/abstractions/user-tmp 2009-11-04 20:25:42 +0000
438 +++ profiles/apparmor.d/abstractions/user-tmp 2010-05-12 08:52:23 +0000
440 # ------------------------------------------------------------------
442 # Copyright (C) 2002-2009 Novell/SUSE
443 -# Copyright (C) 2009 Canonical Ltd.
444 +# Copyright (C) 2009-2010 Canonical Ltd.
446 # This program is free software; you can redistribute it and/or
447 # modify it under the terms of version 2 of the GNU General Public
449 # ------------------------------------------------------------------
451 # per-user tmp directories
452 - @{HOME}/tmp/** rwkl,
454 + owner @{HOME}/tmp/** rwkl,
455 + owner @{HOME}/tmp/ rw,
457 # global tmp directories
462 + owner /var/tmp/** rwkl,
463 + owner /var/tmp/ rw,
464 + owner /tmp/** rwkl,
467 === modified file 'tests/regression/subdomain/prologue.inc'
468 --- tests/regression/subdomain/prologue.inc 2010-02-07 07:04:57 +0000
469 +++ tests/regression/subdomain/prologue.inc 2010-04-27 09:37:30 +0000
474 - if [ -x /usr/bin/readlink ] ; then
475 - target=$(/usr/bin/readlink ${link})
476 + if [ -x /usr/bin/readlink ] ; then
477 + target=$(/usr/bin/readlink -f ${link})
478 + elif [ -x /bin/readlink ] ; then
479 + target=$(/bin/readlink -f ${link})
481 # I'm sure there's a more perlish way to do this
482 target=$( perl -e "printf (\"%s\n\", readlink(\"${link}\"));")
484 === modified file 'tests/stress/parser/stress.rb'
485 --- tests/stress/parser/stress.rb 2008-11-26 22:16:48 +0000
486 +++ tests/stress/parser/stress.rb 2010-03-15 18:31:38 +0000
488 return sprintf("%0#{len}x", rand(2 ** (4 * len)))
491 +def get_random_regex()
494 + return "{#{get_random_name(rand(8) + 2)},#{get_random_name(rand(8) + 2)},#{get_random_name(rand(8) + 2)}}"
496 + return "[#{get_random_name(rand(5) + 1)}]"
504 def get_random_path()
506 - 0.upto(rand(20)) do
507 - out = "#{out}/#{get_random_name(4)}"
508 + 0.upto(rand(20) + 2) do
510 + out = "#{out}/#{get_random_regex}"
512 + out = "#{out}/#{get_random_name(rand(10) + 4)}"
533 +class NetRule < Rule
537 +class RlimitRule < Rule
539 +#"cpu", # cpu rlimit not supported
558 + @rlimit = RLIMIT_LIST[rand(RLIMIT_LIST.length)]
560 + @limit = "infinity"
561 + elsif @rlimit == "nice"
562 + @limit = rand(40) - 20
564 + @limit = rand(2 ** 31)
569 + return " set rlimit #{@rlimit} <= #{@limit},"
578 + "namespace_relative",
580 + "delegate_deleted",
581 + "attach_disconnected",
582 + "no_attach_disconnected",
588 + ["chroot_relative", "namespace_relative"],
589 + ["mediate_deleted", "delegate_deleted"],
590 + ["attach_disconnected", "no_attach_disconnected"],
591 + ["chroot_attach", "chroot_no_attach"]
600 + 0.upto(4 - Math.log(rand(32) + 1).to_int) do |x|
601 + @flags << FLAG_LIST[rand(FLAG_LIST.length)]
604 + FLAG_CONFLICTS.each do |c|
605 + if @flags.include?(c[0]) and @flags.include?(c[1])
606 + @flags.delete(c[rand(2)])
615 + out = @flags.join(",")
616 + return "flags=(#{out})"
620 def prefix_to_s(name)
623 @@ -112,16 +219,19 @@
624 @rvalue = get_random_name()
625 @name = "/does/not/exist/#{@rvalue}"
627 + @flags = Flags.new()
631 - @rules << FileRule.new(@name, "rm")
632 + @rules << FileRule.new(@name, "rm").to_s
633 0.upto(rand($max_rules - $min_rules) + $min_rules) do |x|
636 - @rules << CapRule.new
638 - @rules << FileRule.new
640 + @rules << CapRule.new.to_s
642 + @rules << RlimitRule.new.to_s
644 + @rules << FileRule.new.to_s
648 @@ -132,10 +242,10 @@
649 out << "# profile for #{@name}"
650 out << "# generated by #{__FILE__} #{$my_version}"
652 - out << "#{@name} {"
653 + out << "#{@name} #{@flags} {"
654 out << " #include <abstractions/base>"
656 - @rules.each { |r| out << r.to_s }
657 + @rules.sort.each { |r| out << " #{r}" }
662 === modified file 'utils/SubDomain.pm'
663 --- utils/SubDomain.pm 2010-03-10 23:30:06 +0000
664 +++ utils/SubDomain.pm 2010-03-26 13:51:21 +0000
665 @@ -6612,10 +6612,14 @@
666 LibAppArmor::free_record($event);
668 #map new c and d to w as logprof doesn't support them yet
682 if ($rmask && !validate_log_mode(hide_log_mode($rmask))) {
683 fatal_error(sprintf(gettext('Log contains unknown mode %s.'),
685 === modified file 'utils/apparmor_notify'
686 --- utils/apparmor_notify 2010-03-10 16:11:26 +0000
687 +++ utils/apparmor_notify 2010-05-27 14:08:12 +0000
690 require File::Basename;
692 -use vars qw($opt_p $opt_s $opt_l $opt_h $opt_v $opt_d $opt_w);
697 my $conf = "/etc/apparmor/notify.conf";
699 $ENV{SHELL} = "/bin/sh";
700 defined($ENV{IFS}) and $ENV{IFS} = ' \t\n';
703 my $prog = File::Basename::basename($0);
705 if ($prog !~ /^[a-zA-Z0-9_\-]+$/) {
710 -my $logfile = "/var/log/kern.log";
711 --e "/var/run/auditd.pid" and $logfile = "/var/log/audit/audit.log";
713 $> == $< or die "Cannot be suid\n";
714 $) == $( or die "Cannot be sgid\n";
717 +our $orig_euid = $>;
719 -getopts('dhlpvs:w:');
730 + 'debug|d' => \$opt_d,
731 + 'help|h' => \$opt_h,
732 + 'since-last|l' => \$opt_l,
733 + 'poll|p' => \$opt_p,
734 + 'verbose|v' => \$opt_v,
735 + 'file|f=s' => \$opt_f,
736 + 'since-days|s=n' => \$opt_s,
737 + 'user|u=s' => \$opt_u,
738 + 'wait|w=n' => \$opt_w,
745 +# monitor file specified with -f, else use audit.log if auditd is running,
746 +# otherwise kern.log
747 +our $logfile = "/var/log/kern.log";
749 + -f $opt_f or die "'$opt_f' does not exist. Aborting\n";
752 + -e "/var/run/auditd.pid" and $logfile = "/var/log/audit/audit.log";
755 +-r $logfile or die "Cannot read '$logfile'\n";
756 +our $logfile_inode = get_logfile_inode($logfile);
757 +our $logfile_size = get_logfile_size($logfile);
758 open (LOGFILE, "<$logfile") or die "Could not open '$logfile'\n";
759 # Drop priviliges, if running as root
762 if (defined($ENV{SUDO_UID}) and defined($ENV{SUDO_GID})) {
763 POSIX::setgid($ENV{SUDO_GID}) or _error("Could not change gid");
764 - POSIX::setuid($ENV{SUDO_UID}) or _error("Could not change uid");
765 + $> = $ENV{SUDO_UID} or _error("Could not change euid");
766 defined($ENV{SUDO_USER}) and $login = $ENV{SUDO_USER};
768 + my $drop_to = $nobody_user;
773 - POSIX::setgid(scalar(getpwnam($nobody_group))) or _error("Could not change gid to '$nobody_group'");
774 - POSIX::setuid(scalar(getpwnam($nobody_user))) or _error("Could not change uid to '$nobody_user'");
775 + POSIX::setgid(scalar(getgrnam($nobody_group))) or _error("Could not change gid to '$nobody_group'");
776 + $> = scalar(getpwnam($drop_to)) or _error("Could not change euid to '$drop_to'");
782 if (defined($prefs{use_group})) {
783 my ($name, $passwd, $gid, $members) = getgrnam($prefs{use_group});
784 - if (not defined($members) or not defined($login) or not grep { $_ eq $login } split(/ /, $members)) {
785 + if (not defined($members) or not defined($login) or (not grep { $_ eq $login } split(/ /, $members) and $login ne "root")) {
786 _error("'$login' must be in '$prefs{use_group}' group. Aborting");
790 defined($name) and $formatted .= "Name: $name\n";
791 defined($denied) and $formatted .= "Denied: $denied\n";
792 defined($family) and defined ($sock_type) and $formatted .= "Family: $family\nSocket type: $sock_type\n";
793 - #defined($date) and $since > 0 and $formatted .= "Date: ". scalar(localtime($date)) ."\n";
794 $formatted .= "Logfile: $logfile\n";
805 + if ($pid == 0) { # child
806 + # notify-send needs $< to be the unprivileged user
809 + # 'system' uses execvp() so no shell metacharacters here.
810 + # $notify_exe is an absolute path so execvp won't search PATH.
811 + system "$notify_exe", "-i", "gtk-dialog-warning", "-u", "critical", "--", "AppArmor Message", "$msg";
812 + my $exit_code = $? >> 8;
826 open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
827 open STDOUT, '>/dev/null' or die "Can't write to /dev/null: $!";
828 - open STDERR, '>/dev/null' or die "Can't write to /dev/null: $!";
829 + #open STDERR, '>/dev/null' or die "Can't write to /dev/null: $!";
832 die "Couldn't fork: $!" unless defined($pid);
833 @@ -293,12 +344,24 @@
835 my $footer = "For more information, please see:\n$url";
837 - my $since = $now - (int($opt_s) * 60 * 60 * 24);
839 + if ($opt_s and int($opt_s) > 0) {
840 + $since = $since - (int($opt_s) * 60 * 60 * 24);
842 for (my $i=0; $time_to_die == 0; $i++) {
843 + if ($logfile_inode != get_logfile_inode($logfile)) {
844 + _warn("$logfile changed inodes, reopening");
846 + } elsif (get_logfile_size($logfile) < $logfile_size) {
847 + _warn("$logfile is smaller, reopening");
850 while(my $msg = <LOGFILE>) {
852 - if ($first_run == 1 and $opt_s) {
853 - @attrib = parse_message($msg, $since);
854 + if ($first_run == 1) {
855 + if ($since != $now) {
856 + @attrib = parse_message($msg, $since);
859 @attrib = parse_message($msg);
865 - # 'system' uses execvp() so no shell metacharacters here.
866 - # $notify_exe is an absolute path so execvp won't search PATH.
867 - system "$notify_exe", "-i", "gtk-dialog-warning", "-u", "critical", "--", "AppArmor Message", "$m";
868 - my $exit_code = $? >> 8;
869 - if ($exit_code != 0) {
870 - _warn("'$notify_exe' exited with '$exit_code'");
871 + my $rc = send_message($m);
873 + _warn("'$notify_exe' exited with error '$rc'");
881 - my $m = "$logfile contains $count existing denied message";
882 + my $m = "$logfile contains $count denied message";
883 $count > 1 and $m .= "s";
885 $m .= " in the last ";
890 - system "$notify_exe", "-i", "gtk-dialog-warning", "-u", "critical", "--", "AppArmor Message", "$m";
903 while(my $msg = <LOGFILE>) {
904 my @attrib = parse_message($msg, $_[0]);
905 @@ -397,10 +460,31 @@
907 my $m = format_message(@attrib);
910 - $opt_v and print "$m\n";
911 + my $date = $attrib[6];
913 + if (exists($msg_hash{$m})) {
915 + defined($date) and $last_date{$m} = scalar(localtime($date));
918 + push(@msg_list, $m);
924 + foreach my $m (@msg_list) {
926 + if ($msg_hash{$m} gt 1) {
927 + print "($msg_hash{$m} found";
928 + if (exists($last_date{$m})) {
929 + print ", most recent from '$last_date{$m}'";
939 @@ -452,19 +536,63 @@
942 USAGE: apparmor_notify [OPTIONS]
944 Display AppArmor notifications or messages for DENIED entries.
947 - -p poll AppArmor logs and display notifications
948 - -l display stats since last login
949 - -s NUM show stats for last NUM days (can be used alone or with -p)
950 - -v show messages with stats
951 - -h display this help
952 - -w NUM wait NUM seconds before displaying notifications (with -p)
953 + -p, --poll poll AppArmor logs and display notifications
954 + -f FILE, --file=FILE search FILE for AppArmor messages
955 + -l, --since-last display stats since last login
956 + -s NUM, --since-days=NUM show stats for last NUM days (can be used alone
958 + -v, --verbose show messages with stats
959 + -h, --help display this help
960 + -u USER, --user=USER user to drop privileges to when not using sudo
961 + -w NUM, --wait=NUM wait NUM seconds before displaying
962 + notifications (with -p)
967 +sub reopen_logfile {
968 + # reopen the logfile, temporarily switching back to starting euid for
969 + # file permissions.
973 + my $change_euid = 0;
975 + _debug("raising privileges to '$orig_euid' in reopen_logfile()");
978 + $> == $orig_euid or die "Could not raise privileges\n";
981 + $logfile_inode = get_logfile_inode($logfile);
982 + $logfile_size = get_logfile_size($logfile);
983 + open (LOGFILE, "<$logfile") or die "Could not open '$logfile'\n";
985 + if ($change_euid) {
986 + _debug("dropping privileges to '$old_euid' in reopen_logfile()");
988 + $> == $old_euid or die "Could not drop privileges\n";
992 +sub get_logfile_size {
995 + defined(($size = (stat($fn))[7])) or (sleep(10) and defined(($size = (stat($fn))[7])) or die "'$fn' disappeared. Aborting\n");
999 +sub get_logfile_inode {
1002 + defined(($inode = (stat($fn))[1])) or (sleep(10) and defined(($inode = (stat($fn))[1])) or die "'$fn' disappeared. Aborting\n");
1010 === modified file 'utils/apparmor_notify.pod'
1011 --- utils/apparmor_notify.pod 2010-02-12 16:25:02 +0000
1012 +++ utils/apparmor_notify.pod 2010-05-12 08:46:22 +0000
1020 poll AppArmor logs and display desktop notifications. Can be used with '-s'
1021 option to display a summary on startup.
1024 +=item -f FILE, --file=FILE
1026 +search FILE for AppArmor messages
1028 +=item -l, --since-last
1030 show summary since last login.
1033 +=item -s NUM, --since-days=NUM
1035 show summary for last NUM of days.
1038 +=item -u USER, --user=USER
1040 +user to drop privileges to when running privileged. This has no effect when
1041 +running under sudo.
1043 +=item -w NUM, --wait=NUM
1045 +wait NUM seconds before displaying notifications (for use with -p)
1047 +=item -v, --verbose
1049 show messages with summaries.
1054 displays a short usage statement.