'. t("Searches LDAP to update Drupal user membership and information.") .'

'; break; } return $output; } /** * Implementation of hook_menu(). */ function ldapsync_menu() { return array( 'admin/settings/ldap/ldapsync' => array( 'title' => 'Synchronization', 'description' => 'Configure LDAP sync settings.', 'page callback' => 'drupal_get_form', 'page arguments' => array('ldapsync_admin_settings'), 'access arguments' => array('administer ldap modules'), 'file' => 'ldapsync.admin.inc', ), ); } /** * Implements hook_cron(). * * Checks ldapsync_time_interval and ldapsync_last_sync_time variables to determine whether to run ldapsync. */ function ldapsync_cron() { $time_interval = variable_get('ldapsync_time_interval', -1); // -1 means "only sync manually" $last_sync_time = variable_get('ldapsync_last_sync_time', 0); if (((time() - $last_sync_time) > $time_interval) && ($time_interval != -1)) { _ldapsync_sync(); } } /** * Main routine. */ function _ldapsync_sync() { global $_ldapsync_ldap; // If ldapgroups is enabled, include it for groups-role sync. if (module_exists('ldapgroups')) { module_load_include('inc', 'ldapgroups', 'ldapgroups'); } // Find all users in specified OU (using base DN and bind information from ldapauth). // and take appropriate action on the Drupal side. $ldap_users = _ldapsync_search(); $count_orphaned_users=0; // Do we have any LDAP-authentified Drupal users who don't exist in LDAP? if ($ldap_users) { $result = db_query("SELECT uid, name, data FROM {users} WHERE status = %d", 1); while ($row = db_fetch_array($result)) { if ( ! isset($ldap_users[drupal_strtolower($row['name'])]) ) { $data = unserialize($row['data']); if ($data['ldap_authentified']) { // Block user if appropriate module setting is set. if (variable_get('ldapsync_missing_users_action', 'warn') == 'block') { // Block user. db_query("UPDATE {users} SET status=0 WHERE uid=%d", $row['uid']); // Log out blocked user. $account = user_load(array('uid' => $row['uid'])); $array = array(); user_module_invoke('logout', $array, $account); // Log this. watchdog('ldapsync', 'Disabled LDAP-authentified user %name because the corresponding LDAP account does not exist or is disabled.', array('%name' => $row['name'])); } $count_orphaned_users++; } } } } // Send watchdog message with process summary. $params = array( '@ldap_users' => ldapsync_stats('ldap_users'), '@existing_users' => ldapsync_stats('existing_users'), '@new_users' => ldapsync_stats('new_users'), '@orphaned_users' => $count_orphaned_users, ); $converted = ldapsync_stats('converted'); $ldap_disabled = ldapsync_stats('ldap_users_disabled'); $notices = ldapsync_stats('notices'); $denied_by_module = ldapsync_stats('denied_by_module'); $summary = t('Completed LDAP sync. LDAP users found: @ldap_users. Existing users updated: @existing_users. New users created: @new_users. LDAP-authentified users that do not have an enabled LDAP account: @orphaned_users.', $params); if ( $converted ) { $summary .= ' ' . t('Existing users converted to LDAP: @converted.', array('@converted' => $converted)); } if ( $ldap_disabled ) { $summary .= ' ' . t('Disabled LDAP users: @disabled.', array('@disabled' => $ldap_disabled)); } if ( $notices ) { $summary .= ' ' . t('Watchdog notices/warnings written: @notices.', array('@notices' => $notices)); } if ( $denied_by_module ) { $summary .= ' ' . t('Access denied by other modules: @denied.', array('@denied' => $denied_by_module)); } watchdog('ldapsync', $summary); // Update last sync time variable, so that we don't sync again until the specified time period passes again. variable_set('ldapsync_last_sync_time', time()); // Useful if calling manually from settings page. return $summary; } /** * Find all LDAP users from servers and OUs specified in ldapauth settings and * create or update existing users as needed. * * @return An array keyed by lower cased Drupal account name of all users found. */ function _ldapsync_search() { global $_ldapsync_ldap; $users=array(); // Cycle through LDAP configurations. $result = db_query("SELECT sid FROM {ldapauth} WHERE status = %d ORDER BY sid", 1); while ($row = db_fetch_object($result)) { // Initialize LDAP. if (!_ldapsync_init($row->sid)) { watchdog('ldapsync', 'ldapsync init failed for ldap server %sid.', array('%sid' => $row->sid)); continue; } // Set up for LDAP search. $name_attr = $_ldapsync_ldap->getOption('user_attr') ? $_ldapsync_ldap->getOption('user_attr') : LDAPAUTH_DEFAULT_USER_ATTR; $user_attr = drupal_strtolower($name_attr); // used to find in results. $filters = array(); if ( LDAPSYNC_FILTER ) { $filters = explode("\r\n", LDAPSYNC_FILTER); } else { $filters[] = "({$name_attr}=*)"; } $attrs = ldapauth_attributes_needed(LDAPAUTH_SYNC_CONTEXT_AUTHENTICATE_DRUPAL_USER, $_ldapsync_ldap->getOption('sid')); // If there is no bindn and bindpw - the connect will be an anonymous connect. $_ldapsync_ldap->connect($_ldapsync_ldap->getOption('binddn'), $_ldapsync_ldap->getOption('bindpw')); // Search each basedn defined for this server foreach (explode("\r\n", $_ldapsync_ldap->getOption('basedn')) as $base_dn) { if (empty($base_dn)) { continue; } // Re-initialize database object each time. $ldapresult = array(); $filter_found_users = array(); // Search this server and basedn using all defined filters. foreach ( $filters as $filter ) { $filter = trim($filter); if (empty($filter)) { continue; } if ( variable_get('ldapsync_filter_append_default', 0) ) { $filter = "(&{$filter}({$name_attr}=*))"; } if (!($ldapresult = $_ldapsync_ldap->search($base_dn, $filter, $attrs))) { continue; } // Cycle through results to build array of user information. foreach ($ldapresult as $entry) { $name = $entry[$user_attr][0]; // Don't include if no name attribute. if (empty($name)) { continue; } // Don't process the same entry found by different filters twice. $lcname = drupal_strtolower($name); if ( isset($filter_found_users[$lcname])) { continue; // Already found } $filter_found_users[$lcname] = $name; ldapsync_stats('ldap_users', 1); // Don't include if LDAP account is disabled. $status = $entry['useraccountcontrol'][0]; if (($status & 2) != 0) { // This only works for Active Directory -- search includes disabled accounts in other directories. ldapsync_stats('ldap_users_disabled', 1); continue; } // Process this entry to create/update drupal user (if any). $account = _ldapsync_process_entry($_ldapsync_ldap, $name, $entry); if ( ! $account ) { continue; } $users[drupal_strtolower($account->name)] = array( 'uid' => $account->uid, ); } } } } return $users; } /** * Take an ldap object entry and determine if there is an existing account or * a new account needs to be created. * * @param LDAPInterface $ldap An initialized LDAP server interface object * @param String $name The user name attribute value * @param Array $ldap_entry LDAP attributes for user. * @return The account object or FALSE if problem */ function _ldapsync_process_entry( $ldap, $name, $ldap_entry ) { // check whether user is in an OU mapped in module settings (need to create admin/settings/ldapsync page) $dn = $ldap_entry['dn']; if ( $ldap->getOption('puid_attr')) { $puid = ldapauth_extract_puid($server, $name, $ldap_entry); } // See if there is a matching Drupal user account $error = ''; $account = ldapauth_drupal_user_lookup($ldap, $name, $dn, $error, $puid ); if ( $account === NULL ) { ldapsync_stats('notices', 1 ); watchdog('ldapsync', 'drupal_user_lookup() returned: ' . $error, NULL, WATCHDOG_ERROR); return FALSE; } // Handle map by e-mail option (Issue #1209556) // If no account or PUID not used and account found does not have matching e-mail $user_test_method = variable_get('ldapsync_load_user_by', 'name'); if ( $user_test_method == 'email' && ( ! $account || (! $ldap->getOption('puid_attr') && drupal_strtolower($account->mail) != drupal_strtolower($ldap_entry['mail'])))) { $account = user_load(array('mail' => $ldap_entry['mail'])); } // Allow other modules to determine if this ldap user can access server. if ( ldapauth_user_denied( $ldap, $name, $dn, $account ) ) { ldapsync_stats('denied_by_module', 1); return; } // No account found - try to create one if ( ! $account ) { if ( variable_get('ldapsync_existing_only', 0)) { return FALSE; } $error = ''; $account = ldapauth_drupal_user_create($ldap, $name, $ldap_entry, $error); if ( $account === FALSE ) { ldapsync_stats('notices', 1 ); return FALSE; } ldapsync_stats('new_users', 1 ); // Increment counter } // User exists in Drupal -- check a few things else { // Check authentication method. if (! $account->ldap_authentified ) { $conflict_resolution = LDAPSYNC_LOGIN_CONFLICT; if ( $conflict_resolution == LDAPSYNC_CONFLICT_FOLLOW_LDAPAUTH ) { $conflict_resolution = LDAPAUTH_LOGIN_CONFLICT; } if ($conflict_resolution == LDAPAUTH_CONFLICT_LOG) { ldapsync_stats('notices', 1 ); watchdog('ldapsync', 'Could not create ldap-authentified account for user %name because a local user by that %test_value already exists.', array('%name' => $name, '%test_value' => $user_test_method)); return FALSE; } else { $converted = TRUE; ldapsync_stats('converted', 1); } } // Make sure all the information is up to date. $drupal_name = ldapauth_drupal_user_name($name, $ldap, $dn); $data = array( 'ldap_dn' => $dn, 'ldap_config' => $ldap->getOption('sid'), 'ldap_authentified' => TRUE, 'authname_ldapauth' => $drupal_name, 'ldap_name' => $name, ); // Follow ldapauth password sync rules. if (LDAPAUTH_LOGIN_PROCESS == LDAPAUTH_AUTH_MIXED && LDAPAUTH_SYNC_PASSWORDS) { $data['pass'] = $pass; } $puid = $account->ldap_puid; // save setting from drupal_user_lookupsave. $account = user_save($account, $data); // Make sure the ldapauth_users info is current (User object may have been moved). $user_info = ldapauth_userinfo_load_by_uid( $account->uid ); if ( empty($user_info) ) { // Don't have entry, so make one. $user_info = new stdClass(); $user_info->uid = $account->uid; } $user_info->sid = $account->ldap_config; $user_info->machine_name = $ldap->getOption('machine_name'); $user_info->dn = $dn; $user_info->puid = $puid ? $puid : $account->$name; ldapauth_userinfo_save($user_info); if ( ! $converted ) { ldapsync_stats('existing_users', 1); } } // Update user's groups if ldapgroups is enabled. if ( module_exists('ldapgroups')) { ldapgroups_user_login($account); } // Update user's data if ldapdata is enabled. if ( module_exists('ldapdata') ) { _ldapdata_user_load($account, TRUE, $ldap_users); } // Enable any blocked user who is enabled in LDAP. if (!$account->status) { ldapsync_stats('notices', 1 ); db_query("UPDATE {users} SET status = %d where uid = %d", 1, $account->uid); watchdog('ldapsync', 'Enabled LDAP-authentified user %name because the corresponding LDAP account is enabled.', array('%name' => $name)); } // Reset user specific caches to prevent memory problems ldapauth_user_lookup_by_dn( NULL, NULL, NULL, TRUE); ldapauth_drupal_user_name(NULL, NULL, NULL, TRUE); if ( module_exists('ldapgroups')) { ldapgroups_groups_load(NULL, NULL, NULL, TRUE); } return $account; } ////////////////////////////////////////////////////////////////////////////// // Auxiliary functions /** * Initiates the LDAPInterfase class. * * @param $sid * An ID of the LDAP server configuration. * * @return */ function _ldapsync_init($sid) { global $_ldapsync_ldap; $server = ldapauth_server_load($sid); if (! empty($server) ) { $_ldapsync_ldap = new LDAPInterface(); $_ldapsync_ldap->setOption('sid', $server->sid); $_ldapsync_ldap->setOption('name', $server->name); $_ldapsync_ldap->setOption('machine_name', $server->machine_name); $_ldapsync_ldap->setOption('server', $server->server); $_ldapsync_ldap->setOption('port', $server->port); $_ldapsync_ldap->setOption('tls', $server->tls); $_ldapsync_ldap->setOption('enc_type', $server->enc_type); $_ldapsync_ldap->setOption('basedn', $server->basedn); $_ldapsync_ldap->setOption('user_attr', $server->user_attr); $_ldapsync_ldap->setOption('mail_attr', $server->mail_attr); $_ldapsync_ldap->setOption('puid_attr', $server->puid_attr); $_ldapsync_ldap->setOption('binary_puid', $server->binary_puid); $_ldapsync_ldap->setOption('binddn', $server->binddn); $_ldapsync_ldap->setOption('bindpw', $server->bindpw); return $_ldapsync_ldap; } } /** * Statistics counter function to track summary info. * * @param string $type The statistics category, e.g. new_users, notices, etc. * @param int $n number of users to add to category, defaults to 0. * @return int current count of users in category; */ function ldapsync_stats( $type, $n=0 ) { static $stats = array(); if ( ! isset($stats[$type] ) ) { $stats[$type] = 0; } $stats[$type] += $n; return $stats[$type]; }