diff options
author | Sumit Bose <sbose@nb.localdomain> | 2008-09-17 20:43:35 +0200 |
---|---|---|
committer | Sumit Bose <sbose@nb.localdomain> | 2008-09-17 20:43:35 +0200 |
commit | 575f23f9ca93b302cb487c037edcbb8bf7554437 (patch) | |
tree | 1a83800c45546e2a5ee660d92710cfd9d883c884 | |
download | ipa_policy-575f23f9ca93b302cb487c037edcbb8bf7554437.tar.gz ipa_policy-575f23f9ca93b302cb487c037edcbb8bf7554437.tar.xz ipa_policy-575f23f9ca93b302cb487c037edcbb8bf7554437.zip |
Initial Import
-rw-r--r-- | sudoers2xml | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/sudoers2xml b/sudoers2xml new file mode 100644 index 0000000..4ce9b18 --- /dev/null +++ b/sudoers2xml @@ -0,0 +1,214 @@ +#!/usr/bin/env perl +use strict; +use feature 'state'; +use Data::Dumper; +# +# Converts a sudoers file to LDIF format in prepration for loading into +# the LDAP server. +# +# $Sudo: sudoers2ldif,v 1.2.2.1 2007/06/28 14:45:19 millert Exp $ +# + +# BUGS: +# Does not yet handle multiple lines with : in them +# Does not yet remove quotation marks from options +# Does not yet escape + at the beginning of a dn +# Does not yet handle line wraps correctly +# Does not yet handle multiple roles with same name (needs tiebreaker) +# Sudoers entries can have multiple Runas entries that override former ones, +# with LDAP sudoRunas applies to all commands in a sudoRole + +my %UA; +my %HA; +my %CA; +my %RA; +##my $base=$ENV{SUDOERS_BASE} or die "$0: Container SUDOERS_BASE undefined\n"; +my @options=(); + +my %user_group_namespaces=(); +$user_group_namespaces{'netgroup'}='xmlns="http://freeipa.org/xml/rng/netgroup/1.0"'; +$user_group_namespaces{'posixGroup'}='xmlns="http://freeipa.org/xml/rng/posixGroup/1.0"'; +$user_group_namespaces{'user'}='xmlns="http://freeipa.org/xml/rng/user/1.0"'; +my %user_group_attributename=(); +$user_group_attributename{'netgroup'}='groupnames'; +$user_group_attributename{'posixGroup'}='gids'; +$user_group_attributename{'user'}='uids'; + +my $did_defaults=0; + +print '<?xml version="1.0" encoding="UTF-8"?>'."\n"; +print '<ipa xmlns="http://freeipa.org/xml/rng/ipa/1.0">'."\n"; + +# parse sudoers one line at a time +while (<>){ + + # remove comment + s/#.*//; + + # line continuation + $_.=<> while s/\\\s*$//s; + + # cleanup newline + chomp; + + # ignore blank lines + next if /^\s*$/; + + if (/^Defaults\s+/i) { + my $opt=$'; + $opt=~s/\s+$//; # remove trailing whitespace + push @options,$opt; + } elsif (/^Defaults[:@>]/i) { + #ignore + my $opt=$'; + } elsif (/^(\S+)\s+(.+)=\s*(.*)/) { + + # Aliases or Definitions + my ($p1,$p2,$p3)=($1,$2,$3); + $p2=~s/\s+$//; # remove trailing whitespace + $p3=~s/\s+$//; # remove trailing whitespace + + if ($p1 eq "User_Alias") { + $UA{$p2}=$p3; + } elsif ($p1 eq "Host_Alias") { + $HA{$p2}=$p3; + } elsif ($p1 eq "Cmnd_Alias") { + $CA{$p2}=$p3; + } elsif ($p1 eq "Runas_Alias") { + $RA{$p2}=$p3; + } else { + if (!$did_defaults++){ + # do this once + ##print "dn: cn=defaults,$base\n"; + ##print "objectClass: top\n"; + ##print "objectClass: sudoRole\n"; + ##print "cn: defaults\n"; + ##print "description: Default sudoOption's go here\n"; + ##print "sudoOption: $_\n" foreach @options; + print '<sudoOptions xmlns="http://freeipa.org/xml/rng/sudo/sudoOptions/1.0" '; + #print "$_ " foreach @options; + foreach ( split /,/, (join ',', @options) ) { + $_ =~ s/=(.*)/=\"$1\"/; + print "$_ "; + } + print "/>\n"; + print "\n"; + } + # Definition + my @users=split /\s*,\s*/,$p1; + my @hosts=split /\s*,\s*/,$p2; + $p3 =~ s/\\,/\\#/g; + my @cmds= split /\s*,\s*/,$p3; + s/\\#/,/g foreach @cmds; + @options=(); + foreach my $user (expand(\%UA, @users)) { + my $type="user"; + $type="posixGroup" if $user =~ s/^%//; + $type="netgroup" if $user =~ s/^\+//; + print "<$type $user_group_namespaces{$type} $user_group_attributename{$type}=\"$user\">\n"; + tl(1); + # only "global" user options here!!! + #if (@options) { + # print tl() . '<sudoOptions xmlns="http://freeipa.org/xml/rng/sudo/sudoOptions/1.0"'; + # print "$_ " foreach @options; + # print "/>\n"; + #} + print tl() . '<sudoers xmlns="http://freeipa.org/xml/rng/sudo/sudoers/1.0">'."\n"; + tl(1); +#print Dumper(%CA, @cmds); + my @mycmds=@cmds; + #foreach my $command (expand(\%CA,@cmds)) { + foreach my $command (@mycmds) { + my $runas=''; + if ( $command =~ s/^\(([^\)]+)\)\s*//) { + $runas .= "<runas>$_</runas>" foreach expand(\%RA, split(/,\s*/, $1)); + } + foreach (expand(\%CA,$command)) { + my $tag=''; + if (@options) { + $tag = '<tag>'; + $tag .= "$_ " foreach @options; + $tag =~ s/ $/<\/tag>/; + } + print tl() . "<command><path>$_</path>$tag$runas</command>\n" + } + @options=(); + } + tl(-1); + print tl() . "</sudoers>\n"; + tl(-1); + ##print "dn: cn=$users[0],$base\n"; + ##print "objectClass: top\n"; + ##print "objectClass: sudoRole\n"; + ##print "cn: $users[0]\n"; + # will clobber options + ##print "sudoUser: $_\n" foreach expand(\%UA,@users); + ##print "sudoHost: $_\n" foreach expand(\%HA,@hosts); + ##my $runas = undef; + ##foreach (@cmds) { + ##if (s/^\(([^\)]+)\)\s*//) { + ##print "sudoRunas: $_\n" foreach expand(\%UA, split(/,\s*/, $1)); + ##} + ##} + ##print "sudoCommand: $_\n" foreach expand(\%CA,@cmds); + ##print "sudoOption: $_\n" foreach @options; + print "</$type>\n"; + print "\n"; + } + } + + } else { + print "parse error: $_\n"; + } + +} +print '</ipa>'."\n"; + +# +# recursively expand hash elements +sub expand{ + my $ref=shift; + my @a=(); + + # preen the line a little + foreach (@_){ + # if NOPASSWD: directive found, mark entire entry as not requiring + s/NOPASSWD:\s*// && push @options,'NOPASSWD'; + s/PASSWD:\s*// && push @options,'PASSWD'; + s/NOEXEC:\s*// && push @options,"NOEXEC"; + s/EXEC:\s*// && push @options,"EXEC"; + s/SETENV:\s*// && push @options,"SETENV"; + s/NOSETENV:\s*// && push @options,"NOSETENV"; + s/\w+://; # silently remove other directives + s/\s+$//; # right trim + } + + # do the expanding + #push @a,$ref->{$_} ? expand($ref,split /\s*,\s*/,$ref->{$_}):$_ foreach @_; + foreach (@_) { + if ( s/^!// ) { + my @dummy = $ref->{$_} ? expand($ref,split /\s*,\s*/,$ref->{$_}):$_; + s/^/!/ foreach @dummy; + push @a, @dummy; + } else { + push @a, $ref->{$_} ? expand($ref,split /\s*,\s*/,$ref->{$_}):$_; + } + } + @a; +} + +sub tl { + my $d = @_?$_[0]:0; + + state $tablevel=0; + +#print $d."\n"; +#print "t=" . $tablevel."\n"; + + $tablevel += $d; +#print "t2=" . $tablevel."\n"; + $tablevel=0 if ( $tablevel < 0 ); +#print "t3=" . $tablevel."\n"; + + return "\t" x $tablevel; +} |