Failed Conditions
Push — psr2 ( 64159a )
by Andreas
04:14
created

auth_plugin_authldap::modifyUser()   B

Complexity

Conditions 9
Paths 9

Size

Total Lines 55
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 30
nc 9
nop 2
dl 0
loc 55
rs 7.2446
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * LDAP authentication backend
4
 *
5
 * @license   GPL 2 (http://www.gnu.org/licenses/gpl.html)
6
 * @author    Andreas Gohr <[email protected]>
7
 * @author    Chris Smith <[email protected]>
8
 * @author    Jan Schumann <[email protected]>
9
 */
10
class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
11
    /* @var resource $con holds the LDAP connection*/
12
    protected $con = null;
13
14
    /* @var int $bound What type of connection does already exist? */
15
    protected $bound = 0; // 0: anonymous, 1: user, 2: superuser
16
17
    /* @var array $users User data cache */
18
    protected $users = null;
19
20
    /* @var array $_pattern User filter pattern */
21
    protected $_pattern = null;
22
23
    /**
24
     * Constructor
25
     */
26
    public function __construct() {
27
        parent::__construct();
28
29
        // ldap extension is needed
30
        if(!function_exists('ldap_connect')) {
31
            $this->_debug("LDAP err: PHP LDAP extension not found.", -1, __LINE__, __FILE__);
32
            $this->success = false;
33
            return;
34
        }
35
36
        // Add the capabilities to change the password
37
        $this->cando['modPass'] = $this->getConf('modPass');
38
    }
39
40
    /**
41
     * Check user+password
42
     *
43
     * Checks if the given user exists and the given
44
     * plaintext password is correct by trying to bind
45
     * to the LDAP server
46
     *
47
     * @author  Andreas Gohr <[email protected]>
48
     * @param string $user
49
     * @param string $pass
50
     * @return  bool
51
     */
52
    public function checkPass($user, $pass) {
53
        // reject empty password
54
        if(empty($pass)) return false;
55
        if(!$this->_openLDAP()) return false;
56
57
        // indirect user bind
58
        if($this->getConf('binddn') && $this->getConf('bindpw')) {
59
            // use superuser credentials
60
            if(!@ldap_bind($this->con, $this->getConf('binddn'), conf_decodeString($this->getConf('bindpw')))) {
61
                $this->_debug('LDAP bind as superuser: '.hsc(ldap_error($this->con)), 0, __LINE__, __FILE__);
62
                return false;
63
            }
64
            $this->bound = 2;
65
        } else if($this->getConf('binddn') &&
66
            $this->getConf('usertree') &&
67
            $this->getConf('userfilter')
68
        ) {
69
            // special bind string
70
            $dn = $this->_makeFilter(
71
                $this->getConf('binddn'),
72
                array('user'=> $user, 'server'=> $this->getConf('server'))
73
            );
74
75
        } else if(strpos($this->getConf('usertree'), '%{user}')) {
76
            // direct user bind
77
            $dn = $this->_makeFilter(
78
                $this->getConf('usertree'),
79
                array('user'=> $user, 'server'=> $this->getConf('server'))
80
            );
81
82
        } else {
83
            // Anonymous bind
84
            if(!@ldap_bind($this->con)) {
85
                msg("LDAP: can not bind anonymously", -1);
86
                $this->_debug('LDAP anonymous bind: '.hsc(ldap_error($this->con)), 0, __LINE__, __FILE__);
87
                return false;
88
            }
89
        }
90
91
        // Try to bind to with the dn if we have one.
92
        if(!empty($dn)) {
93
            // User/Password bind
94
            if(!@ldap_bind($this->con, $dn, $pass)) {
95
                $this->_debug("LDAP: bind with $dn failed", -1, __LINE__, __FILE__);
96
                $this->_debug('LDAP user dn bind: '.hsc(ldap_error($this->con)), 0, __LINE__, __FILE__);
97
                return false;
98
            }
99
            $this->bound = 1;
100
            return true;
101
        } else {
102
            // See if we can find the user
103
            $info = $this->_getUserData($user, true);
104
            if(empty($info['dn'])) {
105
                return false;
106
            } else {
107
                $dn = $info['dn'];
108
            }
109
110
            // Try to bind with the dn provided
111
            if(!@ldap_bind($this->con, $dn, $pass)) {
112
                $this->_debug("LDAP: bind with $dn failed", -1, __LINE__, __FILE__);
113
                $this->_debug('LDAP user bind: '.hsc(ldap_error($this->con)), 0, __LINE__, __FILE__);
114
                return false;
115
            }
116
            $this->bound = 1;
117
            return true;
118
        }
119
    }
120
121
    /**
122
     * Return user info
123
     *
124
     * Returns info about the given user needs to contain
125
     * at least these fields:
126
     *
127
     * name string  full name of the user
128
     * mail string  email addres of the user
129
     * grps array   list of groups the user is in
130
     *
131
     * This LDAP specific function returns the following
132
     * addional fields:
133
     *
134
     * dn     string  distinguished name (DN)
135
     * uid    string  Posix User ID
136
     * inbind bool    for internal use - avoid loop in binding
137
     *
138
     * @author  Andreas Gohr <[email protected]>
139
     * @author  Trouble
140
     * @author  Dan Allen <[email protected]>
141
     * @author  <[email protected]>
142
     * @author  Stephane Chazelas <[email protected]>
143
     * @author  Steffen Schoch <[email protected]>
144
     *
145
     * @param   string $user
146
     * @param   bool   $requireGroups (optional) - ignored, groups are always supplied by this plugin
147
     * @return  array containing user data or false
148
     */
149
    public function getUserData($user, $requireGroups=true) {
150
        return $this->_getUserData($user);
151
    }
152
153
    /**
154
     * @param   string $user
155
     * @param   bool   $inbind authldap specific, true if in bind phase
156
     * @return  array containing user data or false
157
     */
158
    protected function _getUserData($user, $inbind = false) {
159
        global $conf;
160
        if(!$this->_openLDAP()) return false;
161
162
        // force superuser bind if wanted and not bound as superuser yet
163
        if($this->getConf('binddn') && $this->getConf('bindpw') && $this->bound < 2) {
164
            // use superuser credentials
165
            if(!@ldap_bind($this->con, $this->getConf('binddn'), conf_decodeString($this->getConf('bindpw')))) {
166
                $this->_debug('LDAP bind as superuser: '.hsc(ldap_error($this->con)), 0, __LINE__, __FILE__);
167
                return false;
168
            }
169
            $this->bound = 2;
170
        } elseif($this->bound == 0 && !$inbind) {
171
            // in some cases getUserData is called outside the authentication workflow
172
            // eg. for sending email notification on subscribed pages. This data might not
173
            // be accessible anonymously, so we try to rebind the current user here
174
            list($loginuser, $loginsticky, $loginpass) = auth_getCookie();
175
            if($loginuser && $loginpass) {
176
                $loginpass = auth_decrypt($loginpass, auth_cookiesalt(!$loginsticky, true));
0 ignored issues
show
Bug introduced by
It seems like auth_cookiesalt(!$loginsticky, true) targeting auth_cookiesalt() can also be of type boolean; however, auth_decrypt() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
177
                $this->checkPass($loginuser, $loginpass);
178
            }
179
        }
180
181
        $info = array();
182
        $info['user']   = $user;
183
		$this->_debug('LDAP user to find: '.hsc($info['user']), 0, __LINE__, __FILE__);
184
185
        $info['server'] = $this->getConf('server');
186
		$this->_debug('LDAP Server: '.hsc($info['server']), 0, __LINE__, __FILE__);
187
188
189
        //get info for given user
190
        $base = $this->_makeFilter($this->getConf('usertree'), $info);
191
        if($this->getConf('userfilter')) {
192
            $filter = $this->_makeFilter($this->getConf('userfilter'), $info);
193
        } else {
194
            $filter = "(ObjectClass=*)";
195
        }
196
197
		$this->_debug('LDAP Filter: '.hsc($filter), 0, __LINE__, __FILE__);
198
199
        $this->_debug('LDAP user search: '.hsc(ldap_error($this->con)), 0, __LINE__, __FILE__);
200
        $this->_debug('LDAP search at: '.hsc($base.' '.$filter), 0, __LINE__, __FILE__);
201
		$sr     = $this->_ldapsearch($this->con, $base, $filter, $this->getConf('userscope'));
202
203
		$result = @ldap_get_entries($this->con, $sr);
204
205
        // if result is not an array
206
        if(!is_array($result)) {
207
			// no objects found
208
			$this->_debug('LDAP search returned non-array result: '.hsc(print($result)), -1, __LINE__, __FILE__);
209
            return false;
210
        }
211
212
		// Don't accept more or less than one response
213
		if ($result['count'] != 1)		{
214
			$this->_debug(
215
			    'LDAP search returned '.hsc($result['count']).' results while it should return 1!',
216
                -1, __LINE__, __FILE__
217
            );
218
			//for($i = 0; $i < $result["count"]; $i++) {
219
				//$this->_debug('result: '.hsc(print_r($result[$i])), 0, __LINE__, __FILE__);
220
			//}
221
			return false;
222
		}
223
224
225
		$this->_debug('LDAP search found single result !', 0, __LINE__, __FILE__);
226
227
        $user_result = $result[0];
228
        ldap_free_result($sr);
229
230
        // general user info
231
        $info['dn']   = $user_result['dn'];
232
        $info['gid']  = $user_result['gidnumber'][0];
233
        $info['mail'] = $user_result['mail'][0];
234
        $info['name'] = $user_result['cn'][0];
235
        $info['grps'] = array();
236
237
        // overwrite if other attribs are specified.
238
        if(is_array($this->getConf('mapping'))) {
239
            foreach($this->getConf('mapping') as $localkey => $key) {
240
                if(is_array($key)) {
241
                    // use regexp to clean up user_result
242
                    // $key = array($key=>$regexp), only handles the first key-value
243
                    $regexp = current($key);
244
                    $key = key($key);
245
                    if($user_result[$key]) foreach($user_result[$key] as $grpkey => $grp) {
246
                        if($grpkey !== 'count' && preg_match($regexp, $grp, $match)) {
247
                            if($localkey == 'grps') {
248
                                $info[$localkey][] = $match[1];
249
                            } else {
250
                                $info[$localkey] = $match[1];
251
                            }
252
                        }
253
                    }
254
                } else {
255
                    $info[$localkey] = $user_result[$key][0];
256
                }
257
            }
258
        }
259
        $user_result = array_merge($info, $user_result);
260
261
        //get groups for given user if grouptree is given
262
        if($this->getConf('grouptree') || $this->getConf('groupfilter')) {
263
            $base   = $this->_makeFilter($this->getConf('grouptree'), $user_result);
264
            $filter = $this->_makeFilter($this->getConf('groupfilter'), $user_result);
265
            $sr     = $this->_ldapsearch(
266
                $this->con,
267
                $base,
268
                $filter,
269
                $this->getConf('groupscope'),
270
                array($this->getConf('groupkey')))
271
            ;
272
            $this->_debug('LDAP group search: '.hsc(ldap_error($this->con)), 0, __LINE__, __FILE__);
273
            $this->_debug('LDAP search at: '.hsc($base.' '.$filter), 0, __LINE__, __FILE__);
274
275
            if(!$sr) {
276
                msg("LDAP: Reading group memberships failed", -1);
277
                return false;
278
            }
279
            $result = ldap_get_entries($this->con, $sr);
280
            ldap_free_result($sr);
281
282
            if(is_array($result)) foreach($result as $grp) {
283
                if(!empty($grp[$this->getConf('groupkey')])) {
284
                    $group = $grp[$this->getConf('groupkey')];
285
                    if(is_array($group)){
286
                        $group = $group[0];
287
                    } else {
288
                        $this->_debug('groupkey did not return a detailled result', 0, __LINE__, __FILE__);
289
                    }
290
                    if($group === '') continue;
291
292
                    $this->_debug('LDAP usergroup: '.hsc($group), 0, __LINE__, __FILE__);
293
                    $info['grps'][] = $group;
294
                }
295
            }
296
        }
297
298
        // always add the default group to the list of groups
299
        if(!$info['grps'] or !in_array($conf['defaultgroup'], $info['grps'])) {
300
            $info['grps'][] = $conf['defaultgroup'];
301
        }
302
        return $info;
303
    }
304
305
    /**
306
     * Definition of the function modifyUser in order to modify the password
307
     *
308
     * @param   string $user    nick of the user to be changed
309
     * @param   array  $changes array of field/value pairs to be changed (password will be clear text)
310
     * @return  bool   true on success, false on error
311
     */
312
313
    function modifyUser($user,$changes){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
314
315
        // open the connection to the ldap
316
        if(!$this->_openLDAP()){
317
            $this->_debug('LDAP cannot connect: '. hsc(ldap_error($this->con)), 0, __LINE__, __FILE__);
318
            return false;
319
        }
320
321
        // find the information about the user, in particular the "dn"
322
        $info = $this->getUserData($user,true);
323
        if(empty($info['dn'])) {
324
            $this->_debug('LDAP cannot find your user dn', 0, __LINE__, __FILE__);
325
            return false;
326
        }
327
        $dn = $info['dn'];
328
329
        // find the old password of the user
330
        list($loginuser,$loginsticky,$loginpass) = auth_getCookie();
331
        if ($loginuser !== null) { // the user is currently logged in
332
            $secret = auth_cookiesalt(!$loginsticky, true);
333
            $pass   = auth_decrypt($loginpass, $secret);
334
335
            // bind with the ldap
336
            if(!@ldap_bind($this->con, $dn, $pass)){
337
                $this->_debug(
338
                    'LDAP user bind failed: '. hsc($dn) .': '.hsc(ldap_error($this->con)), 0, __LINE__, __FILE__
339
                );
340
                return false;
341
            }
342
        } elseif ($this->getConf('binddn') && $this->getConf('bindpw')) {
343
            // we are changing the password on behalf of the user (eg: forgotten password)
344
            // bind with the superuser ldap
345
            if (!@ldap_bind($this->con, $this->getConf('binddn'), conf_decodeString($this->getConf('bindpw')))){
346
                $this->_debug('LDAP bind as superuser: '.hsc(ldap_error($this->con)), 0, __LINE__, __FILE__);
347
                return false;
348
            }
349
        }
350
        else {
351
            return false; // no otherway
352
        }
353
354
        // Generate the salted hashed password for LDAP
355
        $phash = new PassHash();
356
        $hash = $phash->hash_ssha($changes['pass']);
357
358
        // change the password
359
        if(!@ldap_mod_replace($this->con, $dn,array('userpassword' => $hash))){
360
            $this->_debug(
361
                'LDAP mod replace failed: '. hsc($dn) .': '.hsc(ldap_error($this->con)), 0, __LINE__, __FILE__
362
            );
363
            return false;
364
        }
365
366
        return true;
367
    }
368
369
    /**
370
     * Most values in LDAP are case-insensitive
371
     *
372
     * @return bool
373
     */
374
    public function isCaseSensitive() {
375
        return false;
376
    }
377
378
    /**
379
     * Bulk retrieval of user data
380
     *
381
     * @author  Dominik Eckelmann <[email protected]>
382
     * @param   int   $start     index of first user to be returned
383
     * @param   int   $limit     max number of users to be returned
384
     * @param   array $filter  array of field/pattern pairs, null for no filter
385
     * @return  array of userinfo (refer getUserData for internal userinfo details)
386
     */
387
    function retrieveUsers($start = 0, $limit = 0, $filter = array()) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
388
        if(!$this->_openLDAP()) return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type of the parent method DokuWiki_Auth_Plugin::retrieveUsers of type array.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
389
390
        if(is_null($this->users)) {
391
            // Perform the search and grab all their details
392
            if($this->getConf('userfilter')) {
393
                $all_filter = str_replace('%{user}', '*', $this->getConf('userfilter'));
394
            } else {
395
                $all_filter = "(ObjectClass=*)";
396
            }
397
            $sr          = ldap_search($this->con, $this->getConf('usertree'), $all_filter);
398
            $entries     = ldap_get_entries($this->con, $sr);
399
            $users_array = array();
400
            $userkey     = $this->getConf('userkey');
401
            for($i = 0; $i < $entries["count"]; $i++) {
402
                array_push($users_array, $entries[$i][$userkey][0]);
403
            }
404
            asort($users_array);
405
            $result = $users_array;
406
            if(!$result) return array();
0 ignored issues
show
Bug Best Practice introduced by
The expression $result of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
407
            $this->users = array_fill_keys($result, false);
408
        }
409
        $i     = 0;
410
        $count = 0;
411
        $this->_constructPattern($filter);
412
        $result = array();
413
414
        foreach($this->users as $user => &$info) {
415
            if($i++ < $start) {
416
                continue;
417
            }
418
            if($info === false) {
419
                $info = $this->getUserData($user);
420
            }
421
            if($this->_filter($user, $info)) {
422
                $result[$user] = $info;
423
                if(($limit > 0) && (++$count >= $limit)) break;
424
            }
425
        }
426
        return $result;
427
    }
428
429
    /**
430
     * Make LDAP filter strings.
431
     *
432
     * Used by auth_getUserData to make the filter
433
     * strings for grouptree and groupfilter
434
     *
435
     * @author  Troels Liebe Bentsen <[email protected]>
436
     * @param   string $filter ldap search filter with placeholders
437
     * @param   array  $placeholders placeholders to fill in
438
     * @return  string
439
     */
440
    protected function _makeFilter($filter, $placeholders) {
441
        preg_match_all("/%{([^}]+)/", $filter, $matches, PREG_PATTERN_ORDER);
442
        //replace each match
443
        foreach($matches[1] as $match) {
444
            //take first element if array
445
            if(is_array($placeholders[$match])) {
446
                $value = $placeholders[$match][0];
447
            } else {
448
                $value = $placeholders[$match];
449
            }
450
            $value  = $this->_filterEscape($value);
451
            $filter = str_replace('%{'.$match.'}', $value, $filter);
452
        }
453
        return $filter;
454
    }
455
456
    /**
457
     * return true if $user + $info match $filter criteria, false otherwise
458
     *
459
     * @author Chris Smith <[email protected]>
460
     *
461
     * @param  string $user the user's login name
462
     * @param  array  $info the user's userinfo array
463
     * @return bool
464
     */
465
    protected  function _filter($user, $info) {
466
        foreach($this->_pattern as $item => $pattern) {
467
            if($item == 'user') {
468
                if(!preg_match($pattern, $user)) return false;
469
            } else if($item == 'grps') {
470
                if(!count(preg_grep($pattern, $info['grps']))) return false;
471
            } else {
472
                if(!preg_match($pattern, $info[$item])) return false;
473
            }
474
        }
475
        return true;
476
    }
477
478
    /**
479
     * Set the filter pattern
480
     *
481
     * @author Chris Smith <[email protected]>
482
     *
483
     * @param $filter
484
     * @return void
485
     */
486
    protected function _constructPattern($filter) {
487
        $this->_pattern = array();
488
        foreach($filter as $item => $pattern) {
489
            $this->_pattern[$item] = '/'.str_replace('/', '\/', $pattern).'/i'; // allow regex characters
490
        }
491
    }
492
493
    /**
494
     * Escape a string to be used in a LDAP filter
495
     *
496
     * Ported from Perl's Net::LDAP::Util escape_filter_value
497
     *
498
     * @author Andreas Gohr
499
     * @param  string $string
500
     * @return string
501
     */
502
    protected function _filterEscape($string) {
503
        // see https://github.com/adldap/adLDAP/issues/22
504
        return preg_replace_callback(
505
            '/([\x00-\x1F\*\(\)\\\\])/',
506
            function ($matches) {
507
                return "\\".join("", unpack("H2", $matches[1]));
508
            },
509
            $string
510
        );
511
    }
512
513
    /**
514
     * Opens a connection to the configured LDAP server and sets the wanted
515
     * option on the connection
516
     *
517
     * @author  Andreas Gohr <[email protected]>
518
     */
519
    protected function _openLDAP() {
520
        if($this->con) return true; // connection already established
521
522
        if($this->getConf('debug')) {
523
            ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, 7);
524
        }
525
526
        $this->bound = 0;
527
528
        $port    = $this->getConf('port');
529
        $bound   = false;
530
        $servers = explode(',', $this->getConf('server'));
531
        foreach($servers as $server) {
532
            $server    = trim($server);
533
            $this->con = @ldap_connect($server, $port);
534
            if(!$this->con) {
535
                continue;
536
            }
537
538
            /*
539
             * When OpenLDAP 2.x.x is used, ldap_connect() will always return a resource as it does
540
             * not actually connect but just initializes the connecting parameters. The actual
541
             * connect happens with the next calls to ldap_* funcs, usually with ldap_bind().
542
             *
543
             * So we should try to bind to server in order to check its availability.
544
             */
545
546
            //set protocol version and dependend options
547
            if($this->getConf('version')) {
548
                if(!@ldap_set_option(
549
                    $this->con, LDAP_OPT_PROTOCOL_VERSION,
550
                    $this->getConf('version')
551
                )
552
                ) {
553
                    msg('Setting LDAP Protocol version '.$this->getConf('version').' failed', -1);
554
                    $this->_debug('LDAP version set: '.hsc(ldap_error($this->con)), 0, __LINE__, __FILE__);
555
                } else {
556
                    //use TLS (needs version 3)
557
                    if($this->getConf('starttls')) {
558
                        if(!@ldap_start_tls($this->con)) {
559
                            msg('Starting TLS failed', -1);
560
                            $this->_debug('LDAP TLS set: '.hsc(ldap_error($this->con)), 0, __LINE__, __FILE__);
561
                        }
562
                    }
563
                    // needs version 3
564
                    if($this->getConf('referrals') > -1) {
565
                        if(!@ldap_set_option(
566
                            $this->con, LDAP_OPT_REFERRALS,
567
                            $this->getConf('referrals')
568
                        )
569
                        ) {
570
                            msg('Setting LDAP referrals failed', -1);
571
                            $this->_debug('LDAP referal set: '.hsc(ldap_error($this->con)), 0, __LINE__, __FILE__);
572
                        }
573
                    }
574
                }
575
            }
576
577
            //set deref mode
578
            if($this->getConf('deref')) {
579
                if(!@ldap_set_option($this->con, LDAP_OPT_DEREF, $this->getConf('deref'))) {
580
                    msg('Setting LDAP Deref mode '.$this->getConf('deref').' failed', -1);
581
                    $this->_debug('LDAP deref set: '.hsc(ldap_error($this->con)), 0, __LINE__, __FILE__);
582
                }
583
            }
584
            /* As of PHP 5.3.0 we can set timeout to speedup skipping of invalid servers */
585
            if(defined('LDAP_OPT_NETWORK_TIMEOUT')) {
586
                ldap_set_option($this->con, LDAP_OPT_NETWORK_TIMEOUT, 1);
587
            }
588
589
            if($this->getConf('binddn') && $this->getConf('bindpw')) {
590
                $bound = @ldap_bind($this->con, $this->getConf('binddn'), conf_decodeString($this->getConf('bindpw')));
591
                $this->bound = 2;
592
            } else {
593
                $bound = @ldap_bind($this->con);
594
            }
595
            if($bound) {
596
                break;
597
            }
598
        }
599
600
        if(!$bound) {
601
            msg("LDAP: couldn't connect to LDAP server", -1);
602
            $this->_debug(ldap_error($this->con), 0, __LINE__, __FILE__);
603
            return false;
604
        }
605
606
        $this->cando['getUsers'] = true;
607
        return true;
608
    }
609
610
    /**
611
     * Wraps around ldap_search, ldap_list or ldap_read depending on $scope
612
     *
613
     * @author Andreas Gohr <[email protected]>
614
     * @param resource   $link_identifier
615
     * @param string     $base_dn
616
     * @param string     $filter
617
     * @param string     $scope can be 'base', 'one' or 'sub'
618
     * @param null|array $attributes
619
     * @param int        $attrsonly
620
     * @param int        $sizelimit
621
     * @return resource
622
     */
623
    protected function _ldapsearch($link_identifier, $base_dn, $filter, $scope = 'sub', $attributes = null,
624
                         $attrsonly = 0, $sizelimit = 0) {
625
        if(is_null($attributes)) $attributes = array();
626
627
        if($scope == 'base') {
628
            return @ldap_read(
629
                $link_identifier, $base_dn, $filter, $attributes,
630
                $attrsonly, $sizelimit
631
            );
632
        } elseif($scope == 'one') {
633
            return @ldap_list(
634
                $link_identifier, $base_dn, $filter, $attributes,
635
                $attrsonly, $sizelimit
636
            );
637
        } else {
638
            return @ldap_search(
639
                $link_identifier, $base_dn, $filter, $attributes,
640
                $attrsonly, $sizelimit
641
            );
642
        }
643
    }
644
645
    /**
646
     * Wrapper around msg() but outputs only when debug is enabled
647
     *
648
     * @param string $message
649
     * @param int    $err
650
     * @param int    $line
651
     * @param string $file
652
     * @return void
653
     */
654
    protected function _debug($message, $err, $line, $file) {
655
        if(!$this->getConf('debug')) return;
656
        msg($message, $err, $line, $file);
657
    }
658
659
}
660