mirror of
https://gitlab.com/apparmor/apparmor.git
synced 2025-03-05 17:01:00 +01:00

perl utilities to the deprecated to directory; a couple of perl utilities remain, but they are still useful and do not depend on the Immunix module (just the LibAppArmor perl module).
221 lines
6.2 KiB
Perl
221 lines
6.2 KiB
Perl
# ------------------------------------------------------------------
|
|
#
|
|
# 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
|