mirror of
https://gitlab.com/apparmor/apparmor.git
synced 2025-03-04 16:35:02 +01:00

utils package and manually fixed some places where perltidy's reformatting made it harder to read. the options used were-- -i=4 # 4-space indentation -l=0 # unlimited line length (for now) -pt=2 # slightly tightened parens -ce # cuddled elses -nolq # don't outdent long quotes -nsfs # don't add spaces in front of semi-colons in for ( ) statements -isbc # only indent block comments that have whitespace in front of them -otr # don't place a break between a comma and an opening brace the code will be refactored to make it possible to switch to using 80-column line-breaks without resorting to really nasty formatting constructs.
222 lines
6.2 KiB
Perl
222 lines
6.2 KiB
Perl
# $Id$
|
|
# ------------------------------------------------------------------
|
|
#
|
|
# 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
|