#!/usr/bin/perl -w #============================================================================== # lat-dump # ======== # 0.9.0 (2004-09-08) # (c)2003-2004 Altiplano bvba #============================================================================== package esmith; use strict; use esmith::config; use esmith::db; use esmith::util; use Getopt::Long; use Pod::Usage; my %conf; tie %conf, 'esmith::config'; my %accounts; tie %accounts, 'esmith::config', '/home/e-smith/db/accounts'; my %hosts; tie %hosts, 'esmith::config', '/home/e-smith/db/hosts'; my %domains; tie %domains, 'esmith::config', '/home/e-smith/db/domains'; my %processmail; # Really unsure of what this line does - John Bennett tie %processmail, 'esmith::config', '/home/e-smith/db/processmail'; my ($Dump, $OutDir, $Hlp); my $HostName = db_get(\%conf, 'SystemName'); #============================================================================== # Main #============================================================================== # Analyze commandline options GetOptions ("help" => \$Hlp, "dump" => \$Dump, "output-path=s" => \$OutDir); if ( $Hlp ) { &PrintPod(9); exit; } if ($OutDir) { if ( ! -d $OutDir ) { die "Error: $OutDir is not a directory\n\a"; } } else { $OutDir = "./"; } if ($Dump) { print "Creating input files for the lat-toolkit... "; &ReadUsers; &ReadPseudonyms; &ReadProcmail; &ReadQuota; &ReadGroups; &ReadPPTP; &ReadIbays; &ReadDomains; &ReadHosts; &ReadShadow; open (REST, "> $OutDir/lat-restore"); print REST "#!/bin/bash\n"; print REST "echo 'This script was automatically created by lat-dump and will recreate all user'\n"; print REST "echo 'accounts, ibays, etc on this server.'\n"; print REST "echo 'Do you want to continue (Y/N)?'\n"; print REST "read c\n"; print REST 'if [ $c = "y" ] || [ $c = "Y" ]; then'."\n"; print REST " /usr/sbin/lat-users -a -i=$HostName.Users\n"; print REST " /usr/sbin/lat-procmail -i=$HostName.Procmail\n"; print REST " /usr/sbin/lat-quota -i=$HostName.Quota\n"; print REST " /usr/sbin/lat-groups -a -i=$HostName.Groups\n"; print REST " /usr/sbin/lat-pptp -i=$HostName.PPTP\n"; print REST " /usr/sbin/lat-ibays -a -i=$HostName.Ibays\n"; print REST " /usr/sbin/lat-domains -a -i=$HostName.Domains\n"; print REST " /usr/sbin/lat-hosts -a -i=$HostName.Hosts\n"; print REST " /usr/sbin/lat-pseudonyms -a -i=$HostName.Pseudonyms\n"; print REST " /usr/sbin/lat-shadow -a -i=$HostName.shadow\n"; print REST "else\n"; print REST " echo 'Action cancelled!'\n"; print REST "fi\n"; close(REST); chmod 0750, "$OutDir/lat-restore"; print "\nDone!\n"; print "Use lat-restore to recreate the accounts, ibays, etc on a different server \nor on a clean install.\n"; } else { &PrintPod(1); exit; } #============================================================================== # Subroutines #============================================================================== sub ReadShadow { open(BACACC, "> $OutDir/$HostName.shadow"); print BACACC "#--------------------------------#\n"; print BACACC "#User |Encrypted Password |\n"; print BACACC "#--------------------------------#\n"; use esmith::ConfigDB; use esmith::AccountsDB; my $adb = esmith::AccountsDB->open_ro(); foreach my $user ($adb->users) { my %properties = $user->props; my $key = $user->key; # lecture shadow open(ACC, "< /etc/shadow") || die "Can't find /etc/shadow.\a\n"; my $line = ""; while (){ $line = $_; if($line =~ /^$key:(.*):(.*):(.*):(.*):(.*):(.*):(.*):$/){ print BACACC $key.(' ' x (12 - length($key))); print BACACC " |"; print BACACC $1."\n"; } } close(ACC); } } #============================================================================== sub ReadUsers { my @fldinf = ("User", 12, "FirstName", 10, "LastName", 15, "Password", 8, "Dept", 15, "Company", 15, "Street", 15, "City", 20, "Phone", 16, "EmailForward", 12, "ForwardAddress", 30, "Uid", 5); &PrintDump("Users", "user", "accounts", \%accounts, @fldinf); } #============================================================================== sub ReadQuota { my @fldinf = ("User", 30, "MaxBlocksSoftLim", 16, "MaxBlocks", 16); &PrintDump("Quota", "user", "accounts", \%accounts, @fldinf); } #============================================================================== sub ReadDomains { my @fldinf = ("Domain", 30, "Description", 23, "Content", 12); &PrintDump("Domains", "domain", "domains", \%domains, @fldinf); } #============================================================================== sub ReadIbays { my @fldinf = ("User", 12, "Name", 23, "Group", 12, "UserAccess", 20, "PublicAccess", 12, "Password", 8, "CgiBin", 9, "Uid", 5); &PrintDump("Ibays", "ibay", "accounts", \%accounts, @fldinf); } #============================================================================== sub ReadPPTP { my @fldinf = ("PPTPAccess", 10); open(ACC, "< /home/e-smith/db/accounts") || die "Can't find /home/e-smith/db/accounts.\a\n"; my @accounts = sort(grep(/\=user\|/, )); close(ACC); open(BACACC, "> $OutDir/$HostName.PPTP"); print BACACC "#-------------------------#\n"; print BACACC "#User |PPTP Access |\n"; print BACACC "#-------------------------#\n"; foreach (@accounts) { $_ =~ /\=user\|/; my $AccName = $`; print BACACC $AccName.(' ' x (12 - length($AccName))); my $SMEvalue = db_get_prop(\%accounts,$AccName,"PPTPAccess"); if ( ! $SMEvalue) { $SMEvalue = "off" } print BACACC " |"; print BACACC $SMEvalue."\n"; } close(BACACC); } #============================================================================== sub ReadPseudonyms { open(ACC, "< /home/e-smith/db/accounts") || die "Can't find /home/e-smith/db/accounts.\a\n"; my @accounts = sort(grep(/\=user\|/i, )); close(ACC); push(@accounts,"admin=user|"); open(ACC, "< /home/e-smith/db/accounts") || die "Can't find /home/e-smith/db/accounts.\a\n"; my @pseudonyms = grep(/\=pseudonym\|/i, ); close(ACC); open(BACACC, "> $OutDir/$HostName.Pseudonyms"); print BACACC "#".('-' x 78)."#\n"; print BACACC "#User |Pseudonyms".(' ' x 55)."|\n"; print BACACC "#".('-' x 78)."#\n"; foreach (@accounts) { if ($_ =~ /\=user\|/) { my $AccName = $`; my $pseudolist; foreach (@pseudonyms) { my $psinfo = $_; $psinfo =~ /\|Account\|/i; my $owner = $'; chomp($owner); if ($AccName eq $owner) { if ($psinfo =~ /\=pseudonym\|/i) { $pseudolist .= " | ".$`; } } } if ($pseudolist) { print BACACC $AccName.(' ' x (12 - length($AccName))).$pseudolist."\n"; } } } close(BACACC); } #============================================================================== sub ReadGroups { my @finfo = ("Group", 12, "Description", 30, "Gid", 5, "Members", 25); my $nm = "group"; open(ACC, "< /home/e-smith/db/accounts") || die "Can't find /home/e-smith/db/accounts.\a\n"; my @accounts = sort(grep(/\=group\|/, )); close(ACC); open(BACACC, "> $OutDir/$HostName.Groups"); my $Header= "#$finfo[0]".(' ' x ($finfo[1] - 1 - length($finfo[0])))." |"; for (my $cnt=2; $cnt<$#finfo; $cnt=$cnt+2) { $Header .= $finfo[$cnt].(' ' x ($finfo[$cnt+1] - length($finfo[$cnt])))." |"; } print BACACC "#".("-" x (length($Header)-2))."#\n"; print BACACC $Header."\n"; print BACACC "#".("-" x (length($Header)-2))."#\n"; foreach (@accounts) { $_ =~ /\=group\|/; my $AccName = $`; print BACACC $AccName.(' ' x ($finfo[1] - length($AccName))); my $cnt; for ($cnt=2; $cnt<$#finfo-2; $cnt=$cnt+2) { my $SMEvalue = db_get_prop(\%accounts,$AccName,$finfo[$cnt]); if ( ! $SMEvalue) { $SMEvalue = " " } print BACACC " |"; print BACACC $SMEvalue.(' ' x ($finfo[$cnt+1] - length($SMEvalue))); } my $members = db_get_prop(\%accounts, $AccName, $finfo[$cnt]); $members =~ s/,/ \|/g; print BACACC " |$members\n"; } close(BACACC); } #============================================================================== sub ReadProcmail { my @finfo = ("User", 12, "Status", 8, "deldups", 7, "loglevel", 8, "mode", 6); open(ACC, "< /home/e-smith/db/accounts") || die "Can't find /home/e-smith/db/accounts.\a\n"; my @accounts = sort(grep(/\=user\|/, )); close(ACC); open(BACACC, "> $OutDir/$HostName.Procmail"); my $Header= "#User |"; for (my $cnt=2; $cnt<$#finfo; $cnt=$cnt+2) { $Header .= $finfo[$cnt].(' ' x ($finfo[$cnt+1] - length($finfo[$cnt])))." |"; } print BACACC "#".("-" x (length($Header)-2))."#\n"; print BACACC $Header."\n"; print BACACC "#".("-" x (length($Header)-2))."#\n"; foreach (@accounts) { $_ =~ /\=user\|/; my $AccName = $`; print BACACC $AccName.(' ' x ($finfo[1] - length($AccName))); if (db_get_prop(\%accounts, $AccName, "EmailForward") =~ m/procmail/i) { print BACACC " |enabled " } else { print BACACC " |disabled" } for (my $cnt=4; $cnt<$#finfo; $cnt=$cnt+2) { my $SMEvalue = db_get_prop(\%processmail, $AccName, $finfo[$cnt]); if ( ! $SMEvalue) { $SMEvalue = " " } print BACACC " |"; print BACACC $SMEvalue.(' ' x ($finfo[$cnt+1] - length($SMEvalue))); } print BACACC "\n"; } close(BACACC); } #============================================================================== sub ReadHosts { my @finfo = ("HostType", 8, "Visibility", 10, "InternalIP", 15, "ExternalIP", 15, "MACAddress", 17); open(ACC, "< /home/e-smith/db/hosts") || die "Can't find /home/e-smith/db/hosts.\a\n"; my @accounts = sort(grep(/\=host\|/, )); close(ACC); open(BACACC, "> $OutDir/$HostName.Hosts"); my $Header= "#Hosts |"; $Header .= "Domainname |"; for (my $cnt=0; $cnt<$#finfo; $cnt=$cnt+2) { $Header .= $finfo[$cnt].(' ' x ($finfo[$cnt+1] - length($finfo[$cnt])))." |"; } print BACACC "#".("-" x (length($Header)-2))."#\n"; print BACACC $Header."\n"; print BACACC "#".("-" x (length($Header)-2))."#\n"; foreach (@accounts) { $_ =~ /\=host\|/; my $AccName = $`; $AccName =~ m/\./; $AccName = $`; my $Domain = $'; print BACACC $AccName.(' ' x (12 - length($AccName)))." |"; print BACACC $Domain.(' ' x (35 - length($Domain))); for (my $cnt=0; $cnt<$#finfo; $cnt=$cnt+2) { my $SMEvalue = db_get_prop(\%hosts,"$AccName.$Domain",$finfo[$cnt]); if ( ! $SMEvalue) { $SMEvalue = " " } print BACACC " |"; print BACACC $SMEvalue.(' ' x ($finfo[$cnt+1] - length($SMEvalue))); } print BACACC "\n"; } close(BACACC); } #============================================================================== # Print lat-info in a nice format sub PrintDump { my ($out, $nm, $src, $dbpointer, @finfo) = @_; open(ACC, "< /home/e-smith/db/$src") || die "Can't find /home/e-smith/db/$src.\a\n"; my @accounts = sort(grep(/\=$nm\|/, )); close(ACC); open(BACACC, "> $OutDir/$HostName.$out"); my $Header= "#$finfo[0]".(' ' x ($finfo[1] - 1 - length($finfo[0])))." |"; for (my $cnt=2; $cnt<$#finfo; $cnt=$cnt+2) { $Header .= $finfo[$cnt].(' ' x ($finfo[$cnt+1] - length($finfo[$cnt])))." |"; } print BACACC "#".("-" x (length($Header)-2))."#\n"; print BACACC $Header."\n"; print BACACC "#".("-" x (length($Header)-2))."#\n"; foreach (@accounts) { $_ =~ /\=$nm\|/; my $AccName = $`; print BACACC $AccName.(' ' x ($finfo[1] - length($AccName))); for (my $cnt=2; $cnt<$#finfo; $cnt=$cnt+2) { my $SMEvalue = db_get_prop($dbpointer,$AccName,$finfo[$cnt]); if ( ! $SMEvalue) { $SMEvalue = " " } print BACACC " |"; print BACACC $SMEvalue.(' ' x ($finfo[$cnt+1] - length($SMEvalue))); } print BACACC "\n"; } close(BACACC); } #============================================================================== # Print the pod text as a help screen sub PrintPod { my ($verbose, $message) = @_; pod2usage(-verbose => $verbose, -message => $message, -exitval => 64); } #============================================================================== =pod =head1 NAME B - The lazy administrator's tool to extract config info =head1 DESCRIPTION Creates input-files for the lat-toolkit, based on the current configuration of the SME server (5.x/6.x). The information is extracted from the /home/e-smith/db/* databases. The resulting input-files can be used to replicate user accounts, ibays, etc on a different SME server, or recreate them on a clean install. To facilitate the restoring/replicating, the lat-restore script is automatically created. This will launch the various lat-tools in the right sequence. =head1 SYNOPSIS B [options] =head1 OPTIONS The following options are supported: =over 4 =item B<-d>, B<--dump> Create input files =item B<-h>, B<--help> Extended help for this tool =item B<-o=/path/>, B<--output-dir=/path/> Directory where the configuration files should be stored. If omitted, the current directory is used. =back =head1 EXAMPLES B Creates the configuration files and writes them to /var/tmp. =head1 SEE ALSO lat-users(8), lat-group(8), lat-pseudonyms(8), lat-ibays(8), lat-quota(8), lat-domains(8), lat-hosts(8), lat-procmail(8), lat-pptp(8) =head1 VERSION Version 0.9.0 (2004-09-08). The latest version is hosted at B =head1 COPYRIGHT (c)2003-2004, Altiplano bvba (B). Released under the terms of the GNU license. =head1 BUGS Please report bugs to =cut #==============================================================================