MDL-8857
[moodle-linuxchix.git] / auth / ldap / auth.php
blob96d932705234ccd717cf7fe86d0d4906ed2943ba
1 <?php
3 /**
4 * @author Martin Dougiamas
5 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
6 * @package moodle multiauth
8 * Authentication Plugin: LDAP Authentication
10 * Authentication using LDAP (Lightweight Directory Access Protocol).
12 * 2006-08-28 File created.
15 if (!defined('MOODLE_INTERNAL')) {
16 die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page
19 /**
20 * LDAP authentication plugin.
22 class auth_plugin_ldap {
24 /**
25 * The configuration details for the plugin.
27 var $config;
29 /**
30 * Constructor with initialisation.
32 function auth_plugin_ldap() {
33 $this->config = get_config('auth/ldap');
34 if (empty($this->config->ldapencoding)) {
35 $this->config->ldapencoding = 'utf-8';
37 if (empty($this->config->user_type)) {
38 $this->config->user_type = 'default';
41 $default = $this->ldap_getdefaults();
43 //use defaults if values not given
44 foreach ($default as $key => $value) {
45 // watch out - 0, false are correct values too
46 if (!isset($this->config->{$key}) or $this->config->{$key} == '') {
47 $this->config->{$key} = $value[$this->config->user_type];
50 //hack prefix to objectclass
51 if (empty($this->config->objectclass)) { // Can't send empty filter
52 $this->config->objectclass='objectClass=*';
53 } else if (strpos($this->config->objectclass, 'objectClass=') !== 0) {
54 $this->config->objectclass = 'objectClass='.$this->config->objectclass;
59 /**
60 * Returns true if the username and password work and false if they are
61 * wrong or don't exist.
63 * @param string $username The username (with system magic quotes)
64 * @param string $password The password (with system magic quotes)
66 * @return bool Authentication success or failure.
68 function user_login($username, $password) {
69 if (! function_exists('ldap_bind')) {
70 print_error('auth_ldapnotinstalled','auth');
71 return false;
74 if (!$username or !$password) { // Don't allow blank usernames or passwords
75 return false;
78 $textlib = textlib_get_instance();
79 $extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding);
80 $extpassword = $textlib->convert(stripslashes($password), 'utf-8', $this->config->ldapencoding);
82 $ldapconnection = $this->ldap_connect();
84 if ($ldapconnection) {
85 $ldap_user_dn = $this->ldap_find_userdn($ldapconnection, $extusername);
87 //if ldap_user_dn is empty, user does not exist
88 if (!$ldap_user_dn) {
89 ldap_close($ldapconnection);
90 return false;
93 // Try to bind with current username and password
94 $ldap_login = @ldap_bind($ldapconnection, $ldap_user_dn, $extpassword);
95 ldap_close($ldapconnection);
96 if ($ldap_login) {
97 return true;
100 else {
101 @ldap_close($ldapconnection);
102 print_error('auth_ldap_noconnect','auth',$this->config->host_url);
104 return false;
108 * reads userinformation from ldap and return it in array()
110 * Read user information from external database and returns it as array().
111 * Function should return all information available. If you are saving
112 * this information to moodle user-table you should honor syncronization flags
114 * @param string $username username (with system magic quotes)
116 * @return mixed array with no magic quotes or false on error
118 function get_userinfo($username) {
119 $textlib = textlib_get_instance();
120 $extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding);
122 $ldapconnection = $this->ldap_connect();
123 $attrmap = $this->ldap_attributes();
125 $result = array();
126 $search_attribs = array();
128 foreach ($attrmap as $key=>$values) {
129 if (!is_array($values)) {
130 $values = array($values);
132 foreach ($values as $value) {
133 if (!in_array($value, $search_attribs)) {
134 array_push($search_attribs, $value);
139 $user_dn = $this->ldap_find_userdn($ldapconnection, $extusername);
141 if (!$user_info_result = ldap_read($ldapconnection, $user_dn, $this->config->objectclass, $search_attribs)) {
142 return false; // error!
144 $user_entry = $this->ldap_get_entries($ldapconnection, $user_info_result);
145 if (empty($user_entry)) {
146 return false; // entry not found
149 foreach ($attrmap as $key=>$values) {
150 if (!is_array($values)) {
151 $values = array($values);
153 $ldapval = NULL;
154 foreach ($values as $value) {
155 if (!array_key_exists($value, $user_entry[0])) {
156 continue; // wrong data mapping!
158 if (is_array($user_entry[0][$value])) {
159 $newval = $textlib->convert($user_entry[0][$value][0], $this->config->ldapencoding, 'utf-8');
160 } else {
161 $newval = $textlib->convert($user_entry[0][$value], $this->config->ldapencoding, 'utf-8');
163 if (!empty($newval)) { // favour ldap entries that are set
164 $ldapval = $newval;
167 if (!is_null($ldapval)) {
168 $result[$key] = $ldapval;
172 @ldap_close($ldapconnection);
173 return $result;
177 * reads userinformation from ldap and return it in an object
179 * @param string $username username (with system magic quotes)
180 * @return mixed object or false on error
182 function get_userinfo_asobj($username) {
183 $user_array = $this->get_userinfo($username);
184 if ($user_array == false) {
185 return false; //error or not found
187 $user_array = truncate_userinfo($user_array);
188 $user = new object();
189 foreach ($user_array as $key=>$value) {
190 $user->{$key} = $value;
192 return $user;
196 * returns all usernames from external database
198 * get_userlist returns all usernames from external database
200 * @return array
202 function get_userlist() {
203 return $this->ldap_get_userlist("({$this->config->user_attribute}=*)");
207 * checks if user exists on external db
209 * @param string $username (with system magic quotes)
211 function user_exists($username) {
213 $textlib = textlib_get_instance();
214 $extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding);
216 //returns true if given username exist on ldap
217 $users = $this->ldap_get_userlist("({$this->config->user_attribute}=".$this->filter_addslashes($extusername).")");
218 return count($users);
222 * Creates a new user on external database.
223 * By using information in userobject
224 * Use user_exists to prevent dublicate usernames
226 * @param mixed $userobject Moodle userobject (with system magic quotes)
227 * @param mixed $plainpass Plaintext password (with system magic quotes)
229 function user_create($userobject, $plainpass) {
230 $textlib = textlib_get_instance();
231 $extusername = $textlib->convert(stripslashes($userobject->username), 'utf-8', $this->config->ldapencoding);
232 $extpassword = $textlib->convert(stripslashes($plainpass), 'utf-8', $this->config->ldapencoding);
234 $ldapconnection = $this->ldap_connect();
235 $attrmap = $this->ldap_attributes();
237 $newuser = array();
239 foreach ($attrmap as $key => $values) {
240 if (!is_array($values)) {
241 $values = array($values);
243 foreach ($values as $value) {
244 if (!empty($userobject->$key) ) {
245 $newuser[$value] = $textlib->convert(stripslashes($userobject->$key), 'utf-8', $this->config->ldapencoding);
250 //Following sets all mandatory and other forced attribute values
251 //User should be creted as login disabled untill email confirmation is processed
252 //Feel free to add your user type and send patches to paca@sci.fi to add them
253 //Moodle distribution
255 switch ($this->config->user_type) {
256 case 'edir':
257 $newuser['objectClass'] = array("inetOrgPerson","organizationalPerson","person","top");
258 $newuser['uniqueId'] = $extusername;
259 $newuser['logindisabled'] = "TRUE";
260 $newuser['userpassword'] = $extpassword;
261 break;
262 default:
263 print_error('auth_ldap_unsupportedusertype','auth',$this->config->user_type);
265 $uadd = $this->ldap_add($ldapconnection, $this->config->user_attribute.'="'.$this->ldap_addslashes($userobject->username).','.$this->config->create_context.'"', $newuser);
266 ldap_close($ldapconnection);
267 return $uadd;
272 * return number of days to user password expires
274 * If userpassword does not expire it should return 0. If password is already expired
275 * it should return negative value.
277 * @param mixed $username username
278 * @return integer
280 function password_expire($username) {
281 $result = false;
283 $textlib = textlib_get_instance();
284 $extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding);
286 $ldapconnection = $this->ldap_connect();
287 $user_dn = $this->ldap_find_userdn($ldapconnection, $extusername);
288 $search_attribs = array($this->config->expireattr);
289 $sr = ldap_read($ldapconnection, $user_dn, 'objectclass=*', $search_attribs);
290 if ($sr) {
291 $info = $this->ldap_get_entries($ldapconnection, $sr);
292 if (empty ($info) or empty($info[0][$this->config->expireattr][0])) {
293 //error_log("ldap: no expiration value".$info[0][$this->config->expireattr]);
294 // no expiration attribute, password does not expire
295 $result = 0;
297 else {
298 $now = time();
299 $expiretime = $this->ldap_expirationtime2unix($info[0][$this->config->expireattr][0]);
300 if ($expiretime > $now) {
301 $result = ceil(($expiretime - $now) / DAYSECS);
303 else {
304 $result = floor(($expiretime - $now) / DAYSECS);
307 } else {
308 error_log("ldap: password_expire did't find expiration time.");
311 //error_log("ldap: password_expire user $user_dn expires in $result days!");
312 return $result;
316 * syncronizes user fron external db to moodle user table
318 * Sync is now using username attribute.
320 * Syncing users removes or suspends users that dont exists anymore in external db.
321 * Creates new users and updates coursecreator status of users.
323 * @param int $bulk_insert_records will insert $bulkinsert_records per insert statement
324 * valid only with $unsafe. increase to a couple thousand for
325 * blinding fast inserts -- but test it: you may hit mysqld's
326 * max_allowed_packet limit.
327 * @param bool $do_updates will do pull in data updates from ldap if relevant
329 function sync_users ($bulk_insert_records = 1000, $do_updates = true) {
331 global $CFG;
333 $textlib = textlib_get_instance();
335 $droptablesql = array(); /// sql commands to drop the table (because session scope could be a problem for
336 /// some persistent drivers like ODBTP (mssql) or if this function is invoked
337 /// from within a PHP application using persistent connections
339 // configure a temp table
340 print "Configuring temp table\n";
341 switch (strtolower($CFG->dbfamily)) {
342 case 'mysql':
343 $temptable = $CFG->prefix . 'extuser';
344 $droptablesql[] = 'DROP TEMPORARY TABLE ' . $temptable; // sql command to drop the table (because session scope could be a problem)
345 execute_sql_arr($droptablesql, true, false); /// Drop temp table to avoid persistence problems later
346 echo "Creating temp table $temptable\n";
347 execute_sql('CREATE TEMPORARY TABLE ' . $temptable . ' (username VARCHAR(64), PRIMARY KEY (username)) TYPE=MyISAM', false);
348 break;
349 case 'postgres':
350 $temptable = $CFG->prefix . 'extuser';
351 $droptablesql[] = 'DROP TABLE ' . $temptable; // sql command to drop the table (because session scope could be a problem)
352 execute_sql_arr($droptablesql, true, false); /// Drop temp table to avoid persistence problems later
353 echo "Creating temp table $temptable\n";
354 $bulk_insert_records = 1; // no support for multiple sets of values
355 execute_sql('CREATE TEMPORARY TABLE '. $temptable . ' (username VARCHAR(64), PRIMARY KEY (username))', false);
356 break;
357 case 'mssql':
358 $temptable = '#'.$CFG->prefix . 'extuser'; /// MSSQL temp tables begin with #
359 $droptablesql[] = 'DROP TABLE ' . $temptable; // sql command to drop the table (because session scope could be a problem)
360 execute_sql_arr($droptablesql, true, false); /// Drop temp table to avoid persistence problems later
361 echo "Creating temp table $temptable\n";
362 $bulk_insert_records = 1; // no support for multiple sets of values
363 execute_sql('CREATE TABLE ' . $temptable . ' (username VARCHAR(64), PRIMARY KEY (username))', false);
364 break;
365 case 'oracle':
366 $temptable = $CFG->prefix . 'extuser';
367 $droptablesql[] = 'TRUNCATE TABLE ' . $temptable; // oracle requires truncate before being able to drop a temp table
368 $droptablesql[] = 'DROP TABLE ' . $temptable; // sql command to drop the table (because session scope could be a problem)
369 execute_sql_arr($droptablesql, true, false); /// Drop temp table to avoid persistence problems later
370 echo "Creating temp table $temptable\n";
371 $bulk_insert_records = 1; // no support for multiple sets of values
372 execute_sql('CREATE GLOBAL TEMPORARY TABLE '.$temptable.' (username VARCHAR(64), PRIMARY KEY (username)) ON COMMIT PRESERVE ROWS', false);
373 break;
376 print "Connecting to ldap...\n";
377 $ldapconnection = $this->ldap_connect();
379 if (!$ldapconnection) {
380 @ldap_close($ldapconnection);
381 print get_string('auth_ldap_noconnect','auth',$this->config->host_url);
382 exit;
385 ////
386 //// get user's list from ldap to sql in a scalable fashion
387 ////
388 // prepare some data we'll need
389 $filter = "(&(".$this->config->user_attribute."=*)(".$this->config->objectclass."))";
391 $contexts = explode(";",$this->config->contexts);
393 if (!empty($this->config->create_context)) {
394 array_push($contexts, $this->config->create_context);
397 $fresult = array();
398 foreach ($contexts as $context) {
399 $context = trim($context);
400 if (empty($context)) {
401 continue;
403 begin_sql();
404 if ($this->config->search_sub) {
405 //use ldap_search to find first user from subtree
406 $ldap_result = ldap_search($ldapconnection, $context,
407 $filter,
408 array($this->config->user_attribute));
409 } else {
410 //search only in this context
411 $ldap_result = ldap_list($ldapconnection, $context,
412 $filter,
413 array($this->config->user_attribute));
416 if ($entry = ldap_first_entry($ldapconnection, $ldap_result)) {
417 do {
418 $value = ldap_get_values_len($ldapconnection, $entry, $this->config->user_attribute);
419 $value = $textlib->convert($value[0], $this->config->ldapencoding, 'utf-8');
420 array_push($fresult, $value);
421 if (count($fresult) >= $bulk_insert_records) {
422 $this->ldap_bulk_insert($fresult, $temptable);
423 $fresult = array();
425 } while ($entry = ldap_next_entry($ldapconnection, $entry));
427 unset($ldap_result); // free mem
429 // insert any remaining users and release mem
430 if (count($fresult)) {
431 $this->ldap_bulk_insert($fresult, $temptable);
432 $fresult = array();
434 commit_sql();
437 /// preserve our user database
438 /// if the temp table is empty, it probably means that something went wrong, exit
439 /// so as to avoid mass deletion of users; which is hard to undo
440 $count = get_record_sql('SELECT COUNT(username) AS count, 1 FROM ' . $temptable);
441 $count = $count->{'count'};
442 if ($count < 1) {
443 print "Did not get any users from LDAP -- error? -- exiting\n";
444 exit;
445 } else {
446 print "Got $count records from LDAP\n\n";
450 /// User removal
451 // find users in DB that aren't in ldap -- to be removed!
452 // this is still not as scalable (but how often do we mass delete?)
453 if (!empty($this->config->removeuser)) {
454 $sql = "SELECT u.id, u.username, u.email
455 FROM {$CFG->prefix}user u
456 LEFT JOIN $temptable e ON u.username = e.username
457 WHERE u.auth='ldap'
458 AND u.deleted=0
459 AND e.username IS NULL";
460 $remove_users = get_records_sql($sql);
462 if (!empty($remove_users)) {
463 print "User entries to remove: ". count($remove_users) . "\n";
465 begin_sql();
466 foreach ($remove_users as $user) {
467 if ($this->config->removeuser == 2) {
468 //following is copy pasted from admin/user.php
469 //maybe this should moved to function in lib/datalib.php
470 $updateuser = new object();
471 $updateuser->id = $user->id;
472 $updateuser->deleted = 1;
473 $updateuser->username = addslashes("$user->email.".time()); // Remember it just in case
474 $updateuser->email = ''; // Clear this field to free it up
475 $updateuser->idnumber = ''; // Clear this field to free it up
476 $updateuser->timemodified = time();
477 if (update_record('user', $updateuser)) {
478 delete_records('role_assignments', 'userid', $user->id); // unassign all roles
479 //copy pasted part ends
480 echo "\t"; print_string('auth_dbdeleteuser', 'auth', array($user->username, $user->id)); echo "\n";
481 } else {
482 echo "\t"; print_string('auth_dbdeleteusererror', 'auth', $user->username); echo "\n";
484 } else if ($this->config->removeuser == 1) {
485 $updateuser = new object();
486 $updateuser->id = $user->id;
487 $updateuser->auth = 'nologin';
488 if (update_record('user', $updateuser)) {
489 echo "\t"; print_string('auth_dbsuspenduser', 'auth', array($user->username, $user->id)); echo "\n";
490 } else {
491 echo "\t"; print_string('auth_dbsuspendusererror', 'auth', $user->username); echo "\n";
495 commit_sql();
496 } else {
497 print "No user entries to be removed\n";
499 unset($remove_users); // free mem!
502 /// Revive suspended users
503 if (!empty($this->config->removeuser) and $this->config->removeuser == 1) {
504 $sql = "SELECT u.id, u.username
505 FROM $temptable e, {$CFG->prefix}user u
506 WHERE e.username=u.username
507 AND u.auth='nologin'";
508 $revive_users = get_records_sql($sql);
510 if (!empty($revive_users)) {
511 print "User entries to be revived: ". count($revive_users) . "\n";
513 begin_sql();
514 foreach ($revive_users as $user) {
515 $updateuser = new object();
516 $updateuser->id = $user->id;
517 $updateuser->auth = 'ldap';
518 if (update_record('user', $updateuser)) {
519 echo "\t"; print_string('auth_dbreviveser', 'auth', array($user->username, $user->id)); echo "\n";
520 } else {
521 echo "\t"; print_string('auth_dbreviveusererror', 'auth', $user->username); echo "\n";
524 commit_sql();
525 } else {
526 print "No user entries to be revived\n";
529 unset($revive_users);
533 /// User Updates - time-consuming (optional)
534 if ($do_updates) {
535 // narrow down what fields we need to update
536 $all_keys = array_keys(get_object_vars($this->config));
537 $updatekeys = array();
538 foreach ($all_keys as $key) {
539 if (preg_match('/^field_updatelocal_(.+)$/',$key, $match)) {
540 // if we have a field to update it from
541 // and it must be updated 'onlogin' we
542 // update it on cron
543 if ( !empty($this->config->{'field_map_'.$match[1]})
544 and $this->config->{$match[0]} === 'onlogin') {
545 array_push($updatekeys, $match[1]); // the actual key name
549 // print_r($all_keys); print_r($updatekeys);
550 unset($all_keys); unset($key);
552 } else {
553 print "No updates to be done\n";
555 if ( $do_updates and !empty($updatekeys) ) { // run updates only if relevant
556 $users = get_records_sql("SELECT u.username, u.id
557 FROM {$CFG->prefix}user u
558 WHERE u.deleted=0 AND u.auth='ldap'");
559 if (!empty($users)) {
560 print "User entries to update: ". count($users). "\n";
562 $sitecontext = get_context_instance(CONTEXT_SYSTEM);
563 if (!empty($this->config->creators) and !empty($this->config->memberattribute)
564 and $roles = get_roles_with_capability('moodle/legacy:coursecreator', CAP_ALLOW)) {
565 $creatorrole = array_shift($roles); // We can only use one, let's use the first one
566 } else {
567 $creatorrole = false;
570 begin_sql();
571 $xcount = 0;
572 $maxxcount = 100;
574 foreach ($users as $user) {
575 echo "\t"; print_string('auth_dbupdatinguser', 'auth', array($user->username, $user->id));
576 if (!$this->update_user_record(addslashes($user->username), $updatekeys)) {
577 echo " - ".get_string('skipped');
579 echo "\n";
580 $xcount++;
582 // update course creators if needed
583 if ($creatorrole !== false) {
584 if ($this->iscreator($user->username)) {
585 role_assign($creatorrole->id, $user->id, 0, $sitecontext->id, 0, 0, 0, 'ldap');
586 } else {
587 role_unassign($creatorrole->id, $user->id, 0, $sitecontext->id);
591 if ($xcount++ > $maxxcount) {
592 commit_sql();
593 begin_sql();
594 $xcount = 0;
597 commit_sql();
598 unset($users); // free mem
600 } else { // end do updates
601 print "No updates to be done\n";
604 /// User Additions
605 // find users missing in DB that are in LDAP
606 // note that get_records_sql wants at least 2 fields returned,
607 // and gives me a nifty object I don't want.
608 // note: we do not care about deleted accounts anymore, this feature was replaced by suspending to nologin auth plugin
609 $sql = "SELECT e.username, e.username
610 FROM $temptable e LEFT JOIN {$CFG->prefix}user u ON e.username = u.username
611 WHERE u.id IS NULL";
612 $add_users = get_records_sql($sql); // get rid of the fat
614 if (!empty($add_users)) {
615 print "User entries to add: ". count($add_users). "\n";
617 $sitecontext = get_context_instance(CONTEXT_SYSTEM);
618 if (!empty($this->config->creators) and !empty($this->config->memberattribute)
619 and $roles = get_roles_with_capability('moodle/legacy:coursecreator', CAP_ALLOW)) {
620 $creatorrole = array_shift($roles); // We can only use one, let's use the first one
621 } else {
622 $creatorrole = false;
625 begin_sql();
626 foreach ($add_users as $user) {
627 $user = $this->get_userinfo_asobj(addslashes($user->username));
629 // prep a few params
630 $user->modified = time();
631 $user->confirmed = 1;
632 $user->auth = 'ldap';
633 $user->mnethostid = $CFG->mnet_localhost_id;
634 if (empty($user->lang)) {
635 $user->lang = $CFG->lang;
638 $user = addslashes_recursive($user);
640 if ($id = insert_record('user',$user)) {
641 echo "\t"; print_string('auth_dbinsertuser', 'auth', array(stripslashes($user->username), $id)); echo "\n";
642 $userobj = $this->update_user_record($user->username);
643 if (!empty($this->config->forcechangepassword)) {
644 set_user_preference('auth_forcepasswordchange', 1, $userobj->id);
646 } else {
647 echo "\t"; print_string('auth_dbinsertusererror', 'auth', $user->username); echo "\n";
650 // add course creators if needed
651 if ($creatorrole !== false and $this->iscreator(stripslashes($user->username))) {
652 role_assign($creatorrole->id, $user->id, 0, $sitecontext->id, 0, 0, 0, 'ldap');
655 commit_sql();
656 unset($add_users); // free mem
657 } else {
658 print "No users to be added\n";
660 return true;
664 * Update a local user record from an external source.
665 * This is a lighter version of the one in moodlelib -- won't do
666 * expensive ops such as enrolment.
668 * If you don't pass $updatekeys, there is a performance hit and
669 * values removed from LDAP won't be removed from moodle.
671 * @param string $username username (with system magic quotes)
673 function update_user_record($username, $updatekeys = false) {
674 global $CFG;
676 //just in case check text case
677 $username = trim(moodle_strtolower($username));
679 // get the current user record
680 $user = get_record('user', 'username', $username, 'mnethostid', $CFG->mnet_localhost_id);
681 if (empty($user)) { // trouble
682 error_log("Cannot update non-existent user: ".stripslashes($username));
683 print_error('auth_dbusernotexist','auth',$username);
684 die;
687 // Protect the userid from being overwritten
688 $userid = $user->id;
690 if ($newinfo = $this->get_userinfo($username)) {
691 $newinfo = truncate_userinfo($newinfo);
693 if (empty($updatekeys)) { // all keys? this does not support removing values
694 $updatekeys = array_keys($newinfo);
697 foreach ($updatekeys as $key) {
698 if (isset($newinfo[$key])) {
699 $value = $newinfo[$key];
700 } else {
701 $value = '';
704 if (!empty($this->config->{'field_updatelocal_' . $key})) {
705 if ($user->{$key} != $value) { // only update if it's changed
706 set_field('user', $key, addslashes($value), 'id', $userid);
710 } else {
711 return false;
713 return get_record_select('user', "id = $userid AND deleted = 0");
717 * Bulk insert in SQL's temp table
718 * @param array $users is an array of usernames
720 function ldap_bulk_insert($users, $temptable) {
722 // bulk insert -- superfast with $bulk_insert_records
723 $sql = 'INSERT INTO ' . $temptable . ' (username) VALUES ';
724 // make those values safe
725 $users = addslashes_recursive($users);
726 // join and quote the whole lot
727 $sql = $sql . "('" . implode("'),('", $users) . "')";
728 print "\t+ " . count($users) . " users\n";
729 execute_sql($sql, false);
734 * Activates (enables) user in external db so user can login to external db
736 * @param mixed $username username (with system magic quotes)
737 * @return boolen result
739 function user_activate($username) {
740 $textlib = textlib_get_instance();
741 $extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding);
743 $ldapconnection = $this->ldap_connect();
745 $userdn = $this->ldap_find_userdn($ldapconnection, $extusername);
746 switch ($this->config->user_type) {
747 case 'edir':
748 $newinfo['loginDisabled']="FALSE";
749 break;
750 default:
751 error ('auth: ldap user_activate() does not support selected usertype:"'.$this->config->user_type.'" (..yet)');
753 $result = ldap_modify($ldapconnection, $userdn, $newinfo);
754 ldap_close($ldapconnection);
755 return $result;
759 * Disables user in external db so user can't login to external db
761 * @param mixed $username username
762 * @return boolean result
764 /* function user_disable($username) {
765 $textlib = textlib_get_instance();
766 $extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding);
768 $ldapconnection = $this->ldap_connect();
770 $userdn = $this->ldap_find_userdn($ldapconnection, $extusername);
771 switch ($this->config->user_type) {
772 case 'edir':
773 $newinfo['loginDisabled']="TRUE";
774 break;
775 default:
776 error ('auth: ldap user_disable() does not support selected usertype (..yet)');
778 $result = ldap_modify($ldapconnection, $userdn, $newinfo);
779 ldap_close($ldapconnection);
780 return $result;
784 * Returns true if user should be coursecreator.
786 * @param mixed $username username (with system magic quotes)
787 * @return boolean result
789 function iscreator($username = false) {
790 global $USER;
792 if (empty($this->config->creators) or empty($this->config->memberattribute)) {
793 return false;
796 if ($username === false) {
797 $username = $USER->username;
798 } else {
799 $username = stripslashes($username);
802 $textlib = textlib_get_instance();
803 $extusername = $textlib->convert($username, 'utf-8', $this->config->ldapencoding);
805 return $this->ldap_isgroupmember($extusername, $this->config->creators);
809 * Called when the user record is updated.
810 * Modifies user in external database. It takes olduser (before changes) and newuser (after changes)
811 * conpares information saved modified information to external db.
813 * @param mixed $olduser Userobject before modifications (without system magic quotes)
814 * @param mixed $newuser Userobject new modified userobject (without system magic quotes)
815 * @return boolean result
818 function user_update($olduser, $newuser) {
820 global $USER;
822 if (isset($olduser->username) and isset($newuser->username) and $olduser->username != $newuser->username) {
823 error_log("ERROR:User renaming not allowed in LDAP");
824 return false;
827 if (isset($olduser->auth) and $olduser->auth == 'ldap') {
828 return true; // just change auth and skip update
831 $textlib = textlib_get_instance();
832 $extoldusername = $textlib->convert($olduser->username, 'utf-8', $this->config->ldapencoding);
834 $ldapconnection = $this->ldap_connect();
836 $search_attribs = array();
838 $attrmap = $this->ldap_attributes();
839 foreach ($attrmap as $key => $values) {
840 if (!is_array($values)) {
841 $values = array($values);
843 foreach ($values as $value) {
844 if (!in_array($value, $search_attribs)) {
845 array_push($search_attribs, $value);
850 $user_dn = $this->ldap_find_userdn($ldapconnection, $extoldusername);
852 $user_info_result = ldap_read($ldapconnection, $user_dn,
853 $this->config->objectclass, $search_attribs);
855 if ($user_info_result) {
857 $user_entry = $this->ldap_get_entries($ldapconnection, $user_info_result);
858 if (empty($user_entry)) {
859 return false; // old user not found!
860 } else if (count($user_entry) > 1) {
861 trigger_error("ldap: Strange! More than one user record found in ldap. Only using the first one.");
862 return false;
864 $user_entry = $user_entry[0];
866 //error_log(var_export($user_entry) . 'fpp' );
868 foreach ($attrmap as $key => $ldapkeys) {
869 // only process if the moodle field ($key) has changed and we
870 // are set to update LDAP with it
871 if (isset($olduser->$key) and isset($newuser->$key)
872 and $olduser->$key !== $newuser->$key
873 and !empty($this->config->{'field_updateremote_'. $key})) {
874 // for ldap values that could be in more than one
875 // ldap key, we will do our best to match
876 // where they came from
877 $ambiguous = true;
878 $changed = false;
879 if (!is_array($ldapkeys)) {
880 $ldapkeys = array($ldapkeys);
882 if (count($ldapkeys) < 2) {
883 $ambiguous = false;
886 $nuvalue = $textlib->convert($newuser->$key, 'utf-8', $this->config->ldapencoding);
887 $ouvalue = $textlib->convert($olduser->$key, 'utf-8', $this->config->ldapencoding);
889 foreach ($ldapkeys as $ldapkey) {
890 $ldapkey = $ldapkey;
891 $ldapvalue = $user_entry[$ldapkey][0];
892 if (!$ambiguous) {
893 // skip update if the values already match
894 if ($nuvalue !== $ldapvalue) {
895 //this might fail due to schema validation
896 if (@ldap_modify($ldapconnection, $user_dn, array($ldapkey => $nuvalue))) {
897 continue;
898 } else {
899 error_log('Error updating LDAP record. Error code: '
900 . ldap_errno($ldapconnection) . '; Error string : '
901 . ldap_err2str(ldap_errno($ldapconnection))
902 . "\nKey ($key) - old moodle value: '$ouvalue' new value: '$nuvalue'");
903 continue;
906 } else {
907 // ambiguous
908 // value empty before in Moodle (and LDAP) - use 1st ldap candidate field
909 // no need to guess
910 if ($ouvalue === '') { // value empty before - use 1st ldap candidate
911 //this might fail due to schema validation
912 if (@ldap_modify($ldapconnection, $user_dn, array($ldapkey => $nuvalue))) {
913 $changed = true;
914 continue;
915 } else {
916 error_log('Error updating LDAP record. Error code: '
917 . ldap_errno($ldapconnection) . '; Error string : '
918 . ldap_err2str(ldap_errno($ldapconnection))
919 . "\nKey ($key) - old moodle value: '$ouvalue' new value: '$nuvalue'");
920 continue;
924 // we found which ldap key to update!
925 if ($ouvalue !== '' and $ouvalue === $ldapvalue ) {
926 //this might fail due to schema validation
927 if (@ldap_modify($ldapconnection, $user_dn, array($ldapkey => $nuvalue))) {
928 $changed = true;
929 continue;
930 } else {
931 error_log('Error updating LDAP record. Error code: '
932 . ldap_errno($ldapconnection) . '; Error string : '
933 . ldap_err2str(ldap_errno($ldapconnection))
934 . "\nKey ($key) - old moodle value: '$ouvalue' new value: '$nuvalue'");
935 continue;
941 if ($ambiguous and !$changed) {
942 error_log("Failed to update LDAP with ambiguous field $key".
943 " old moodle value: '" . $ouvalue .
944 "' new value '" . $nuvalue );
948 } else {
949 error_log("ERROR:No user found in LDAP");
950 @ldap_close($ldapconnection);
951 return false;
954 @ldap_close($ldapconnection);
956 return true;
961 * changes userpassword in external db
963 * called when the user password is updated.
964 * changes userpassword in external db
966 * @param object $user User table object (with system magic quotes)
967 * @param string $newpassword Plaintext password (with system magic quotes)
968 * @return boolean result
971 function user_update_password($user, $newpassword) {
972 /// called when the user password is updated -- it assumes it is called by an admin
973 /// or that you've otherwise checked the user's credentials
974 /// IMPORTANT: $newpassword must be cleartext, not crypted/md5'ed
976 global $USER;
977 $result = false;
978 $username = $user->username;
980 $textlib = textlib_get_instance();
981 $extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding);
982 $extpassword = $textlib->convert(stripslashes($newpassword), 'utf-8', $this->config->ldapencoding);
984 $ldapconnection = $this->ldap_connect();
986 $user_dn = $this->ldap_find_userdn($ldapconnection, $extusername);
988 if (!$user_dn) {
989 error_log('LDAP Error in user_update_password(). No DN for: ' . stripslashes($user->username));
990 return false;
993 switch ($this->config->user_type) {
994 case 'edir':
995 //Change password
996 $result = ldap_modify($ldapconnection, $user_dn, array('userPassword' => $extpassword));
997 if (!$result) {
998 error_log('LDAP Error in user_update_password(). Error code: '
999 . ldap_errno($ldapconnection) . '; Error string : '
1000 . ldap_err2str(ldap_errno($ldapconnection)));
1002 //Update password expiration time, grace logins count
1003 $search_attribs = array($this->config->expireattr, 'passwordExpirationInterval','loginGraceLimit' );
1004 $sr = ldap_read($ldapconnection, $user_dn, 'objectclass=*', $search_attribs);
1005 if ($sr) {
1006 $info=$this->ldap_get_entries($ldapconnection, $sr);
1007 $newattrs = array();
1008 if (!empty($info[0][$this->config->expireattr][0])) {
1009 //Set expiration time only if passwordExpirationInterval is defined
1010 if (!empty($info[0]['passwordExpirationInterval'][0])) {
1011 $expirationtime = time() + $info[0]['passwordExpirationInterval'][0];
1012 $ldapexpirationtime = $this->ldap_unix2expirationtime($expirationtime);
1013 $newattrs['passwordExpirationTime'] = $ldapexpirationtime;
1016 //set gracelogin count
1017 if (!empty($info[0]['loginGraceLimit'][0])) {
1018 $newattrs['loginGraceRemaining']= $info[0]['loginGraceLimit'][0];
1021 //Store attribute changes to ldap
1022 $result = ldap_modify($ldapconnection, $user_dn, $newattrs);
1023 if (!$result) {
1024 error_log('LDAP Error in user_update_password() when modifying expirationtime and/or gracelogins. Error code: '
1025 . ldap_errno($ldapconnection) . '; Error string : '
1026 . ldap_err2str(ldap_errno($ldapconnection)));
1030 else {
1031 error_log('LDAP Error in user_update_password() when reading password expiration time. Error code: '
1032 . ldap_errno($ldapconnection) . '; Error string : '
1033 . ldap_err2str(ldap_errno($ldapconnection)));
1035 break;
1037 default:
1038 $usedconnection = &$ldapconnection;
1039 // send ldap the password in cleartext, it will md5 it itself
1040 $result = ldap_modify($ldapconnection, $user_dn, array('userPassword' => $extpassword));
1041 if (!$result) {
1042 error_log('LDAP Error in user_update_password(). Error code: '
1043 . ldap_errno($ldapconnection) . '; Error string : '
1044 . ldap_err2str(ldap_errno($ldapconnection)));
1049 @ldap_close($ldapconnection);
1050 return $result;
1053 //PRIVATE FUNCTIONS starts
1054 //private functions are named as ldap_*
1057 * returns predefined usertypes
1059 * @return array of predefined usertypes
1061 function ldap_suppported_usertypes() {
1062 $types = array();
1063 $types['edir']='Novell Edirectory';
1064 $types['rfc2307']='posixAccount (rfc2307)';
1065 $types['rfc2307bis']='posixAccount (rfc2307bis)';
1066 $types['samba']='sambaSamAccount (v.3.0.7)';
1067 $types['ad']='MS ActiveDirectory';
1068 $types['default']=get_string('default');
1069 return $types;
1074 * Initializes needed variables for ldap-module
1076 * Uses names defined in ldap_supported_usertypes.
1077 * $default is first defined as:
1078 * $default['pseudoname'] = array(
1079 * 'typename1' => 'value',
1080 * 'typename2' => 'value'
1081 * ....
1082 * );
1084 * @return array of default values
1086 function ldap_getdefaults() {
1087 $default['objectclass'] = array(
1088 'edir' => 'User',
1089 'rfc2307' => 'posixAccount',
1090 'rfc2307bis' => 'posixAccount',
1091 'samba' => 'sambaSamAccount',
1092 'ad' => 'user',
1093 'default' => '*'
1095 $default['user_attribute'] = array(
1096 'edir' => 'cn',
1097 'rfc2307' => 'uid',
1098 'rfc2307bis' => 'uid',
1099 'samba' => 'uid',
1100 'ad' => 'cn',
1101 'default' => 'cn'
1103 $default['memberattribute'] = array(
1104 'edir' => 'member',
1105 'rfc2307' => 'member',
1106 'rfc2307bis' => 'member',
1107 'samba' => 'member',
1108 'ad' => 'member',
1109 'default' => 'member'
1111 $default['memberattribute_isdn'] = array(
1112 'edir' => '1',
1113 'rfc2307' => '0',
1114 'rfc2307bis' => '1',
1115 'samba' => '0', //is this right?
1116 'ad' => '1',
1117 'default' => '0'
1119 $default['expireattr'] = array (
1120 'edir' => 'passwordExpirationTime',
1121 'rfc2307' => 'shadowExpire',
1122 'rfc2307bis' => 'shadowExpire',
1123 'samba' => '', //No support yet
1124 'ad' => '', //No support yet
1125 'default' => ''
1127 return $default;
1131 * return binaryfields of selected usertype
1134 * @return array
1136 function ldap_getbinaryfields () {
1137 $binaryfields = array (
1138 'edir' => array('guid'),
1139 'rfc2307' => array(),
1140 'rfc2307bis' => array(),
1141 'samba' => array(),
1142 'ad' => array(),
1143 'default' => array()
1145 if (!empty($this->config->user_type)) {
1146 return $binaryfields[$this->config->user_type];
1148 else {
1149 return $binaryfields['default'];
1153 function ldap_isbinary ($field) {
1154 if (empty($field)) {
1155 return false;
1157 return array_search($field, $this->ldap_getbinaryfields());
1161 * take expirationtime and return it as unixseconds
1163 * takes expriration timestamp as readed from ldap
1164 * returns it as unix seconds
1165 * depends on $this->config->user_type variable
1167 * @param mixed time Time stamp readed from ldap as it is.
1168 * @return timestamp
1170 function ldap_expirationtime2unix ($time) {
1171 $result = false;
1172 switch ($this->config->user_type) {
1173 case 'edir':
1174 $yr=substr($time,0,4);
1175 $mo=substr($time,4,2);
1176 $dt=substr($time,6,2);
1177 $hr=substr($time,8,2);
1178 $min=substr($time,10,2);
1179 $sec=substr($time,12,2);
1180 $result = mktime($hr,$min,$sec,$mo,$dt,$yr);
1181 break;
1182 case 'posix':
1183 $result = $time * DAYSECS; //The shadowExpire contains the number of DAYS between 01/01/1970 and the actual expiration date
1184 break;
1185 default:
1186 print_error('auth_ldap_usertypeundefined', 'auth');
1188 return $result;
1192 * takes unixtime and return it formated for storing in ldap
1194 * @param integer unix time stamp
1196 function ldap_unix2expirationtime($time) {
1197 $result = false;
1198 switch ($this->config->user_type) {
1199 case 'edir':
1200 $result=date('YmdHis', $time).'Z';
1201 break;
1202 case 'posix':
1203 $result = $time ; //Already in correct format
1204 break;
1205 default:
1206 print_error('auth_ldap_usertypeundefined2', 'auth');
1208 return $result;
1213 * checks if user belong to specific group(s)
1215 * Returns true if user belongs group in grupdns string.
1217 * @param mixed $username username
1218 * @param mixed $groupdns string of group dn separated by ;
1221 function ldap_isgroupmember($extusername='', $groupdns='') {
1222 // Takes username and groupdn(s) , separated by ;
1223 // Returns true if user is member of any given groups
1225 $result = false;
1226 $ldapconnection = $this->ldap_connect();
1228 if (empty($username) or empty($groupdns)) {
1229 return $result;
1232 if ($this->config->memberattribute_isdn) {
1233 $username=$this->ldap_find_userdn($ldapconnection, $username);
1235 if (! $username ) {
1236 return $result;
1239 $groups = explode(";",$groupdns);
1241 foreach ($groups as $group) {
1242 $group = trim($group);
1243 if (empty($group)) {
1244 continue;
1246 //echo "Checking group $group for member $username\n";
1247 $search = @ldap_read($ldapconnection, $group, '('.$this->config->memberattribute.'='.$this->filter_addslashes($username).')', array($this->config->memberattribute));
1249 if (!empty($search) and ldap_count_entries($ldapconnection, $search)) {$info = $this->ldap_get_entries($ldapconnection, $search);
1251 if (count($info) > 0 ) {
1252 // user is member of group
1253 $result = true;
1254 break;
1259 return $result;
1264 * connects to ldap server
1266 * Tries connect to specified ldap servers.
1267 * Returns connection result or error.
1269 * @return connection result
1271 function ldap_connect($binddn='',$bindpwd='') {
1272 //Select bind password, With empty values use
1273 //ldap_bind_* variables or anonymous bind if ldap_bind_* are empty
1274 if ($binddn == '' and $bindpwd == '') {
1275 if (!empty($this->config->bind_dn)) {
1276 $binddn = $this->config->bind_dn;
1278 if (!empty($this->config->bind_pw)) {
1279 $bindpwd = $this->config->bind_pw;
1283 $urls = explode(";",$this->config->host_url);
1285 foreach ($urls as $server) {
1286 $server = trim($server);
1287 if (empty($server)) {
1288 continue;
1291 $connresult = ldap_connect($server);
1292 //ldap_connect returns ALWAYS true
1294 if (!empty($this->config->version)) {
1295 ldap_set_option($connresult, LDAP_OPT_PROTOCOL_VERSION, $this->config->version);
1298 if (!empty($binddn)) {
1299 //bind with search-user
1300 //$debuginfo .= 'Using bind user'.$binddn.'and password:'.$bindpwd;
1301 $bindresult=ldap_bind($connresult, $binddn,$bindpwd);
1303 else {
1304 //bind anonymously
1305 $bindresult=@ldap_bind($connresult);
1308 if (!empty($this->config->opt_deref)) {
1309 ldap_set_option($connresult, LDAP_OPT_DEREF, $this->config->opt_deref);
1312 if ($bindresult) {
1313 return $connresult;
1316 $debuginfo .= "<br/>Server: '$server' <br/> Connection: '$connresult'<br/> Bind result: '$bindresult'</br>";
1319 //If any of servers are alive we have already returned connection
1320 print_error('auth_ldap_noconnect_all','auth',$this->config->user_type);
1321 return false;
1325 * retuns dn of username
1327 * Search specified contexts for username and return user dn
1328 * like: cn=username,ou=suborg,o=org
1330 * @param mixed $ldapconnection $ldapconnection result
1331 * @param mixed $username username (external encoding no slashes)
1335 function ldap_find_userdn ($ldapconnection, $extusername) {
1337 //default return value
1338 $ldap_user_dn = FALSE;
1340 //get all contexts and look for first matching user
1341 $ldap_contexts = explode(";",$this->config->contexts);
1343 if (!empty($this->config->create_context)) {
1344 array_push($ldap_contexts, $this->config->create_context);
1347 foreach ($ldap_contexts as $context) {
1349 $context = trim($context);
1350 if (empty($context)) {
1351 continue;
1354 if ($this->config->search_sub) {
1355 //use ldap_search to find first user from subtree
1356 $ldap_result = ldap_search($ldapconnection, $context, "(".$this->config->user_attribute."=".$this->filter_addslashes($extusername).")",array($this->config->user_attribute));
1359 else {
1360 //search only in this context
1361 $ldap_result = ldap_list($ldapconnection, $context, "(".$this->config->user_attribute."=".$this->filter_addslashes($extusername).")",array($this->config->user_attribute));
1364 $entry = ldap_first_entry($ldapconnection,$ldap_result);
1366 if ($entry) {
1367 $ldap_user_dn = ldap_get_dn($ldapconnection, $entry);
1368 break ;
1372 return $ldap_user_dn;
1376 * retuns user attribute mappings between moodle and ldap
1378 * @return array
1381 function ldap_attributes () {
1382 $fields = array("firstname", "lastname", "email", "phone1", "phone2",
1383 "department", "address", "city", "country", "description",
1384 "idnumber", "lang" );
1385 $moodleattributes = array();
1386 foreach ($fields as $field) {
1387 if (!empty($this->config->{"field_map_$field"})) {
1388 $moodleattributes[$field] = $this->config->{"field_map_$field"};
1389 if (preg_match('/,/',$moodleattributes[$field])) {
1390 $moodleattributes[$field] = explode(',', $moodleattributes[$field]); // split ?
1394 $moodleattributes['username'] = $this->config->user_attribute;
1395 return $moodleattributes;
1399 * return all usernames from ldap
1401 * @return array
1404 function ldap_get_userlist($filter="*") {
1405 /// returns all users from ldap servers
1406 $fresult = array();
1408 $ldapconnection = $this->ldap_connect();
1410 if ($filter=="*") {
1411 $filter = "(&(".$this->config->user_attribute."=*)(".$this->config->objectclass."))";
1414 $contexts = explode(";",$this->config->contexts);
1416 if (!empty($this->config->create_context)) {
1417 array_push($contexts, $this->config->create_context);
1420 foreach ($contexts as $context) {
1422 $context = trim($context);
1423 if (empty($context)) {
1424 continue;
1427 if ($this->config->search_sub) {
1428 //use ldap_search to find first user from subtree
1429 $ldap_result = ldap_search($ldapconnection, $context,$filter,array($this->config->user_attribute));
1431 else {
1432 //search only in this context
1433 $ldap_result = ldap_list($ldapconnection, $context,
1434 $filter,
1435 array($this->config->user_attribute));
1438 $users = $this->ldap_get_entries($ldapconnection, $ldap_result);
1440 //add found users to list
1441 for ($i=0;$i<count($users);$i++) {
1442 array_push($fresult, ($users[$i][$this->config->user_attribute][0]) );
1446 return $fresult;
1450 * return entries from ldap
1452 * Returns values like ldap_get_entries but is
1453 * binary compatible and return all attributes as array
1455 * @return array ldap-entries
1458 function ldap_get_entries($conn, $searchresult) {
1459 //Returns values like ldap_get_entries but is
1460 //binary compatible
1461 $i=0;
1462 $fresult=array();
1463 $entry = ldap_first_entry($conn, $searchresult);
1464 do {
1465 $attributes = @ldap_get_attributes($conn, $entry);
1466 for ($j=0; $j<$attributes['count']; $j++) {
1467 $values = ldap_get_values_len($conn, $entry,$attributes[$j]);
1468 if (is_array($values)) {
1469 $fresult[$i][$attributes[$j]] = $values;
1471 else {
1472 $fresult[$i][$attributes[$j]] = array($values);
1475 $i++;
1477 while ($entry = @ldap_next_entry($conn, $entry));
1478 //were done
1479 return ($fresult);
1483 * Returns true if this authentication plugin is 'internal'.
1485 * @return bool
1487 function is_internal() {
1488 return false;
1492 * Returns true if this authentication plugin can change the user's
1493 * password.
1495 * @return bool
1497 function can_change_password() {
1498 return !empty($this->config->stdchangepassword) or !empty($this->config->changepasswordurl);
1502 * Returns the URL for changing the user's pw, or empty if the default can
1503 * be used.
1505 * @return string url
1507 function change_password_url() {
1508 if (empty($this->config->stdchangepassword)) {
1509 return $this->config->changepasswordurl;
1510 } else {
1511 return '';
1516 * Prints a form for configuring this authentication plugin.
1518 * This function is called from admin/auth.php, and outputs a full page with
1519 * a form for configuring this plugin.
1521 * @param array $page An object containing all the data for this page.
1523 function config_form($config, $err, $user_fields) {
1524 include 'config.html';
1528 * Processes and stores configuration data for this authentication plugin.
1530 function process_config($config) {
1531 // set to defaults if undefined
1532 if (!isset($config->host_url))
1533 { $config->host_url = ''; }
1534 if (empty($config->ldapencoding))
1535 { $config->ldapencoding = 'utf-8'; }
1536 if (!isset($config->contexts))
1537 { $config->contexts = ''; }
1538 if (!isset($config->user_type))
1539 { $config->user_type = 'default'; }
1540 if (!isset($config->user_attribute))
1541 { $config->user_attribute = ''; }
1542 if (!isset($config->search_sub))
1543 { $config->search_sub = ''; }
1544 if (!isset($config->opt_deref))
1545 { $config->opt_deref = ''; }
1546 if (!isset($config->preventpassindb))
1547 { $config->preventpassindb = 0; }
1548 if (!isset($config->bind_dn))
1549 {$config->bind_dn = ''; }
1550 if (!isset($config->bind_pw))
1551 {$config->bind_pw = ''; }
1552 if (!isset($config->version))
1553 {$config->version = '2'; }
1554 if (!isset($config->objectclass))
1555 {$config->objectclass = ''; }
1556 if (!isset($config->memberattribute))
1557 {$config->memberattribute = ''; }
1558 if (!isset($config->creators))
1559 {$config->creators = ''; }
1560 if (!isset($config->create_context))
1561 {$config->create_context = ''; }
1562 if (!isset($config->expiration))
1563 {$config->expiration = ''; }
1564 if (!isset($config->expiration_warning))
1565 {$config->expiration_warning = '10'; }
1566 if (!isset($config->expireattr))
1567 {$config->expireattr = ''; }
1568 if (!isset($config->gracelogins))
1569 {$config->gracelogins = ''; }
1570 if (!isset($config->graceattr))
1571 {$config->graceattr = ''; }
1572 if (!isset($config->auth_user_create))
1573 {$config->auth_user_create = ''; }
1574 if (!isset($config->forcechangepassword))
1575 {$config->forcechangepassword = 0; }
1576 if (!isset($config->stdchangepassword))
1577 {$config->stdchangepassword = 0; }
1578 if (!isset($config->changepasswordurl))
1579 {$config->changepasswordurl = ''; }
1580 if (!isset($config->removeuser))
1581 {$config->removeuser = 0; }
1583 // save settings
1584 set_config('host_url', $config->host_url, 'auth/ldap');
1585 set_config('ldapencoding', $config->ldapencoding, 'auth/ldap');
1586 set_config('host_url', $config->host_url, 'auth/ldap');
1587 set_config('contexts', $config->contexts, 'auth/ldap');
1588 set_config('user_type', $config->user_type, 'auth/ldap');
1589 set_config('user_attribute', $config->user_attribute, 'auth/ldap');
1590 set_config('search_sub', $config->search_sub, 'auth/ldap');
1591 set_config('opt_deref', $config->opt_deref, 'auth/ldap');
1592 set_config('preventpassindb', $config->preventpassindb, 'auth/ldap');
1593 set_config('bind_dn', $config->bind_dn, 'auth/ldap');
1594 set_config('bind_pw', $config->bind_pw, 'auth/ldap');
1595 set_config('version', $config->version, 'auth/ldap');
1596 set_config('objectclass', $config->objectclass, 'auth/ldap');
1597 set_config('memberattribute', $config->memberattribute, 'auth/ldap');
1598 set_config('creators', $config->creators, 'auth/ldap');
1599 set_config('create_context', $config->create_context, 'auth/ldap');
1600 set_config('expiration', $config->expiration, 'auth/ldap');
1601 set_config('expiration_warning', $config->expiration_warning, 'auth/ldap');
1602 set_config('expireattr', $config->expireattr, 'auth/ldap');
1603 set_config('gracelogins', $config->gracelogins, 'auth/ldap');
1604 set_config('graceattr', $config->graceattr, 'auth/ldap');
1605 set_config('auth_user_create', $config->auth_user_create, 'auth/ldap');
1606 set_config('forcechangepassword', $config->forcechangepassword, 'auth/ldap');
1607 set_config('stdchangepassword', $config->stdchangepassword, 'auth/ldap');
1608 set_config('changepasswordurl', $config->changepasswordurl, 'auth/ldap');
1609 set_config('removeuser', $config->removeuser, 'auth/ldap');
1611 return true;
1615 * Quote control characters in texts used in ldap filters - see rfc2254.txt
1617 * @param string
1619 function filter_addslashes($text) {
1620 $text = str_replace('\\', '\\5c', $text);
1621 $text = str_replace(array('*', '(', ')', "\0"),
1622 array('\\2a', '\\28', '\\29', '\\00'), $text);
1623 return $text;
1627 * Quote control characters in quoted "texts" used in ldap
1629 * @param string
1631 function ldap_addslashes($text) {
1632 $text = str_replace('\\', '\\\\', $text);
1633 $text = str_replace(array('"', "\0"),
1634 array('\\"', '\\00'), $text);
1635 return $text;