multiauth: migrated all files to the new OO API, written new API documentation
[moodle.git] / auth / ldap / auth.php
CommitLineData
b9ddb2d5 1<?php
2
3/**
4 * @author Martin Dougiamas
5 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
6 * @package moodle multiauth
7 *
8 * Authentication Plugin: LDAP Authentication
9 *
10 * Authentication using LDAP (Lightweight Directory Access Protocol).
11 *
12 * 2006-08-28 File created.
13 */
14
15// This page cannot be called directly
16if (!isset($CFG)) exit;
17
18// LDAP functions are reused by other auth libs
19if (!defined('AUTH_LDAP_NAME')) {
20 define('AUTH_LDAP_NAME', 'ldap');
21}
22
23/**
24 * LDAP authentication plugin.
25 */
26class auth_plugin_ldap {
27
28 /**
29 * The configuration details for the plugin.
30 */
31 var $config;
32
33 /**
34 * Constructor.
35 */
36 function auth_plugin_ldap() {
37 $this->config = get_config('auth/ldap');
38 }
39
40 /**
41 * Returns true if the username and password work and false if they are
42 * wrong or don't exist.
43 *
44 * @param string $username The username
45 * @param string $password The password
46 * @returns bool Authentication success or failure.
47 */
48 function user_login($username, $password) {
49
50 global $CFG;
51
52 if (!$username or !$password) { // Don't allow blank usernames or passwords
53 return false;
54 }
55
56 // CAS-supplied auth tokens override LDAP auth
57 if ($CFG->auth == "cas" and !empty($CFG->cas_enabled)) {
58 return cas_ldap_auth_user_login($username, $password);
59 }
60
61 $ldapconnection = $this->ldap_connect();
62
63 if ($ldapconnection) {
64 $ldap_user_dn = $this->ldap_find_userdn($ldapconnection, $username);
65
66 //if ldap_user_dn is empty, user does not exist
67 if (!$ldap_user_dn) {
68 ldap_close($ldapconnection);
69 return false;
70 }
71
72 // Try to bind with current username and password
73 $ldap_login = @ldap_bind($ldapconnection, $ldap_user_dn, stripslashes($password));
74 ldap_close($ldapconnection);
75 if ($ldap_login) {
76 return true;
77 }
78 }
79 else {
80 @ldap_close($ldapconnection);
81 error("LDAP-module cannot connect to server: $this->config->host_url");
82 }
83 return false;
84 }
85
86 /**
87 * reads userinformation from ldap and return it in array()
88 *
89 * Read user information from external database and returns it as array().
90 * Function should return all information available. If you are saving
91 * this information to moodle user-table you should honor syncronization flags
92 *
93 * @param string $username username
94 * @return array
95 */
96 function get_userinfo($username) {
97 global $CFG;
98 $ldapconnection = $this->ldap_connect();
99 $config = (array)$CFG;
100 $attrmap = $this->ldap_attributes();
101
102 $result = array();
103 $search_attribs = array();
104
105 foreach ($attrmap as $key=>$values) {
106 if (!is_array($values)) {
107 $values = array($values);
108 }
109 foreach ($values as $value) {
110 if (!in_array($value, $search_attribs)) {
111 array_push($search_attribs, $value);
112 }
113 }
114 }
115
116 $user_dn = $this->ldap_find_userdn($ldapconnection, $username);
117
118 if (empty($this->config->objectclass)) { // Can't send empty filter
119 $this->config->objectclass="objectClass=*";
120 }
121
122 $user_info_result = ldap_read($ldapconnection, $user_dn, $this->config->objectclass, $search_attribs);
123
124 if ($user_info_result) {
125 $user_entry = $this->ldap_get_entries($ldapconnection, $user_info_result);
126 foreach ($attrmap as $key=>$values) {
127 if (!is_array($values)) {
128 $values = array($values);
129 }
130 $ldapval = NULL;
131 foreach ($values as $value) {
132 if (is_array($user_entry[0][strtolower($value)])) {
133 if (!empty($CFG->unicodedb)) {
134 $newval = addslashes(stripslashes($user_entry[0][strtolower($value)][0]));
135 }
136 else {
137 $newval = addslashes(stripslashes(utf8_decode($user_entry[0][strtolower($value)][0])));
138 }
139 }
140 else {
141 if (!empty($CFG->unicodedb)) {
142 $newval = addslashes(stripslashes($user_entry[0][strtolower($value)]));
143 }
144 else {
145 $newval = addslashes(stripslashes(utf8_decode($user_entry[0][strtolower($value)])));
146 }
147 }
148 if (!empty($newval)) { // favour ldap entries that are set
149 $ldapval = $newval;
150 }
151 }
152 if (!is_null($ldapval)) {
153 $result[$key] = $ldapval;
154 }
155 }
156 }
157
158 @ldap_close($ldapconnection);
159
160 return $result;
161 }
162
163 /**
164 * reads userinformation from ldap and return it in an object
165 *
166 * @param string $username username
167 * @return array
168 */
169 function get_userinfo_asobj($username) {
170 $user_array = truncate_userinfo($this->get_userinfo($username));
171 $user = new object;
172 foreach ($user_array as $key=>$value) {
173 $user->{$key} = $value;
174 }
175 return $user;
176 }
177
178 /**
179 * returns all usernames from external database
180 *
181 * get_userlist returns all usernames from external database
182 *
183 * @return array
184 */
185 function get_userlist() {
186 global $CFG;
187 $this->ldap_init();
188 return $this->ldap_get_userlist("({$this->config->user_attribute}=*)");
189 }
190
191 /**
192 * checks if user exists on external db
193 */
194 function user_exists($username) {
195 global $CFG;
196 $this->ldap_init();
197 //returns true if given usernname exist on ldap
198 $users = $this->ldap_get_userlist("({$this->config->user_attribute}=$username)");
199 return count($users);
200 }
201
202 /**
203 * creates new user on external database
204 *
205 * user_create() creates new user on external database
206 * By using information in userobject
207 * Use user_exists to prevent dublicate usernames
208 *
209 * @param mixed $userobject Moodle userobject
210 * @param mixed $plainpass Plaintext password
211 */
212 function user_create($userobject, $plainpass) {
213 global $CFG;
214 $ldapconnection = $this->ldap_connect();
215 $attrmap = $this->ldap_attributes();
216
217 $newuser = array();
218
219 foreach ($attrmap as $key => $values) {
220 if (!is_array($values)) {
221 $values = array($values);
222 }
223 foreach ($values as $value) {
224 if (!empty($userobject->$key) ) {
225 if (!empty($CFG->unicodedb)) {
226 $newuser[$value] = $userobject->$key;
227 }
228 else {
229 $newuser[$value] = utf8_encode($userobject->$key);
230 }
231 }
232 }
233 }
234
235 //Following sets all mandatory and other forced attribute values
236 //User should be creted as login disabled untill email confirmation is processed
237 //Feel free to add your user type and send patches to paca@sci.fi to add them
238 //Moodle distribution
239
240 switch ($this->config->user_type) {
241 case 'edir':
242 $newuser['objectClass']= array("inetOrgPerson","organizationalPerson","person","top");
243 $newuser['uniqueId']= $userobject->username;
244 $newuser['logindisabled']="TRUE";
245 $newuser['userpassword']=$plainpass;
246 break;
247 default:
248 error('auth: ldap user_create() does not support selected usertype:"'.$this->config->user_type.'" (..yet)');
249 }
250 $uadd = $this->ldap_add($ldapconnection, "{$this->config->user_attribute}={$userobject->username},{$this->config->create_context}", $newuser);
251 ldap_close($ldapconnection);
252 return $uadd;
253
254 }
255
256 /**
257 *
258 * get_users() returns userobjects from external database
259 *
260 * Function returns users from external databe as Moodle userobjects
261 * If filter is not present it should return ALL users in external database
262 *
263 * @param mixed $filter substring of username
264 * @returns array of userobjects
265 */
266 function get_users($filter = '*', $dontlistcreated = false) {
267 global $CFG;
268
269 $ldapconnection = $this->ldap_connect();
270 $fresult = array();
271
272 if ($filter=="*") {
273 $filter = "(&(".$this->config->user_attribute."=*)(".$this->config->objectclass."))";
274 }
275
276 $contexts = explode(";",$this->config->contexts);
277
278 if (!empty($this->config->create_context) and empty($dontlistcreated)) {
279 array_push($contexts, $this->config->create_context);
280 }
281
282 $attrmap = $this->ldap_attributes();
283
284 $search_attribs = array();
285
286 foreach ($attrmap as $key=>$values) {
287 if (!is_array($values)) {
288 $values = array($values);
289 }
290 foreach ($values as $value) {
291 if (!in_array($value, $search_attribs)) {
292 array_push($search_attribs, $value);
293 }
294 }
295 }
296
297
298 foreach ($contexts as $context) {
299
300 $context = trim($context);
301 if (empty($context)) {
302 continue;
303 }
304
305 if ($this->config->search_sub) {
306 //use ldap_search to find first user from subtree
307 $ldap_result = ldap_search($ldapconnection, $context,
308 $filter,
309 $search_attribs);
310 }
311 else {
312 //search only in this context
313 $ldap_result = ldap_list($ldapconnection, $context,
314 $filter,
315 $search_attribs);
316 }
317
318 $users = $this->ldap_get_entries($ldapconnection, $ldap_result);
319
320 //add found users to list
321 foreach ($users as $ldapuser=>$attribs) {
322 $user = new object();
323 foreach ($attrmap as $key=>$value) {
324 if (isset($users[$ldapuser][$value][0])) {
325 $user->$key=$users[$ldapuser][$value][0];
326 }
327 }
328 //quick way to get around binarystrings
329 $user->guid=bin2hex($user->guid);
330 //add authentication source stamp
331 $user->auth = AUTH_LDAP_NAME;
332 $fresult[$user->username]=$user;
333
334 }
335 }
336
337 return $fresult;
338 }
339
340 /**
341 * return number of days to user password expires
342 *
343 * If userpassword does not expire it should return 0. If password is already expired
344 * it should return negative value.
345 *
346 * @param mixed $username username
347 * @return integer
348 */
349 function password_expire($username) {
350 global $CFG ;
351 $result = false;
352
353 $ldapconnection = $this->ldap_connect();
354 $user_dn = $this->ldap_find_userdn($ldapconnection, $username);
355 $search_attribs = array($this->config->expireattr);
356 $sr = ldap_read($ldapconnection, $user_dn, 'objectclass=*', $search_attribs);
357 if ($sr) {
358 $info=$this->ldap_get_entries($ldapconnection, $sr);
359 if ( empty($info[0][strtolower($this->config->expireattr)][0])) {
360 //error_log("ldap: no expiration value".$info[0][$this->config->expireattr]);
361 // no expiration attribute, password does not expire
362 $result = 0;
363 }
364 else {
365 $now = time();
366 $expiretime = $this->ldap_expirationtime2unix($info[0][strtolower($this->config->expireattr)][0]);
367 if ($expiretime > $now) {
368 $result = ceil(($expiretime - $now) / DAYSECS);
369 }
370 else {
371 $result = floor(($expiretime - $now) / DAYSECS);
372 }
373 }
374 }
375 else {
376 error_log("ldap: password_expire did't find expiration time.");
377 }
378
379 //error_log("ldap: password_expire user $user_dn expires in $result days!");
380 return $result;
381 }
382
383 /**
384 * syncronizes user fron external db to moodle user table
385 *
386 * Sync shouid be done by using idnumber attribute, not username.
387 * You need to pass firstsync parameter to function to fill in
388 * idnumbers if they dont exists in moodle user table.
389 *
390 * Syncing users removes (disables) users that dont exists anymore in external db.
391 * Creates new users and updates coursecreator status of users.
392 *
393 * @param mixed $firstsync Optional: set to true to fill idnumber fields if not filled yet
394 */
395 function sync_users ($bulk_insert_records = 1000, $do_updates = 1) {
396 //Syncronizes userdb with ldap
397 //This will add, rename
398 /// OPTIONAL PARAMETERS
399 /// $bulk_insert_records = 1 // will insert $bulkinsert_records per insert statement
400 /// valid only with $unsafe. increase to a couple thousand for
401 /// blinding fast inserts -- but test it: you may hit mysqld's
402 /// max_allowed_packet limit.
403 /// $do_updates = 1 // will do pull in data updates from ldap if relevant
404
405
406 global $CFG ;
407
408 // configure a temp table
409 print "Configuring temp table\n";
410 if (strtolower($CFG->dbtype) === 'mysql') {
411 // help old mysql versions cope with large temp tables
412 execute_sql('SET SQL_BIG_TABLES=1', false);
413 execute_sql('CREATE TEMPORARY TABLE ' . $CFG->prefix .'extuser (idnumber VARCHAR(64), PRIMARY KEY (idnumber)) TYPE=MyISAM',false);
414 }
415 elseif (strtolower($CFG->dbtype) === 'postgres7') {
416 $bulk_insert_records = 1; // no support for multiple sets of values
417 execute_sql('CREATE TEMPORARY TABLE '.$CFG->prefix.'extuser (idnumber VARCHAR(64), PRIMARY KEY (idnumber))',false);
418 }
419
420 print "connecting to ldap\n";
421 $ldapconnection = $this->ldap_connect();
422
423 if (!$ldapconnection) {
424 @ldap_close($ldapconnection);
425 notify("LDAP-module cannot connect to server: $CFG->ldap_host_url");
426 return false;
427 }
428
429 ////
430 //// get user's list from ldap to sql in a scalable fashion
431 ////
432 // prepare some data we'll need
433 if (! empty($this->config->objectclass)) {
434 $this->config->objectclass="objectClass=*";
435 }
436
437 $filter = "(&(".$this->config->user_attribute."=*)(".$this->config->objectclass."))";
438
439 $contexts = explode(";",$this->config->contexts);
440
441 if (!empty($this->config->create_context)) {
442 array_push($contexts, $this->config->create_context);
443 }
444
445 $fresult = array();
446 $count = 0;
447 foreach ($contexts as $context) {
448 $context = trim($context);
449 if (empty($context)) {
450 continue;
451 }
452 begin_sql();
453 if ($this->config->search_sub) {
454 //use ldap_search to find first user from subtree
455 $ldap_result = ldap_search($ldapconnection, $context,
456 $filter,
457 array($this->config->user_attribute));
458 }
459 else {
460 //search only in this context
461 $ldap_result = ldap_list($ldapconnection, $context,
462 $filter,
463 array($this->config->user_attribute));
464 }
465
466 if ($entry = ldap_first_entry($ldapconnection, $ldap_result)) {
467 do {
468 $value = ldap_get_values_len($ldapconnection, $entry,$this->config->user_attribute);
469 $value = $value[0];
470 $count++;
471 array_push($fresult, $value);
472 if (count($fresult) >= $bulk_insert_records) {
473 $this->ldap_bulk_insert($fresult);
474 //print var_dump($fresult);
475 $fresult=array();
476 }
477 }
478 while ($entry = ldap_next_entry($ldapconnection, $entry));
479 }
480
481 // insert any remaining users and release mem
482 if (count($fresult)) {
483 $this->ldap_bulk_insert($fresult);
484 $fresult=array();
485 }
486 commit_sql();
487 }
488 // free mem
489 $ldap_results = 0;
490
491 /// preserve our user database
492 /// if the temp table is empty, it probably means that something went wrong, exit
493 /// so as to avoid mass deletion of users; which is hard to undo
494 $count = get_record_sql('SELECT COUNT(idnumber) AS count, 1 FROM ' . $CFG->prefix .'extuser');
495 $count = $count->{'count'};
496 if ($count < 1) {
497 print "Did not get any users from LDAP -- error? -- exiting\n";
498 exit;
499 }
500
501 ////
502 //// User removal
503 ////
504 // find users in DB that aren't in ldap -- to be removed!
505 // this is still not as scalable
506 $sql = 'SELECT u.id, u.username
507 FROM ' . $CFG->prefix .'user u LEFT JOIN ' . $CFG->prefix .'extuser e
508 ON u.idnumber = e.idnumber
509 WHERE u.auth=\'' . AUTH_LDAP_NAME . '\' AND u.deleted=\'0\' AND e.idnumber IS NULL';
510 //print($sql);
511 $remove_users = get_records_sql($sql);
512
513 if (!empty($remove_users)) {
514 print "User entries to remove: ". count($remove_users) . "\n";
515
516 begin_sql();
517 foreach ($remove_users as $user) {
518 //following is copy pasted from admin/user.php
519 //maybe this should moved to function in lib/datalib.php
520 unset($updateuser);
521 $updateuser->id = $user->id;
522 $updateuser->deleted = '1';
523 //$updateuser->username = "$user->username".time(); // Remember it just in case
524 //$updateuser->email = ''; // Clear this field to free it up
525 $updateuser->timemodified = time();
526 if (update_record("user", $updateuser)) {
527 // unenrol_student($user->id); // From all courses
528 // remove_teacher($user->id); // From all courses
529 // remove_admin($user->id);
530 delete_records('role_assignments', 'userid', $user->id); // unassign all roles
531 notify(get_string('deletedactivity', '', fullname($user, true)) );
532 }
533 else {
534 notify(get_string('deletednot', '', fullname($user, true)));
535 }
536 //copy pasted part ends
537 }
538 commit_sql();
539 }
540 $remove_users = 0; // free mem!
541
542 ////
543 //// User Updates
544 //// (time-consuming, optional)
545 ////
546 if ($do_updates) {
547 // narrow down what fields we need to update
548 $all_keys = array_keys(get_object_vars($this->config));
549 $updatekeys = array();
550 foreach ($all_keys as $key) {
551 if (preg_match('/^field_updatelocal_(.+)$/',$key, $match)) {
552 // if we have a field to update it from
553 // and it must be updated 'onlogin' we
554 // update it on cron
555 if ( !empty($this->config->{'field_map_'.$match[1]})
556 and $this->config->{$match[0]} === 'onlogin') {
557 array_push($updatekeys, $match[1]); // the actual key name
558 }
559 }
560 }
561 // print_r($all_keys); print_r($updatekeys);
562 unset($all_keys); unset($key);
563
564 }
565 if ( $do_updates and !(empty($updatekeys)) ) { // run updates only if relevant
566 $users = get_records_sql('SELECT u.username, u.id FROM ' . $CFG->prefix . 'user u WHERE u.deleted=0 and u.auth=\'' . AUTH_LDAP_NAME . '\'' );
567 if (!empty($users)) {
568 print "User entries to update: ". count($users). "\n";
569 $sitecontext = get_context_instance(CONTEXT_SYSTEM);
570
571 if ($creatorroles = get_roles_with_capability('moodle/legacy:coursecreator', CAP_ALLOW)) {
572 $creatorrole = array_shift($creatorroles); // We can only use one, let's use the first one
573
574 begin_sql();
575 $xcount = 0;
576 $maxxcount = 100;
577
578 foreach ($users as $user) {
579 echo "updating user $user->username \n";
580 $this->update_user_record($user->username, $updatekeys);
581
582 // update course creators
583 if (!empty($this->config->creators) and !empty($this->config->memberattribute) ) {
584 if ($this->iscreator($user->username)) { // Following calls will not create duplicates
585 role_assign($creatorrole->id, $user->id, 0, $sitecontext->id, 0, 0, 0, 'ldap');
586 $xcount++;
587 } else {
588 role_unassign($creatorrole->id, $user->id, 0, $sitecontext->id);
589 $xcount++;
590 }
591 }
592
593 if ($xcount++ > $maxxcount) {
594 commit_sql();
595 begin_sql();
596 $xcount = 0;
597 }
598 }
599 commit_sql();
600 unset($users); // free mem
601 }
602 }
603 } // end do updates
604
605 ////
606 //// User Additions
607 ////
608 // find users missing in DB that are in LDAP
609 // note that get_records_sql wants at least 2 fields returned,
610 // and gives me a nifty object I don't want.
611 $sql = 'SELECT e.idnumber,1
612 FROM ' . $CFG->prefix .'extuser e LEFT JOIN ' . $CFG->prefix .'user u
613 ON e.idnumber = u.idnumber
614 WHERE u.id IS NULL OR (u.id IS NOT NULL AND u.deleted=1)';
615 $add_users = get_records_sql($sql); // get rid of the fat
616
617 if (!empty($add_users)) {
618 print "User entries to add: ". count($add_users). "\n";
619
620 if ($creatorroles = get_roles_with_capability('moodle/legacy:coursecreator', CAP_ALLOW)) {
621 $creatorrole = array_shift($roles); // We can only use one, let's use the first one
622 }
623
624 begin_sql();
625 foreach ($add_users as $user) {
626 $user = $this->get_userinfo_asobj($user->idnumber);
627 //print $user->username . "\n";
628
629 // prep a few params
630 $user->modified = time();
631 $user->confirmed = 1;
632 $user->auth = AUTH_LDAP_NAME;
633
634 // insert it
635 $old_debug=$CFG->debug;
636 $CFG->debug=10;
637
638 // maybe the user has been deleted before
639 if ($old_user = get_record('user', 'idnumber', $user->idnumber, 'deleted', 1)) {
640 $user->id = $old_user->id;
641 set_field('user', 'deleted', 0, 'idnumber', $user->idnumber);
642 echo "Revived user $user->username with idnumber $user->idnumber id $user->id\n";
643 }
644 elseif ($id = insert_record('user',$user)) { // it is truly a new user
645 echo "inserted user $user->username with idnumber $user->idnumber id $id\n";
646 $user->id = $id;
647 }
648 else {
649 echo "error inserting user $user->username with idnumber $user->idnumber \n";
650 }
651 $CFG->debug = $old_debug;
652 $userobj = $this->update_user_record($user->username);
653 if (isset($this->config->forcechangepassword) and $this->config->forcechangepassword) {
654 set_user_preference('auth_forcepasswordchange', 1, $userobj->id);
655 }
656
657 // update course creators
658 if (isset($creatorrole->id) and !empty($this->config->creators) and !empty($this->config->memberattribute)) {
659 if ($this->iscreator($user->username)) {
660 if (user_has_role_assignment($user->id, $creatorrole->id, $sitecontext->id)) {
661 role_unassign($creatorrole->id, $user->id, 0, $sitecontext->id);
662 } else {
663 role_assign($creatorrole->id, $user->id, 0, $sitecontext->id, 0, 0, 0, 'ldap');
664 }
665 }
666 }
667 }
668 commit_sql();
669 unset($add_users); // free mem
670 }
671 return true;
672 }
673
674 /**
675 * Update a local user record from an external source.
676 * This is a lighter version of the one in moodlelib -- won't do
677 * expensive ops such as enrolment.
678 *
679 * If you don't pass $updatekeys, there is a performance hit and
680 * values removed from LDAP won't be removed from moodle.
681 */
682 function update_user_record($username, $updatekeys = false) {
683
684 global $CFG;
685
686 //just in case check text case
687 $username = trim(moodle_strtolower($username));
688
689 // get the current user record
690 $user = get_record('user', 'username', $username);
691 if (empty($user)) { // trouble
692 error_log("Cannot update non-existent user: $username");
693 die;
694 }
695
696 if (function_exists('auth_get_userinfo')) {
697 if ($newinfo = auth_get_userinfo($username)) {
698 $newinfo = truncate_userinfo($newinfo);
699
700 if (empty($updatekeys)) { // all keys? this does not support removing values
701 $updatekeys = array_keys($newinfo);
702 }
703
704 foreach ($updatekeys as $key) {
705 unset($value);
706 if (isset($newinfo[$key])) {
707 $value = $newinfo[$key];
708 $value = addslashes(stripslashes($value)); // Just in case
709 }
710 else {
711 $value = '';
712 }
713 if (!empty($this->config->{'field_updatelocal_' . $key})) {
714 if ($user->{$key} != $value) { // only update if it's changed
715 set_field('user', $key, $value, 'username', $username);
716 }
717 }
718 }
719 }
720 }
721 return get_record_select("user", "username = '$username' AND deleted <> '1'");
722 }
723
724 function ldap_bulk_insert($users) {
725 // bulk insert in SQL's temp table
726 // $users is an array of usernames
727 global $CFG;
728
729 // bulk insert -- superfast with $bulk_insert_records
730 $sql = 'INSERT INTO '.$CFG->prefix.'extuser (idnumber) VALUES ';
731 // make those values safe
732 array_map('addslashes', $users);
733 // join and quote the whole lot
734 $sql = $sql . '(\'' . join('\'),(\'', $users) . '\')';
735 print "+ " . count($users) . " users\n";
736 execute_sql($sql, false);
737
738 }
739
740
741 /*
742 * user_activate activates user in external db.
743 *
744 * Activates (enables) user in external db so user can login to external db
745 *
746 * @param mixed $username username
747 * @return boolen result
748 */
749 function user_activate($username) {
750
751 global $CFG;
752
753 $ldapconnection = $this->ldap_connect();
754
755 $userdn = $this->ldap_find_userdn($ldapconnection, $username);
756 switch ($this->config->user_type) {
757 case 'edir':
758 $newinfo['loginDisabled']="FALSE";
759 break;
760 default:
761 error ('auth: ldap user_activate() does not support selected usertype:"'.$this->config->user_type.'" (..yet)');
762 }
763 $result = ldap_modify($ldapconnection, $userdn, $newinfo);
764 ldap_close($ldapconnection);
765 return $result;
766 }
767
768 /*
769 * user_disables disables user in external db.
770 *
771 * Disables user in external db so user can't login to external db
772 *
773 * @param mixed $username username
774 * @return boolean result
775 */
776 function user_disable($username) {
777 global $CFG;
778
779 $ldapconnection = $this->ldap_connect();
780
781 $userdn = $this->ldap_find_userdn($ldapconnection, $username);
782 switch ($this->config->user_type) {
783 case 'edir':
784 $newinfo['loginDisabled']="TRUE";
785 break;
786 default:
787 error ('auth: ldap user_disable() does not support selected usertype (..yet)');
788 }
789 $result = ldap_modify($ldapconnection, $userdn, $newinfo);
790 ldap_close($ldapconnection);
791 return $result;
792 }
793
794 /*
795 * Returns true if user should be coursecreator.
796 *
797 * @param mixed $username username
798 * @return boolean result
799 */
800 function iscreator($username = false) {
801 ///if user is member of creator group return true
802 global $USER, $CFG;
803 $this->ldap_init();
804 if (! $username) {
805 $username = $USER->username;
806 }
807 if ((! $this->config->creators) or (! $this->config->memberattribute)) {
808 return null;
809 }
810 return $this->ldap_isgroupmember($username, $this->config->creators);
811 }
812
813 /*
814 * user_update saves userinformation from moodle to external db
815 *
816 * Called when the user record is updated.
817 * Modifies user in external database. It takes olduser (before changes) and newuser (after changes)
818 * conpares information saved modified information to external db.
819 *
820 * @param mixed $olduser Userobject before modifications
821 * @param mixed $newuser Userobject new modified userobject
822 * @return boolean result
823 *
824 */
825 function user_update($olduser, $newuser) {
826
827 global $USER, $CFG;
828
829 $ldapconnection = $this->ldap_connect();
830
831 $result = array();
832 $search_attribs = array();
833
834 $attrmap = $this->ldap_attributes();
835 foreach ($attrmap as $key => $values) {
836 if (!is_array($values)) {
837 $values = array($values);
838 }
839 foreach ($values as $value) {
840 if (!in_array($value, $search_attribs)) {
841 array_push($search_attribs, $value);
842 }
843 }
844 }
845
846 $user_dn = $this->ldap_find_userdn($ldapconnection, $olduser->username);
847
848 $user_info_result = ldap_read($ldapconnection, $user_dn,
849 $this->config->objectclass, $search_attribs);
850
851 if ($user_info_result) {
852
853 $user_entry = $this->ldap_get_entries($ldapconnection, $user_info_result);
854 if (count($user_entry) > 1) {
855 trigger_error("ldap: Strange! More than one user record found in ldap. Only using the first one.");
856 }
857 $user_entry = $user_entry[0];
858
859 //error_log(var_export($user_entry) . 'fpp' );
860
861 foreach ($attrmap as $key => $ldapkeys) {
862
863 // only process if the moodle field ($key) has changed and we
864 // are set to update LDAP with it
865 if ($olduser->$key !== $newuser->$key and
866 !empty($this->config->{'field_updateremote_'. $key})) {
867
868 // for ldap values that could be in more than one
869 // ldap key, we will do our best to match
870 // where they came from
871 $ambiguous = true;
872 $changed = false;
873 if (!is_array($ldapkeys)) {
874 $ldapkeys = array($ldapkeys);
875 }
876 if (count($ldapkeys) < 2) {
877 $ambiguous = false;
878 }
879
880 foreach ($ldapkeys as $ldapkey) {
881 $ldapkey = strtolower($ldapkey);
882 $ldapvalue = $user_entry[$ldapkey][0];
883 if (!$ambiguous) {
884 // skip update if the values already match
885 if ( !($newuser->$key === $ldapvalue) ) {
886 ldap_modify($ldapconnection, $user_dn, array($ldapkey => $newuser->$key));
887 }
888 else {
889 error_log("Skip updating field $key for entry $user_dn: it seems to be already same on LDAP.
890 old moodle value: '{$olduser->$key}'
891 new value: '{$newuser->$key}'
892 current value in ldap entry: '{$ldapvalue}'");
893 }
894 }
895 else {
896 // ambiguous
897 // value empty before in Moodle (and LDAP) - use 1st ldap candidate field
898 // no need to guess
899 if (empty($olduser->$key)) { // value empty before - use 1st ldap candidate
900 if (ldap_modify($ldapconnection, $user_dn, array($ldapkey => $newuser->$key))) {
901 $changed = true;
902 last;
903 }
904 else {
905 error ('Error updating LDAP record. Error code: '
906 . ldap_errno($ldapconnection) . '; Error string : '
907 . ldap_err2str(ldap_errno($ldapconnection)));
908 }
909 }
910
911 // we found which ldap key to update!
912 if (!empty($ldapvalue) and $olduser->$key === $ldapvalue ) {
913 // error_log("Matched: ". $olduser->$key . " === " . $ldapvalue);
914 if (ldap_modify($ldapconnection, $user_dn, array($ldapkey => $newuser->$key))) {
915 $changed = true;
916 last;
917 }
918 else {
919 error ('Error updating LDAP record. Error code: '
920 . ldap_errno($ldapconnection) . '; Error string : '
921 . ldap_err2str(ldap_errno($ldapconnection)));
922 }
923 }
924 }
925 }
926
927 if ($ambiguous and !$changed) {
928 error_log("Failed to update LDAP with ambiguous field $key".
929 " old moodle value: '" . $olduser->$key .
930 "' new value '" . $newuser->$key );
931 }
932 }
933 }
934
935
936 }
937 else {
938 error_log("ERROR:No user found in LDAP");
939 @ldap_close($ldapconnection);
940 return false;
941 }
942
943 @ldap_close($ldapconnection);
944
945 return true;
946
947 }
948
949 /*
950 * changes userpassword in external db
951 *
952 * called when the user password is updated.
953 * changes userpassword in external db
954 *
955 * @param mixed $username Username
956 * @param mixed $newpassword Plaintext password
957 * @param mixed $oldpassword Plaintext old password to bind ldap with
958 * @return boolean result
959 *
960 */
961 // function user_update_password($username, $newpassword) {
962 function user_update_password($user, $newpassword) {
963 /// called when the user password is updated -- it assumes it is called by an admin
964 /// or that you've otherwise checked the user's credentials
965 /// IMPORTANT: $newpassword must be cleartext, not crypted/md5'ed
966
967 global $CFG, $USER;
968 $result = false;
969 $username = $user->username;
970
971 $ldapconnection = $this->ldap_connect();
972
973 $user_dn = $this->ldap_find_userdn($ldapconnection, $username);
974
975 if (!$user_dn) {
976 error_log('LDAP Error in user_update_password(). No DN for: ' . $username);
977 return false;
978 }
979
980 switch ($this->config->user_type) {
981 case 'edir':
982 //Change password
983 $result = ldap_modify($ldapconnection, $user_dn, array('userPassword' => $newpassword));
984 if (!$result) {
985 error_log('LDAP Error in user_update_password(). Error code: '
986 . ldap_errno($ldapconnection) . '; Error string : '
987 . ldap_err2str(ldap_errno($ldapconnection)));
988 }
989 //Update password expiration time, grace logins count
990 $search_attribs = array($this->config->expireattr, 'passwordExpirationInterval','loginGraceLimit' );
991 $sr = ldap_read($ldapconnection, $user_dn, 'objectclass=*', $search_attribs);
992 if ($sr) {
993 $info=$this->ldap_get_entries($ldapconnection, $sr);
994 $newattrs = array();
995 if (!empty($info[0][$this->config->expireattr][0])) {
996 //Set expiration time only if passwordExpirationInterval is defined
997 if (!empty($info[0]['passwordExpirationInterval'][0])) {
998 $expirationtime = time() + $info[0]['passwordExpirationInterval'][0];
999 $ldapexpirationtime = $this->ldap_unix2expirationtime($expirationtime);
1000 $newattrs['passwordExpirationTime'] = $ldapexpirationtime;
1001 }
1002
1003 //set gracelogin count
1004 if (!empty($info[0]['loginGraceLimit'][0])) {
1005 $newattrs['loginGraceRemaining']= $info[0]['loginGraceLimit'][0];
1006 }
1007
1008 //Store attribute changes to ldap
1009 $result = ldap_modify($ldapconnection, $user_dn, $newattrs);
1010 if (!$result) {
1011 error_log('LDAP Error in user_update_password() when modifying expirationtime and/or gracelogins. Error code: '
1012 . ldap_errno($ldapconnection) . '; Error string : '
1013 . ldap_err2str(ldap_errno($ldapconnection)));
1014 }
1015 }
1016 }
1017 else {
1018 error_log('LDAP Error in user_update_password() when reading password expiration time. Error code: '
1019 . ldap_errno($ldapconnection) . '; Error string : '
1020 . ldap_err2str(ldap_errno($ldapconnection)));
1021 }
1022 break;
1023
1024 default:
1025 $usedconnection = &$ldapconnection;
1026 // send ldap the password in cleartext, it will md5 it itself
1027 $result = ldap_modify($ldapconnection, $user_dn, array('userPassword' => $newpassword));
1028 if (!$result) {
1029 error_log('LDAP Error in user_update_password(). Error code: '
1030 . ldap_errno($ldapconnection) . '; Error string : '
1031 . ldap_err2str(ldap_errno($ldapconnection)));
1032 }
1033
1034 }
1035
1036 @ldap_close($ldapconnection);
1037 return $result;
1038 }
1039
1040 //PRIVATE FUNCTIONS starts
1041 //private functions are named as ldap_*
1042
1043 /**
1044 * returns predefined usertypes
1045 *
1046 * @return array of predefined usertypes
1047 */
1048
1049 function ldap_suppported_usertypes() {
1050 // returns array of supported usertypes (schemas)
1051 // If you like to add our own please name and describe it here
1052 // And then add case clauses in relevant places in functions
1053 // iauth_ldap_init, auth_user_create, auth_check_expire, auth_check_grace
1054 $types['edir']='Novell Edirectory';
1055 $types['rfc2307']='posixAccount (rfc2307)';
1056 $types['rfc2307bis']='posixAccount (rfc2307bis)';
1057 $types['samba']='sambaSamAccount (v.3.0.7)';
1058 $types['ad']='MS ActiveDirectory';
1059 return $types;
1060 }
1061
1062
1063 /**
1064 * initializes needed variables for ldap-module
1065 *
1066 * Uses names defined in ldap_supported_usertypes.
1067 * $default is first defined as:
1068 * $default['pseudoname'] = array(
1069 * 'typename1' => 'value',
1070 * 'typename2' => 'value'
1071 * ....
1072 * );
1073 *
1074 * @return array of default values
1075 */
1076 function ldap_getdefaults() {
1077 $default['objectclass'] = array(
1078 'edir' => 'User',
1079 'rfc2703' => 'posixAccount',
1080 'rfc2703bis' => 'posixAccount',
1081 'samba' => 'sambaSamAccount',
1082 'ad' => 'user',
1083 'default' => '*'
1084 );
1085 $default['user_attribute'] = array(
1086 'edir' => 'cn',
1087 'rfc2307' => 'uid',
1088 'rfc2307bis' => 'uid',
1089 'samba' => 'uid',
1090 'ad' => 'cn',
1091 'default' => 'cn'
1092 );
1093 $default['memberattribute'] = array(
1094 'edir' => 'member',
1095 'rfc2307' => 'member',
1096 'rfc2307bis' => 'member',
1097 'samba' => 'member',
1098 'ad' => 'member',
1099 'default' => 'member'
1100 );
1101 $default['memberattribute_isdn'] = array(
1102 'edir' => '1',
1103 'rfc2307' => '0',
1104 'rfc2307bis' => '1',
1105 'samba' => '0', //is this right?
1106 'ad' => '1',
1107 'default' => '0'
1108 );
1109 $default['expireattr'] = array (
1110 'edir' => 'passwordExpirationTime',
1111 'rfc2307' => 'shadowExpire',
1112 'rfc2307bis' => 'shadowExpire',
1113 'samba' => '', //No support yet
1114 'ad' => '', //No support yet
1115 'default' => ''
1116 );
1117 return $default;
1118 }
1119
1120 /**
1121 * return binaryfields of selected usertype
1122 *
1123 *
1124 * @return array
1125 */
1126 function ldap_getbinaryfields () {
1127 global $CFG;
1128 $binaryfields = array (
1129 'edir' => array('guid'),
1130 'rfc2703' => array(),
1131 'rfc2703bis' => array(),
1132 'samba' => array(),
1133 'ad' => array(),
1134 'default' => '*'
1135 );
1136 if (!empty($this->config->user_type)) {
1137 return $binaryfields[$this->config->user_type];
1138 }
1139 else {
1140 return $binaryfields['default'];
1141 }
1142 }
1143
1144 function ldap_isbinary ($field) {
1145 if (!isset($field)) {
1146 return null ;
1147 }
1148 return array_search($field, $this->ldap_getbinaryfields());
1149 }
1150
1151 /**
1152 * set $CFG-values for ldap_module
1153 *
1154 * Get default configuration values with ldap_getdefaults()
1155 * and by using this information $CFG-> values are set
1156 * If $CFG->value is alredy set current value is honored.
1157 *
1158 *
1159 */
1160 function ldap_init () {
1161 global $CFG;
1162
1163 $default = $this->ldap_getdefaults();
1164
1165 // TODO: do we need set_config calls here?
1166
1167 foreach ($default as $key => $value) {
1168 //set defaults if overriding fields not set
1169 if (empty($this->config->{$key})) {
1170 if (!empty($this->config->user_type) and !empty($default[$key][$this->config->user_type])) {
1171 $this->config->{$key} = $default[$key][$this->config->user_type];
1172 }
1173 else {
1174 //use default value if user_type not set
1175 if (!empty($default[$key]['default'])) {
1176 $this->config->{$key} = $default[$key]['default'];
1177 }
1178 else {
1179 unset($this->config->{$key});
1180 }
1181 }
1182 }
1183 }
1184 //hack prefix to objectclass
1185 if ('objectClass=' != substr($this->config->objectclass, 0, 12)) {
1186 $this->config->objectclass = 'objectClass='.$this->config->objectclass;
1187 }
1188
1189 //all chages go in $CFG , no need to return value
1190 }
1191
1192 /**
1193 * take expirationtime and return it as unixseconds
1194 *
1195 * takes expriration timestamp as readed from ldap
1196 * returns it as unix seconds
1197 * depends on $config->user_type variable
1198 *
1199 * @param mixed time Time stamp readed from ldap as it is.
1200 * @return timestamp
1201 */
1202 function ldap_expirationtime2unix ($time) {
1203
1204 global $CFG;
1205 $result = false;
1206 switch ($this->config->user_type) {
1207 case 'edir':
1208 $yr=substr($time,0,4);
1209 $mo=substr($time,4,2);
1210 $dt=substr($time,6,2);
1211 $hr=substr($time,8,2);
1212 $min=substr($time,10,2);
1213 $sec=substr($time,12,2);
1214 $result = mktime($hr,$min,$sec,$mo,$dt,$yr);
1215 break;
1216 case 'posix':
1217 $result = $time * DAYSECS; //The shadowExpire contains the number of DAYS between 01/01/1970 and the actual expiration date
1218 break;
1219 default:
1220 error('config.user_type not defined or function ldap_expirationtime2unix does not support selected type!');
1221 }
1222 return $result;
1223 }
1224
1225 /**
1226 * takes unixtime and return it formated for storing in ldap
1227 *
1228 * @param integer unix time stamp
1229 */
1230 function ldap_unix2expirationtime($time) {
1231 global $CFG;
1232 $result = false;
1233 switch ($this->config->user_type) {
1234 case 'edir':
1235 $result=date('YmdHis', $time).'Z';
1236 break;
1237 case 'posix':
1238 $result = $time ; //Already in correct format
1239 break;
1240 default:
1241 error('config.user_type not defined or function ldap_unixi2expirationtime does not support selected type!');
1242 }
1243 return $result;
1244
1245 }
1246
1247 /*
1248 * checks if user belong to specific group(s)
1249 *
1250 * Returns true if user belongs group in grupdns string.
1251 *
1252 * @param mixed $username username
1253 * @param mixed $groupdns string of group dn separated by ;
1254 *
1255 */
1256 function ldap_isgroupmember($username='', $groupdns='') {
1257 // Takes username and groupdn(s) , separated by ;
1258 // Returns true if user is member of any given groups
1259
1260 global $CFG ;
1261 $result = false;
1262 $ldapconnection = $this->ldap_connect();
1263
1264 if (empty($username) or empty($groupdns)) {
1265 return $result;
1266 }
1267
1268 if ($this->config->memberattribute_isdn) {
1269 $username=$this->ldap_find_userdn($ldapconnection, $username);
1270 }
1271 if (! $username ) {
1272 return $result;
1273 }
1274
1275 $groups = explode(";",$groupdns);
1276
1277 foreach ($groups as $group) {
1278 $group = trim($group);
1279 if (empty($group)) {
1280 continue;
1281 }
1282 //echo "Checking group $group for member $username\n";
1283 $search = @ldap_read($ldapconnection, $group, '('.$this->config->memberattribute.'='.$username.')', array($this->config->memberattribute));
1284
1285 if (!empty($search) and ldap_count_entries($ldapconnection, $search)) {$info = $this->ldap_get_entries($ldapconnection, $search);
1286
1287 if (count($info) > 0 ) {
1288 // user is member of group
1289 $result = true;
1290 break;
1291 }
1292 }
1293 }
1294
1295 return $result;
1296
1297 }
1298
1299 /**
1300 * connects to ldap server
1301 *
1302 * Tries connect to specified ldap servers.
1303 * Returns connection result or error.
1304 *
1305 * @return connection result
1306 */
1307 function ldap_connect($binddn='',$bindpwd='') {
1308 /// connects and binds to ldap-server
1309 /// Returns connection result
1310
1311 global $CFG;
1312 $this->ldap_init();
1313
1314 //Select bind password, With empty values use
1315 //ldap_bind_* variables or anonymous bind if ldap_bind_* are empty
1316 if ($binddn == '' and $bindpwd == '') {
1317 if (!empty($this->config->bind_dn)) {
1318 $binddn = $this->config->bind_dn;
1319 }
1320 if (!empty($this->config->bind_pw)) {
1321 $bindpwd = $this->config->bind_pw;
1322 }
1323 }
1324
1325 $urls = explode(";",$this->config->host_url);
1326
1327 foreach ($urls as $server) {
1328 $server = trim($server);
1329 if (empty($server)) {
1330 continue;
1331 }
1332
1333 $connresult = ldap_connect($server);
1334 //ldap_connect returns ALWAYS true
1335
1336 if (!empty($this->config->version)) {
1337 ldap_set_option($connresult, LDAP_OPT_PROTOCOL_VERSION, $this->config->version);
1338 }
1339
1340 if (!empty($binddn)) {
1341 //bind with search-user
1342 //$debuginfo .= 'Using bind user'.$binddn.'and password:'.$bindpwd;
1343 $bindresult=ldap_bind($connresult, $binddn,$bindpwd);
1344 }
1345 else {
1346 //bind anonymously
1347 $bindresult=@ldap_bind($connresult);
1348 }
1349
1350 if (!empty($this->config->opt_deref)) {
1351 ldap_set_option($connresult, LDAP_OPT_DEREF, $this->config->opt_deref);
1352 }
1353
1354 if ($bindresult) {
1355 return $connresult;
1356 }
1357
1358 $debuginfo .= "<br/>Server: '$server' <br/> Connection: '$connresult'<br/> Bind result: '$bindresult'</br>";
1359 }
1360
1361 //If any of servers are alive we have already returned connection
1362 error("LDAP-module cannot connect any LDAP servers : $debuginfo");
1363 return false;
1364 }
1365
1366 /**
1367 * retuns dn of username
1368 *
1369 * Search specified contexts for username and return user dn
1370 * like: cn=username,ou=suborg,o=org
1371 *
1372 * @param mixed $ldapconnection $ldapconnection result
1373 * @param mixed $username username
1374 *
1375 */
1376
1377 function ldap_find_userdn ($ldapconnection, $username) {
1378
1379 global $CFG;
1380
1381 //default return value
1382 $ldap_user_dn = FALSE;
1383
1384 //get all contexts and look for first matching user
1385 $ldap_contexts = explode(";",$this->config->contexts);
1386
1387 if (!empty($this->config->create_context)) {
1388 array_push($ldap_contexts, $this->config->create_context);
1389 }
1390
1391 foreach ($ldap_contexts as $context) {
1392
1393 $context = trim($context);
1394 if (empty($context)) {
1395 continue;
1396 }
1397
1398 if ($this->config->search_sub) {
1399 //use ldap_search to find first user from subtree
1400 $ldap_result = ldap_search($ldapconnection, $context, "(".$this->config->user_attribute."=".$username.")",array($this->config->user_attribute));
1401
1402 }
1403 else {
1404 //search only in this context
1405 $ldap_result = ldap_list($ldapconnection, $context, "(".$this->config->user_attribute."=".$username.")",array($this->config->user_attribute));
1406 }
1407
1408 $entry = ldap_first_entry($ldapconnection,$ldap_result);
1409
1410 if ($entry) {
1411 $ldap_user_dn = ldap_get_dn($ldapconnection, $entry);
1412 break ;
1413 }
1414 }
1415
1416 return $ldap_user_dn;
1417 }
1418
1419 /**
1420 * retuns user attribute mappings between moodle and ldap
1421 *
1422 * @return array
1423 */
1424
1425 function ldap_attributes () {
1426 $fields = array("firstname", "lastname", "email", "phone1", "phone2",
1427 "department", "address", "city", "country", "description",
1428 "idnumber", "lang" );
1429 $moodleattributes = array();
1430 foreach ($fields as $field) {
1431 if (!empty($this->config->{"field_map_$field"})) {
1432 $moodleattributes[$field] = $this->config->{"field_map_$field"};
1433 if (preg_match('/,/',$moodleattributes[$field])) {
1434 $moodleattributes[$field] = explode(',', $moodleattributes[$field]); // split ?
1435 }
1436 }
1437 }
1438 $moodleattributes['username'] = $this->config->user_attribute;
1439 return $moodleattributes;
1440 }
1441
1442 /**
1443 * return all usernames from ldap
1444 *
1445 * @return array
1446 */
1447
1448 function ldap_get_userlist($filter="*") {
1449 /// returns all users from ldap servers
1450 global $CFG;
1451
1452 $fresult = array();
1453
1454 $ldapconnection = $this->ldap_connect();
1455
1456 if ($filter=="*") {
1457 $filter = "(&(".$this->config->user_attribute."=*)(".$this->config->objectclass."))";
1458 }
1459
1460 $contexts = explode(";",$this->config->contexts);
1461
1462 if (!empty($this->config->create_context)) {
1463 array_push($contexts, $this->config->create_context);
1464 }
1465
1466 foreach ($contexts as $context) {
1467
1468 $context = trim($context);
1469 if (empty($context)) {
1470 continue;
1471 }
1472
1473 if ($this->config->search_sub) {
1474 //use ldap_search to find first user from subtree
1475 $ldap_result = ldap_search($ldapconnection, $context,$filter,array($this->config->user_attribute));
1476 }
1477 else {
1478 //search only in this context
1479 $ldap_result = ldap_list($ldapconnection, $context,
1480 $filter,
1481 array($this->config->user_attribute));
1482 }
1483
1484 $users = $this->ldap_get_entries($ldapconnection, $ldap_result);
1485
1486 //add found users to list
1487 for ($i=0;$i<count($users);$i++) {
1488 array_push($fresult, ($users[$i][$this->config->user_attribute][0]) );
1489 }
1490 }
1491
1492 return $fresult;
1493 }
1494
1495 /**
1496 * return entries from ldap
1497 *
1498 * Returns values like ldap_get_entries but is
1499 * binary compatible and return all attributes as array
1500 *
1501 * @return array ldap-entries
1502 */
1503
1504 function ldap_get_entries($conn, $searchresult) {
1505 //Returns values like ldap_get_entries but is
1506 //binary compatible
1507 $i=0;
1508 $fresult=array();
1509 $entry = ldap_first_entry($conn, $searchresult);
1510 do {
1511 $attributes = @ldap_get_attributes($conn, $entry);
1512 for ($j=0; $j<$attributes['count']; $j++) {
1513 $values = ldap_get_values_len($conn, $entry,$attributes[$j]);
1514 if (is_array($values)) {
1515 $fresult[$i][$attributes[$j]] = $values;
1516 }
1517 else {
1518 $fresult[$i][$attributes[$j]] = array($values);
1519 }
1520 }
1521 $i++;
1522 }
1523 while ($entry = @ldap_next_entry($conn, $entry));
1524 //were done
1525 return ($fresult);
1526 }
1527
1528 /**
1529 * Returns true if this authentication plugin is 'internal'.
1530 *
1531 * @returns bool
1532 */
1533 function is_internal() {
1534 return false;
1535 }
1536
1537 /**
1538 * Returns true if this authentication plugin can change the user's
1539 * password.
1540 *
1541 * @returns bool
1542 */
1543 function can_change_password() {
1544 return true;
1545 }
1546
1547 /**
1548 * Returns the URL for changing the user's pw, or false if the default can
1549 * be used.
1550 *
1551 * @returns bool
1552 */
1553 function change_password_url() {
1554 return $CFG->changepasswordurl; // TODO: will this be global?
1555 }
1556
1557 /**
1558 * Prints a form for configuring this authentication plugin.
1559 *
1560 * This function is called from admin/auth.php, and outputs a full page with
1561 * a form for configuring this plugin.
1562 *
1563 * @param array $page An object containing all the data for this page.
1564 */
1565 function config_form($config, $err) {
1566 include "config.html";
1567 }
1568
1569 /**
1570 * Processes and stores configuration data for this authentication plugin.
1571 */
1572 function process_config($config) {
1573 // set to defaults if undefined
1574 if (!isset($config->host_url))
1575 { $config->host_url = ''; }
1576 if (!isset($config->contexts))
1577 { $config->contexts = ''; }
1578 if (!isset($config->user_type))
1579 { $config->user_type = ''; }
1580 if (!isset($config->user_attribute))
1581 { $config->user_attribute = ''; }
1582 if (!isset($config->search_sub))
1583 { $config->search_sub = ''; }
1584 if (!isset($config->opt_deref))
1585 { $config->opt_deref = ''; }
1586 if (!isset($config->preventpassindb))
1587 { $config->preventpassindb = 0; }
1588 if (!isset($config->bind_dn))
1589 {$config->bind_dn = ''; }
1590 if (!isset($config->bind_pw))
1591 {$config->bind_pw = ''; }
1592 if (!isset($config->version))
1593 {$config->version = '2'; }
1594 if (!isset($config->objectclass))
1595 {$config->objectclass = ''; }
1596 if (!isset($config->memberattribute))
1597 {$config->memberattribute = ''; }
1598 if (!isset($config->creators))
1599 {$config->creators = ''; }
1600 if (!isset($config->create_context))
1601 {$config->create_context = ''; }
1602 if (!isset($config->expiration))
1603 {$config->expiration = ''; }
1604 if (!isset($config->expiration_warning))
1605 {$config->expiration_warning = '10'; }
1606 if (!isset($config->expireattr))
1607 {$config->expireattr = ''; }
1608 if (!isset($config->gracelogins))
1609 {$config->gracelogins = ''; }
1610 if (!isset($config->graceattr))
1611 {$config->graceattr = ''; }
1612 if (!isset($config->auth_user_create))
1613 {$config->auth_user_create = ''; }
1614 if (!isset($config->forcechangepassword))
1615 {$config->forcechangepassword = false; }
1616 if (!isset($config->stdchangepassword))
1617 {$config->stdchangepassword = false; }
1618 if (!isset($config->changepasswordurl))
1619 {$config->changepasswordurl = ''; }
1620
1621 // save settings
1622 set_config('host_url', $config->host_url, 'auth/ldap');
1623 set_config('contexts', $config->contexts, 'auth/ldap');
1624 set_config('user_type', $config->user_type, 'auth/ldap');
1625 set_config('user_attribute', $config->user_attribute, 'auth/ldap');
1626 set_config('search_sub', $config->search_sub, 'auth/ldap');
1627 set_config('opt_deref', $config->opt_deref, 'auth/ldap');
1628 set_config('preventpassindb', $config->preventpassindb, 'auth/ldap');
1629 set_config('bind_dn', $config->bind_dn, 'auth/ldap');
1630 set_config('bind_pw', $config->bind_pw, 'auth/ldap');
1631 set_config('version', $config->version, 'auth/ldap');
1632 set_config('objectclass', $config->objectclass, 'auth/ldap');
1633 set_config('memberattribute', $config->memberattribute, 'auth/ldap');
1634 set_config('creators', $config->creators, 'auth/ldap');
1635 set_config('create_context', $config->create_context, 'auth/ldap');
1636 set_config('expiration', $config->expiration, 'auth/ldap');
1637 set_config('expiration_warning', $config->expiration_warning, 'auth/ldap');
1638 set_config('expireattr', $config->expireattr, 'auth/ldap');
1639 set_config('gracelogins', $config->gracelogins, 'auth/ldap');
1640 set_config('graceattr', $config->graceattr, 'auth/ldap');
1641 set_config('auth_user_create', $config->auth_user_create, 'auth/ldap');
1642 set_config('forcechangepassword', $config->forcechangepassword, 'auth/ldap');
1643 set_config('stdchangepassword', $config->stdchangepassword, 'auth/ldap');
1644 set_config('changepasswordurl', $config->changepasswordurl, 'auth/ldap');
1645
1646 return true;
1647 }
1648
1649}
1650
1651?>