#!/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 ''."\n"; print ''."\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 '\n'."\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; }