diff --git a/auth/ldap/auth.php b/auth/ldap/auth.php
index 384157d..73418b9 100644
--- a/auth/ldap/auth.php
+++ b/auth/ldap/auth.php
@@ -23,6 +23,10 @@ if (!defined('AUTH_AD_ACCOUNTDISABLE')) {
 if (!defined('AUTH_AD_NORMAL_ACCOUNT')) {
     define('AUTH_AD_NORMAL_ACCOUNT', 0x0200);
 }
+if (!defined('AUTH_NTLMTIMEOUT')) {  // timewindow for the NTLM SSO process, in secs...
+    define('AUTH_NTLMTIMEOUT', 10);
+}
+
 
 require_once($CFG->libdir.'/authlib.php');
 
@@ -85,6 +89,46 @@ class auth_plugin_ldap extends auth_plugin_base {
         $extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding);
         $extpassword = $textlib->convert(stripslashes($password), 'utf-8', $this->config->ldapencoding);
 
+        //
+        // Before we connect to LDAP, check if this is an AD SSO login
+        // if we succeed in this block, we'll return success early.
+        //
+        $key = sesskey();
+        if (!empty($this->config->ntlmsso_enabled) && $key === $password) {
+            if ($cookie   = get_config('auth/ldap/ntlmsess', $key)) {
+                // These checks match the work done
+                if (preg_match('/^(\d+):(.+)$/',$cookie,$matches)) {
+                    // $matches[0] is the whole matched string...
+                    $time         = $matches[1];
+                    $sessusername = $matches[2];
+                    if (((time() - ((int)$time)) < AUTH_NTLMTIMEOUT)
+                        && $sessusername === $username) {
+
+                        unset($cookie);
+                        unset($time);
+                        unset($sessusername);
+
+                        // Check that the user is inside one of the configured LDAP contexts
+                        $validuser = false;
+                        $ldapconnection = $this->ldap_connect();
+                        if ($ldapconnection) {
+                            // if the user is not inside the configured contexts,
+                            // ldap_find_userdn returns false.
+                            if ($this->ldap_find_userdn($ldapconnection, $extusername)) {
+                                $validuser = true;
+                            }
+                            ldap_close($ldapconnection);
+                        }
+
+                        // Shortcut here - SSO confirmed
+                        return $validuser;
+                    }
+                }
+            }
+        } // End SSO processing
+        unset($key);
+
+
         $ldapconnection = $this->ldap_connect();
 
         if ($ldapconnection) {
@@ -1709,6 +1753,103 @@ class auth_plugin_ldap extends auth_plugin_base {
     }
 
     /**
+     * Will get called before the login page is shown, if NTLM SSO
+     * is enabled, and the user is in the right network, we'll redirect
+     * to the magic NTLM page for SSO...
+     *
+     */
+    function loginpage_hook() {
+        global $CFG;
+
+        if ($_SERVER['REQUEST_METHOD'] === 'GET'    // Only on initial GET 
+                                                    // of loginpage
+            &&!empty($this->config->ntlmsso_enabled)// SSO enabled
+            && !empty($this->config->ntlmsso_subnet)// have a subnet to test for
+            && empty($_GET['authldap_skipntlmsso']) // haven't failed it yet
+            && (isguestuser() || !isloggedin())     // guestuser or not-logged-in users
+            && address_in_subnet($_SERVER['REMOTE_ADDR'],$this->config->ntlmsso_subnet)) {
+            redirect("{$CFG->wwwroot}/auth/ldap/ntlmsso_attempt.php");
+        }
+    }
+
+    /**
+     * To be called from a page running under NTLM's
+     * "Integrated Windows Authentication". 
+     *
+     * If successful, it will set a special "cookie" (not an HTTP cookie!) 
+     * in cache_flags under the "auth/ldap/ntlmsess" "plugin" and return true.
+     * The "cookie" will be picked up by ntlmsso_finish() to complete the
+     * process.
+     *
+     * On failure it will return false for the caller to display an appropriate
+     * error message (probably saying that Integrated Windows Auth isn't enabled!)
+     *
+     * NOTE that this code will execute under the OS user credentials, 
+     * so we MUST avoid dealing with files -- such as session files.
+     * (The caller should set $nomoodlecookie before including config.php)
+     *
+     */
+    function ntlmsso_magic($sesskey) {
+        if (isset($_SERVER['REMOTE_USER']) && !empty($_SERVER['REMOTE_USER'])) {
+            $username = $_SERVER['REMOTE_USER'];
+            $username = substr(strrchr($username, '\\'), 1); //strip domain info
+            $username = moodle_strtolower($username); //compatibility hack
+            set_cache_flag('auth/ldap/ntlmsess', $sesskey, $username, AUTH_NTLMTIMEOUT);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Find the session set by ntlmsso_magic(), validate it and 
+     * call authenticate_user_login() to authenticate the user through
+     * the auth machinery.
+     * 
+     * It is complemented by a similar check in user_login().
+     * 
+     * If it succeeds, it never returns. 
+     *
+     */
+    function ntlmsso_finish() {
+        global $CFG, $USER;
+
+        $key = sesskey();
+        $cf = get_cached_flags('auth/ldap/ntlmsess');
+        if (!isset($cf[$key]) && $cf[$key] !== '') {
+            return false;
+        }
+        $username   = $cf[$key];
+        // Here we want to trigger the whole authentication machinery
+        // to make sure no step is bypassed...
+        $user = authenticate_user_login($username, $key);
+        if ($user) {
+            add_to_log(SITEID, 'user', 'login', "view.php?id=$USER->id&course=".SITEID,
+                       $user->id, 0, $user->id);
+            $USER = complete_user_login($user);
+
+            // Cleanup the key to prevent reuse...
+            // and to allow re-logins with normal credentials
+            unset_cache_flag('auth/ldap/ntlmsess', $key);
+
+            /// Redirection
+            if (user_not_fully_set_up($USER)) {
+                $urltogo = $CFG->wwwroot.'/user/edit.php';
+                // We don't delete $SESSION->wantsurl yet, so we get there later
+            } else if (isset($SESSION->wantsurl) and (strpos($SESSION->wantsurl, $CFG->wwwroot) === 0)) {
+                $urltogo = $SESSION->wantsurl;    /// Because it's an address in this site
+                unset($SESSION->wantsurl);
+            } else {
+                // no wantsurl stored or external - go to homepage
+                $urltogo = $CFG->wwwroot.'/';
+                unset($SESSION->wantsurl);
+            }
+            redirect($urltogo);
+        }
+        // Should never reach here.
+        return false;
+    }    
+
+    /**
      * Sync roles for this user
      *
      * @param $user object user object (without system magic quotes)
@@ -1803,6 +1944,10 @@ class auth_plugin_ldap extends auth_plugin_base {
             {$config->changepasswordurl = ''; }
         if (!isset($config->removeuser))
             {$config->removeuser = 0; }
+        if (!isset($config->ntlmsso_enabled))
+            {$config->ntlmsso_enabled = 0; }
+        if (!isset($config->ntlmsso_subnet))
+            {$config->ntlmsso_subnet = ''; }
 
         // save settings
         set_config('host_url', $config->host_url, 'auth/ldap');
@@ -1833,6 +1978,8 @@ class auth_plugin_ldap extends auth_plugin_base {
         set_config('passtype', $config->passtype, 'auth/ldap');
         set_config('changepasswordurl', $config->changepasswordurl, 'auth/ldap');
         set_config('removeuser', $config->removeuser, 'auth/ldap');
+        set_config('ntlmsso_enabled', (int)$config->ntlmsso_enabled, 'auth/ldap');
+        set_config('ntlmsso_subnet', $config->ntlmsso_subnet, 'auth/ldap');
 
         return true;
     }
diff --git a/auth/ldap/config.html b/auth/ldap/config.html
index 30036f8..55fe2de 100644
--- a/auth/ldap/config.html
+++ b/auth/ldap/config.html
@@ -55,6 +55,10 @@
         {$config->changepasswordurl = ''; }
     if (!isset($config->removeuser))
         {$config->removeuser = 0; }
+    if (!isset($config->ntlmsso_enabled))
+        {$config->ntlmsso_enabled = 0; }
+    if (!isset($config->ntlmsso_subnet))
+        {$config->ntlmsso_subnet = ''; }
 
     $yesno = array( get_string('no'), get_string('yes') );
 
@@ -439,6 +443,32 @@ if (!function_exists('ldap_connect')) { // Is php4-ldap really there?
     </td>
 </tr>
 
+<tr>
+   <td colspan="2">
+        <h4><?php print_string('auth_ntlmsso', 'auth') ?> </h4>
+   </td>
+</tr>
+
+<tr valign="top">
+    <td align="right"><label for="ntlmsso_enabled"><?php print_string('auth_ntlmsso_enabled_key','auth') ?></label></td>
+    <td>
+    <?php
+       choose_from_menu($yesno, 'ntlmsso_enabled', $config->ntlmsso_enabled, '0');
+    ?>
+    </td>
+    <td>
+    <?php print_string('auth_ntlmsso_enabled','auth') ?>
+    </td>
+</tr>
+<tr valign="top">
+    <td align="right"><label for="ntlmsso_subnet"><?php print_string('auth_ntlmsso_subnet_key','auth') ?></label></td>
+    <td><input name="ntlmsso_subnet" id="ntlmsso_subnet" type="text" size="30" value="<?php p($config->ntlmsso_subnet) ?>"
+    </td>
+    <td>
+    <?php print_string('auth_ntlmsso_subnet','auth') ?>
+    </td>
+</tr>
+
 <?php
 
 $help  = get_string('auth_ldapextrafields','auth');
diff --git a/auth/ldap/ntlmsso_attempt.php b/auth/ldap/ntlmsso_attempt.php
new file mode 100644
index 0000000..c9fc469
--- /dev/null
+++ b/auth/ldap/ntlmsso_attempt.php
@@ -0,0 +1,34 @@
+<?php
+
+require_once(dirname(dirname(dirname(__FILE__)))."/config.php");
+
+//HTTPS is potentially required in this page
+httpsrequired();
+
+/// Define variables used in page
+if (!$site = get_site()) {
+    error("No site found!");
+}
+
+$authsequence = get_enabled_auth_plugins(true); // auths, in sequence
+if (!in_array('ldap',$authsequence,true)) {
+    print_error('ldap_isdisabled','auth');
+}
+
+$authplugin = get_auth_plugin('ldap');
+if (empty($authplugin->config->ntlmsso_enabled)) {
+    print_error('ntlmsso_isdisabled','auth');
+}
+
+$sesskey = sesskey();
+
+//print_header("$site->fullname: $loginsite", $site->fullname, $loginsite, $focus, '', true);
+$msg = '<p>'.get_string('ntlmsso_attempting','auth').'</p>'
+    . '<img width="1", height="1" '
+    . ' src="' . $CFG->wwwroot . '/auth/ldap/ntlmsso_magic.php?sesskey='
+    . $sesskey . '" />';
+redirect($CFG->wwwroot . '/auth/ldap/ntlmsso_finish.php', $msg, 3);
+
+
+
+?>
\ No newline at end of file
diff --git a/auth/ldap/ntlmsso_finish.php b/auth/ldap/ntlmsso_finish.php
new file mode 100644
index 0000000..c64e755
--- /dev/null
+++ b/auth/ldap/ntlmsso_finish.php
@@ -0,0 +1,30 @@
+<?php
+
+require_once(dirname(dirname(dirname(__FILE__)))."/config.php");
+
+//HTTPS is potentially required in this page
+httpsrequired();
+
+/// Define variables used in page
+if (!$site = get_site()) {
+    error("No site found!");
+}
+
+$authsequence = get_enabled_auth_plugins(true); // auths, in sequence
+if (!in_array('ldap',$authsequence,true)) {
+    print_error('ldap_isdisabled','auth');
+}
+
+$authplugin = get_auth_plugin('ldap');
+if (empty($authplugin->config->ntlmsso_enabled)) {
+    print_error('ntlmsso_isdisabled','auth');
+}
+
+// If ntlmsso_finish() succeeds, then the code never returns,
+// so we only worry about failure.
+if (!$authplugin->ntlmsso_finish()) {
+    // Redirect to login, saying "don't try again!"
+    redirect($CFG->wwwroot . '/login/index.php?authldap_skipntlmsso=1', 
+             get_string('ntlmsso_failed','auth'), 3);
+}
+?>
\ No newline at end of file
diff --git a/auth/ldap/ntlmsso_magic.php b/auth/ldap/ntlmsso_magic.php
new file mode 100644
index 0000000..79077ef
--- /dev/null
+++ b/auth/ldap/ntlmsso_magic.php
@@ -0,0 +1,44 @@
+<?php
+
+// Don't let lib/setup.php set any cookies
+// as we will be executing under the OS security
+// context of the user we are trying to login, rather than
+// of the webserver.
+$nomoodlecookie=true;
+
+require_once(dirname(dirname(dirname(__FILE__)))."/config.php");
+
+//HTTPS is potentially required in this page
+httpsrequired();
+
+$authsequence = get_enabled_auth_plugins(true); // auths, in sequence
+if (!in_array('ldap',$authsequence,true)) {
+    print_error('ldap_isdisabled','auth');
+}
+
+$authplugin = get_auth_plugin('ldap');
+if (empty($authplugin->config->ntlmsso_enabled)) {
+    print_error('ntlmsso_isdisabled','auth');
+}
+
+$sesskey = required_param('sesskey', PARAM_RAW);
+$file = $CFG->dirroot . '/pix/spacer.gif';
+
+if ($authplugin->ntlmsso_magic($sesskey) 
+    && file_exists($file)) {
+
+    // Serve GIF
+    // Type
+    header('Content-Type: image/gif');
+    header('Content-Length: '.filesize($file));
+
+    // Output file
+    $handle=fopen($file,'r');
+    fpassthru($handle);
+    fclose($handle);
+    exit;
+} else {
+    print_error('ntlmsso_iwamagicnotenabled','auth');
+}
+
+?>
\ No newline at end of file
diff --git a/auth/mnet/land.php b/auth/mnet/land.php
index 905119a..82ddd16 100644
--- a/auth/mnet/land.php
+++ b/auth/mnet/land.php
@@ -33,7 +33,7 @@ $localuser = $mnetauth->confirm_mnet_session($token, $remotewwwroot);
 
 // log in
 $USER = get_complete_user_data('id', $localuser->id, $localuser->mnethostid);
-load_all_capabilities();
+complete_user_login($USER);
 
 if (!empty($localuser->mnet_foreign_host_array)) {
     $USER->mnet_foreign_host_array = $localuser->mnet_foreign_host_array;
diff --git a/auth/shibboleth/index.php b/auth/shibboleth/index.php
index 347e6a8..e014894 100644
--- a/auth/shibboleth/index.php
+++ b/auth/shibboleth/index.php
@@ -72,6 +72,7 @@
                 }
             }
 
+            check_enrolment_plugins($USER);
             load_all_capabilities();     /// This is what lets the user do anything on the site  :-)
 
             redirect($urltogo);
diff --git a/course/loginas.php b/course/loginas.php
index 8b93bca..5cd9e36 100644
--- a/course/loginas.php
+++ b/course/loginas.php
@@ -90,6 +90,7 @@
     $USER = get_complete_user_data('id', $userid);
     $USER->realuser = $olduserid;
     $USER->loginascontext = $context;
+    check_enrolment_plugins($USER);
     load_all_capabilities();   // reload capabilities
 
     if (isset($SESSION->currentgroup)) {    // Remember current cache setting for later
diff --git a/lib/accesslib.php b/lib/accesslib.php
index 233dcd9..27e21e2 100755
--- a/lib/accesslib.php
+++ b/lib/accesslib.php
@@ -1567,7 +1567,10 @@ function compact_rdefs(&$rdefs) {
 
 /**
  *  A convenience function to completely load all the capabilities 
- *  for the current user.   This is what gets called from login, for example.
+ *  for the current user.   This is what gets called from complete_user_login()
+ *  for example. Call it only _after_ you've setup $USER and called
+ *  check_enrolment_plugins();
+ *
  */
 function load_all_capabilities() {
     global $USER, $CFG, $DIRTYCONTEXTS;
@@ -1585,8 +1588,6 @@ function load_all_capabilities() {
 
     } else if (isloggedin()) {
 
-        check_enrolment_plugins($USER);
-
         $accessdata = get_user_access_sitewide($USER->id);
 
         //
diff --git a/lib/moodlelib.php b/lib/moodlelib.php
index abde06a..73003f3 100644
--- a/lib/moodlelib.php
+++ b/lib/moodlelib.php
@@ -597,6 +597,8 @@ function clean_param($param, $type) {
  * Can also be used to update keys for plugin-scoped configs in config_plugin table.
  * In that case it doesn't affect $CFG.
  *
+ * A NULL value will delete the entry.
+ *
  * @param string $name the key to set
  * @param string $value the value to set (without magic quotes)
  * @param string $plugin (optional) the plugin scope
@@ -612,8 +614,16 @@ function set_config($name, $value, $plugin=NULL) {
         $CFG->$name = $value;  // So it's defined for this invocation at least
 
         if (get_field('config', 'name', 'name', $name)) {
-            return set_field('config', 'value', addslashes($value), 'name', $name);
+            if ($value===null) {
+                unset($CFG->$name);
+                return delete_records('config', 'name', $name);
+            } else {
+                return set_field('config', 'value', addslashes($value), 'name', $name);
+            }
         } else {
+            if ($value===null) {
+                return true;
+            }
             $config = new object();
             $config->name = $name;
             $config->value = addslashes($value);
@@ -621,8 +631,15 @@ function set_config($name, $value, $plugin=NULL) {
         }
     } else { // plugin scope
         if ($id = get_field('config_plugins', 'id', 'name', $name, 'plugin', $plugin)) {
-            return set_field('config_plugins', 'value', addslashes($value), 'id', $id);
+            if ($value===null) {
+                return delete_records('config_plugins', 'name', $name, 'plugin', $plugin);
+            } else {
+                return set_field('config_plugins', 'value', addslashes($value), 'id', $id);
+            }
         } else {
+            if ($value===null) {
+                return true;
+            }
             $config = new object();
             $config->plugin = addslashes($plugin);
             $config->name   = $name;
@@ -2921,6 +2938,10 @@ function guest_user() {
  *
  * Uses auth_ functions from the currently active auth module
  *
+ * After authenticate_user_login() returns success, you will need to
+ * log that the user has logged in, and call complete_user_login() to set
+ * the session up.
+ *
  * @uses $CFG
  * @param string $username  User's username (with system magic quotes)
  * @param string $password  User's password (with system magic quotes)
@@ -3006,6 +3027,60 @@ function authenticate_user_login($username, $password) {
 }
 
 /**
+ * Call to complete the user login process after authenticate_user_login()
+ * has succeeded. It will setup the $USER variable and other required bits
+ * and pieces.
+ * 
+ * NOTE:
+ * - It will NOT log anything -- up to the caller to decide what to log.
+ *
+ *
+ *
+ * @uses $CFG, $USER
+ * @param string $user obj
+ * @return user|flase A {@link $USER} object or false if error
+ */
+function complete_user_login($user) {
+    global $CFG, $USER;
+    
+    $USER = $user; // should not be needed, but cover for legacy code
+
+    update_user_login_times();
+    if (empty($CFG->nolastloggedin)) {
+        set_moodle_cookie($USER->username);
+    } else {
+        // do not store last logged in user in cookie
+        // auth plugins can temporarily override this from loginpage_hook()
+        // do not save $CFG->nolastloggedin in database!
+        set_moodle_cookie('nobody');
+    }
+    set_login_session_preferences();
+
+    // Call enrolment plugins
+    check_enrolment_plugins($user);
+
+    /// This is what lets the user do anything on the site :-)
+    load_all_capabilities();
+
+    /// Select password change url
+    $userauth = get_auth_plugin($USER->auth);
+
+    /// check whether the user should be changing password
+    if (get_user_preferences('auth_forcepasswordchange', false)){
+        if ($userauth->can_change_password()) {
+            if ($changeurl = $userauth->change_password_url()) {
+                redirect($changeurl);
+            } else {
+                redirect($CFG->httpswwwroot.'/login/change_password.php');
+            }
+        } else {
+            error(get_string('nopasswordchangeforced', 'auth'));
+        }
+    }
+    return $USER;
+}
+
+/**
  * Compare password against hash stored in internal user table.
  * If necessary it also updates the stored hash to new format.
  *
diff --git a/login/index.php b/login/index.php
index af0d68b..82b125e 100644
--- a/login/index.php
+++ b/login/index.php
@@ -150,47 +150,15 @@ httpsrequired();
                 die;
             }
 
-        /// Let's get them all set up.
-            $USER = $user;
-
-            add_to_log(SITEID, 'user', 'login', "view.php?id=$USER->id&course=".SITEID, $USER->id, 0, $USER->id);
-
-
-            update_user_login_times();
-            if (empty($CFG->nolastloggedin)) {
-                set_moodle_cookie($USER->username);
-            } else {
-                // do not store last logged in user in cookie
-                // auth plugins can temporarily override this from loginpage_hook()
-                // do not save $CFG->nolastloggedin in database!
-                set_moodle_cookie('nobody');
-            }
-            set_login_session_preferences();
-
-        /// This is what lets the user do anything on the site :-)
-            load_all_capabilities();
-
-        /// Select password change url
-            $userauth = get_auth_plugin($USER->auth);
-
-        /// check whether the user should be changing password
-            if (get_user_preferences('auth_forcepasswordchange', false) || $frm->password == 'changeme'){
-                if ($frm->password == 'changeme') {
-                    //force the change
-                    set_user_preference('auth_forcepasswordchange', true);
-                }
-                //Select password change url
-                if ($userauth->can_change_password()) {
-                    if ($changeurl = $userauth->change_password_url()) {
-                        redirect($changeurl);
-                    } else {
-                        redirect($CFG->httpswwwroot.'/login/change_password.php');
-                    }
-                } else {
-                    error(get_string('nopasswordchangeforced', 'auth'));
-                }
+            if ($frm->password == 'changeme') {
+                //force the change
+                set_user_preference('auth_forcepasswordchange', true, $user->id);
             }
 
+        /// Let's get them all set up.
+            add_to_log(SITEID, 'user', 'login', "view.php?id=$USER->id&course=".SITEID,
+                       $user->id, 0, $user->id);
+            $USER = complete_user_login($user);
 
         /// Prepare redirection
             if (user_not_fully_set_up($USER)) {

