> 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.



Attachment: DateTime.pm
Description: Binary data

Reply via email to