#! /usr/bin/perl # Copyright (C) 2004 Nick Urbanik # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. use warnings; use strict; use Net::LDAP qw( LDAP_NO_SUCH_OBJECT LDAP_NOT_ALLOWED_ON_NONLEAF ); use Carp; use constant ADMIN_DN => 'uid=nicku,ou=People,ou=sys,o=ICT'; use constant TOP_DN => 'ou=nicku,o=ICT'; use constant LDAP_SERVER => 'ldap1.tyict.vtc.edu.hk'; sub die_on_error { my ( $mesg, $additional_info ) = @_; if ( $additional_info ) { $additional_info .= ": " if index( $additional_info, ':' ) == -1; } else { $additional_info = ''; } confess $additional_info, "bad message object\n" unless $mesg; confess $additional_info, '[', $mesg->code, ']: ', $mesg->error if $mesg->code; } sub entry_exists($$) { my ( $ldap, $entry ) = @_; #my $dn = $entry->dn or die "Bad entry $entry"; my $mesg = $ldap->search( #base => $dn, base => $entry, scope => 'base', filter => '(objectClass=*)', attr => [ 'dn' ], ); return if $mesg->code == LDAP_NO_SUCH_OBJECT; die_on_error $mesg; return 1; } sub make_ou_entry($$) { my ( $ou_name, $parent ) = @_; my $entry = new Net::LDAP::Entry; my $dn = "ou=$ou_name,$parent"; $entry->dn( $dn ); $entry->add( objectClass => 'organizationalUnit', ou => $ou_name, ); return $entry; } # Assume have already bound with permission to write sub make_ou($$$) { my ( $ldap, $ou_name, $parent ) = @_; my $entry = make_ou_entry $ou_name, $parent; my $mesg = $entry->update( $ldap ); die_on_error $mesg; return 1; } # can call with DN or entry. # assume have bound beforehand. sub delete_entry($$) { my ( $ldap, $dn ) = @_; my $mesg = $ldap->delete( $dn ); if ( $mesg->code == LDAP_NOT_ALLOWED_ON_NONLEAF ) { print STDERR "\tEntries exist under \"$dn\"\n", "\tso I will not delete this non-leaf node.\n"; return; } die_on_error $mesg; return 1; } use Term::ReadKey; sub read_password() { print "Password: "; ReadMode 'noecho'; my $passwd = ReadLine 0; ReadMode 'restore'; print "\n"; chomp $passwd; return $passwd; } sub bind_as_admin($$) { my ( $ldap, $binddn ) = @_; my $pw = read_password; #print "I got $pw\n"; my $mesg = $ldap->bind( $binddn, 'password' => $pw ); die "Bad Password\n" if $mesg->code; die_on_error $mesg; } sub main($) { my ( $host ) = @_; my $ldap = Net::LDAP->new( $host ) or die "Unable to connect to $host: $!"; my $mesg = $ldap->start_tls; die_on_error $mesg; bind_as_admin $ldap, ADMIN_DN; foreach my $ou_name ( qw( People Group ) ) { my $dn = "ou=$ou_name," . TOP_DN; if ( entry_exists $ldap, $dn ) { print "deleting $dn\n"; delete_entry $ldap, $dn; } else { print "creating $dn\n"; make_ou $ldap, $ou_name, TOP_DN; } } $ldap->unbind; } main LDAP_SERVER;