#!/usr/bin/perl -w # jabber_auth_ad.pl # # Simple Active Directory / LDAP authreg module # for jabberd2 # # based on sample pipe authenticator module from jabberd-2.0s6. # # Status: Works For Me (TM) # Written by Filip Rembialkowski (mailto:plk.zuber@gmail.com) # This code is placed by the author in public domain use strict; use MIME::Base64; use Net::LDAP; use DBI; # LDAP-specific settings my $pdc = 'dc.sample.xx'; my $dom = 'sample.xx'; my $fixed_realm = 'jabberserver.sample.xx'; my $adbase = 'CN=Users,DC=sample,DC=xx'; my $mysql_server='localhost'; my $mysql_database='jabberd2'; my $mysql_user='jabberd2'; my $mysql_password='secret'; my $mysql_dbh; sub mysql_db_connect { my $dsn = "DBI:mysql:database=$mysql_database;host=$mysql_server"; $mysql_dbh = DBI->connect($dsn, $mysql_user, $mysql_password, { PrintError => 0, RaiseError => 0, AutoCommit => 1 } ); $mysql_dbh or die "Cannot connect to MS SQL ($!), error: $DBI::errstr\n"; } # Flush output immediately. $| = 1; # Set to 1 for debugging my $DEBUG = 1; sub debug { print STDERR "@_" if $DEBUG; } mysql_db_connect; # On startup, we have to inform c2s of the functions we can deal with. USER-EXISTS is not optional. #print "OK USER-EXISTS GET-PASSWORD CHECK-PASSWORD SET-PASSWORD GET-ZEROK SET-ZEROK CREATE-USER DESTROY-USER FREE\n"; print "OK USER-EXISTS CHECK-PASSWORD FREE\n"; # Our main loop my $buf; while(sysread (STDIN, $buf, 1024) > 0) { my ($cmd, @args) = split ' ', $buf; next unless $cmd; $cmd =~ tr/[A-Z]/[a-z]/; $cmd =~ tr/-/_/; eval "print _cmd_$cmd(\@args), '\n'"; } # Determine if the requested user exists. sub _cmd_user_exists { my ($user, $realm) = @_; # !!! return "OK" if user exists; # fake - I am lazy, and this requires extra AD LDAP binding return "OK"; } # Compare the given password with the stored password. sub _cmd_check_password { # !!! $pass = decode_base64($encoded_pass); # return "NO" if not $pass; # $spass = [password in database]; # return "OK" if $pass eq $spass; debug "_cmd_check_password(@_) CALL\n"; my ($user, $encoded_pass, $realm) = @_; my $pass = decode_base64($encoded_pass); debug "_cmd_check_password PARSE_ARGS //$user//$pass//$realm//\n"; return "NO empty-user" if not $user; return "NO empty-pass" if not $pass; return "NO bad-realm" if defined $realm and $realm ne $fixed_realm; warn "_cmd_check_password $user $realm START\n"; my $ad = Net::LDAP->new($pdc); $ad or return "NO bind-error"; my $aduser=$user.'@'.$dom; my $mesg=$ad->bind($aduser, password=>"$pass"); # Proceed only if binding with this user/pass was succesful do { $ad->unbind; warn "_cmd_check_password $user $realm FAILED\n"; return "NO bad-password"; } if $mesg->code(); $ad->unbind; # update `active` so we have some tracking my $now = time; my $update_time='UPDATE `active` set `time`='.$now.' WHERE `collection-owner`='."'$user\@$realm'"; debug "About to run SQL: \n$update_time\n"; mysql_db_connect unless $mysql_dbh->ping; my $sth = $mysql_dbh->prepare($update_time); $sth->execute() or warn "SQL query failed:\n$update_time\n"; warn "_cmd_check_password $user $realm PASSED\n"; return "OK"; } # c2s shutting down, do the same. sub _cmd_free { # !!! free data # close database handles $mysql_dbh->disconnect; exit(0); }