#!/usr/bin/perl use Net::LDAP; use Carp; use DateTime; use Data::Dumper; use Mail::Sender; my $ldapserver = 'ldaps://ldap.mydomain.com'; my $basedn = 'dc=mydomain,dc=com'; my $defaultpolicy = "cn=sysadmins-policy,$basedn"; my ($entry,$warnage); my %policy; my $ldap = Net::LDAP->new($ldapserver); my $mesg; #We can do anonymous bind here for now ... $mesg = $ldap->bind; $mesg->code && croak $mesg->error; #2)Find all password policies $mesg = $ldap->search( base => $basedn, filter => '(objectclass=pwdPolicy)', attrs => ['cn','pwdMaxAge','pwdExpireWarning'], ); $mesg->code && warn $mesg->error; foreach $entry ($mesg->entries) { print {*STDERR} "Found password policy " . $entry->dn . " with max age " . $entry->get_value('pwdMaxAge') . "\n"; $warnage = $entry->get_value('pwdMaxAge') - $entry->get_value('pwdExpireWarning'); my $policyname = $entry->get_value('cn'); my $policydn = $entry->dn; if ($warnage gt 0) { #$policy{$entry->dn} = $warnage; } else { #print "Policy $policydn has no warning time set, or no expiry\n"; next; } $expireage = $entry->get_value('pwdMaxAge'); $warnage = $entry->get_value('pwdMaxAge') - $entry->get_value('pwdExpireWarning'); my $filterwarn = gen_filter($warnage); my $filterexpire = gen_filter($expireage); my $filter; if ( $entry->dn eq $defaultpolicy ) { $filter = "(&(|(!(pwdPolicySubEntry=*))(pwdPolicySubEntry=$defaultpolicy))(pwdChangedTime<=$filterwarn)(pwdChangedTime>=$filterexpire))"; } else { $filter = "(&(pwdPolicySubEntry=$policydn)(pwdChangedTime<=$filterwarn)(pwdChangedTime>=$filterexpire))" } #print "Searching for users about to expire for policy $policyname\n"; $mesg = $ldap->search( base => $basedn, filter => $filter, attrs => ['cn', 'uid', 'mail', 'pwdChangedTime'], ); $mesg->code && warn $mesg->error; @entries = $mesg->entries; foreach $entry (@entries) { my $changedtime = $entry->get_value('pwdChangedTime'); my $willexpire=$filterexpire; #$changed="20090123100521Z"; if ($changedtime =~ m/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\w+)$/) { #print "Got time $1 - $2 - $3 $4 : $5 : $6 $7\n"; $willexpire=DateTime->new(year=>$1,month=>$2,day=>$3,hour=>$4,minute=>$5,second=>$6,time_zone=>$7); $willexpire->add(seconds=>$expireage); } print "User " . $entry->get_value('uid') . "(" . $entry->get_value('cn') . ") with email " . $entry->get_value('mail') . " has an expired password\n"; notify_user($entry->get_value('uid'),$entry->get_value('cn'),$entry->get_value('mail')||"",$policyname,$willexpire); } } $ldap->unbind if (defined $ldap); sub gen_filter { my ($warningtime) = @_; my $dt = DateTime->now; $dt->subtract(seconds => $warningtime); my $filtertime = $dt->strftime('%Y%m%d%H%M%SZ'); return $filtertime; } sub notify_user { my ($username,$fullname,$email,$policyname,$expiretime) = @_; #$expiretime =~ s/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})Z/$1-$2-$3 $4h$5:$6 (UTC)/; $expiretime->set_time_zone('Africa/Johannesburg'); my $expiretimetext = $expiretime->strftime("%Y-%m-%d %H:%M:%S (%Z)"); if ($ENV{'DEBUG'}) { print "Warning user $username ($fullname) at $email according to policy $policyname expiring at $expiretimetext\n"; return 0; } else { my $mail = new Mail::Sender { smtp => 'smtp.mydomain.com', from => 'Authentication team ', to => ($email ne "") ? "$fullname <$email>" : "Password admin ", subject => 'Your password is about to expire', } or warn "Creating mail failed"; $mail->Open or warn "Opening mail failed"; $mail->SendLineEnc( "Dear $fullname,\n", "Your password will expire at $expiretimetext.\n", "Please change your password at one of the following locations:\n", "https://staff.mydomain.com/cgi-bin/password.cgi\n", "https://hobbit.mydomain.com/cgi-bin/password.cgi\n", "https://svn.mydomain.com/cgi-bin/password.cgi\n", "https://spam.mydomain.com/cgi-bin/password.cgi\n", ) or warn "Adding content to mail failed"; $mail->Close or warn "Sending mail failed"; } }