Completed
Push — keepfilteroptionsextentionmgr ( 655dcd...4f30d1 )
by Gerrit
04:10
created

auth_plugin_authldap::_getUserData()   D

Complexity

Conditions 31
Paths 122

Size

Total Lines 114
Code Lines 71

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 114
rs 4.1804
cc 31
eloc 71
nc 122
nop 2

How to fix   Long Method    Complexity   

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
// must be run within Dokuwiki
3
if(!defined('DOKU_INC')) die();
4
5
/**
6
 * LDAP authentication backend
7
 *
8
 * @license   GPL 2 (http://www.gnu.org/licenses/gpl.html)
9
 * @author    Andreas Gohr <[email protected]>
10
 * @author    Chris Smith <[email protected]>
11
 * @author    Jan Schumann <[email protected]>
12
 */
13
class auth_plugin_authldap extends DokuWiki_Auth_Plugin {
14
    /* @var resource $con holds the LDAP connection*/
15
    protected $con = null;
16
17
    /* @var int $bound What type of connection does already exist? */
18
    protected $bound = 0; // 0: anonymous, 1: user, 2: superuser
19
20
    /* @var array $users User data cache */
21
    protected $users = null;
22
23
    /* @var array $_pattern User filter pattern */
24
    protected $_pattern = null;
25
26
    /**
27
     * Constructor
28
     */
29
    public function __construct() {
30
        parent::__construct();
31
32
        // ldap extension is needed
33
        if(!function_exists('ldap_connect')) {
34
            $this->_debug("LDAP err: PHP LDAP extension not found.", -1, __LINE__, __FILE__);
35
            $this->success = false;
36
            return;
37
        }
38
39
        // Add the capabilities to change the password
40
        $this->cando['modPass'] = $this->getConf('modPass');
41
    }
42
43
    /**
44
     * Check user+password
45
     *
46
     * Checks if the given user exists and the given
47
     * plaintext password is correct by trying to bind
48
     * to the LDAP server
49
     *
50
     * @author  Andreas Gohr <[email protected]>
51
     * @param string $user
52
     * @param string $pass
53
     * @return  bool
54
     */
55
    public function checkPass($user, $pass) {
56
        // reject empty password
57
        if(empty($pass)) return false;
58
        if(!$this->_openLDAP()) return false;
59
60
        // indirect user bind
61
        if($this->getConf('binddn') && $this->getConf('bindpw')) {
62
            // use superuser credentials
63
            if(!@ldap_bind($this->con, $this->getConf('binddn'), conf_decodeString($this->getConf('bindpw')))) {
64
                $this->_debug('LDAP bind as superuser: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
65
                return false;
66
            }
67
            $this->bound = 2;
68
        } else if($this->getConf('binddn') &&
69
            $this->getConf('usertree') &&
70
            $this->getConf('userfilter')
71
        ) {
72
            // special bind string
73
            $dn = $this->_makeFilter(
74
                $this->getConf('binddn'),
75
                array('user'=> $user, 'server'=> $this->getConf('server'))
76
            );
77
78
        } else if(strpos($this->getConf('usertree'), '%{user}')) {
79
            // direct user bind
80
            $dn = $this->_makeFilter(
81
                $this->getConf('usertree'),
82
                array('user'=> $user, 'server'=> $this->getConf('server'))
83
            );
84
85
        } else {
86
            // Anonymous bind
87
            if(!@ldap_bind($this->con)) {
88
                msg("LDAP: can not bind anonymously", -1);
89
                $this->_debug('LDAP anonymous bind: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
90
                return false;
91
            }
92
        }
93
94
        // Try to bind to with the dn if we have one.
95
        if(!empty($dn)) {
96
            // User/Password bind
97
            if(!@ldap_bind($this->con, $dn, $pass)) {
98
                $this->_debug("LDAP: bind with $dn failed", -1, __LINE__, __FILE__);
99
                $this->_debug('LDAP user dn bind: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
100
                return false;
101
            }
102
            $this->bound = 1;
103
            return true;
104
        } else {
105
            // See if we can find the user
106
            $info = $this->_getUserData($user, true);
107
            if(empty($info['dn'])) {
108
                return false;
109
            } else {
110
                $dn = $info['dn'];
111
            }
112
113
            // Try to bind with the dn provided
114
            if(!@ldap_bind($this->con, $dn, $pass)) {
115
                $this->_debug("LDAP: bind with $dn failed", -1, __LINE__, __FILE__);
116
                $this->_debug('LDAP user bind: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
117
                return false;
118
            }
119
            $this->bound = 1;
120
            return true;
121
        }
122
    }
123
124
    /**
125
     * Return user info
126
     *
127
     * Returns info about the given user needs to contain
128
     * at least these fields:
129
     *
130
     * name string  full name of the user
131
     * mail string  email addres of the user
132
     * grps array   list of groups the user is in
133
     *
134
     * This LDAP specific function returns the following
135
     * addional fields:
136
     *
137
     * dn     string  distinguished name (DN)
138
     * uid    string  Posix User ID
139
     * inbind bool    for internal use - avoid loop in binding
140
     *
141
     * @author  Andreas Gohr <[email protected]>
142
     * @author  Trouble
143
     * @author  Dan Allen <[email protected]>
144
     * @author  <[email protected]>
145
     * @author  Stephane Chazelas <[email protected]>
146
     * @author  Steffen Schoch <[email protected]>
147
     *
148
     * @param   string $user
149
     * @param   bool   $requireGroups (optional) - ignored, groups are always supplied by this plugin
150
     * @return  array containing user data or false
151
     */
152
    public function getUserData($user, $requireGroups=true) {
153
        return $this->_getUserData($user);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->_getUserData($user); of type false|array adds the type array to the return on line 153 which is incompatible with the return type of the parent method DokuWiki_Auth_Plugin::getUserData of type boolean.
Loading history...
154
    }
155
156
    /**
157
     * @param   string $user
158
     * @param   bool   $inbind authldap specific, true if in bind phase
159
     * @return  array containing user data or false
160
     */
161
    protected function _getUserData($user, $inbind = false) {
162
        global $conf;
163
        if(!$this->_openLDAP()) return false;
164
165
        // force superuser bind if wanted and not bound as superuser yet
166
        if($this->getConf('binddn') && $this->getConf('bindpw') && $this->bound < 2) {
167
            // use superuser credentials
168
            if(!@ldap_bind($this->con, $this->getConf('binddn'), conf_decodeString($this->getConf('bindpw')))) {
169
                $this->_debug('LDAP bind as superuser: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
170
                return false;
171
            }
172
            $this->bound = 2;
173
        } elseif($this->bound == 0 && !$inbind) {
174
            // in some cases getUserData is called outside the authentication workflow
175
            // eg. for sending email notification on subscribed pages. This data might not
176
            // be accessible anonymously, so we try to rebind the current user here
177
            list($loginuser, $loginsticky, $loginpass) = auth_getCookie();
178
            if($loginuser && $loginpass) {
179
                $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...
180
                $this->checkPass($loginuser, $loginpass);
181
            }
182
        }
183
184
        $info = array();
185
        $info['user']   = $user;
186
        $info['server'] = $this->getConf('server');
187
188
        //get info for given user
189
        $base = $this->_makeFilter($this->getConf('usertree'), $info);
190
        if($this->getConf('userfilter')) {
191
            $filter = $this->_makeFilter($this->getConf('userfilter'), $info);
192
        } else {
193
            $filter = "(ObjectClass=*)";
194
        }
195
196
        $sr     = $this->_ldapsearch($this->con, $base, $filter, $this->getConf('userscope'));
197
        $result = @ldap_get_entries($this->con, $sr);
198
        $this->_debug('LDAP user search: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
199
        $this->_debug('LDAP search at: '.htmlspecialchars($base.' '.$filter), 0, __LINE__, __FILE__);
200
201
        // Don't accept more or less than one response
202
        if(!is_array($result) || $result['count'] != 1) {
203
            return false; //user not found
204
        }
205
206
        $user_result = $result[0];
207
        ldap_free_result($sr);
208
209
        // general user info
210
        $info['dn']   = $user_result['dn'];
211
        $info['gid']  = $user_result['gidnumber'][0];
212
        $info['mail'] = $user_result['mail'][0];
213
        $info['name'] = $user_result['cn'][0];
214
        $info['grps'] = array();
215
216
        // overwrite if other attribs are specified.
217
        if(is_array($this->getConf('mapping'))) {
218
            foreach($this->getConf('mapping') as $localkey => $key) {
219
                if(is_array($key)) {
220
                    // use regexp to clean up user_result
221
                    list($key, $regexp) = each($key);
222
                    if($user_result[$key]) foreach($user_result[$key] as $grpkey => $grp) {
223
                        if($grpkey !== 'count' && preg_match($regexp, $grp, $match)) {
224
                            if($localkey == 'grps') {
225
                                $info[$localkey][] = $match[1];
226
                            } else {
227
                                $info[$localkey] = $match[1];
228
                            }
229
                        }
230
                    }
231
                } else {
232
                    $info[$localkey] = $user_result[$key][0];
233
                }
234
            }
235
        }
236
        $user_result = array_merge($info, $user_result);
237
238
        //get groups for given user if grouptree is given
239
        if($this->getConf('grouptree') || $this->getConf('groupfilter')) {
240
            $base   = $this->_makeFilter($this->getConf('grouptree'), $user_result);
241
            $filter = $this->_makeFilter($this->getConf('groupfilter'), $user_result);
242
            $sr     = $this->_ldapsearch($this->con, $base, $filter, $this->getConf('groupscope'), array($this->getConf('groupkey')));
243
            $this->_debug('LDAP group search: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
244
            $this->_debug('LDAP search at: '.htmlspecialchars($base.' '.$filter), 0, __LINE__, __FILE__);
245
246
            if(!$sr) {
247
                msg("LDAP: Reading group memberships failed", -1);
248
                return false;
249
            }
250
            $result = ldap_get_entries($this->con, $sr);
251
            ldap_free_result($sr);
252
253
            if(is_array($result)) foreach($result as $grp) {
254
                if(!empty($grp[$this->getConf('groupkey')])) {
255
                    $group = $grp[$this->getConf('groupkey')];
256
                    if(is_array($group)){
257
                        $group = $group[0];
258
                    } else {
259
                        $this->_debug('groupkey did not return a detailled result', 0, __LINE__, __FILE__);
260
                    }
261
                    if($group === '') continue;
262
263
                    $this->_debug('LDAP usergroup: '.htmlspecialchars($group), 0, __LINE__, __FILE__);
264
                    $info['grps'][] = $group;
265
                }
266
            }
267
        }
268
269
        // always add the default group to the list of groups
270
        if(!$info['grps'] or !in_array($conf['defaultgroup'], $info['grps'])) {
271
            $info['grps'][] = $conf['defaultgroup'];
272
        }
273
        return $info;
274
    }
275
276
    /**
277
     * Definition of the function modifyUser in order to modify the password
278
     *
279
     * @param   string $user    nick of the user to be changed
280
     * @param   array  $changes array of field/value pairs to be changed (password will be clear text)
281
     * @return  bool   true on success, false on error
282
     */
283
284
    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...
285
286
        // open the connection to the ldap
287
        if(!$this->_openLDAP()){
288
            $this->_debug('LDAP cannot connect: '. htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
289
            return false;
290
        }
291
292
        // find the information about the user, in particular the "dn"
293
        $info = $this->getUserData($user,true);
294
        if(empty($info['dn'])) {
295
            $this->_debug('LDAP cannot find your user dn', 0, __LINE__, __FILE__);
296
            return false;
297
        }
298
        $dn = $info['dn'];
299
300
        // find the old password of the user
301
        list($loginuser,$loginsticky,$loginpass) = auth_getCookie();
302
        if ($loginuser !== null) { // the user is currently logged in
303
            $secret = auth_cookiesalt(!$loginsticky, true);
304
            $pass   = auth_decrypt($loginpass, $secret);
305
306
            // bind with the ldap
307
            if(!@ldap_bind($this->con, $dn, $pass)){
308
                $this->_debug('LDAP user bind failed: '. htmlspecialchars($dn) .': '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
309
                return false;
310
            }
311
        } elseif ($this->getConf('binddn') && $this->getConf('bindpw')) {
312
            // we are changing the password on behalf of the user (eg: forgotten password)
313
            // bind with the superuser ldap
314
            if (!@ldap_bind($this->con, $this->getConf('binddn'), conf_decodeString($this->getConf('bindpw')))){
315
                $this->_debug('LDAP bind as superuser: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
316
                return false;
317
            }
318
        }
319
        else {
320
            return false; // no otherway
321
        }
322
323
        // Generate the salted hashed password for LDAP
324
        $phash = new PassHash();
325
        $hash = $phash->hash_ssha($changes['pass']);
326
327
        // change the password
328
        if(!@ldap_mod_replace($this->con, $dn,array('userpassword' => $hash))){
329
            $this->_debug('LDAP mod replace failed: '. htmlspecialchars($dn) .': '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
330
            return false;
331
        }
332
333
        return true;
334
    }
335
336
    /**
337
     * Most values in LDAP are case-insensitive
338
     *
339
     * @return bool
340
     */
341
    public function isCaseSensitive() {
342
        return false;
343
    }
344
345
    /**
346
     * Bulk retrieval of user data
347
     *
348
     * @author  Dominik Eckelmann <[email protected]>
349
     * @param   int   $start     index of first user to be returned
350
     * @param   int   $limit     max number of users to be returned
351
     * @param   array $filter  array of field/pattern pairs, null for no filter
352
     * @return  array of userinfo (refer getUserData for internal userinfo details)
353
     */
354
    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...
355
        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...
356
357
        if(is_null($this->users)) {
358
            // Perform the search and grab all their details
359
            if($this->getConf('userfilter')) {
360
                $all_filter = str_replace('%{user}', '*', $this->getConf('userfilter'));
361
            } else {
362
                $all_filter = "(ObjectClass=*)";
363
            }
364
            $sr          = ldap_search($this->con, $this->getConf('usertree'), $all_filter);
365
            $entries     = ldap_get_entries($this->con, $sr);
366
            $users_array = array();
367
            $userkey     = $this->getConf('userkey');
368
            for($i = 0; $i < $entries["count"]; $i++) {
369
                array_push($users_array, $entries[$i][$userkey][0]);
370
            }
371
            asort($users_array);
372
            $result = $users_array;
373
            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...
374
            $this->users = array_fill_keys($result, false);
375
        }
376
        $i     = 0;
377
        $count = 0;
378
        $this->_constructPattern($filter);
379
        $result = array();
380
381
        foreach($this->users as $user => &$info) {
382
            if($i++ < $start) {
383
                continue;
384
            }
385
            if($info === false) {
386
                $info = $this->getUserData($user);
387
            }
388
            if($this->_filter($user, $info)) {
389
                $result[$user] = $info;
390
                if(($limit > 0) && (++$count >= $limit)) break;
391
            }
392
        }
393
        return $result;
394
    }
395
396
    /**
397
     * Make LDAP filter strings.
398
     *
399
     * Used by auth_getUserData to make the filter
400
     * strings for grouptree and groupfilter
401
     *
402
     * @author  Troels Liebe Bentsen <[email protected]>
403
     * @param   string $filter ldap search filter with placeholders
404
     * @param   array  $placeholders placeholders to fill in
405
     * @return  string
406
     */
407
    protected function _makeFilter($filter, $placeholders) {
408
        preg_match_all("/%{([^}]+)/", $filter, $matches, PREG_PATTERN_ORDER);
409
        //replace each match
410
        foreach($matches[1] as $match) {
411
            //take first element if array
412
            if(is_array($placeholders[$match])) {
413
                $value = $placeholders[$match][0];
414
            } else {
415
                $value = $placeholders[$match];
416
            }
417
            $value  = $this->_filterEscape($value);
418
            $filter = str_replace('%{'.$match.'}', $value, $filter);
419
        }
420
        return $filter;
421
    }
422
423
    /**
424
     * return true if $user + $info match $filter criteria, false otherwise
425
     *
426
     * @author Chris Smith <[email protected]>
427
     *
428
     * @param  string $user the user's login name
429
     * @param  array  $info the user's userinfo array
430
     * @return bool
431
     */
432
    protected  function _filter($user, $info) {
433
        foreach($this->_pattern as $item => $pattern) {
434
            if($item == 'user') {
435
                if(!preg_match($pattern, $user)) return false;
436
            } else if($item == 'grps') {
437
                if(!count(preg_grep($pattern, $info['grps']))) return false;
438
            } else {
439
                if(!preg_match($pattern, $info[$item])) return false;
440
            }
441
        }
442
        return true;
443
    }
444
445
    /**
446
     * Set the filter pattern
447
     *
448
     * @author Chris Smith <[email protected]>
449
     *
450
     * @param $filter
451
     * @return void
452
     */
453
    protected function _constructPattern($filter) {
454
        $this->_pattern = array();
455
        foreach($filter as $item => $pattern) {
456
            $this->_pattern[$item] = '/'.str_replace('/', '\/', $pattern).'/i'; // allow regex characters
457
        }
458
    }
459
460
    /**
461
     * Escape a string to be used in a LDAP filter
462
     *
463
     * Ported from Perl's Net::LDAP::Util escape_filter_value
464
     *
465
     * @author Andreas Gohr
466
     * @param  string $string
467
     * @return string
468
     */
469
    protected function _filterEscape($string) {
470
        // see https://github.com/adldap/adLDAP/issues/22
471
        return preg_replace_callback(
472
            '/([\x00-\x1F\*\(\)\\\\])/',
473
            function ($matches) {
474
                return "\\".join("", unpack("H2", $matches[1]));
475
            },
476
            $string
477
        );
478
    }
479
480
    /**
481
     * Opens a connection to the configured LDAP server and sets the wanted
482
     * option on the connection
483
     *
484
     * @author  Andreas Gohr <[email protected]>
485
     */
486
    protected function _openLDAP() {
487
        if($this->con) return true; // connection already established
488
489
        if($this->getConf('debug')) {
490
            ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, 7);
491
        }
492
493
        $this->bound = 0;
494
495
        $port    = $this->getConf('port');
496
        $bound   = false;
497
        $servers = explode(',', $this->getConf('server'));
498
        foreach($servers as $server) {
499
            $server    = trim($server);
500
            $this->con = @ldap_connect($server, $port);
501
            if(!$this->con) {
502
                continue;
503
            }
504
505
            /*
506
             * When OpenLDAP 2.x.x is used, ldap_connect() will always return a resource as it does
507
             * not actually connect but just initializes the connecting parameters. The actual
508
             * connect happens with the next calls to ldap_* funcs, usually with ldap_bind().
509
             *
510
             * So we should try to bind to server in order to check its availability.
511
             */
512
513
            //set protocol version and dependend options
514
            if($this->getConf('version')) {
515
                if(!@ldap_set_option(
516
                    $this->con, LDAP_OPT_PROTOCOL_VERSION,
517
                    $this->getConf('version')
518
                )
519
                ) {
520
                    msg('Setting LDAP Protocol version '.$this->getConf('version').' failed', -1);
521
                    $this->_debug('LDAP version set: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
522
                } else {
523
                    //use TLS (needs version 3)
524
                    if($this->getConf('starttls')) {
525
                        if(!@ldap_start_tls($this->con)) {
526
                            msg('Starting TLS failed', -1);
527
                            $this->_debug('LDAP TLS set: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
528
                        }
529
                    }
530
                    // needs version 3
531
                    if($this->getConf('referrals') > -1) {
532
                        if(!@ldap_set_option(
533
                            $this->con, LDAP_OPT_REFERRALS,
534
                            $this->getConf('referrals')
535
                        )
536
                        ) {
537
                            msg('Setting LDAP referrals failed', -1);
538
                            $this->_debug('LDAP referal set: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
539
                        }
540
                    }
541
                }
542
            }
543
544
            //set deref mode
545
            if($this->getConf('deref')) {
546
                if(!@ldap_set_option($this->con, LDAP_OPT_DEREF, $this->getConf('deref'))) {
547
                    msg('Setting LDAP Deref mode '.$this->getConf('deref').' failed', -1);
548
                    $this->_debug('LDAP deref set: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
549
                }
550
            }
551
            /* As of PHP 5.3.0 we can set timeout to speedup skipping of invalid servers */
552
            if(defined('LDAP_OPT_NETWORK_TIMEOUT')) {
553
                ldap_set_option($this->con, LDAP_OPT_NETWORK_TIMEOUT, 1);
554
            }
555
556
            if($this->getConf('binddn') && $this->getConf('bindpw')) {
557
                $bound = @ldap_bind($this->con, $this->getConf('binddn'), conf_decodeString($this->getConf('bindpw')));
558
                $this->bound = 2;
559
            } else {
560
                $bound = @ldap_bind($this->con);
561
            }
562
            if($bound) {
563
                break;
564
            }
565
        }
566
567
        if(!$bound) {
568
            msg("LDAP: couldn't connect to LDAP server", -1);
569
            $this->_debug(ldap_error($this->con), 0, __LINE__, __FILE__);
570
            return false;
571
        }
572
573
        $this->cando['getUsers'] = true;
574
        return true;
575
    }
576
577
    /**
578
     * Wraps around ldap_search, ldap_list or ldap_read depending on $scope
579
     *
580
     * @author Andreas Gohr <[email protected]>
581
     * @param resource   $link_identifier
582
     * @param string     $base_dn
583
     * @param string     $filter
584
     * @param string     $scope can be 'base', 'one' or 'sub'
585
     * @param null|array $attributes
586
     * @param int        $attrsonly
587
     * @param int        $sizelimit
588
     * @return resource
589
     */
590
    protected function _ldapsearch($link_identifier, $base_dn, $filter, $scope = 'sub', $attributes = null,
591
                         $attrsonly = 0, $sizelimit = 0) {
592
        if(is_null($attributes)) $attributes = array();
593
594
        if($scope == 'base') {
595
            return @ldap_read(
596
                $link_identifier, $base_dn, $filter, $attributes,
597
                $attrsonly, $sizelimit
598
            );
599
        } elseif($scope == 'one') {
600
            return @ldap_list(
601
                $link_identifier, $base_dn, $filter, $attributes,
602
                $attrsonly, $sizelimit
603
            );
604
        } else {
605
            return @ldap_search(
606
                $link_identifier, $base_dn, $filter, $attributes,
607
                $attrsonly, $sizelimit
608
            );
609
        }
610
    }
611
612
    /**
613
     * Wrapper around msg() but outputs only when debug is enabled
614
     *
615
     * @param string $message
616
     * @param int    $err
617
     * @param int    $line
618
     * @param string $file
619
     * @return void
620
     */
621
    protected function _debug($message, $err, $line, $file) {
622
        if(!$this->getConf('debug')) return;
623
        msg($message, $err, $line, $file);
624
    }
625
626
}
627