> From: Al Lilianstrom [mailto:[EMAIL PROTECTED]] > > Hi, > > I'm managing AD accounts from a Unix system via LDAP. I'm > trying to set > the accountExpires field with the proper value. > > The schema definition for the field is as follows; > > Syntax - INTEGER8 > OID - 1.2.840.113556.1.4.159 > > Digging deeper I find that this field is the number of seconds since > 00:00:00 on Jan 1, 1970 (Unix epoch time) expressed as a > large integer.
This is unfortunately horribly inaccurate. I've reported it to Microsoft a long while back, but I don't think they have yet cleaned up all documenation references that state it as such. Anything in AD that is a Date/Time attribute and uses the INTEGER8 syntax is using the same representation as the FILETIME format (http://www.vbapi.com/ref/f/filetime.html). The 64-bit integer is actually the number of *100-nanosecond* intervals since Jan 1, 1601!!! (no wonder it needs 64 bits!). > For example - if I set an account (using AD Users&Computers) with a > account expiration date of Friday March 1, 2002 and then look at that > field using ldapsearch the field is > > accountExpires: 126595224000000000 If you use the module I developed and have attached (DateTime.pm - put it in your perl\site\lib\Win32 directory) you can convert to a human readable GMT date using this oneliner: perl -MWin32::DateTime -e "print scalar gmtime Win32::DateTime->new(big_int => shift)->utc_seconds" 126595224000000000 Sat Mar 2 06:00:00 2002 The module requires Win32::API, Math::BigInt, Date::Manip and a recent version of Perl/ActivePerl. Here's the minimal POD i've put in it so far NAME Win32::DateTime - OO model for Win32 Date/Time conversion SYNOPSIS use Win32::DateTime; # new() valid args: # utc_seconds - epoch seconds # big_int - string decimal representation of 64-bit LargeInteger # filetime - either 8 byte packed struct, 2 integer element array ref # OR Win32::OLE LargeInteger object (from ADO) # systemtime - 16 byte packed struct my $dt = Win32::DateTime->new(utc_seconds => time()); print $dt->utc_seconds; # secs since epoch (midnight 1970 GMT) print $dt->filetime; # filetime structure print $dt->big_int; # big integer object print $dt->big_int_string; # useful in ADO queries print $dt->systemtime; # much like what localtime() returns DESCRIPTION Helps you convert between the many ugly date/time formats that one has to deal with on windows and especially Active Directory. EXPORT None by default. AUTHOR [EMAIL PROTECTED] SEE ALSO Math::BigInt Win32::API Date::Manip > > If you convert that number (in seconds) to a date you get > December 31st, > 1969 as it is larger than expected by any of the perl code I've used. > > If you convert the date, Friday March 1, 2002 to seconds > since the epoch > you get 1014962400 seconds. If you plug that number in as a expiration > date via a ldapmodify to an account the date AD U&C returns > is Thursday > Feb 14, 2002. Setting to any date using epoch seconds seems to set to > the current date. Odd behavior, but probably some sort of builtin failsafe since it interpreted the date as somewhere in the 1600's. > So after all that - does anyone know exactly how to calculate > the number > for that field? The basic formula for UTC seconds <=> FILETIME 100-nanoseconds conversion is utc = floor((filetime - 116,444,736,000,000,000) / 10,000,000) 116,444,736,000,000,000 = number of 100-nanosecond intervals between epoch and Jan 1, 1601 10,000,000 = number of 100-nanosecond intervals in a second Simple formula but requires 64-bit integer math so it's not trivial on 32-bit platform. That's why I needed to use Math::BigInt. I also have conversions <=> Win32 systemtime format. If you want the gory details you can examine the module code. Cheers, - Jason PS: If the attachment gets filtered out, let me know and I'll try to post it somewhere.
DateTime.pm
Description: Binary data