Completed
Push — remoteapiGetversions ( 33fe8b...b2f4ab )
by Gerrit
12s
created

auth_plugin_authldap::_openLDAP()   F

Complexity

Conditions 18
Paths 1065

Size

Total Lines 90
Code Lines 49

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 90
rs 2
cc 18
eloc 49
nc 1065
nop 0

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
280
    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...
281
282
        // open the connection to the ldap
283
        if(!$this->_openLDAP()){
284
            $this->_debug('LDAP cannot connect: '. htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
285
            return false;
286
        }
287
288
        // find the information about the user, in particular the "dn"
289
        $info = $this->getUserData($user,true);
290
        if(empty($info['dn'])) {
291
            $this->_debug('LDAP cannot find your user dn', 0, __LINE__, __FILE__);
292
            return false;
293
        }
294
        $dn = $info['dn'];
295
296
        // find the old password of the user
297
        list($loginuser,$loginsticky,$loginpass) = auth_getCookie();
298
        if ($loginuser !== null) { // the user is currently logged in
299
            $secret = auth_cookiesalt(!$loginsticky, true);
300
            $pass   = auth_decrypt($loginpass, $secret);
301
302
            // bind with the ldap
303
            if(!@ldap_bind($this->con, $dn, $pass)){
304
                $this->_debug('LDAP user bind failed: '. htmlspecialchars($dn) .': '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
305
                return false;
306
            }
307
        } elseif ($this->getConf('binddn') && $this->getConf('bindpw')) {
308
            // we are changing the password on behalf of the user (eg: forgotten password)
309
            // bind with the superuser ldap
310
            if (!@ldap_bind($this->con, $this->getConf('binddn'), conf_decodeString($this->getConf('bindpw')))){
311
                $this->_debug('LDAP bind as superuser: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
312
                return false;
313
            }
314
        }
315
        else {
316
            return false; // no otherway
317
        }
318
319
        // Generate the salted hashed password for LDAP
320
        $phash = new PassHash();
321
        $hash = $phash->hash_ssha($changes['pass']);
322
323
        // change the password
324
        if(!@ldap_mod_replace($this->con, $dn,array('userpassword' => $hash))){
325
            $this->_debug('LDAP mod replace failed: '. htmlspecialchars($dn) .': '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
326
            return false;
327
        }
328
329
        return true;
330
    }
331
332
    /**
333
     * Most values in LDAP are case-insensitive
334
     *
335
     * @return bool
336
     */
337
    public function isCaseSensitive() {
338
        return false;
339
    }
340
341
    /**
342
     * Bulk retrieval of user data
343
     *
344
     * @author  Dominik Eckelmann <[email protected]>
345
     * @param   int   $start     index of first user to be returned
346
     * @param   int   $limit     max number of users to be returned
347
     * @param   array $filter  array of field/pattern pairs, null for no filter
348
     * @return  array of userinfo (refer getUserData for internal userinfo details)
349
     */
350
    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...
351
        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...
352
353
        if(is_null($this->users)) {
354
            // Perform the search and grab all their details
355
            if($this->getConf('userfilter')) {
356
                $all_filter = str_replace('%{user}', '*', $this->getConf('userfilter'));
357
            } else {
358
                $all_filter = "(ObjectClass=*)";
359
            }
360
            $sr          = ldap_search($this->con, $this->getConf('usertree'), $all_filter);
361
            $entries     = ldap_get_entries($this->con, $sr);
362
            $users_array = array();
363
            $userkey     = $this->getConf('userkey');
364
            for($i = 0; $i < $entries["count"]; $i++) {
365
                array_push($users_array, $entries[$i][$userkey][0]);
366
            }
367
            asort($users_array);
368
            $result = $users_array;
369
            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...
370
            $this->users = array_fill_keys($result, false);
371
        }
372
        $i     = 0;
373
        $count = 0;
374
        $this->_constructPattern($filter);
375
        $result = array();
376
377
        foreach($this->users as $user => &$info) {
378
            if($i++ < $start) {
379
                continue;
380
            }
381
            if($info === false) {
382
                $info = $this->getUserData($user);
383
            }
384
            if($this->_filter($user, $info)) {
385
                $result[$user] = $info;
386
                if(($limit > 0) && (++$count >= $limit)) break;
387
            }
388
        }
389
        return $result;
390
    }
391
392
    /**
393
     * Make LDAP filter strings.
394
     *
395
     * Used by auth_getUserData to make the filter
396
     * strings for grouptree and groupfilter
397
     *
398
     * @author  Troels Liebe Bentsen <[email protected]>
399
     * @param   string $filter ldap search filter with placeholders
400
     * @param   array  $placeholders placeholders to fill in
401
     * @return  string
402
     */
403
    protected function _makeFilter($filter, $placeholders) {
404
        preg_match_all("/%{([^}]+)/", $filter, $matches, PREG_PATTERN_ORDER);
405
        //replace each match
406
        foreach($matches[1] as $match) {
407
            //take first element if array
408
            if(is_array($placeholders[$match])) {
409
                $value = $placeholders[$match][0];
410
            } else {
411
                $value = $placeholders[$match];
412
            }
413
            $value  = $this->_filterEscape($value);
414
            $filter = str_replace('%{'.$match.'}', $value, $filter);
415
        }
416
        return $filter;
417
    }
418
419
    /**
420
     * return true if $user + $info match $filter criteria, false otherwise
421
     *
422
     * @author Chris Smith <[email protected]>
423
     *
424
     * @param  string $user the user's login name
425
     * @param  array  $info the user's userinfo array
426
     * @return bool
427
     */
428
    protected  function _filter($user, $info) {
429
        foreach($this->_pattern as $item => $pattern) {
430
            if($item == 'user') {
431
                if(!preg_match($pattern, $user)) return false;
432
            } else if($item == 'grps') {
433
                if(!count(preg_grep($pattern, $info['grps']))) return false;
434
            } else {
435
                if(!preg_match($pattern, $info[$item])) return false;
436
            }
437
        }
438
        return true;
439
    }
440
441
    /**
442
     * Set the filter pattern
443
     *
444
     * @author Chris Smith <[email protected]>
445
     *
446
     * @param $filter
447
     * @return void
448
     */
449
    protected function _constructPattern($filter) {
450
        $this->_pattern = array();
451
        foreach($filter as $item => $pattern) {
452
            $this->_pattern[$item] = '/'.str_replace('/', '\/', $pattern).'/i'; // allow regex characters
453
        }
454
    }
455
456
    /**
457
     * Escape a string to be used in a LDAP filter
458
     *
459
     * Ported from Perl's Net::LDAP::Util escape_filter_value
460
     *
461
     * @author Andreas Gohr
462
     * @param  string $string
463
     * @return string
464
     */
465
    protected function _filterEscape($string) {
466
        // see https://github.com/adldap/adLDAP/issues/22
467
        return preg_replace_callback(
468
            '/([\x00-\x1F\*\(\)\\\\])/',
469
            function ($matches) {
470
                return "\\".join("", unpack("H2", $matches[1]));
471
            },
472
            $string
473
        );
474
    }
475
476
    /**
477
     * Opens a connection to the configured LDAP server and sets the wanted
478
     * option on the connection
479
     *
480
     * @author  Andreas Gohr <[email protected]>
481
     */
482
    protected function _openLDAP() {
483
        if($this->con) return true; // connection already established
484
485
        if($this->getConf('debug')) {
486
            ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, 7);
487
        }
488
489
        $this->bound = 0;
490
491
        $port    = $this->getConf('port');
492
        $bound   = false;
493
        $servers = explode(',', $this->getConf('server'));
494
        foreach($servers as $server) {
495
            $server    = trim($server);
496
            $this->con = @ldap_connect($server, $port);
497
            if(!$this->con) {
498
                continue;
499
            }
500
501
            /*
502
             * When OpenLDAP 2.x.x is used, ldap_connect() will always return a resource as it does
503
             * not actually connect but just initializes the connecting parameters. The actual
504
             * connect happens with the next calls to ldap_* funcs, usually with ldap_bind().
505
             *
506
             * So we should try to bind to server in order to check its availability.
507
             */
508
509
            //set protocol version and dependend options
510
            if($this->getConf('version')) {
511
                if(!@ldap_set_option(
512
                    $this->con, LDAP_OPT_PROTOCOL_VERSION,
513
                    $this->getConf('version')
514
                )
515
                ) {
516
                    msg('Setting LDAP Protocol version '.$this->getConf('version').' failed', -1);
517
                    $this->_debug('LDAP version set: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
518
                } else {
519
                    //use TLS (needs version 3)
520
                    if($this->getConf('starttls')) {
521
                        if(!@ldap_start_tls($this->con)) {
522
                            msg('Starting TLS failed', -1);
523
                            $this->_debug('LDAP TLS set: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
524
                        }
525
                    }
526
                    // needs version 3
527
                    if($this->getConf('referrals') > -1) {
528
                        if(!@ldap_set_option(
529
                            $this->con, LDAP_OPT_REFERRALS,
530
                            $this->getConf('referrals')
531
                        )
532
                        ) {
533
                            msg('Setting LDAP referrals failed', -1);
534
                            $this->_debug('LDAP referal set: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
535
                        }
536
                    }
537
                }
538
            }
539
540
            //set deref mode
541
            if($this->getConf('deref')) {
542
                if(!@ldap_set_option($this->con, LDAP_OPT_DEREF, $this->getConf('deref'))) {
543
                    msg('Setting LDAP Deref mode '.$this->getConf('deref').' failed', -1);
544
                    $this->_debug('LDAP deref set: '.htmlspecialchars(ldap_error($this->con)), 0, __LINE__, __FILE__);
545
                }
546
            }
547
            /* As of PHP 5.3.0 we can set timeout to speedup skipping of invalid servers */
548
            if(defined('LDAP_OPT_NETWORK_TIMEOUT')) {
549
                ldap_set_option($this->con, LDAP_OPT_NETWORK_TIMEOUT, 1);
550
            }
551
552
            if($this->getConf('binddn') && $this->getConf('bindpw')) {
553
                $bound = @ldap_bind($this->con, $this->getConf('binddn'), conf_decodeString($this->getConf('bindpw')));
554
                $this->bound = 2;
555
            } else {
556
                $bound = @ldap_bind($this->con);
557
            }
558
            if($bound) {
559
                break;
560
            }
561
        }
562
563
        if(!$bound) {
564
            msg("LDAP: couldn't connect to LDAP server", -1);
565
            $this->_debug(ldap_error($this->con), 0, __LINE__, __FILE__);
566
            return false;
567
        }
568
569
        $this->cando['getUsers'] = true;
570
        return true;
571
    }
572
573
    /**
574
     * Wraps around ldap_search, ldap_list or ldap_read depending on $scope
575
     *
576
     * @author Andreas Gohr <[email protected]>
577
     * @param resource   $link_identifier
578
     * @param string     $base_dn
579
     * @param string     $filter
580
     * @param string     $scope can be 'base', 'one' or 'sub'
581
     * @param null|array $attributes
582
     * @param int        $attrsonly
583
     * @param int        $sizelimit
584
     * @return resource
585
     */
586
    protected function _ldapsearch($link_identifier, $base_dn, $filter, $scope = 'sub', $attributes = null,
587
                         $attrsonly = 0, $sizelimit = 0) {
588
        if(is_null($attributes)) $attributes = array();
589
590
        if($scope == 'base') {
591
            return @ldap_read(
592
                $link_identifier, $base_dn, $filter, $attributes,
593
                $attrsonly, $sizelimit
594
            );
595
        } elseif($scope == 'one') {
596
            return @ldap_list(
597
                $link_identifier, $base_dn, $filter, $attributes,
598
                $attrsonly, $sizelimit
599
            );
600
        } else {
601
            return @ldap_search(
602
                $link_identifier, $base_dn, $filter, $attributes,
603
                $attrsonly, $sizelimit
604
            );
605
        }
606
    }
607
608
    /**
609
     * Wrapper around msg() but outputs only when debug is enabled
610
     *
611
     * @param string $message
612
     * @param int    $err
613
     * @param int    $line
614
     * @param string $file
615
     * @return void
616
     */
617
    protected function _debug($message, $err, $line, $file) {
618
        if(!$this->getConf('debug')) return;
619
        msg($message, $err, $line, $file);
620
    }
621
622
}
623