#!/usr/bin/perl -w # # this script creates a new SELinux type which is the union of several old types # (C) 2005 by Thomas Bleher under the GNU GPL # Idea from Ivan Gyurdiev # # Please note that this is just proof of concept code; it has some limitations: # * assumes every statement is one line # * does not really handle "{ domain - foo_t }" # * does not always handle ~ correctly; this shouldn't be a problem with current policy # * does not handle type_change and type_transition (not sure if there even is a correct way) # * only works on file_type (domains would need role type statements and are more difficult # because of domain_auto_trans()) # * neverallow and constraints are not properly handled # * might generate duplicate permissions (these are not harmful) # # despite this, it should work most of the time # # TODO: support typealias # add better argument support # default to system policy.conf # if (@ARGV < 3) { print STDERR "Usage: createcon [NewType] [Type1] [Type2] [Type3] ...\n"; print STDERR "policy info (policy.conf) is read from standard in\n"; print STDERR "Example: createcon samba_httpd_content_t samba_share_t httpd_sys_content_t < policy.conf\n"; exit(1); } # get command line arguments my ($new_type) = shift(@ARGV); my (@parent_types) = splice(@ARGV, 0, $#ARGV+1); # parse the policy $pat = '(\w+|~?{[^}]+}|\*)\s*'; # $pat matches on foo_t or { foo_t bar_t } or * while (<>) { # remove everything we do not need s/#.*?$//mg; # comments s/^\s*$//mg; # empty lines next if /^[\s\n]*$/; # remove duplicate braces (we have to loop until all are gone) # this is for things like "{ read{getattr {write setattr }}}" while (s/{([^}]*){([^}]*)}/{$1 $2/g) {} if (/if \s* \( ([^\)]+) \)/x) { # save all active bools in a stack push @bools, $1; } elsif (/(allow|dontaudit|auditallow|auditdeny) \s+ $pat \s+ $pat : \s* $pat \s+ $pat;/x) { # normal rules my $bool = join ') && (', @bools; push @{$rules{$1}}, [$2,$3,$4,$5,$bool]; } elsif (/type\s+([^;]+);/) { my @tmp = split /,\s+/, $1; # get attributes my $type = shift @tmp; $types{$type} = [@tmp]; } elsif (/typeattribute\s+(\w+)\s+(\w+)/) { push @{$types{$1}}, $2; } elsif (/\}/) { # this rule has to be the last so we don't grab braces from an allow rule pop @bools; } } # create a new type which is the union of the old types my (%tmp); for (@parent_types) { for (@{$types{$_}}) { $tmp{$_}++; } } print "type $new_type, ", join(", ", keys %tmp), ";\n"; # now create the rules for $ruletype (keys %rules) { for (@{$rules{$ruletype}}) { # traverse all the rules my ($types_expr) = join("|", @parent_types); if ($_->[0] =~ /\b($types_expr)\b/) { # not sure if this is correct; what happens if a type is twice in a rule? $_->[0] = $new_type; # replace source } elsif ($_->[1] =~ /\b($types_expr)\b/) { $_->[1] = $new_type; # replace target } else { # ignore all other rules next; } # now print it if ($_->[4] ne '') { # any bools active? print "if ($_->[4]) {\n"; print "$ruletype $_->[0] $_->[1]:$_->[2] $_->[3];\n"; print "}\n"; } else { print "$ruletype $_->[0] $_->[1]:$_->[2] $_->[3];\n"; } } } __END__ # not used currently, but nice for debugging: # print all the stuff we have extracted for (keys %types) { print "type $_, ", join(", ", @{$types{$_}}), ";\n"; } for $ruletype (keys %rules) { for (@{$rules{$ruletype}}) { if ($_->[4] ne '') { print "if ($_->[4]) {\n$ruletype $_->[0] $_->[1]:$_->[2] $_->[3];\n}\n"; } else { print "$ruletype $_->[0] $_->[1]:$_->[2] $_->[3];\n"; } } }