I think I have answered 1 and 3 on my own by reading newsgroups.
But I would still like an easy way to convert the pwdLastSet attribute and know how to set the password in active directory. My program now looks like this. #!/usr/bin/perl -w use strict; my $perllib; BEGIN { $ENV{PERL_LIB} =~ m/(.*)/; $perllib = $1 } # untaint PERL_LIB use lib $perllib; use Net::LDAP; use Net::LDAPS; use Net::LDAP::Extension::SetPassword; use Net::LDAP::RootDSE; use Net::LDAP::Constant; my $addr = "**********"; my $short_user = "jeffk"; my $user = "CORUSENT\\$short_user"; my $pass = "*********"; my $new_password = "*********"; my $path = "DC=corusent,DC=intra"; my $ldap = Net::LDAP->new($addr) or die "$@"; my $login = $ldap->bind($user, password=> $pass); my @srcargs1 = ( base => $path, scope => "sub", filter => "(sAMAccountName=$short_user)", attrs => ['unicodePwd', 'memberOf', 'pwdLastSet', 'displayName', 'description', 'managedBy', 'distinguishedName', 'createTimeStamp' , 'modifyTimeStamp'], ); my $search = $ldap->search(@srcargs1); foreach my $entry ($search->entries) { my $DN = $entry->get_value("distinguishedName"); my $pwdLastSet = $entry->get_value("pwdLastSet"); my $displayName = $entry->get_value("displayName"); if ((defined $DN) && ($DN ne '')){ print "$short_user is not empty\n"; print "\nDN : " . $DN; print "\npwdLastSet : " . $pwdLastSet; print "\ndisplayName : " . $displayName; print "\n\n"; } my $newPassword = '1fotcn$75'; my $secureLDAP = Net::LDAPS->new( $addr ); $secureLDAP->bind($DN, password => $pass); #$secureLDAP->root_dse->supported_extension( LDAP_EXTENSION_WHO_AM_I ); $secureLDAP->root_dse->supported_extension( "LDAP_EXTENSION_PASSWORD_MODIFY" ); my $mesg = $secureLDAP->set_password( user => $short_user ,oldpasswd => $pass, newpassword=> $newPassword); die "error: ", $mesg->code(), ": ", $mesg->error(), " \n" if ($mesg->code()); print "changed your password to", $mesg->gen_password() , "\n"; } print "\n\n"; and I am now getting the error error: 2: 0000203D: LdapErr: DSID-0C090C7D, comment: Unknown extended request OID, data 0, vece Which I have tried to resolve using the support_extension function which did not fix the problem. If I don't put the quotes I get BAREWORD not allowed LDAP_EXTENSION_PASSWORD_MODIFY when trying to run my program. ________________________________ From: Jeff Kalbfleisch Sent: Tuesday, February 06, 2007 6:38 PM To: 'perl-ldap@perl.org' Subject: 4 issues with Net::LDAP and Active Directory I have 4 issues which I do not understand and I have searched the Net::LDAP documentation up and down and cannot figure it out. 1. pwdLastSet is only available for the DN of the user who is logged in. (That seems a little odd, why is that?) and yes I logged in as another user using LDAP and it was available for them and not me. 2. pwdLastSet is some Active Directory timestamp (Why oh why cant Microsoft just use utc like every other application on the planet.). Is there a function included with Net::LDAP to convert this number into utc. So I can tell when the user last set their password in meaningful terms in perl on linux. 3. I have real difficult with determining the DN. In my program you can see that I looked at the Server Level DN(At least that is what I think it is. I got it by seeing what I was a member of. My sysadmin for Active Directory told me my DN to start). If I knew my login name is there a way I can find my DN easily. 4. I do not seem to be able to set the value of unicodePwd even though I can change my own password in Active Directory. Any help is appreciated. Jeff K ---------------------------------------------------------- When the time comes and my password is going to expire I can set my password leading me to believe that I can change my own password and my sysadmin for Active directory swears up and down that each user has the rights to modify their own password. And I suspect maybe the password is not in unicodePwd field as suggested because I do not see that field when I list all the properties of my DN. Or maybe its hidden for security reasons? And I get the following Access rights Violation error. Display Date [CN=Jeff Kalbfleisch,OU=Nelvana,DC=corusent,DC=intra] [Dec 31, 1969] [128126604183974767]<h1>Software error:</h1> <pre>00000005: SecErr: DSID-031A0F44, problem 4003 (INSUFF_ACCESS_RIGHTS), data 0 at ldappass_set line 120.</pre> <p> For help, please send mail to this site's webmaster, giving this error message and the time and date of the error. </p> [Tue Feb 6 18:14:01 2007] ldappass_set: 00000005: SecErr: DSID-031A0F44, problem 4003 (INSUFF_ACCESS_RIGHTS), data 0 [Tue Feb 6 18:14:01 2007] ldappass_set: at ldappass_set line 120. I wrote this code which gives the above result my $ldap = Net::LDAPS->new("myDNS") or die "$@"; my $login = "CORUSENT\\jeffk"; my $password = "-----"; # I emptied this field for security reasons my $message = $ldap->bind($login, password=>$password, version=> 3); my $schema = $ldap->schema(); my $dse = $ldap->root_dse(); my $resultCode = $message->{'resultCode'}; #Nel::Core::Common::dump($dse); my $mesg = $ldap->search( base => "OUR BASE DN", filter => "cn=*" ); $mesg->code && die $mesg->error; my @entries = $mesg->entries; my @all_nelvana_DNs; foreach my $entr ( @entries ) { my $attr; foreach $attr ( sort $entr->attributes ) { next if ( $attr =~ /;binary$/ ); if ($attr eq 'member'){ @all_nelvana_DNs = $entr->get_value($attr); } } } foreach my $DN(@all_nelvana_DNs){ #if ($DN !~ 'Richard Gopaul') { next; } if ($DN !~ 'Jeff Kalbfleisch') { next; } my $ldap_hash = &get_dn_hash($ldap,$DN); my $pwdLastSet = $ldap_hash->{pwdLastSet}[0]; my $date = &get_date($pwdLastSet); my $display_date = $date->get_display_date(); print "\nDisplay Date [$DN] [$display_date] [$pwdLastSet]"; my $newPW = "---------"; # PURPOSLY BLANKED OUT BY ME FOR THIS POSTING &set_password($ldap,$DN,$newPW); } sub get_dn_hash(){ my $ldap = shift; my $DN = shift; my %ldap_record; my $ldap_record = \%ldap_record; # Do An LDAP Search On This USER my $mesg2 = $ldap->search( base => $DN, filter => "cn=*", ); my @entries = $mesg2->entries; foreach my $entry(@entries){ my $asn = $entry->{asn}; my $attributes = $asn->{attributes}; foreach my $attribute(@$attributes){ my $type = $attribute->{type}; my $vals = $attribute->{vals}; $ldap_record->{$type} = $vals; } } return $ldap_record; } sub set_password(){ my $ldap = shift; my $DN = shift; my $newPW = shift; my $charmap = Unicode::Map8->new('latin1') or die; my $newUniPW = $charmap->tou('"'.$newPW.'"')->byteswap()->utf16(); $mesg = $ldap->modify($DN, changes => [ replace => [ unicodePwd => $newUniPW ]]); $mesg->code && die $mesg->error; } Corus(tm) Entertainment Inc. / Nelvana ________________________________ Jeff Kalbfleisch 135 Liberty Street, suite 100 416.535.0935 [EMAIL PROTECTED] Programmer/Analyst Toronto, Ontario M6K 1A7 ext. 3255 Corus(tm) is a trade-mark of Corus(tm) Entertainment Inc. or a subsidiary thereof, which might be used under licence.