function ldap_get_ad_pwdexpire($pwdlastset, $ldapconn, $user_dn){
        global $CFG;

        if (!function_exists('bcsub')) {
            error_log($this->errorlogtag.get_string ('needbcmath', 'auth_ldap'));
            return 0;
        }

        // If UF_DONT_EXPIRE_PASSWD flag is set in user's
        // userAccountControl attribute, the password doesn't expire.
        $sr = ldap_read($ldapconn, $user_dn, '(objectClass=*)',
                        array('userAccountControl'));
        if (!$sr) {
            error_log($this->errorlogtag.get_string ('useracctctrlerror', 'auth_ldap', $user_dn));
            // Don't expire password, as we are not sure if it has to be
            // expired or not.
            return 0;
        }

        $entry = ldap_get_entries_moodle($ldapconn, $sr);
        $info = $entry[0];
        $useraccountcontrol = $info['useraccountcontrol'][0];
        if ($useraccountcontrol & UF_DONT_EXPIRE_PASSWD) {
            // Password doesn't expire.
            return 0;
        }

        // If pwdLastSet is zero, the user must change his/her password now
        // (unless UF_DONT_EXPIRE_PASSWD flag is set, but we already
        // tested this above)
        if ($pwdlastset === '0') {
            // Password has expired
            return -1;
        }

        // ----------------------------------------------------------------
        // Password expiration time in Active Directory is the composition of
        // two values:
        //
        //   - User's pwdLastSet attribute, that stores the last time
        //     the password was changed.
        //
        //   - Domain's maxPwdAge attribute, that sets how long
        //     passwords last in this domain.
        //
        // We already have the first value (passed in as a parameter). We
        // need to get the second one. As we don't know the domain DN, we
        // have to query rootDSE's defaultNamingContext attribute to get
        // it. Then we have to query that DN's maxPwdAge attribute to get
        // the real value.
        //
        // Once we have both values, we just need to combine them. But MS
        // chose to use a different base and unit for time measurements.
        // So we need to convert the values to Unix timestamps (see
        // details below).
        // ----------------------------------------------------------------

        $sr = ldap_read($ldapconn, ROOTDSE, '(objectClass=*)',
                        array('defaultNamingContext'));
        if (!$sr) {
            error_log($this->errorlogtag.get_string ('rootdseerror', 'auth_ldap'));
            return 0;
        }

        $entry = ldap_get_entries_moodle($ldapconn, $sr);
        $info = $entry[0];
        $domaindn = $info['defaultnamingcontext'][0];

        $sr = ldap_read ($ldapconn, $domaindn, '(objectClass=*)',
                         array('maxPwdAge'));
        $entry = ldap_get_entries_moodle($ldapconn, $sr);
        $info = $entry[0];
        $maxpwdage = $info['maxpwdage'][0];
        if ($sr = ldap_read($ldapconn, $user_dn, '(objectClass=*)', array('msDS-ResultantPSO'))) {
            if ($entry = ldap_get_entries_moodle($ldapconn, $sr)) {
                $info = $entry[0];
                $userpso = $info['msds-resultantpso'][0];

                // If a PSO exists, FGPP is being utilized.
                // Grab the new maxpwdage from the msDS-MaximumPasswordAge attribute of the PSO.
                if (!empty($userpso)) {
                    $sr = ldap_read($ldapconn, $userpso, '(objectClass=*)', array('msDS-MaximumPasswordAge'));
                    if ($entry = ldap_get_entries_moodle($ldapconn, $sr)) {
                        $info = $entry[0];
                        // Default value of msds-maximumpasswordage is 42 and is always set.
                        $maxpwdage = $info['msds-maximumpasswordage'][0];
                    }
                }
            }
        }
        // ----------------------------------------------------------------
        // MSDN says that "pwdLastSet contains the number of 100 nanosecond
        // intervals since January 1, 1601 (UTC), stored in a 64 bit integer".
        //
        // According to Perl's Date::Manip, the number of seconds between
        // this date and Unix epoch is 11644473600. So we have to
        // substract this value to calculate a Unix time, once we have
        // scaled pwdLastSet to seconds. This is the script used to
        // calculate the value shown above:
        //
        //    #!/usr/bin/perl -w
        //
        //    use Date::Manip;
        //
        //    $date1 = ParseDate ("160101010000 UTC");
        //    $date2 = ParseDate ("197001010000 UTC");
        //    $delta = DateCalc($date1, $date2, \$err);
        //    $secs = Delta_Format($delta, 0, "%st");
        //    print "$secs \n";
        //
        // MSDN also says that "maxPwdAge is stored as a large integer that
        // represents the number of 100 nanosecond intervals from the time
        // the password was set before the password expires." We also need
        // to scale this to seconds. Bear in mind that this value is stored
        // as a _negative_ quantity (at least in my AD domain).
        //
        // As a last remark, if the low 32 bits of maxPwdAge are equal to 0,
        // the maximum password age in the domain is set to 0, which means
        // passwords do not expire (see
        // http://msdn2.microsoft.com/en-us/library/ms974598.aspx)
        //
        // As the quantities involved are too big for PHP integers, we
        // need to use BCMath functions to work with arbitrary precision
        // numbers.
        // ----------------------------------------------------------------

        // If the low order 32 bits are 0, then passwords do not expire in
        // the domain. Just do '$maxpwdage mod 2^32' and check the result
        // (2^32 = 4294967296)
        if (bcmod ($maxpwdage, 4294967296) === '0') {
            return 0;
        }

        // Add up pwdLastSet and maxPwdAge to get password expiration
        // time, in MS time units. Remember maxPwdAge is stored as a
        // _negative_ quantity, so we need to substract it in fact.
        $pwdexpire = bcsub ($pwdlastset, $maxpwdage);

        // Scale the result to convert it to Unix time units and return
        // that value.
        return bcsub( bcdiv($pwdexpire, '10000000'), '11644473600');
    }
function ldap_get_ad_pwdexpire($pwdlastset, $ldapconn, $user_dn){
        global $CFG;

        if (!function_exists('bcsub')) {
            error_log($this->errorlogtag.get_string ('needbcmath', 'auth_ldap'));
            return 0;
        }

        // If UF_DONT_EXPIRE_PASSWD flag is set in user's
        // userAccountControl attribute, the password doesn't expire.
        $sr = ldap_read($ldapconn, $user_dn, '(objectClass=*)',
                        array('userAccountControl'));
        if (!$sr) {
            error_log($this->errorlogtag.get_string ('useracctctrlerror', 'auth_ldap', $user_dn));
            // Don't expire password, as we are not sure if it has to be
            // expired or not.
            return 0;
        }

        $entry = ldap_get_entries_moodle($ldapconn, $sr);
        $info = $entry[0];
        $useraccountcontrol = $info['useraccountcontrol'][0];
        if ($useraccountcontrol & UF_DONT_EXPIRE_PASSWD) {
            // Password doesn't expire.
            return 0;
        }

        // If pwdLastSet is zero, the user must change his/her password now
        // (unless UF_DONT_EXPIRE_PASSWD flag is set, but we already
        // tested this above)
        if ($pwdlastset === '0') {
            // Password has expired
            return -1;
        }

        // ----------------------------------------------------------------
        // Password expiration time in Active Directory is the composition of
        // two values:
        //
        //   - User's pwdLastSet attribute, that stores the last time
        //     the password was changed.
        //
        //   - Domain's maxPwdAge attribute, that sets how long
        //     passwords last in this domain.
        //
        // We already have the first value (passed in as a parameter). We
        // need to get the second one. As we don't know the domain DN, we
        // have to query rootDSE's defaultNamingContext attribute to get
        // it. Then we have to query that DN's maxPwdAge attribute to get
        // the real value.
        //
        // Once we have both values, we just need to combine them. But MS
        // chose to use a different base and unit for time measurements.
        // So we need to convert the values to Unix timestamps (see
        // details below).
        // ----------------------------------------------------------------

        $sr = ldap_read($ldapconn, ROOTDSE, '(objectClass=*)',
                        array('defaultNamingContext'));
        if (!$sr) {
            error_log($this->errorlogtag.get_string ('rootdseerror', 'auth_ldap'));
            return 0;
        }

        $entry = ldap_get_entries_moodle($ldapconn, $sr);
        $info = $entry[0];
        $domaindn = $info['defaultnamingcontext'][0];

        $sr = ldap_read ($ldapconn, $domaindn, '(objectClass=*)',
                         array('maxPwdAge'));
        $entry = ldap_get_entries_moodle($ldapconn, $sr);
        $info = $entry[0];
        $maxpwdage = $info['maxpwdage'][0];
        if ($sr = ldap_read($ldapconn, $user_dn, '(objectClass=*)', array('msDS-ResultantPSO'))) {
            if ($entry = ldap_get_entries_moodle($ldapconn, $sr)) {
                $info = $entry[0];
                $userpso = $info['msds-resultantpso'][0];

                // If a PSO exists, FGPP is being utilized.
                // Grab the new maxpwdage from the msDS-MaximumPasswordAge attribute of the PSO.
                if (!empty($userpso)) {
                    $sr = ldap_read($ldapconn, $userpso, '(objectClass=*)', array('msDS-MaximumPasswordAge'));
                    if ($entry = ldap_get_entries_moodle($ldapconn, $sr)) {
                        $info = $entry[0];
                        // Default value of msds-maximumpasswordage is 42 and is always set.
                        $maxpwdage = $info['msds-maximumpasswordage'][0];
                    }
                }
            }
        }
        // ----------------------------------------------------------------
        // MSDN says that "pwdLastSet contains the number of 100 nanosecond
        // intervals since January 1, 1601 (UTC), stored in a 64 bit integer".
        //
        // According to Perl's Date::Manip, the number of seconds between
        // this date and Unix epoch is 11644473600. So we have to
        // substract this value to calculate a Unix time, once we have
        // scaled pwdLastSet to seconds. This is the script used to
        // calculate the value shown above:
        //
        //    #!/usr/bin/perl -w
        //
        //    use Date::Manip;
        //
        //    $date1 = ParseDate ("160101010000 UTC");
        //    $date2 = ParseDate ("197001010000 UTC");
        //    $delta = DateCalc($date1, $date2, \$err);
        //    $secs = Delta_Format($delta, 0, "%st");
        //    print "$secs \n";
        //
        // MSDN also says that "maxPwdAge is stored as a large integer that
        // represents the number of 100 nanosecond intervals from the time
        // the password was set before the password expires." We also need
        // to scale this to seconds. Bear in mind that this value is stored
        // as a _negative_ quantity (at least in my AD domain).
        //
        // As a last remark, if the low 32 bits of maxPwdAge are equal to 0,
        // the maximum password age in the domain is set to 0, which means
        // passwords do not expire (see
        // http://msdn2.microsoft.com/en-us/library/ms974598.aspx)
        //
        // As the quantities involved are too big for PHP integers, we
        // need to use BCMath functions to work with arbitrary precision
        // numbers.
        // ----------------------------------------------------------------

        // If the low order 32 bits are 0, then passwords do not expire in
        // the domain. Just do '$maxpwdage mod 2^32' and check the result
        // (2^32 = 4294967296)
        if (bcmod ($maxpwdage, 4294967296) === '0') {
            return 0;
        }

        // Add up pwdLastSet and maxPwdAge to get password expiration
        // time, in MS time units. Remember maxPwdAge is stored as a
        // _negative_ quantity, so we need to substract it in fact.
        $pwdexpire = bcsub ($pwdlastset, $maxpwdage);

        // Scale the result to convert it to Unix time units and return
        // that value.
        return bcsub( bcdiv($pwdexpire, '10000000'), '11644473600');
    }
function ldap_get_ad_pwdexpire ( $ pwdlastset , $ ldapconn , $ user_dn ) { global $ CFG ; if ( ! function_exists ( 'bcsub' ) ) { error_log ( $ this -> errorlogtag . get_string ( 'needbcmath' , 'auth_ldap' ) ) ; return 0 ; } // If UF_DONT_EXPIRE_PASSWD flag is set in user's // userAccountControl attribute, the password doesn't expire. $ sr = ldap_read ( $ ldapconn , $ user_dn , '(objectClass=*)' , array ( 'userAccountControl' ) ) ; if ( ! $ sr ) { error_log ( $ this -> errorlogtag . get_string ( 'useracctctrlerror' , 'auth_ldap' , $ user_dn ) ) ; // Don't expire password, as we are not sure if it has to be // expired or not. return 0 ; } $ entry = ldap_get_entries_moodle ( $ ldapconn , $ sr ) ; $ info = $ entry [ 0 ] ; $ useraccountcontrol = $ info [ 'useraccountcontrol' ] [ 0 ] ; if ( $ useraccountcontrol & UF_DONT_EXPIRE_PASSWD ) { // Password doesn't expire. return 0 ; } // If pwdLastSet is zero, the user must change his/her password now // (unless UF_DONT_EXPIRE_PASSWD flag is set, but we already // tested this above) if ( $ pwdlastset === '0' ) { // Password has expired return - 1 ; } // ---------------------------------------------------------------- // Password expiration time in Active Directory is the composition of // two values: // //   - User's pwdLastSet attribute, that stores the last time //     the password was changed. // //   - Domain's maxPwdAge attribute, that sets how long //     passwords last in this domain. // // We already have the first value (passed in as a parameter). We // need to get the second one. As we don't know the domain DN, we // have to query rootDSE's defaultNamingContext attribute to get // it. Then we have to query that DN's maxPwdAge attribute to get // the real value. // // Once we have both values, we just need to combine them. But MS // chose to use a different base and unit for time measurements. // So we need to convert the values to Unix timestamps (see // details below). // ---------------------------------------------------------------- $ sr = ldap_read ( $ ldapconn , ROOTDSE , '(objectClass=*)' , array ( 'defaultNamingContext' ) ) ; if ( ! $ sr ) { error_log ( $ this -> errorlogtag . get_string ( 'rootdseerror' , 'auth_ldap' ) ) ; return 0 ; } $ entry = ldap_get_entries_moodle ( $ ldapconn , $ sr ) ; $ info = $ entry [ 0 ] ; $ domaindn = $ info [ 'defaultnamingcontext' ] [ 0 ] ; $ sr = ldap_read ( $ ldapconn , $ domaindn , '(objectClass=*)' , array ( 'maxPwdAge' ) ) ; $ entry = ldap_get_entries_moodle ( $ ldapconn , $ sr ) ; $ info = $ entry [ 0 ] ; $ maxpwdage = $ info [ 'maxpwdage' ] [ 0 ] ; if ( $ sr = ldap_read ( $ ldapconn , $ user_dn , '(objectClass=*)' , array ( 'msDS-ResultantPSO' ) ) ) { if ( $ entry = ldap_get_entries_moodle ( $ ldapconn , $ sr ) ) { $ info = $ entry [ 0 ] ; $ userpso = $ info [ 'msds-resultantpso' ] [ 0 ] ; // If a PSO exists, FGPP is being utilized. // Grab the new maxpwdage from the msDS-MaximumPasswordAge attribute of the PSO. if ( ! empty ( $ userpso ) ) { $ sr = ldap_read ( $ ldapconn , $ userpso , '(objectClass=*)' , array ( 'msDS-MaximumPasswordAge' ) ) ; if ( $ entry = ldap_get_entries_moodle ( $ ldapconn , $ sr ) ) { $ info = $ entry [ 0 ] ; // Default value of msds-maximumpasswordage is 42 and is always set. $ maxpwdage = $ info [ 'msds-maximumpasswordage' ] [ 0 ] ; } } } } // ---------------------------------------------------------------- // MSDN says that "pwdLastSet contains the number of 100 nanosecond // intervals since January 1, 1601 (UTC), stored in a 64 bit integer". // // According to Perl's Date::Manip, the number of seconds between // this date and Unix epoch is 11644473600. So we have to // substract this value to calculate a Unix time, once we have // scaled pwdLastSet to seconds. This is the script used to // calculate the value shown above: // //    #!/usr/bin/perl -w // //    use Date::Manip; // //    $date1 = ParseDate ("160101010000 UTC"); //    $date2 = ParseDate ("197001010000 UTC"); //    $delta = DateCalc($date1, $date2, \$err); //    $secs = Delta_Format($delta, 0, "%st"); //    print "$secs \n"; // // MSDN also says that "maxPwdAge is stored as a large integer that // represents the number of 100 nanosecond intervals from the time // the password was set before the password expires." We also need // to scale this to seconds. Bear in mind that this value is stored // as a _negative_ quantity (at least in my AD domain). // // As a last remark, if the low 32 bits of maxPwdAge are equal to 0, // the maximum password age in the domain is set to 0, which means // passwords do not expire (see // http://msdn2.microsoft.com/en-us/library/ms974598.aspx) // // As the quantities involved are too big for PHP integers, we // need to use BCMath functions to work with arbitrary precision // numbers. // ---------------------------------------------------------------- // If the low order 32 bits are 0, then passwords do not expire in // the domain. Just do '$maxpwdage mod 2^32' and check the result // (2^32 = 4294967296) if ( bcmod ( $ maxpwdage , 4294967296 ) === '0' ) { return 0 ; } // Add up pwdLastSet and maxPwdAge to get password expiration // time, in MS time units. Remember maxPwdAge is stored as a // _negative_ quantity, so we need to substract it in fact. $ pwdexpire = bcsub ( $ pwdlastset , $ maxpwdage ) ; // Scale the result to convert it to Unix time units and return // that value. return bcsub ( bcdiv ( $ pwdexpire , '10000000' ) , '11644473600' ) ; }
Get password expiration time for a given user from Active Directory

@param string $pwdlastset The time last time we changed the password.
@param resource $lcapconn The open LDAP connection.
@param string $user_dn The distinguished name of the user we are checking.

@return string $unixtime
Get password expiration time for a given user from Active Directory