2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-09-04 00:05:14 +00:00

Added checks for profile syntax and error dialogs in the yastui.

This commit is contained in:
Dominic Reynolds
2006-10-05 21:29:22 +00:00
parent c231a42cf4
commit 1fe7e92955
13 changed files with 230 additions and 114 deletions

View File

@@ -27,24 +27,24 @@ use Data::Dumper;
sub getSubdomainStatus { sub getSubdomainStatus {
my $sdStatus = "disabled"; my $sdStatus = "disabled";
# Ok check that there are profiles loaded to # Ok check that there are profiles loaded to
# determine status # determine status
my $mountpoint = Immunix::SubDomain::check_for_subdomain(); my $mountpoint = Immunix::SubDomain::check_for_subdomain();
if ( $mountpoint ) { if ( $mountpoint ) {
open( PROFILES, "cat $mountpoint/profiles|" ); open( PROFILES, "cat $mountpoint/profiles|" );
while (<PROFILES>) { while (<PROFILES>) {
# Ensure we have loaded profiles # Ensure we have loaded profiles
# not just a loaded module # not just a loaded module
if ( /\// ) { if ( /\// ) {
$sdStatus = "enabled"; $sdStatus = "enabled";
last; last;
} }
}
close PROFILES;
} }
return $sdStatus; close PROFILES;
}
return $sdStatus;
} }
sub getNotifySettings { sub getNotifySettings {
@@ -79,43 +79,58 @@ sub getNotifyStatus {
return $noteStatus; return $noteStatus;
} }
sub profileSyntaxCheck {
my $errlist = [];
Immunix::SubDomain::checkIncludeSyntax($errlist);
Immunix::SubDomain::checkProfileSyntax($errlist);
my @errlist = Immunix::SubDomain::uniq(@$errlist);
return \@errlist;
}
# Main # Main
################################################################################ ################################################################################
my $line = <STDIN>;
my ($command, $path, $argument) = Immunix::Ycp::ParseCommand($line); while ( <STDIN> ) {
my ($command, $path, $argument) = Immunix::Ycp::ParseCommand($_);
my $result = undef; my $result = undef;
my $donereturn = 0; my $donereturn = 0;
if ( $command && $path && $argument ) { if ( $command && $path && $argument ) {
if ( $argument eq 'sd-all') { if ( $argument eq 'sd-all') {
my %hResult = ''; # hashed result, duh my %hResult = ''; # hashed result, duh
$hResult{'sd-status'} = getSubdomainStatus(); $hResult{'sd-status'} = getSubdomainStatus();
$hResult{'sd-notify'} = getNotifyStatus(); $hResult{'sd-notify'} = getNotifyStatus();
Immunix::Ycp::ycpReturnHashAsMap( %hResult ); Immunix::Ycp::ycpReturnHashAsMap( %hResult );
$donereturn = 1; $donereturn = 1;
} elsif ( $argument eq 'sd-status') { } elsif ( $argument eq 'sd-status') {
$result = getSubdomainStatus(); $result = getSubdomainStatus();
} elsif ( $argument eq 'sd-notify') { } elsif ( $argument eq 'sd-notify') {
$result = getNotifyStatus(); $result = getNotifyStatus();
} elsif ( $argument eq 'sd-notify-settings') { } elsif ( $command eq "Read" and $argument eq 'custom-includes') {
$result = getNotifySettings(); Immunix::SubDomain::readconfig();
Immunix::Ycp::ycpReturn($result); Immunix::Ycp::ycpReturn(\@Immunix::SubDomain::custom_includes);
$donereturn = 1; $donereturn = 1;
} } elsif ( $command eq "Execute" and $argument eq 'profile-syntax-check') {
$result = profileSyntaxCheck();
Immunix::Ycp::ycpReturnSkalarAsString( $result ) if ( ! $donereturn ); Immunix::Ycp::ycpReturn($result);
$donereturn = 1;
} else { } elsif ( $argument eq 'sd-notify-settings') {
$result = getNotifySettings();
my $ycpCmd = ycpGetCommand() || ""; Immunix::Ycp::ycpReturn($result);
my $ycpArg = ycpGetArgType() || ""; $donereturn = 1;
$result = "Unknown instruction $ycpCmd or argument: $ycpArg\n"; }
Immunix::Ycp::ycpReturnSkalarAsString( $result ); Immunix::Ycp::ycpReturnSkalarAsString( $result ) if ( ! $donereturn );
} else {
my $ycpCmd = ycpGetCommand() || "";
my $ycpArg = ycpGetArgType() || "";
$result = "Unknown instruction $ycpCmd or argument: $ycpArg\n";
Immunix::Ycp::ycpReturnSkalarAsString( $result );
}
print "\n";
} }
exit 0; exit 0;

View File

@@ -94,7 +94,7 @@ while ( <STDIN> ) {
} }
} elsif ( $command eq "Read") { } elsif ( $command eq "Read") {
$UI_Mode = "yast"; $UI_Mode = "yast";
Immunix::SubDomain::readprofile("$profiledir/$argument"); Immunix::SubDomain::readprofile("$profiledir/$argument", \&$Immunix::SubDomain::fatal_error);
Immunix::Ycp::Return( \%sd ); Immunix::Ycp::Return( \%sd );
} elsif ( $command eq "Write" and $path eq ".delete") { } elsif ( $command eq "Write" and $path eq ".delete") {
if ( $argument ne "" ) { if ( $argument ne "" ) {

View File

@@ -12,6 +12,7 @@
import "Wizard"; import "Wizard";
import "Popup"; import "Popup";
import "Sequencer"; import "Sequencer";
include "subdomain/apparmor_profile_check.ycp";
include "subdomain/apparmor_packages.ycp"; include "subdomain/apparmor_packages.ycp";
textdomain "yast2-apparmor"; textdomain "yast2-apparmor";
@@ -37,6 +38,9 @@
if (!installAppArmorPackages()) { if (!installAppArmorPackages()) {
return; return;
} }
if (!checkProfileSyntax()) {
return;
}
// initiate the handshake with the backend agent // initiate the handshake with the backend agent
map agent_data = (map) SCR::Read(.genprof); map agent_data = (map) SCR::Read(.genprof);

View File

@@ -13,6 +13,7 @@
import "Popup"; import "Popup";
import "Sequencer"; import "Sequencer";
include "subdomain/apparmor_packages.ycp"; include "subdomain/apparmor_packages.ycp";
include "subdomain/apparmor_profile_check.ycp";
textdomain "yast2-apparmor"; textdomain "yast2-apparmor";
boolean done = false; boolean done = false;
@@ -37,6 +38,9 @@
if (!installAppArmorPackages()) { if (!installAppArmorPackages()) {
return; return;
} }
if (!checkProfileSyntax()) {
return;
}
// initiate the handshake with the backend agent // initiate the handshake with the backend agent
map agent_data = (map) SCR::Read(.logprof); map agent_data = (map) SCR::Read(.logprof);

View File

@@ -12,6 +12,7 @@ import "Wizard";
import "Popup"; import "Popup";
import "Sequencer"; import "Sequencer";
include "subdomain/apparmor_packages.ycp"; include "subdomain/apparmor_packages.ycp";
include "subdomain/apparmor_profile_check.ycp";
include "subdomain/profile_dialogs.ycp"; include "subdomain/profile_dialogs.ycp";
textdomain "yast2-apparmor"; textdomain "yast2-apparmor";
@@ -86,6 +87,9 @@ any ret = nil;
if (!installAppArmorPackages()) { if (!installAppArmorPackages()) {
return ret; return ret;
} }
if (!checkProfileSyntax()) {
return ret;
}
ret = MainSequence(); ret = MainSequence();
return ret; return ret;
} }

View File

@@ -12,6 +12,7 @@ import "Wizard";
import "Popup"; import "Popup";
import "Sequencer"; import "Sequencer";
include "subdomain/apparmor_packages.ycp"; include "subdomain/apparmor_packages.ycp";
include "subdomain/apparmor_profile_check.ycp";
include "subdomain/profile_dialogs.ycp"; include "subdomain/profile_dialogs.ycp";
textdomain "yast2-apparmor"; textdomain "yast2-apparmor";
@@ -67,6 +68,11 @@ any ret = nil;
if (!installAppArmorPackages()) { if (!installAppArmorPackages()) {
return ret; return ret;
} }
if (!checkProfileSyntax()) {
return true;
}
ret = MainSequence(); ret = MainSequence();
return ret; return ret;
} }

View File

@@ -12,6 +12,7 @@ import "Wizard";
import "Popup"; import "Popup";
import "Sequencer"; import "Sequencer";
include "subdomain/apparmor_packages.ycp"; include "subdomain/apparmor_packages.ycp";
include "subdomain/apparmor_profile_check.ycp";
include "subdomain/profile_dialogs.ycp"; include "subdomain/profile_dialogs.ycp";
textdomain "yast2-apparmor"; textdomain "yast2-apparmor";
@@ -67,9 +68,16 @@ define any MainSequence() ``{
// YEAH BABY RUN BABY RUN // YEAH BABY RUN BABY RUN
// //
any ret = nil; any ret = nil;
if (!installAppArmorPackages()) { if (!installAppArmorPackages()) {
return ret; return ret;
} }
if (!checkProfileSyntax()) {
return ret;
}
ret = MainSequence(); ret = MainSequence();
return ret; return ret;
} }

View File

@@ -13,6 +13,7 @@ import "Wizard";
import "Popup"; import "Popup";
import "Sequencer"; import "Sequencer";
include "subdomain/apparmor_packages.ycp"; include "subdomain/apparmor_packages.ycp";
include "subdomain/apparmor_profile_check.ycp";
include "subdomain/reporting_dialogues.ycp"; include "subdomain/reporting_dialogues.ycp";
include "subdomain/report_helptext.ycp"; include "subdomain/report_helptext.ycp";
textdomain "yast2-apparmor"; textdomain "yast2-apparmor";
@@ -29,11 +30,6 @@ define any mainSequence() ``{
"schedReport" : ``(displaySchedForm()), "schedReport" : ``(displaySchedForm()),
"viewreport" : ``(displayArchForm()), "viewreport" : ``(displayArchForm()),
"runReport" : ``(displayRunForm()) "runReport" : ``(displayRunForm())
/*
"addSched" : ``(addSchedForm()),
"editSched" : ``(editSchedForm()),
"delSched" : ``(delSchedForm())
*/
]; ];
map sequence = $[ map sequence = $[
@@ -48,44 +44,18 @@ define any mainSequence() ``{
"schedReport": $[ "schedReport": $[
`back : `ws_start, `back : `ws_start,
`abort : `abort, `abort : `abort,
// `add : "mainreport",
// `edit : "editSched",
// `del : "delSched",
`viewrep : "viewreport", `viewrep : "viewreport",
`runrep : "runReport", `runrep : "runReport",
`next : "runReport", `next : "runReport",
`finish : `ws_finish `finish : `ws_finish
], ],
/*
"addSched" : $[
`back : "schedReport",
`abort : `abort,
`save : `finish,
`finish : `ws_finish
],
"editSched" : $[
`back : "schedReport",
`abort : `abort,
`save : `finish,
`finish : `ws_finish
],
"delSched" : $[
`back : "schedReport",
`abort : `abort,
`save : `finish,
`finish : `ws_finish
],
*/
"viewreport" : $[ "viewreport" : $[
//`back : "viewreport",
`back : "mainreport", `back : "mainreport",
`abort : `abort, `abort : `abort,
//`next : `finish,
`next : "mainreport", `next : "mainreport",
`finish : `ws_finish `finish : `ws_finish
], ],
"runReport": $[ "runReport": $[
//`back : "runReport",
`back : `back, `back : `back,
`abort : `abort, `abort : `abort,
`next : `finish, `next : `finish,
@@ -116,9 +86,13 @@ any ret = nil;
if (!installAppArmorPackages()) { if (!installAppArmorPackages()) {
return ret; return ret;
} }
checkProfileSyntax();
ret = mainSequence(); ret = mainSequence();
return ret; return ret;
} }

View File

@@ -622,15 +622,34 @@ define symbol DisplayProfileForm(string pathname, boolean hat) {
return `showhat; return `showhat;
} }
} else if ( id == `include ) { } else if ( id == `include ) {
string newInclude = UI::AskForExistingFile( "/etc/apparmor.d", "", _("Select File To Include")); any ci = SCR::Read(.subdomain, "custom-includes");
if ( newInclude == nil || (string)newInclude == "" ) { list <any> customIncludes = tolist(ci);
string newInclude = UI::AskForExistingFile( "/etc/apparmor.d/abstractions", "", _("Select File To Include"));
if ( newInclude == nil || (string)newInclude == "" ) {
continue; continue;
} }
integer includeRootBad = find (newInclude, "/etc/apparmor.d"); list <string> validIncludes = [ "/etc/apparmor.d/abstractions", "/etc/apparmor.d/program-chunks", "/etc/apparmor.d/tunables" ];
if ( includeRootBad == -1 ) { foreach( any incPath, (list<any>) customIncludes, {
Popup::Error("AppArmor include files must be located in the directory /etc/apparmor.d"); string incPathStr = tostring(incPath);
validIncludes = add( validIncludes, "/etc/apparmor.d/" + incPathStr);
});
integer result = 0;
boolean includePathOK = false;
foreach( string pathToCheck, (list<string>) validIncludes, {
result = find (newInclude, pathToCheck);
if ( result != -1 ) {
includePathOK = true;
}
});
if ( ! includePathOK ) {
string pathListMsg = "";
foreach( string pathItem, (list<string>) validIncludes, {
pathListMsg = pathListMsg + "\n " + pathItem;
});
Popup::Error(_("Invalid #include file. Include files must be located in one of these directores: \n") + pathListMsg );
} else { } else {
// string includeName = substring(newInclude, 17 );
string includeName = substring(newInclude, 16 ); string includeName = substring(newInclude, 16 );
includes = add( includes, includeName, 1 ); includes = add( includes, includeName, 1 );
profile["include"] = includes; profile["include"] = includes;
@@ -647,7 +666,7 @@ define symbol DisplayProfileForm(string pathname, boolean hat) {
if ( ! hat ) { if ( ! hat ) {
if (Popup::YesNoHeadline(_("Save changes to the Profile"), if (Popup::YesNoHeadline(_("Save changes to the Profile"),
"Would you like to save the changes to this profile? \n(Note: after saving the changes the AppArmor profiles will be reloaded.)")) { "Would you like to save the changes to this profile? \n(Note: after saving the changes the AppArmor profiles will be reloaded.)")) {
map argmap = $[ "PROFILE_HASH" : Settings["PROFILE_MAP"]:$[], map argmap = $[ "PROFILE_HASH" : Settings["PROFILE_MAP"]:$[],
"PROFILE_NAME" : pathname "PROFILE_NAME" : pathname
]; ];
any result = SCR::Write(.subdomain_profiles, argmap); any result = SCR::Write(.subdomain_profiles, argmap);
@@ -677,7 +696,7 @@ define symbol DisplayProfileForm(string pathname, boolean hat) {
// //
// Select a profile to edit and populate // Select a profile to edit and populate

View File

@@ -17,7 +17,7 @@
Summary: Yast2 plugins for AppArmor management Summary: Yast2 plugins for AppArmor management
Name: yast2-apparmor Name: yast2-apparmor
Version: @@immunix_version@@ Version: @@immunix_version@@
Release: 7.10 Release: 7.11
Group: Productivity/Security Group: Productivity/Security
Source0: %{name}-%{version}-@@repo_version@@.tar.gz Source0: %{name}-%{version}-@@repo_version@@.tar.gz
License: GPL and LGPL License: GPL and LGPL
@@ -88,6 +88,8 @@ REPDIR3='/var/log/apparmor/reports-exported'
%preun %preun
%changelog %changelog
* Thu Oct 5 2006 Dominic Reynolds <dreynolds@suse.de> 2.0-7.11
- Add syntax checks for profiles and display to user.
* Wed May 31 2006 Dominic Reynolds <dreynolds@suse.de> 2.0-7.10 * Wed May 31 2006 Dominic Reynolds <dreynolds@suse.de> 2.0-7.10
- Fixes for https://bugzilla.novell.com/show_bug.cgi?id=175388, - Fixes for https://bugzilla.novell.com/show_bug.cgi?id=175388,
https://bugzilla.novell.com/show_bug.cgi?id=172061. Added support https://bugzilla.novell.com/show_bug.cgi?id=172061. Added support

View File

@@ -36,7 +36,7 @@ use Immunix::Severity;
require Exporter; require Exporter;
our @ISA = qw(Exporter); our @ISA = qw(Exporter);
our @EXPORT = qw(%sd $filename $profiledir $parser %qualifiers %include %helpers $UI_Mode which getprofilefilename getprofileflags setprofileflags complain enforce autodep reload UI_GetString UI_GetFile UI_YesNo UI_Important UI_Info getkey do_logprof_pass readconfig loadincludes check_for_subdomain UI_PromptUser $running_under_genprof GetDataFromYast SendDataToYast setup_yast shutdown_yast readprofile readprofiles writeprofile get_full_path fatal_error); our @EXPORT = qw(%sd $filename $profiledir $parser %qualifiers %include %helpers $UI_Mode which getprofilefilename getprofileflags setprofileflags complain enforce autodep reload UI_GetString UI_GetFile UI_YesNo UI_Important UI_Info getkey do_logprof_pass readconfig loadincludes check_for_subdomain UI_PromptUser $running_under_genprof GetDataFromYast SendDataToYast setup_yast shutdown_yast readprofile readprofiles writeprofile get_full_path fatal_error checkProfileSyntax checkIncludeSyntax);
no warnings 'all'; no warnings 'all';
@@ -95,6 +95,7 @@ our %qualifiers;
our %required_hats; our %required_hats;
our %defaulthat; our %defaulthat;
our %globmap; our %globmap;
our @custom_includes;
# these are globs that the user specifically entered. we'll keep track of # these are globs that the user specifically entered. we'll keep track of
# them so that if one later matches, we'll suggest it again. # them so that if one later matches, we'll suggest it again.
@@ -1359,7 +1360,7 @@ sub do_logprof_pass {
%variables = ( ); %variables = ( );
UI_Info(sprintf(gettext('Reading log entries from %s.'), $filename)); UI_Info(sprintf(gettext('Reading log entries from %s.'), $filename));
UI_Info(sprintf(gettext('Updating subdomain profiles in %s.'), $profiledir)); UI_Info(sprintf(gettext('Updating AppArmor profiles in %s.'), $profiledir));
readprofiles(); readprofiles();
@@ -1778,15 +1779,24 @@ sub do_logprof_pass {
# check the path against the available set of include files # check the path against the available set of include files
my @newincludes; my @newincludes;
my $includevalid;
for my $incname (keys %include) { for my $incname (keys %include) {
$includevalid = 0;
# don't suggest it if we're already including it, that's dumb # don't suggest it if we're already including it, that's dumb
next if $sd{$profile}{$hat}{$incname}; next if $sd{$profile}{$hat}{$incname};
# only match includes that can be suggested to the user
for my $incmatch( @custom_includes ) {
$includevalid = 1 if $incname =~ /$incmatch/;
}
$includevalid = 1 if $incname =~ /abstractions/;
next if ( $includevalid == 0 );
($cm, @m) = matchinclude($incname, $path); ($cm, @m) = matchinclude($incname, $path);
if($cm && contains($cm, $mode)) { if($cm && contains($cm, $mode)) {
unless(grep { $_ eq "/**" } @m) { unless(grep { $_ eq "/**" } @m) {
push @newincludes, $incname if $incname =~ /abstractions/; push @newincludes, $incname;
} }
} }
} }
@@ -2135,18 +2145,70 @@ sub contains ($$) {
return 1; return 1;
} }
sub checkIncludeSyntax($) {
my $errors = shift;
if(opendir(SDDIR, $profiledir )) {
my @incdirs = grep { (! /^\./) && (-d "$profiledir/$_") } readdir(SDDIR);
close(SDDIR);
while(my $id = shift @incdirs) {
if(opendir(SDDIR, "$profiledir/$id" )) {
for my $path (grep { ! /^\./ } readdir(SDDIR)) {
chomp($path);
next if $path =~ /\.rpm(save|new)$/;
if(-f "$profiledir/$id/$path") {
my $file = "$id/$path";
$file =~ s/$profiledir\///;
my $err = loadinclude($file, \&printMessageErrorHandler);
if ( $err ne 0 ) {
push @$errors, $err;
}
} elsif(-d "$id/$path") {
push @incdirs, "$id/$path";
}
}
closedir(SDDIR);
}
}
}
return $errors;
}
sub checkProfileSyntax ($) {
my $errors = shift;
# Check the syntax of profiles
opendir(SDDIR, $profiledir) or fatal_error "Can't read AppArmor profiles in $profiledir.";
for my $file (grep { -f "$profiledir/$_" } readdir(SDDIR)) {
next if $file =~ /\.rpm(save|new)$/;
my $err = readprofile( "$profiledir/$file", \&printMessageErrorHandler);
if ( defined $err and $err ne 1) {
push @$errors, $err;
}
}
closedir(SDDIR);
return $errors;
}
sub printMessageErrorHandler ($) {
my $message = shift;
return $message
}
sub readprofiles () { sub readprofiles () {
opendir(SDDIR, $profiledir) or fatal_error "Can't read AppArmor profiles in $profiledir."; opendir(SDDIR, $profiledir) or fatal_error "Can't read AppArmor profiles in $profiledir.";
for my $file (grep { -f "$profiledir/$_" } readdir(SDDIR)) { for my $file (grep { -f "$profiledir/$_" } readdir(SDDIR)) {
next if $file =~ /\.rpm(save|new)$/; next if $file =~ /\.rpm(save|new)$/;
readprofile("$profiledir/$file"); readprofile("$profiledir/$file", \&fatal_error);
} }
closedir(SDDIR); closedir(SDDIR);
} }
sub readprofile ($) { sub readprofile ($$) {
my $file = shift; my $file = shift;
my $error_handler = shift;
if(open(SDPROF, "$file")) { if(open(SDPROF, "$file")) {
my ($profile, $hat, $in_contained_hat); my ($profile, $hat, $in_contained_hat);
my $initial_comment = ""; my $initial_comment = "";
@@ -2162,7 +2224,7 @@ sub readprofile ($) {
# if we run into the start of a profile while we're already in a # if we run into the start of a profile while we're already in a
# profile, something's wrong... # profile, something's wrong...
if($profile) { if($profile) {
fatal_error "$profile profile in $file contains syntax errors."; return &$error_handler( "$profile profile in $file contains syntax errors.");
} }
# we hit the start of a profile, keep track of it... # we hit the start of a profile, keep track of it...
@@ -2202,7 +2264,7 @@ sub readprofile ($) {
# if we hit the end of a profile when we're not in one, something's # if we hit the end of a profile when we're not in one, something's
# wrong... # wrong...
if(not $profile) { if(not $profile) {
fatal_error(sprintf(gettext('%s contains syntax errors.'), $file)); return &$error_handler( sprintf(gettext('%s contains syntax errors.'), $file));
} }
if($in_contained_hat) { if($in_contained_hat) {
@@ -2232,7 +2294,7 @@ sub readprofile ($) {
} elsif(m/^\s*capability\s+(\S+)\s*,\s*$/) { # capability entry } elsif(m/^\s*capability\s+(\S+)\s*,\s*$/) { # capability entry
if(not $profile) { if(not $profile) {
fatal_error(sprintf(gettext('%s contains syntax errors.'), $file)); return &$error_handler(sprintf(gettext('%s contains syntax errors.'), $file));
} }
my $capability = $1; my $capability = $1;
@@ -2246,7 +2308,7 @@ sub readprofile ($) {
} elsif(m/^\s*if\s+(not\s+)?defined\s+(\$\{?[[:alpha:]][[:alnum:]_]+\}?)\s*\{\s*$/) { # conditional -- boolean defined } elsif(m/^\s*if\s+(not\s+)?defined\s+(\$\{?[[:alpha:]][[:alnum:]_]+\}?)\s*\{\s*$/) { # conditional -- boolean defined
} elsif(m/^\s*([\"\@\/].*)\s+(\S+)\s*,\s*$/) { # path entry } elsif(m/^\s*([\"\@\/].*)\s+(\S+)\s*,\s*$/) { # path entry
if(not $profile) { if(not $profile) {
fatal_error(sprintf(gettext('%s contains syntax errors.'), $file)); return &$error_handler(sprintf(gettext('%s contains syntax errors.'), $file));
} }
my ($path, $mode) = ($1, $2); my ($path, $mode) = ($1, $2);
@@ -2260,7 +2322,7 @@ sub readprofile ($) {
my $p_re = convert_regexp($path); my $p_re = convert_regexp($path);
eval { "foo" =~ m/^$p_re$/; }; eval { "foo" =~ m/^$p_re$/; };
if($@) { if($@) {
fatal_error sprintf(gettext('Profile %s contains invalid regexp %s.'), $file, $path); return &$error_handler(sprintf(gettext('Profile %s contains invalid regexp %s.'), $file, $path));
} }
$sd{$profile}{$hat}{path}{$path} = $mode; $sd{$profile}{$hat}{path}{$path} = $mode;
@@ -2276,12 +2338,12 @@ sub readprofile ($) {
} }
$variables{$file}{"#" . $include} = 1; # sorry $variables{$file}{"#" . $include} = 1; # sorry
} }
my $ret = loadinclude($include, $error_handler);
loadinclude($include); return $ret if ( $ret != 0 );
} elsif(/^\s*(tcp_connect|tcp_accept|udp_send|udp_receive)/) { } elsif(/^\s*(tcp_connect|tcp_accept|udp_send|udp_receive)/) {
if(not $profile) { if(not $profile) {
fatal_error(sprintf(gettext('%s contains syntax errors.'), $file)); return &$error_handler(sprintf(gettext('%s contains syntax errors.'), $file));
} }
# XXX - BUGBUGBUG - don't strip netdomain entries # XXX - BUGBUGBUG - don't strip netdomain entries
@@ -2301,7 +2363,7 @@ sub readprofile ($) {
# if we hit the start of a contained hat when we're not in a profile # if we hit the start of a contained hat when we're not in a profile
# something is wrong... # something is wrong...
if(not $profile) { if(not $profile) {
fatal_error(sprintf(gettext('%s contains syntax errors.'), $file)); return &$error_handler(sprintf(gettext('%s contains syntax errors.'), $file));
} }
$in_contained_hat = 1; $in_contained_hat = 1;
@@ -2338,20 +2400,19 @@ sub readprofile ($) {
} else { } else {
# we hit something we don't understand in a profile... # we hit something we don't understand in a profile...
fatal_error(sprintf(gettext('%s contains syntax errors.'), $file)); return &$error_handler(sprintf(gettext('%s contains syntax errors.'), $file));
} }
} }
# if we're still in a profile when we hit the end of the file, it's bad # if we're still in a profile when we hit the end of the file, it's bad
if($profile) { if($profile) {
fatal_error "Reached the end of $file while we were still inside the $profile profile."; return &$error_handler("Reached the end of $file while we were still inside the $profile profile.");
} }
close(SDPROF); close(SDPROF);
} else { } else {
$DEBUGGING && debug "readprofile: can't read $file - skipping"; $DEBUGGING && debug "readprofile: can't read $file - skipping";
} }
} }
sub escape($) { sub escape($) {
@@ -2476,7 +2537,7 @@ sub writeprofile ($) {
open(SDPROF, ">$filename") or fatal_error "Can't write new AppArmor profile $filename: $!"; open(SDPROF, ">$filename") or fatal_error "Can't write new AppArmor profile $filename: $!";
# stick in a vim mode line to turn on subdomain syntax highlighting # stick in a vim mode line to turn on AppArmor syntax highlighting
print SDPROF "# vim:syntax=apparmor\n"; print SDPROF "# vim:syntax=apparmor\n";
# keep track of when the file was last updated # keep track of when the file was last updated
@@ -2557,7 +2618,7 @@ sub matchliteral {
sub reload ($) { sub reload ($) {
my $bin = shift; my $bin = shift;
# don't try to reload profile if subdomain is not running # don't try to reload profile if AppArmor is not running
return unless check_for_subdomain(); return unless check_for_subdomain();
# don't reload the profile if the corresponding executable doesn't exist # don't reload the profile if the corresponding executable doesn't exist
@@ -2570,9 +2631,10 @@ sub reload ($) {
sub loadinclude { sub loadinclude {
my $which= shift; my $which= shift;
my $error_handler = shift;
# don't bother loading it again if we already have # don't bother loading it again if we already have
return if $include{$which}; return 0 if $include{$which};
my @loadincludes = ( $which ); my @loadincludes = ( $which );
while(my $incfile = shift @loadincludes) { while(my $incfile = shift @loadincludes) {
@@ -2602,7 +2664,7 @@ sub loadinclude {
my $p_re = convert_regexp($path); my $p_re = convert_regexp($path);
eval { "foo" =~ m/^$p_re$/; }; eval { "foo" =~ m/^$p_re$/; };
if($@) { if($@) {
fatal_error sprintf(gettext('Include %s contains invalid regexp %s.'), $incfile, $path); return &$error_handler(sprintf(gettext('Include file %s contains invalid regexp %s.'), $incfile, $path));
} }
$include{$incfile}{path}{$path} = $mode; $include{$incfile}{path}{$path} = $mode;
@@ -2625,12 +2687,12 @@ sub loadinclude {
next if /^\s*\#/; next if /^\s*\#/;
# we hit something we don't understand in a profile... # we hit something we don't understand in a profile...
fatal_error sprintf(gettext('%s contains syntax errors.'), $incfile); return &$error_handler(sprintf(gettext('Include file %s contains syntax errors or is not a valid #include file.'), $incfile));
} }
} }
close(INCLUDE); close(INCLUDE);
} }
return 0;
} }
sub rematchfrag{ sub rematchfrag{
@@ -2664,7 +2726,7 @@ sub matchincludes {
# scan the include fragments for this profile looking for matches # scan the include fragments for this profile looking for matches
my @includelist = keys %{$frag->{include}}; my @includelist = keys %{$frag->{include}};
while(my $include = shift @includelist) { while(my $include = shift @includelist) {
loadinclude($include); loadinclude($include, \&fatal_error);
my ($cm, @m) = rematchfrag($include{$include}, $path); my ($cm, @m) = rematchfrag($include{$include}, $path);
if($cm) { if($cm) {
$combinedmode .= $cm; $combinedmode .= $cm;
@@ -2741,6 +2803,11 @@ sub readconfig () {
} elsif($which eq "required_hats") { } elsif($which eq "required_hats") {
$required_hats{$key} = $value; $required_hats{$key} = $value;
} }
} elsif(m/^\s*(\S+)\s*$/) {
my $val = $1;
if($which eq "custom_includes") {
push @custom_includes, $val;
}
} }
} }
close(LPCONF); close(LPCONF);
@@ -2760,7 +2827,7 @@ if(opendir(SDDIR, $profiledir )) {
if(-f "$profiledir/$id/$path") { if(-f "$profiledir/$id/$path") {
my $file = "$id/$path"; my $file = "$id/$path";
$file =~ s/$profiledir\///; $file =~ s/$profiledir\///;
loadinclude($file); loadinclude($file, \&fatal_error);
} elsif(-d "$id/$path") { } elsif(-d "$id/$path") {
push @incdirs, "$id/$path"; push @incdirs, "$id/$path";
} }

View File

@@ -25,7 +25,7 @@
Summary: AppArmor userlevel utilities that are useful in creating AppArmor profiles. Summary: AppArmor userlevel utilities that are useful in creating AppArmor profiles.
Name: apparmor-utils Name: apparmor-utils
Version: @@immunix_version@@ Version: @@immunix_version@@
Release: 6 Release: 7
Group: Productivity/Security Group: Productivity/Security
Source0: %{name}-%{version}-@@repo_version@@.tar.gz Source0: %{name}-%{version}-@@repo_version@@.tar.gz
License: GPL License: GPL
@@ -95,6 +95,8 @@ fi
%changelog %changelog
* Thu Oct 5 2006 - <dreynolds@suse.de> 2.0-7
- add support syntax checking for profiles.
* Thu Jun 01 2006 - jmichael@suse.de * Thu Jun 01 2006 - jmichael@suse.de
- add support for the new m mode (#175388) - add support for the new m mode (#175388)
- add support for the new Px/Ux modes (#172061) - add support for the new Px/Ux modes (#172061)

View File

@@ -98,3 +98,14 @@
^/etc/pam.d/[^\/]+$ = /etc/pam.d/* ^/etc/pam.d/[^\/]+$ = /etc/pam.d/*
^/etc/profile.d/[^\/]+\.sh$ = /etc/profile.d/*.sh ^/etc/profile.d/[^\/]+\.sh$ = /etc/profile.d/*.sh
[custom_includes]
# custom directory locations to look for #includes
#
# One directory name per-line - each name should be a valid directory
# containing possble #include candidate fies under the profile dir
# which by default is /etc/apparmor.d.
# So an entry of my-includes will allow /etc/apparmor.d/my-includes to
# be used by the yast UI and profiling tools as a source of #include
# files.