alias.pm
changeset 0 2a5f2464f8c6
child 3 1f0b4cd76cc8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/alias.pm	Fri Nov 04 06:29:26 2005 +0000
@@ -0,0 +1,215 @@
+package alias;
+# © Heiko Schlittermann
+# $Id$
+# $URL$
+
+use strict;
+use warnings;
+use Net::LDAP;
+use Net::LDAP::Constant qw(
+    LDAP_ALREADY_EXISTS 
+    LDAP_NO_SUCH_OBJECT
+    LDAP_NO_SUCH_ATTRIBUTE
+    LDAP_TYPE_OR_VALUE_EXISTS);
+use Net::LDAP::Entry;
+use Text::Wrap;
+
+use password;
+
+my $Cf;
+my ($ldap, $abase);
+
+sub _add();
+sub _list();
+sub _delete();
+sub uniq(@);
+sub verbose(@);
+sub columns();
+
+sub OU_ALIASES();
+sub OC_ALIAS();
+sub AT_FORWARDINGADDRESS();
+
+sub import(@) {
+    $Cf = shift;
+
+    require constant;
+    import constant OU_ALIASES => $Cf->ldap_ou_aliases;
+    import constant OC_ALIAS => $Cf->ldap_oc_alias;
+    import constant AT_FORWARDINGADDRESS => $Cf->ldap_at_forwardingaddress;
+
+    $abase = OU_ALIASES . "," . $Cf->ldap_base;
+}
+
+sub run($) {
+    # Eigentlich brauchen wir für alles ldap
+    $ldap = new Net::LDAP $Cf->ldap_server or die;
+    my $r = $ldap->bind($Cf->ldap_bind_dn,
+	password => $Cf->ldap_password || $ENV{LDAP_PASS} || password::ask("LDAP (". $Cf->ldap_bind_dn .") password: "));
+    die $r->error, "\n" if $r->code;
+
+
+    if ($Cf->list) { _list() }
+    elsif ($Cf->add) { _add() }
+    elsif ($Cf->delete) { _delete() }
+    elsif ($Cf->modify) { _modify() }
+    else { die "Need action (--add|--modify|--list|--delete)\n" };
+
+}
+
+sub _add() {
+# Wenn's den Alias schon gibt, wird er nicht mehr
+# angelegt
+
+    die "Need alias name for creation\n" if not @ARGV;
+    die "Need members\n" if not defined $Cf->members;
+    my $alias = shift @ARGV;
+    my @members = split /,/, $Cf->members;
+    my $dn = "mail=$alias,$abase";
+
+    my $r;
+
+    verbose("$alias:\n");
+    verbose("\t$dn...");
+
+    $r = $ldap->search(base => $abase, filter => "(mail=$alias)");
+    die $r->error if $r->code;
+    die "Multiple entries not expected" if $r->count > 1;
+    
+    $r = $ldap->add($dn, attrs => [
+	objectClass => OC_ALIAS,
+	mail => $alias,
+	(AT_FORWARDINGADDRESS) => \@members
+    ]);
+    if ($r->code == LDAP_ALREADY_EXISTS) { verbose "exists" }
+    elsif ($r->code) { die $r->error } 
+    else { verbose "ok" }
+
+    verbose("\n");
+}
+
+sub _modify() {
+# Auch hier gehen wir davon aus, daß die dn direkt aus dem Alias-Namen folgt:
+# dn: cn=USER,...
+# Jetzt behandeln wir lediglich die Modifikation auf Basis eines
+# alias-Namens!
+
+    my (@users) = @ARGV or die "Need alias names(s)\n";
+    my @members = split /,/, $Cf->members;
+    my @add = grep { s/^\+// } @_ = @members;
+    my @del = grep { s/^-// } @_ = @members;
+    my @set = grep { !/^[\+-]/ } @members;
+
+
+    foreach my $alias (@ARGV) {
+	my $dn = "mail=$alias,$abase";
+	verbose "$alias:";
+
+	my $r = $ldap->search(base => $abase, filter => "(mail=$alias)");
+	die $r->error if $r->code;
+
+	if ($r->count == 0) {
+	    verbose " not found\n";
+	    next;
+	}
+
+	while (my $e = $r->shift_entry) {
+
+	    verbose "\n\t" . $e->dn . " ";
+
+	    if (@set) {
+		$e->replace((AT_FORWARDINGADDRESS) => \@set);
+	    } else {
+		@add and $e->replace((AT_FORWARDINGADDRESS) => [uniq $e->get(AT_FORWARDINGADDRESS), @add]);
+		@del and $e->delete((AT_FORWARDINGADDRESS) => \@del);
+	    }
+
+	    $e->dump if $Cf->debug;
+
+	    my $r = $e->update($ldap);
+	    if ($r->code == LDAP_NO_SUCH_ATTRIBUTE) {
+		verbose "no member";
+	    } elsif ($r->code) {
+		die $r->error . "/" . $r->code;
+	    }  else {
+		verbose "ok";
+	    }
+	}
+
+	print "\n";
+    }
+}
+
+sub _delete() {
+# Wir gehen davon aus, daß es einen dn mail=ALIAS,ou=MailAliases,...
+# gibt und löschen diesen gnadenlos.
+
+    if (!@ARGV) {
+	print "User: ";
+	chomp($_ = <>);
+	@ARGV = ($_);
+    }
+
+    foreach (@ARGV) {
+	my $dn = "mail=$_,$abase";
+
+	verbose("$_:\n");
+	verbose("\tdeleting $dn...");
+	my $r = $ldap->delete($dn);
+
+	if ($r->code == LDAP_NO_SUCH_OBJECT) {
+	    verbose("doesn't exist");
+	} elsif ($r->code == 0) {
+	    verbose("ok");
+	} else {
+	    die $r->error;
+	}
+	
+	verbose("\n");
+
+    }
+}
+
+sub _list() {
+    my $filter;
+    @ARGV = ("*") unless @ARGV;
+    $filter = "(|" . join("", map { "(mail=$_)" } @ARGV) . ")";
+
+    my $r = $ldap->search(
+	filter => $filter,
+	base => $abase,
+	attrs => [qw/mail/, AT_FORWARDINGADDRESS],
+    );
+
+    die $r->error if $r->code;
+
+    $Text::Wrap::columns = columns() || 80;
+
+    while (my $e = $r->shift_entry) {
+	my $mail = $e->get("mail");
+
+	print wrap("", "\t", $e->get_value("mail") 
+	    . ": "
+	    . join(", ", $e->get(AT_FORWARDINGADDRESS))
+	    . "\n");
+	    
+    }
+}
+
+sub verbose(@) {
+    printf STDERR @_;
+}
+
+sub uniq(@) {
+    my %x;
+    @x{@_} = ();
+    return keys %x;
+}
+
+sub columns() {
+    `stty -a` =~ /columns\s+(\d+)/;
+    $1;
+}
+
+1;
+# vim:sts=4 sw=4 aw ai sm: