Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
/**
3
 * LDAP driver.
4
 *
5
 * Provides a subset of ADOdb commands, allowing read-only access to an LDAP database.
6
 *
7
 * This file is part of ADOdb, a Database Abstraction Layer library for PHP.
8
 *
9
 * @package ADOdb
10
 * @link https://adodb.org Project's web site and documentation
11
 * @link https://github.com/ADOdb/ADOdb Source code and issue tracker
12
 *
13
 * The ADOdb Library is dual-licensed, released under both the BSD 3-Clause
14
 * and the GNU Lesser General Public Licence (LGPL) v2.1 or, at your option,
15
 * any later version. This means you can use it in proprietary products.
16
 * See the LICENSE.md file distributed with this source code for details.
17
 * @license BSD-3-Clause
18
 * @license LGPL-2.1-or-later
19
 *
20
 * @copyright 2000-2013 John Lim
21
 * @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community
22
 * @author Joshua Eldridge <joshuae74@hotmail.com>
23
 */
24
 
25
// security - hide paths
26
if (!defined('ADODB_DIR')) die();
27
 
28
if (!defined('LDAP_ASSOC')) {
29
	define('LDAP_ASSOC',ADODB_FETCH_ASSOC);
30
	define('LDAP_NUM',ADODB_FETCH_NUM);
31
	define('LDAP_BOTH',ADODB_FETCH_BOTH);
32
}
33
 
34
class ADODB_ldap extends ADOConnection {
35
	var $databaseType = 'ldap';
36
	var $dataProvider = 'ldap';
37
 
38
	# Connection information
39
	var $username = false;
40
	var $password = false;
41
 
42
	# Used during searches
43
	var $filter;
44
	var $dn;
45
	var $version;
46
	var $port = 389;
47
 
48
	# Options configuration information
49
	var $LDAP_CONNECT_OPTIONS;
50
 
51
	# error on binding, eg. "Binding: invalid credentials"
52
	var $_bind_errmsg = "Binding: %s";
53
 
54
	// returns true or false
55
 
56
	function _connect( $host, $username, $password, $ldapbase)
57
	{
58
		global $LDAP_CONNECT_OPTIONS;
59
 
60
		if ( !function_exists( 'ldap_connect' ) ) return null;
61
 
62
		if (strpos($host,'ldap://') === 0 || strpos($host,'ldaps://') === 0) {
63
			$this->_connectionID = @ldap_connect($host);
64
		} else {
65
			$conn_info = array( $host,$this->port);
66
 
67
			if ( strstr( $host, ':' ) ) {
68
				$conn_info = explode( ':', $host );
69
			}
70
 
71
			$this->_connectionID = @ldap_connect( $conn_info[0], $conn_info[1] );
72
		}
73
		if (!$this->_connectionID) {
74
			$e = 'Could not connect to ' . $conn_info[0];
75
			$this->_errorMsg = $e;
76
			if ($this->debug) ADOConnection::outp($e);
77
			return false;
78
		}
79
		if( count( $LDAP_CONNECT_OPTIONS ) > 0 ) {
80
			$this->_inject_bind_options( $LDAP_CONNECT_OPTIONS );
81
		}
82
 
83
		if ($username) {
84
			$bind = @ldap_bind( $this->_connectionID, $username, $password );
85
		} else {
86
			$username = 'anonymous';
87
			$bind = @ldap_bind( $this->_connectionID );
88
		}
89
 
90
		if (!$bind) {
91
			$e = sprintf($this->_bind_errmsg,ldap_error($this->_connectionID));
92
			$this->_errorMsg = $e;
93
			if ($this->debug) ADOConnection::outp($e);
94
			return false;
95
		}
96
		$this->_errorMsg = '';
97
		$this->database = $ldapbase;
98
		return $this->_connectionID;
99
	}
100
 
101
/*
102
	Valid Domain Values for LDAP Options:
103
 
104
	LDAP_OPT_DEREF (integer)
105
	LDAP_OPT_SIZELIMIT (integer)
106
	LDAP_OPT_TIMELIMIT (integer)
107
	LDAP_OPT_PROTOCOL_VERSION (integer)
108
	LDAP_OPT_ERROR_NUMBER (integer)
109
	LDAP_OPT_REFERRALS (boolean)
110
	LDAP_OPT_RESTART (boolean)
111
	LDAP_OPT_HOST_NAME (string)
112
	LDAP_OPT_ERROR_STRING (string)
113
	LDAP_OPT_MATCHED_DN (string)
114
	LDAP_OPT_SERVER_CONTROLS (array)
115
	LDAP_OPT_CLIENT_CONTROLS (array)
116
 
117
	Make sure to set this BEFORE calling Connect()
118
 
119
	Example:
120
 
121
	$LDAP_CONNECT_OPTIONS = Array(
122
		Array (
123
			"OPTION_NAME"=>LDAP_OPT_DEREF,
124
			"OPTION_VALUE"=>2
125
		),
126
		Array (
127
			"OPTION_NAME"=>LDAP_OPT_SIZELIMIT,
128
			"OPTION_VALUE"=>100
129
		),
130
		Array (
131
			"OPTION_NAME"=>LDAP_OPT_TIMELIMIT,
132
			"OPTION_VALUE"=>30
133
		),
134
		Array (
135
			"OPTION_NAME"=>LDAP_OPT_PROTOCOL_VERSION,
136
			"OPTION_VALUE"=>3
137
		),
138
		Array (
139
			"OPTION_NAME"=>LDAP_OPT_ERROR_NUMBER,
140
			"OPTION_VALUE"=>13
141
		),
142
		Array (
143
			"OPTION_NAME"=>LDAP_OPT_REFERRALS,
144
			"OPTION_VALUE"=>FALSE
145
		),
146
		Array (
147
			"OPTION_NAME"=>LDAP_OPT_RESTART,
148
			"OPTION_VALUE"=>FALSE
149
		)
150
	);
151
*/
152
 
153
	function _inject_bind_options( $options ) {
154
		foreach( $options as $option ) {
155
			ldap_set_option( $this->_connectionID, $option["OPTION_NAME"], $option["OPTION_VALUE"] )
156
				or die( "Unable to set server option: " . $option["OPTION_NAME"] );
157
		}
158
	}
159
 
160
	function _query($sql,$inputarr=false)
161
	{
162
		$rs = @ldap_search( $this->_connectionID, $this->database, $sql );
163
		$this->_errorMsg = ($rs) ? '' : 'Search error on '.$sql.': '.ldap_error($this->_connectionID);
164
		return $rs;
165
	}
166
 
167
	function ErrorMsg()
168
	{
169
		return $this->_errorMsg;
170
	}
171
 
172
	function ErrorNo()
173
	{
174
		return @ldap_errno($this->_connectionID);
175
	}
176
 
177
	/* closes the LDAP connection */
178
	function _close()
179
	{
180
		@ldap_close( $this->_connectionID );
181
		$this->_connectionID = false;
182
	}
183
 
184
	function SelectDB($db) {
185
		$this->database = $db;
186
		return true;
187
	} // SelectDB
188
 
189
	function ServerInfo()
190
	{
191
		if( !empty( $this->version ) ) {
192
			return $this->version;
193
		}
194
 
195
		$version = array();
196
		/*
197
		Determines how aliases are handled during search.
198
		LDAP_DEREF_NEVER (0x00)
199
		LDAP_DEREF_SEARCHING (0x01)
200
		LDAP_DEREF_FINDING (0x02)
201
		LDAP_DEREF_ALWAYS (0x03)
202
		The LDAP_DEREF_SEARCHING value means aliases are dereferenced during the search but
203
		not when locating the base object of the search. The LDAP_DEREF_FINDING value means
204
		aliases are dereferenced when locating the base object but not during the search.
205
		Default: LDAP_DEREF_NEVER
206
		*/
207
		ldap_get_option( $this->_connectionID, LDAP_OPT_DEREF, $version['LDAP_OPT_DEREF'] ) ;
208
		switch ( $version['LDAP_OPT_DEREF'] ) {
209
			case 0:
210
				$version['LDAP_OPT_DEREF'] = 'LDAP_DEREF_NEVER';
211
			case 1:
212
				$version['LDAP_OPT_DEREF'] = 'LDAP_DEREF_SEARCHING';
213
			case 2:
214
				$version['LDAP_OPT_DEREF'] = 'LDAP_DEREF_FINDING';
215
			case 3:
216
				$version['LDAP_OPT_DEREF'] = 'LDAP_DEREF_ALWAYS';
217
		}
218
 
219
		/*
220
		A limit on the number of entries to return from a search.
221
		LDAP_NO_LIMIT (0) means no limit.
222
		Default: LDAP_NO_LIMIT
223
		*/
224
		ldap_get_option( $this->_connectionID, LDAP_OPT_SIZELIMIT, $version['LDAP_OPT_SIZELIMIT'] );
225
		if ( $version['LDAP_OPT_SIZELIMIT'] == 0 ) {
226
			$version['LDAP_OPT_SIZELIMIT'] = 'LDAP_NO_LIMIT';
227
		}
228
 
229
		/*
230
		A limit on the number of seconds to spend on a search.
231
		LDAP_NO_LIMIT (0) means no limit.
232
		Default: LDAP_NO_LIMIT
233
		*/
234
		ldap_get_option( $this->_connectionID, LDAP_OPT_TIMELIMIT, $version['LDAP_OPT_TIMELIMIT'] );
235
		if ( $version['LDAP_OPT_TIMELIMIT'] == 0 ) {
236
			$version['LDAP_OPT_TIMELIMIT'] = 'LDAP_NO_LIMIT';
237
		}
238
 
239
		/*
240
		Determines whether the LDAP library automatically follows referrals returned by LDAP servers or not.
241
		LDAP_OPT_ON
242
		LDAP_OPT_OFF
243
		Default: ON
244
		*/
245
		ldap_get_option( $this->_connectionID, LDAP_OPT_REFERRALS, $version['LDAP_OPT_REFERRALS'] );
246
		if ( $version['LDAP_OPT_REFERRALS'] == 0 ) {
247
			$version['LDAP_OPT_REFERRALS'] = 'LDAP_OPT_OFF';
248
		} else {
249
			$version['LDAP_OPT_REFERRALS'] = 'LDAP_OPT_ON';
250
		}
251
 
252
		/*
253
		Determines whether LDAP I/O operations are automatically restarted if they abort prematurely.
254
		LDAP_OPT_ON
255
		LDAP_OPT_OFF
256
		Default: OFF
257
		*/
258
		ldap_get_option( $this->_connectionID, LDAP_OPT_RESTART, $version['LDAP_OPT_RESTART'] );
259
		if ( $version['LDAP_OPT_RESTART'] == 0 ) {
260
			$version['LDAP_OPT_RESTART'] = 'LDAP_OPT_OFF';
261
		} else {
262
			$version['LDAP_OPT_RESTART'] = 'LDAP_OPT_ON';
263
		}
264
 
265
		/*
266
		This option indicates the version of the LDAP protocol used when communicating with the primary LDAP server.
267
		LDAP_VERSION2 (2)
268
		LDAP_VERSION3 (3)
269
		Default: LDAP_VERSION2 (2)
270
		*/
271
		ldap_get_option( $this->_connectionID, LDAP_OPT_PROTOCOL_VERSION, $version['LDAP_OPT_PROTOCOL_VERSION'] );
272
		if ( $version['LDAP_OPT_PROTOCOL_VERSION'] == 2 ) {
273
			$version['LDAP_OPT_PROTOCOL_VERSION'] = 'LDAP_VERSION2';
274
		} else {
275
			$version['LDAP_OPT_PROTOCOL_VERSION'] = 'LDAP_VERSION3';
276
		}
277
 
278
		/* The host name (or list of hosts) for the primary LDAP server. */
279
		ldap_get_option( $this->_connectionID, LDAP_OPT_HOST_NAME, $version['LDAP_OPT_HOST_NAME'] );
280
		ldap_get_option( $this->_connectionID, LDAP_OPT_ERROR_NUMBER, $version['LDAP_OPT_ERROR_NUMBER'] );
281
		ldap_get_option( $this->_connectionID, LDAP_OPT_ERROR_STRING, $version['LDAP_OPT_ERROR_STRING'] );
282
		ldap_get_option( $this->_connectionID, LDAP_OPT_MATCHED_DN, $version['LDAP_OPT_MATCHED_DN'] );
283
 
284
		return $this->version = $version;
285
	}
286
}
287
 
288
/*--------------------------------------------------------------------------------------
289
	Class Name: Recordset
290
--------------------------------------------------------------------------------------*/
291
 
292
class ADORecordSet_ldap extends ADORecordSet{
293
 
294
	var $databaseType = "ldap";
295
	var $canSeek = false;
296
	var $_entryID; /* keeps track of the entry resource identifier */
297
 
298
	function __construct($queryID,$mode=false)
299
	{
300
		if ($mode === false) {
301
			global $ADODB_FETCH_MODE;
302
			$mode = $ADODB_FETCH_MODE;
303
		}
304
		switch ($mode)
305
		{
306
		case ADODB_FETCH_NUM:
307
			$this->fetchMode = LDAP_NUM;
308
			break;
309
		case ADODB_FETCH_ASSOC:
310
			$this->fetchMode = LDAP_ASSOC;
311
			break;
312
		case ADODB_FETCH_DEFAULT:
313
		case ADODB_FETCH_BOTH:
314
		default:
315
			$this->fetchMode = LDAP_BOTH;
316
			break;
317
		}
318
 
319
		parent::__construct($queryID);
320
	}
321
 
322
	function _initrs()
323
	{
324
		/*
325
		This could be teaked to respect the $COUNTRECS directive from ADODB
326
		It's currently being used in the _fetch() function and the
327
		GetAssoc() function
328
		*/
329
		$this->_numOfRows = ldap_count_entries( $this->connection->_connectionID, $this->_queryID );
330
	}
331
 
332
	/*
333
	Return whole recordset as a multi-dimensional associative array
334
	*/
335
	function GetAssoc($force_array = false, $first2cols = false, $fetchMode = -1)
336
	{
337
		$records = $this->_numOfRows;
338
		$results = array();
339
		for ( $i=0; $i < $records; $i++ ) {
340
			foreach ( $this->fields as $k=>$v ) {
341
				if ( is_array( $v ) ) {
342
					if ( $v['count'] == 1 ) {
343
						$results[$i][$k] = $v[0];
344
					} else {
345
						array_shift( $v );
346
						$results[$i][$k] = $v;
347
					}
348
				}
349
			}
350
		}
351
 
352
		return $results;
353
	}
354
 
355
	function GetRowAssoc($upper = ADODB_ASSOC_CASE)
356
	{
357
		$results = array();
358
		foreach ( $this->fields as $k=>$v ) {
359
			if ( is_array( $v ) ) {
360
				if ( $v['count'] == 1 ) {
361
					$results[$k] = $v[0];
362
				} else {
363
					array_shift( $v );
364
					$results[$k] = $v;
365
				}
366
			}
367
		}
368
 
369
		return $results;
370
	}
371
 
372
	function GetRowNums()
373
	{
374
		$results = array();
375
		foreach ( $this->fields as $k=>$v ) {
376
			static $i = 0;
377
			if (is_array( $v )) {
378
				if ( $v['count'] == 1 ) {
379
					$results[$i] = $v[0];
380
				} else {
381
					array_shift( $v );
382
					$results[$i] = $v;
383
				}
384
				$i++;
385
			}
386
		}
387
		return $results;
388
	}
389
 
390
	function _fetch()
391
	{
392
		if ( $this->_currentRow >= $this->_numOfRows && $this->_numOfRows >= 0 ) {
393
			return false;
394
		}
395
 
396
		if ( $this->_currentRow == 0 ) {
397
			$this->_entryID = ldap_first_entry( $this->connection->_connectionID, $this->_queryID );
398
		} else {
399
			$this->_entryID = ldap_next_entry( $this->connection->_connectionID, $this->_entryID );
400
		}
401
 
402
		$this->fields = ldap_get_attributes( $this->connection->_connectionID, $this->_entryID );
403
		$this->_numOfFields = $this->fields['count'];
404
 
405
		switch ( $this->fetchMode ) {
406
 
407
			case LDAP_ASSOC:
408
				$this->fields = $this->GetRowAssoc();
409
				break;
410
 
411
			case LDAP_NUM:
412
				$this->fields = array_merge($this->GetRowNums(),$this->GetRowAssoc());
413
				break;
414
 
415
			case LDAP_BOTH:
416
			default:
417
				$this->fields = $this->GetRowNums();
418
				break;
419
		}
420
 
421
		return is_array( $this->fields );
422
	}
423
 
424
	function _close() {
425
		@ldap_free_result( $this->_queryID );
426
		$this->_queryID = false;
427
	}
428
 
429
}