ispman/bin ispman.ldifupdate,NONE,1.1

Joerg Delker <[email protected]>
Newsgroups gmane.comp.isp.ispman.cvs
Message-ID <[email protected]>
Update of /cvsroot/ispman/ispman/bin
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19651/bin

Added Files:
	ispman.ldifupdate 
Log Message:
moved ldifupdate to bin

--- NEW FILE: ispman.ldifupdate ---
#!/usr/bin/perl -w

# Script to update LDIF data
# Reads from one ldif file and writes to another ldif
# Messages are dumped on STDERR

# please adjust defines below to suit your environment

# All entries are parsed (unless filtered with option "-b") and changed
# according to current schema
# For details see comments below

use strict;
use Getopt::Std;
use Net::LDAP::LDIF;
use Net::LDAP::Entry;
use HTML::Entities;
use MIME::Base64;

# defines
my @oc_normalDomain       = qw(ispmanDomain PureFTPdUser posixAccount);
my @oc_replicaDomain      = qw(ispmanDomain ispmanBranch);
my @oc_virtualHost        = qw(ispmanVirtualHost posixAccount PureFTPdUser);
my @oc_domainUser         = qw(ispmanDomainUser posixAccount);
my $default_domainHomedir = "/ispman/domains";
my @default_fileserver    = qw( );
my @default_webhost       = qw( );
my $default_loginShell    = "/bin/false";
my $default_vhostShell    = "/bin/false";
my $dummyUid              = "999999";
my $dummyGid              = "999999";
my $dummyPassword         = "123456";

# private variables
my ( $ldif_in, $ldif_out, $basedn );
my ( %opts,    $mode );

sub usage {
    print qq[
ISPMan ldifupdate

A utility to update your ispman LDAP data according to current ISPMan schema.
It will convert the given input LDIF and output it to an output LDIF
either in add or modify format.

Syntax: ldifupdate <options>
Options:
  -i <file>        input LDIF filename
  -o <file>        output LDIF filename
  -b <basedn>      base DN (optional), which limits changes to this subtree
  -m <add/modify>  type of LDIF to create (default=add)
];
}

sub update_oc {
    my ( $entry, $src, $dst, %opt ) = @_;
    my $msg = "";
    my %in_src;
    my %in_dst;

    for (@$src) { $in_src{$_} = 1; }
    for (@$dst) {
        if ( !$in_src{$_} ) {
            $msg .= "adding objectclass: \"$_\"\n";
            $entry->add( "objectclass", $_ );
        }
        $in_dst{$_} = 1;
    }
    
    if (!$opt{addonly}){
        for (@$src) {
            if ( !$in_dst{$_} ) {
                $msg .= "deleting objectclass: \"$_\"\n";
                $entry->delete( "objectclass" => [$_] );
            }
        }
    }

    return $msg;
}

## main

# get parameters
getopt( 'iobm', \%opts );
unless ( $opts{'i'} or $opts{'o'} ) {
    usage();
    exit 1;
}

# set mode
$mode = $opts{'m'} || "add";

if ( $mode ne "add" and $mode ne "modify" ) {
    print STDERR "unknown mode: $mode\n";
    usage();
    exit 1;
}

# input file
$ldif_in = Net::LDAP::LDIF->new( $opts{'i'} );

# basedn
$basedn = $opts{'b'};

#### Phase 1: Preparation ####
print "Phase 1: Preparing...\n\n";

my %clients = ();
my %groups  = ();

# read and parse ldap data
while ( not $ldif_in->eof() ) {
    my $entry = $ldif_in->read_entry();

    # skip entry if we find an error
    if ( $ldif_in->error() ) {
        print STDERR "Error msg: ",    $ldif_in->error(),       "\n";
        print STDERR "Error lines:\n", $ldif_in->error_lines(), "\n";
    }

    my $dn = $entry->dn();

    next unless !defined($basedn) or $dn =~ m/$basedn$/;

    my @oc = $entry->get_value("objectclass");
    my %oc;
    for (@oc) { $oc{$_} = 1 }

    if ( $oc{"ispmanClient"} ) {
        $clients{ $entry->get_value("ispmanClientId") } = $entry->{'attrs'};
    }

    if ( $oc{"posixGroup"} ) {
        if ( $dn =~ /^cn=(.*?),/ ) {
            $groups{$1} = 1;
        }
    }
}
$ldif_in->done();

print "Phase 2: Checking...\n\n";

# input file
$ldif_in = Net::LDAP::LDIF->new( $opts{'i'} );

# output file
$ldif_out =
  Net::LDAP::LDIF->new( $opts{'o'}, "w", 'change' => ( $mode eq "modify" ) );

# read and parse ldap data
while ( not $ldif_in->eof() ) {
    my $entry = $ldif_in->read_entry();

    # define slot for new entry
    my $added_entry;

    # skip entry if we find an error
    if ( $ldif_in->error() ) {
        print STDERR "Error msg: ",    $ldif_in->error(),       "\n";
        print STDERR "Error lines:\n", $ldif_in->error_lines(), "\n";
    }

    $entry->changetype($mode);
    my $dn = $entry->dn();

    next unless !defined($basedn) or $dn =~ m/$basedn$/;

    my $msg  = "";
    my $chng = "";

    my @oc = $entry->get_value("objectclass");
    my %oc;
    for (@oc) { $oc{$_} = 1 }

    ## work on entry

    if ( $#oc == 0 && $oc[0] eq "top" ) {

        # if there is only one objectclass: top
        # replace with ispmanBranch
        $msg .= "replacing objectclass: \"top\" -> \"ispmanBranch\"\n";
        $entry->replace( "objectclass", "ispmanBranch" );

    }
    elsif ( $dn =~ m/^ou=/ && $oc[0] ne "ispmanBranch" ) {

        # if entry starts with "ou=" replace
        # objectclasses top, organizationalunit with ispmanBranch
        $msg .= "replacing objectclass: -> \"ispmanBranch\"\n";
        $entry->replace( "objectclass", "ispmanBranch" );

    }
    elsif ( $oc{"ispmanDomain"} ) {
        my $ispmanDomain = $entry->get_value("ispmanDomain");

        # update ispmanDomain objectclasses
        if ( $entry->get_value("ispmanDomainType") eq "replica" ) {
            $msg .= update_oc( $entry, \@oc, \@oc_replicaDomain );
        }
        else {

            ## normal domain
            $msg .= update_oc( $entry, \@oc, \@oc_normalDomain );

            # check ispmanDomainDefaultFileServer attribute
            if ( !defined $entry->get_value("ispmanDomainDefaultFileServer") ) {
                $msg .= "WARNING! no \"Default Fileserver\" defined!\n";
                if (@default_fileserver) {
                    foreach (@default_fileserver) {
                        $msg .=
                          "adding ispmanDomainDefaultFileServer: \"$_\"\n";
                        $entry->add( "ispmanDomainDefaultFileServer", $_ );
                    }
                }
                else {
                    $msg .=
"Please adjust \@default_fileserver array to set them automatically\n";
                }
            }

            # check ispmanDomainDefaultWebServer attribute
            if ( !defined $entry->get_value("ispmanDomainDefaultWebHost") ) {
                $msg .= "WARNING! no \"Default Webhost\" defined!\n";
                if (@default_webhost) {
                    foreach (@default_webhost) {
                        $msg .= "adding ispmanDomainWebHost: \"$_\"\n";
                        $entry->add( "ispmanDomainDefaultWebHost", $_ );
                    }
                }
                else {
                    $msg .=
"Please adjust \@default_webhost array to set them automatically\n";
                }
            }

            # checking FTPStatus
            if ( !$entry->get_value("FTPStatus") ) {
                $msg .= "adding FTPStatus: active\n";
                $entry->add( "FTPStatus", "active" );
            }

            # check related group entry
            if ( !$groups{$ispmanDomain} ) {

                # add new group entry
                $added_entry = Net::LDAP::Entry->new;

                $added_entry->dn( "cn=" . $ispmanDomain . "," . $dn );
                $added_entry->add(
                    objectclass => 'posixGroup',
                    cn          => $ispmanDomain,
                    gidnumber   => $entry->get_value("gidnumber")
                );
                $msg .=
                  "creating new posixGroup entry for domain "
                  . $ispmanDomain . "\n";
            }

            # check ResellerId
            my $clientId   = $entry->get_value("ispmanClientId");
            my $resellerId = $entry->get_value("ispmanResellerId");
            if ( $clientId && !$resellerId ) {
                $resellerId = $clients{$clientId}{"ispmanresellerid"}[0];
                if ($resellerId) {
                    $msg .= "adding ispmanResellerId: $resellerId\n";
                    $entry->add( "ispmanResellerId", $resellerId );
                }
                else {
                    $msg .=
                        "ERROR: unable to determine ispmanResellerId"
                      . " for domain $ispmanDomain\n";
                }
                my $resellerName = $clients{$clientId}{"ispmanresellername"}[0];
                if ($resellerName) {
                    $msg .= "adding ispmanResellerName: $resellerName\n";
                    $entry->add( "ispmanResellerName", $resellerName );
                }
                else {
                    $msg .=
                        "ERROR: unable to determine ispmanResellerName"
                      . " for domain $ispmanDomain\n";
                }
            }

        }

    }
    elsif ( $oc{'ispmanVirtualHost'} ) {

        # update ispmanVhost
        my $ispmanDomain = $entry->get_value("ispmanDomain")
          || die("ispmanDomain undefined!");
        my $ispmanVhostName = $entry->get_value("ispmanVhostName")
          || die("ispmanVhostName undefined!");

        # checking/replacing vhost objectclasses
        $msg .= update_oc( $entry, \@oc, \@oc_virtualHost );

        # checking vhost cn attribute
        my $lcn = $entry->get_value("cn");
        my $cn = join ".", ( $ispmanVhostName, $ispmanDomain );
        if ( !defined $lcn ) {
            $msg .= "adding cn with \"$cn\"\n";
            $entry->add( "cn", $cn );
        }
        elsif ( $lcn ne $cn ) {
            $msg .= "changing cn: \"$lcn\" -> \"$cn\"\n";
            $entry->replace( "cn", $cn );
        }

        # checking vhost uid attribute
        my $luid = $entry->get_value("uid");
        my $uid = join ".", ( $ispmanVhostName, $ispmanDomain );
        if ( !defined $luid ) {
            $msg .= "adding uid with \"$uid\"\n";
            $entry->add( "uid", $uid );
        }
        elsif ( $luid ne $uid ) {
            $msg .= "changing uid: \"$luid\" -> \"$uid\"\n";
            $entry->replace( "uid", $uid );
        }

        # checking vhost uidNumber attribute
        unless ( $entry->get_value("uidNumber") ) {
            $msg .=
"adding dummy uidNumber: $dummyUid (This should be replaced later!\n)";
            $entry->add( "uidNumber", $dummyUid );
        }

        # checking vhost gidNumber attribute
        unless ( $entry->get_value("gidNumber") ) {
            $msg .=
"adding dummy gidNumber: $dummyGid (This should be replaced later!)\n";
            $entry->add( "gidNumber", $dummyGid );
        }

        # checking vhost homeDirectory attribute
        my $homedir = join '/',
          ( $default_domainHomedir, $ispmanDomain, 'vhosts', $ispmanVhostName );
        unless ( $entry->get_value("homeDirectory") ) {
            $msg .= "adding homeDirectory: \"$homedir\"\n";
            $entry->add( "homeDirectory", $homedir );
        }

        # checking vhost userPassword attribute
        unless ( $entry->get_value("userPassword") ) {
            $msg .=
"adding userPassword: \"$dummyPassword\" (This should be replaced later!)\n";
            $entry->add( "userPassword", $dummyPassword );
        }

        # checking vhost ispmanVhostDocumentRoot
        my $docroot = $entry->get_value("ispmanVhostDocumentRoot");
        if ($docroot) {
            if ( $docroot =~ /^$ispmanVhostName\// ) {
                $msg .=
                  "NOTICE: ispmanVhostDocumentRoot looks like old entry\n";
                my ($fixeddocroot) = $docroot =~ m/^$ispmanVhostName\/(.*)/;
                $msg .=
"changing ispmanVhostDocumentRoot: \"$docroot\" -> \"$fixeddocroot\"\n";
                $entry->replace( "ispmanVhostDocumentRoot", $fixeddocroot );
            }
        }
        else {
            $msg .= "ERROR: ispmanVhostDocumentRoot is missing!\n";
        }

        # checking vhost ispmanVhostScriptDir
        my $scdir = $entry->get_value("ispmanVhostScriptDir");
        if ($scdir) {
            if ( $scdir =~ /^$ispmanVhostName\// ) {
                $msg .=
                  "NOTICE: ispmanVhostDocumentRoot looks like old entry\n";
                my ($fixedscdir) = $scdir =~ m/^$ispmanVhostName\/(.*)/;
                $msg .=
"changing ispmanVhostScriptDir: \"$scdir\" -> \"$fixedscdir\"\n";
                $entry->replace( "ispmanVhostScriptDir", $fixedscdir );
            }
        }
        else {
            $msg .= "ERROR: ispmanVhostScriptDir is missing!\n";
        }

        # checking vhost ispmanVhostLogdir attribute
        my $logdir = $entry->get_value("ispmanVhostLogdir");
        if ($logdir) {
            if ( $logdir =~ /^$ispmanVhostName\// ) {
                $msg .= "NOTICE: ispmanVhostLogdir looks like old entry\n";
                my ($fixedlogdir) = $logdir =~ m/^$ispmanVhostName\/(.*)/;
                $msg .=
"changing ispmanVhostLogdir: \"$logdir\" -> \"$fixedlogdir\"\n";
                $entry->replace( "ispmanVhostLogdir", $fixedlogdir );
            }
        }
        else {
            $msg .= "WARNING: ispmanVhostLogdir is missing!\n";
            $msg .= "adding ispmanVhostLogdir: \"logs\"\n";
            $entry->add( "ispmanVhostLogdir", "logs" );
        }

        # checking vhost ispmanVhostStatdir attribute
        my $statdir = $entry->get_value("ispmanVhostStatdir");
        if ($statdir) {
            if ( $statdir =~ /^$ispmanVhostName\// ) {
                $msg .= "NOTICE: ispmanVhostStatdir looks like old entry\n";
                my ($fixedstatdir) = $statdir =~ m/^$ispmanVhostName\/(.*)/;
                $msg .=
"changing ispmanVhostStatdir: \"$statdir\" -> \"$fixedstatdir\"\n";
                $entry->replace( "ispmanVhostStatdir", $fixedstatdir );
            }
        }
        else {
            $msg .= "WARNING: ispmanVhostStatdir is missing!\n";
            $msg .= "adding ispmanVhostStatdir: \"stats\"\n";
            $entry->add( "ispmanVhostStatdir", "stats" );
        }

        # checking vhost loginShell
        unless ( $entry->get_value("loginshell") ) {
            $msg .= "adding loginShell: $default_vhostShell\n";
            $entry->add( "loginshell", $default_vhostShell );
        }

        # checking ispmanVhostExtraConf
        my $extraconf = $entry->get_value("ispmanVhostExtraConf");
        if ( $extraconf && $extraconf =~ /<.*>/ ) {
            my $codedconf = HTML::Entities::encode($extraconf);
            $msg .= "NOTICE: ispmanVhostExtraConf is not HTML encoded!\n";
            $msg .= "changing: ispmanVhostExtraConf\n";
            $entry->replace( "ispmanVhostExtraConf", $codedconf );
        }

        # checking ispmanStatus
        if ( !$entry->get_value("ispmanStatus") ) {
            $msg .= "adding ispmanStatus: active\n";
            $entry->add( "ispmanStatus", "active" );
        }

        # checking FTPStatus
        if ( !$entry->get_value("FTPStatus") ) {
            $msg .= "adding FTPStatus: active\n";
            $entry->add( "FTPStatus", "active" );
        }

        # checking ispmanVhostServerAlias
        my @aliases = $entry->get_value("ispmanVhostServerAlias");
        if (@aliases) {

            # create new alias container
            my $ou = Net::LDAP::Entry->new;
            $ou->add(
                'objectclass' => 'ispmanBranch',
                'ou'          => 'vhostAliases'
            );
            $ou->dn( "ou=vhostAliases," . $entry->dn() );
            $ou->changetype("add");
            $ldif_out->write_entry($ou);
            $msg .= "creating vhostAlias container...\n";

            # move all aliases to new entries
            for (@aliases) {
                my $alias = Net::LDAP::Entry->new;
                $alias->add(
                    'objectclass'            => 'ispmanVirtualHostAlias',
                    'ispmanDomain'           => $ispmanDomain,
                    'ispmanVhostName'        => $ispmanVhostName,
                    'ispmanVhostServerAlias' => $_
                );
                $alias->dn( "ispmanVhostServerAlias=$_," . $ou->dn() );
                $alias->changetype("add");
                $ldif_out->write_entry($alias);

                $entry->delete("ispmanVhostServerAlias");
                $msg .= "moving vhostAlias \"$_\" to container\n";
            }
        }
    }
    elsif ( $oc{'ispmanDomainUser'} ) {

        # checking minimum objectclasses
        $msg .= update_oc( $entry, \@oc, \@oc_domainUser,
                           addonly => 1);

        # checking for alternate uid
        my @uids = $entry->get_value("uid");
        my $uid = join "@", $entry->get_value("ispmanUserId"),
          $entry->get_value("ispmanDomain");
        my $hasAlternateUid = 0;
        for (@uids) {
            if ( $_ eq $uid ) { $hasAlternateUid = 1; }
        }
        if ( !$hasAlternateUid ) {
            $msg .= "adding uid: \"$uid\"\n";
            $entry->add( "uid", $uid );
        }

        # checking for bogus mailHost
        if (   $entry->get_value("mailHost")
            && $entry->get_value("mailHost") eq "undefined" )
        {
            $msg .= "deleting mailhost: undefined\n";
            $entry->delete( "mailhost" => ["undefined"] );
        }

        # checking for bogus fileHost
        if (   $entry->get_value("fileHost")
            && $entry->get_value("fileHost") eq "undefined" )
        {
            $msg .= "deleting filehost: undefined\n";
            $entry->delete( "filehost" => ["undefined"] );
        }

        # checking loginShell
        unless ( $entry->get_value("loginshell") ) {
            $msg .= "adding default loginShell: $default_loginShell\n";
            $entry->add( "loginshell", $default_loginShell );
        }

    }
    else {

        # check other entries here

    }

    ## check that RDN is also attribute/value pair

    # get the RDN as attr/value
    my ( $attrib, $attribval ) = $dn =~ m/^(\w+)?\=([^,]*)/;
    my @values = $entry->get_value($attrib);
    my $found  = 0;

    for (@values) {
        if ( $_ eq $attribval ) { $found = 1 }
    }
    if ( !$found ) {
        $msg .= "adding RDN to attributes ($attrib: $attribval)\n";
        $entry->add( $attrib, $attribval );
    }

    # output msg
    if ($msg) {
        print STDERR "DN: $dn\n";
        print STDERR $msg, "\n";
    }

    # write ldif data
    $ldif_out->write_entry($entry);

    # write added ldif data when present
    $ldif_out->write_entry($added_entry) if ($added_entry);
}

$ldif_in->done();

$ldif_out->done();

__END__




-------------------------------------------------------
This SF.Net email is sponsored by OSTG. Have you noticed the changes on
Linux.com, ITManagersJournal and NewsForge in the past few weeks? Now,
one more big change to announce. We are now OSTG- Open Source Technology
Group. Come see the changes on the new OSTG site. www.ostg.com
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.