xref: /PHP-5.3/ext/ldap/ldap.c (revision a2045ff3)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 5                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2013 The PHP Group                                |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Authors: Amitay Isaacs  <amitay@w-o-i.com>                           |
16    |          Eric Warnke    <ericw@albany.edu>                           |
17    |          Rasmus Lerdorf <rasmus@php.net>                             |
18    |          Gerrit Thomson <334647@swin.edu.au>                         |
19    |          Jani Taskinen  <sniper@iki.fi>                              |
20    |          Stig Venaas    <venaas@uninett.no>                          |
21    |          Doug Goldstein <cardoe@cardoe.com>                          |
22    | PHP 4.0 updates:  Zeev Suraski <zeev@zend.com>                       |
23    +----------------------------------------------------------------------+
24  */
25 
26 /* $Id$ */
27 #define IS_EXT_MODULE
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 
33 /* Additional headers for NetWare */
34 #if defined(NETWARE) && (NEW_LIBC)
35 #include <sys/select.h>
36 #include <sys/timeval.h>
37 #endif
38 
39 #include "php.h"
40 #include "php_ini.h"
41 
42 #include <stddef.h>
43 
44 #include "ext/standard/dl.h"
45 #include "php_ldap.h"
46 
47 #ifdef PHP_WIN32
48 #include <string.h>
49 #include "config.w32.h"
50 #if HAVE_NSLDAP
51 #include <winsock2.h>
52 #endif
53 #define strdup _strdup
54 #undef WINDOWS
55 #undef strcasecmp
56 #undef strncasecmp
57 #define WINSOCK 1
58 #define __STDC__ 1
59 #endif
60 
61 #include "ext/standard/php_string.h"
62 #include "ext/standard/info.h"
63 
64 #ifdef HAVE_LDAP_SASL_H
65 #include <sasl.h>
66 #elif defined(HAVE_LDAP_SASL_SASL_H)
67 #include <sasl/sasl.h>
68 #endif
69 
70 typedef struct {
71 	LDAP *link;
72 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)
73 	zval *rebindproc;
74 #endif
75 } ldap_linkdata;
76 
77 typedef struct {
78 	LDAPMessage *data;
79 	BerElement *ber;
80 	int id;
81 } ldap_resultentry;
82 
83 ZEND_DECLARE_MODULE_GLOBALS(ldap)
84 static PHP_GINIT_FUNCTION(ldap);
85 
86 static int le_link, le_result, le_result_entry;
87 
88 #ifdef COMPILE_DL_LDAP
ZEND_GET_MODULE(ldap)89 ZEND_GET_MODULE(ldap)
90 #endif
91 
92 static void _close_ldap_link(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
93 {
94 	ldap_linkdata *ld = (ldap_linkdata *)rsrc->ptr;
95 
96 	ldap_unbind_s(ld->link);
97 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)
98 	if (ld->rebindproc != NULL) {
99 		zval_dtor(ld->rebindproc);
100 		FREE_ZVAL(ld->rebindproc);
101 	}
102 #endif
103 	efree(ld);
104 	LDAPG(num_links)--;
105 }
106 /* }}} */
107 
_free_ldap_result(zend_rsrc_list_entry * rsrc TSRMLS_DC)108 static void _free_ldap_result(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
109 {
110 	LDAPMessage *result = (LDAPMessage *)rsrc->ptr;
111 	ldap_msgfree(result);
112 }
113 /* }}} */
114 
_free_ldap_result_entry(zend_rsrc_list_entry * rsrc TSRMLS_DC)115 static void _free_ldap_result_entry(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
116 {
117 	ldap_resultentry *entry = (ldap_resultentry *)rsrc->ptr;
118 
119 	if (entry->ber != NULL) {
120 		ber_free(entry->ber, 0);
121 		entry->ber = NULL;
122 	}
123 	zend_list_delete(entry->id);
124 	efree(entry);
125 }
126 /* }}} */
127 
128 /* {{{ PHP_INI_BEGIN
129  */
130 PHP_INI_BEGIN()
131 	STD_PHP_INI_ENTRY_EX("ldap.max_links", "-1", PHP_INI_SYSTEM, OnUpdateLong, max_links, zend_ldap_globals, ldap_globals, display_link_numbers)
PHP_INI_END()132 PHP_INI_END()
133 /* }}} */
134 
135 /* {{{ PHP_GINIT_FUNCTION
136  */
137 static PHP_GINIT_FUNCTION(ldap)
138 {
139 	ldap_globals->num_links = 0;
140 }
141 /* }}} */
142 
143 /* {{{ PHP_MINIT_FUNCTION
144  */
PHP_MINIT_FUNCTION(ldap)145 PHP_MINIT_FUNCTION(ldap)
146 {
147 	REGISTER_INI_ENTRIES();
148 
149 	/* Constants to be used with deref-parameter in php_ldap_do_search() */
150 	REGISTER_LONG_CONSTANT("LDAP_DEREF_NEVER", LDAP_DEREF_NEVER, CONST_PERSISTENT | CONST_CS);
151 	REGISTER_LONG_CONSTANT("LDAP_DEREF_SEARCHING", LDAP_DEREF_SEARCHING, CONST_PERSISTENT | CONST_CS);
152 	REGISTER_LONG_CONSTANT("LDAP_DEREF_FINDING", LDAP_DEREF_FINDING, CONST_PERSISTENT | CONST_CS);
153 	REGISTER_LONG_CONSTANT("LDAP_DEREF_ALWAYS", LDAP_DEREF_ALWAYS, CONST_PERSISTENT | CONST_CS);
154 
155 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10
156 	/* LDAP options */
157 	REGISTER_LONG_CONSTANT("LDAP_OPT_DEREF", LDAP_OPT_DEREF, CONST_PERSISTENT | CONST_CS);
158 	REGISTER_LONG_CONSTANT("LDAP_OPT_SIZELIMIT", LDAP_OPT_SIZELIMIT, CONST_PERSISTENT | CONST_CS);
159 	REGISTER_LONG_CONSTANT("LDAP_OPT_TIMELIMIT", LDAP_OPT_TIMELIMIT, CONST_PERSISTENT | CONST_CS);
160 #ifdef LDAP_OPT_NETWORK_TIMEOUT
161 	REGISTER_LONG_CONSTANT("LDAP_OPT_NETWORK_TIMEOUT", LDAP_OPT_NETWORK_TIMEOUT, CONST_PERSISTENT | CONST_CS);
162 #elif defined (LDAP_X_OPT_CONNECT_TIMEOUT)
163 	REGISTER_LONG_CONSTANT("LDAP_OPT_NETWORK_TIMEOUT", LDAP_X_OPT_CONNECT_TIMEOUT, CONST_PERSISTENT | CONST_CS);
164 #endif
165 	REGISTER_LONG_CONSTANT("LDAP_OPT_PROTOCOL_VERSION", LDAP_OPT_PROTOCOL_VERSION, CONST_PERSISTENT | CONST_CS);
166 	REGISTER_LONG_CONSTANT("LDAP_OPT_ERROR_NUMBER", LDAP_OPT_ERROR_NUMBER, CONST_PERSISTENT | CONST_CS);
167 	REGISTER_LONG_CONSTANT("LDAP_OPT_REFERRALS", LDAP_OPT_REFERRALS, CONST_PERSISTENT | CONST_CS);
168 #ifdef LDAP_OPT_RESTART
169 	REGISTER_LONG_CONSTANT("LDAP_OPT_RESTART", LDAP_OPT_RESTART, CONST_PERSISTENT | CONST_CS);
170 #endif
171 #ifdef LDAP_OPT_HOST_NAME
172 	REGISTER_LONG_CONSTANT("LDAP_OPT_HOST_NAME", LDAP_OPT_HOST_NAME, CONST_PERSISTENT | CONST_CS);
173 #endif
174 	REGISTER_LONG_CONSTANT("LDAP_OPT_ERROR_STRING", LDAP_OPT_ERROR_STRING, CONST_PERSISTENT | CONST_CS);
175 #ifdef LDAP_OPT_MATCHED_DN
176 	REGISTER_LONG_CONSTANT("LDAP_OPT_MATCHED_DN", LDAP_OPT_MATCHED_DN, CONST_PERSISTENT | CONST_CS);
177 #endif
178 	REGISTER_LONG_CONSTANT("LDAP_OPT_SERVER_CONTROLS", LDAP_OPT_SERVER_CONTROLS, CONST_PERSISTENT | CONST_CS);
179 	REGISTER_LONG_CONSTANT("LDAP_OPT_CLIENT_CONTROLS", LDAP_OPT_CLIENT_CONTROLS, CONST_PERSISTENT | CONST_CS);
180 #endif
181 #ifdef LDAP_OPT_DEBUG_LEVEL
182 	REGISTER_LONG_CONSTANT("LDAP_OPT_DEBUG_LEVEL", LDAP_OPT_DEBUG_LEVEL, CONST_PERSISTENT | CONST_CS);
183 #endif
184 
185 #ifdef HAVE_LDAP_SASL
186 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_SASL_MECH", LDAP_OPT_X_SASL_MECH, CONST_PERSISTENT | CONST_CS);
187 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_SASL_REALM", LDAP_OPT_X_SASL_REALM, CONST_PERSISTENT | CONST_CS);
188 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_SASL_AUTHCID", LDAP_OPT_X_SASL_AUTHCID, CONST_PERSISTENT | CONST_CS);
189 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_SASL_AUTHZID", LDAP_OPT_X_SASL_AUTHZID, CONST_PERSISTENT | CONST_CS);
190 #endif
191 
192 #ifdef ORALDAP
193 	REGISTER_LONG_CONSTANT("GSLC_SSL_NO_AUTH", GSLC_SSL_NO_AUTH, CONST_PERSISTENT | CONST_CS);
194 	REGISTER_LONG_CONSTANT("GSLC_SSL_ONEWAY_AUTH", GSLC_SSL_ONEWAY_AUTH, CONST_PERSISTENT | CONST_CS);
195 	REGISTER_LONG_CONSTANT("GSLC_SSL_TWOWAY_AUTH", GSLC_SSL_TWOWAY_AUTH, CONST_PERSISTENT | CONST_CS);
196 #endif
197 
198 	le_link = zend_register_list_destructors_ex(_close_ldap_link, NULL, "ldap link", module_number);
199 	le_result = zend_register_list_destructors_ex(_free_ldap_result, NULL, "ldap result", module_number);
200 	le_result_entry = zend_register_list_destructors_ex(_free_ldap_result_entry, NULL, "ldap result entry", module_number);
201 
202 	Z_TYPE(ldap_module_entry) = type;
203 
204 	return SUCCESS;
205 }
206 /* }}} */
207 
208 /* {{{ PHP_MSHUTDOWN_FUNCTION
209  */
PHP_MSHUTDOWN_FUNCTION(ldap)210 PHP_MSHUTDOWN_FUNCTION(ldap)
211 {
212 	UNREGISTER_INI_ENTRIES();
213 	return SUCCESS;
214 }
215 /* }}} */
216 
217 /* {{{ PHP_MINFO_FUNCTION
218  */
PHP_MINFO_FUNCTION(ldap)219 PHP_MINFO_FUNCTION(ldap)
220 {
221 	char tmp[32];
222 #if HAVE_NSLDAP
223 	LDAPVersion ver;
224 	double SDKVersion;
225 #endif
226 
227 	php_info_print_table_start();
228 	php_info_print_table_row(2, "LDAP Support", "enabled");
229 	php_info_print_table_row(2, "RCS Version", "$Id$");
230 
231 	if (LDAPG(max_links) == -1) {
232 		snprintf(tmp, 31, "%ld/unlimited", LDAPG(num_links));
233 	} else {
234 		snprintf(tmp, 31, "%ld/%ld", LDAPG(num_links), LDAPG(max_links));
235 	}
236 	php_info_print_table_row(2, "Total Links", tmp);
237 
238 #ifdef LDAP_API_VERSION
239 	snprintf(tmp, 31, "%d", LDAP_API_VERSION);
240 	php_info_print_table_row(2, "API Version", tmp);
241 #endif
242 
243 #ifdef LDAP_VENDOR_NAME
244 	php_info_print_table_row(2, "Vendor Name", LDAP_VENDOR_NAME);
245 #endif
246 
247 #ifdef LDAP_VENDOR_VERSION
248 	snprintf(tmp, 31, "%d", LDAP_VENDOR_VERSION);
249 	php_info_print_table_row(2, "Vendor Version", tmp);
250 #endif
251 
252 #if HAVE_NSLDAP
253 	SDKVersion = ldap_version(&ver);
254 	snprintf(tmp, 31, "%F", SDKVersion/100.0);
255 	php_info_print_table_row(2, "SDK Version", tmp);
256 
257 	snprintf(tmp, 31, "%F", ver.protocol_version/100.0);
258 	php_info_print_table_row(2, "Highest LDAP Protocol Supported", tmp);
259 
260 	snprintf(tmp, 31, "%F", ver.SSL_version/100.0);
261 	php_info_print_table_row(2, "SSL Level Supported", tmp);
262 
263 	if (ver.security_level != LDAP_SECURITY_NONE) {
264 		snprintf(tmp, 31, "%d", ver.security_level);
265 	} else {
266 		strcpy(tmp, "SSL not enabled");
267 	}
268 	php_info_print_table_row(2, "Level of Encryption", tmp);
269 #endif
270 
271 #ifdef HAVE_LDAP_SASL
272 	php_info_print_table_row(2, "SASL Support", "Enabled");
273 #endif
274 
275 	php_info_print_table_end();
276 	DISPLAY_INI_ENTRIES();
277 }
278 /* }}} */
279 
280 /* {{{ proto resource ldap_connect([string host [, int port [, string wallet [, string wallet_passwd [, int authmode]]]]])
281    Connect to an LDAP server */
PHP_FUNCTION(ldap_connect)282 PHP_FUNCTION(ldap_connect)
283 {
284 	char *host = NULL;
285 	int hostlen;
286 	long port = 389; /* Default port */
287 #ifdef HAVE_ORALDAP
288 	char *wallet = NULL, *walletpasswd = NULL;
289 	int walletlen = 0, walletpasswdlen = 0;
290 	long authmode = GSLC_SSL_NO_AUTH;
291 	int ssl=0;
292 #endif
293 	ldap_linkdata *ld;
294 	LDAP *ldap;
295 
296 #ifdef HAVE_ORALDAP
297 	if (ZEND_NUM_ARGS() == 3 || ZEND_NUM_ARGS() == 4) {
298 		WRONG_PARAM_COUNT;
299 	}
300 
301 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|slssl", &host, &hostlen, &port, &wallet, &walletlen, &walletpasswd, &walletpasswdlen, &authmode) != SUCCESS) {
302 		RETURN_FALSE;
303 	}
304 
305 	if (ZEND_NUM_ARGS() == 5) {
306 		ssl = 1;
307 	}
308 #else
309 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sl", &host, &hostlen, &port) != SUCCESS) {
310 		RETURN_FALSE;
311 	}
312 #endif
313 
314 	if (LDAPG(max_links) != -1 && LDAPG(num_links) >= LDAPG(max_links)) {
315 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Too many open links (%ld)", LDAPG(num_links));
316 		RETURN_FALSE;
317 	}
318 
319 	ld = ecalloc(1, sizeof(ldap_linkdata));
320 
321 #ifdef LDAP_API_FEATURE_X_OPENLDAP
322 	if (host != NULL && strchr(host, '/')) {
323 		int rc;
324 
325 		rc = ldap_initialize(&ldap, host);
326 		if (rc != LDAP_SUCCESS) {
327 			efree(ld);
328 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not create session handle: %s", ldap_err2string(rc));
329 			RETURN_FALSE;
330 		}
331 	} else {
332 		ldap = ldap_init(host, port);
333 	}
334 #else
335 	ldap = ldap_open(host, port);
336 #endif
337 
338 	if (ldap == NULL) {
339 		efree(ld);
340 		RETURN_FALSE;
341 	} else {
342 #ifdef HAVE_ORALDAP
343 		if (ssl) {
344 			if (ldap_init_SSL(&ldap->ld_sb, wallet, walletpasswd, authmode)) {
345 				efree(ld);
346 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSL init failed");
347 				RETURN_FALSE;
348 			}
349 		}
350 #endif
351 		LDAPG(num_links)++;
352 		ld->link = ldap;
353 		ZEND_REGISTER_RESOURCE(return_value, ld, le_link);
354 	}
355 
356 }
357 /* }}} */
358 
359 /* {{{ _get_lderrno
360  */
_get_lderrno(LDAP * ldap)361 static int _get_lderrno(LDAP *ldap)
362 {
363 #if !HAVE_NSLDAP
364 #if LDAP_API_VERSION > 2000 || HAVE_ORALDAP_10
365 	int lderr;
366 
367 	/* New versions of OpenLDAP do it this way */
368 	ldap_get_option(ldap, LDAP_OPT_ERROR_NUMBER, &lderr);
369 	return lderr;
370 #else
371 	return ldap->ld_errno;
372 #endif
373 #else
374 	return ldap_get_lderrno(ldap, NULL, NULL);
375 #endif
376 }
377 /* }}} */
378 
379 /* {{{ proto bool ldap_bind(resource link [, string dn [, string password]])
380    Bind to LDAP directory */
PHP_FUNCTION(ldap_bind)381 PHP_FUNCTION(ldap_bind)
382 {
383 	zval *link;
384 	char *ldap_bind_dn = NULL, *ldap_bind_pw = NULL;
385 	int ldap_bind_dnlen, ldap_bind_pwlen;
386 	ldap_linkdata *ld;
387 	int rc;
388 
389 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|ss", &link, &ldap_bind_dn, &ldap_bind_dnlen, &ldap_bind_pw, &ldap_bind_pwlen) != SUCCESS) {
390 		RETURN_FALSE;
391 	}
392 
393 	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
394 
395 	if ((rc = ldap_bind_s(ld->link, ldap_bind_dn, ldap_bind_pw, LDAP_AUTH_SIMPLE)) != LDAP_SUCCESS) {
396 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to bind to server: %s", ldap_err2string(rc));
397 		RETURN_FALSE;
398 	} else {
399 		RETURN_TRUE;
400 	}
401 }
402 /* }}} */
403 
404 #ifdef HAVE_LDAP_SASL
405 typedef struct {
406 	char *mech;
407 	char *realm;
408 	char *authcid;
409 	char *passwd;
410 	char *authzid;
411 } php_ldap_bictx;
412 
413 /* {{{ _php_sasl_setdefs
414  */
_php_sasl_setdefs(LDAP * ld,char * sasl_mech,char * sasl_realm,char * sasl_authc_id,char * passwd,char * sasl_authz_id)415 static php_ldap_bictx *_php_sasl_setdefs(LDAP *ld, char *sasl_mech, char *sasl_realm, char *sasl_authc_id, char *passwd, char *sasl_authz_id)
416 {
417 	php_ldap_bictx *ctx;
418 
419 	ctx = ber_memalloc(sizeof(php_ldap_bictx));
420 	ctx->mech    = (sasl_mech) ? ber_strdup(sasl_mech) : NULL;
421 	ctx->realm   = (sasl_realm) ? ber_strdup(sasl_realm) : NULL;
422 	ctx->authcid = (sasl_authc_id) ? ber_strdup(sasl_authc_id) : NULL;
423 	ctx->passwd  = (passwd) ? ber_strdup(passwd) : NULL;
424 	ctx->authzid = (sasl_authz_id) ? ber_strdup(sasl_authz_id) : NULL;
425 
426 	if (ctx->mech == NULL) {
427 		ldap_get_option(ld, LDAP_OPT_X_SASL_MECH, &ctx->mech);
428 	}
429 	if (ctx->realm == NULL) {
430 		ldap_get_option(ld, LDAP_OPT_X_SASL_REALM, &ctx->realm);
431 	}
432 	if (ctx->authcid == NULL) {
433 		ldap_get_option(ld, LDAP_OPT_X_SASL_AUTHCID, &ctx->authcid);
434 	}
435 	if (ctx->authzid == NULL) {
436 		ldap_get_option(ld, LDAP_OPT_X_SASL_AUTHZID, &ctx->authzid);
437 	}
438 
439 	return ctx;
440 }
441 /* }}} */
442 
443 /* {{{ _php_sasl_freedefs
444  */
_php_sasl_freedefs(php_ldap_bictx * ctx)445 static void _php_sasl_freedefs(php_ldap_bictx *ctx)
446 {
447 	if (ctx->mech) ber_memfree(ctx->mech);
448 	if (ctx->realm) ber_memfree(ctx->realm);
449 	if (ctx->authcid) ber_memfree(ctx->authcid);
450 	if (ctx->passwd) ber_memfree(ctx->passwd);
451 	if (ctx->authzid) ber_memfree(ctx->authzid);
452 	ber_memfree(ctx);
453 }
454 /* }}} */
455 
456 /* {{{ _php_sasl_interact
457    Internal interact function for SASL */
_php_sasl_interact(LDAP * ld,unsigned flags,void * defaults,void * in)458 static int _php_sasl_interact(LDAP *ld, unsigned flags, void *defaults, void *in)
459 {
460 	sasl_interact_t *interact = in;
461 	const char *p;
462 	php_ldap_bictx *ctx = defaults;
463 
464 	for (;interact->id != SASL_CB_LIST_END;interact++) {
465 		p = NULL;
466 		switch(interact->id) {
467 			case SASL_CB_GETREALM:
468 				p = ctx->realm;
469 				break;
470 			case SASL_CB_AUTHNAME:
471 				p = ctx->authcid;
472 				break;
473 			case SASL_CB_USER:
474 				p = ctx->authzid;
475 				break;
476 			case SASL_CB_PASS:
477 				p = ctx->passwd;
478 				break;
479 		}
480 		if (p) {
481 			interact->result = p;
482 			interact->len = strlen(interact->result);
483 		}
484 	}
485 	return LDAP_SUCCESS;
486 }
487 /* }}} */
488 
489 /* {{{ proto bool ldap_sasl_bind(resource link [, string binddn [, string password [, string sasl_mech [, string sasl_realm [, string sasl_authc_id [, string sasl_authz_id [, string props]]]]]]])
490    Bind to LDAP directory using SASL */
PHP_FUNCTION(ldap_sasl_bind)491 PHP_FUNCTION(ldap_sasl_bind)
492 {
493 	zval *link;
494 	ldap_linkdata *ld;
495 	char *binddn = NULL;
496 	char *passwd = NULL;
497 	char *sasl_mech = NULL;
498 	char *sasl_realm = NULL;
499 	char *sasl_authz_id = NULL;
500 	char *sasl_authc_id = NULL;
501 	char *props = NULL;
502 	int rc, dn_len, passwd_len, mech_len, realm_len, authc_id_len, authz_id_len, props_len;
503 	php_ldap_bictx *ctx;
504 
505 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|sssssss", &link, &binddn, &dn_len, &passwd, &passwd_len, &sasl_mech, &mech_len, &sasl_realm, &realm_len, &sasl_authc_id, &authc_id_len, &sasl_authz_id, &authz_id_len, &props, &props_len) != SUCCESS) {
506 		RETURN_FALSE;
507 	}
508 
509 	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
510 
511 	ctx = _php_sasl_setdefs(ld->link, sasl_mech, sasl_realm, sasl_authc_id, passwd, sasl_authz_id);
512 
513 	if (props) {
514 		ldap_set_option(ld->link, LDAP_OPT_X_SASL_SECPROPS, props);
515 	}
516 
517 	rc = ldap_sasl_interactive_bind_s(ld->link, binddn, ctx->mech, NULL, NULL, LDAP_SASL_QUIET, _php_sasl_interact, ctx);
518 	if (rc != LDAP_SUCCESS) {
519 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to bind to server: %s", ldap_err2string(rc));
520 		RETVAL_FALSE;
521 	} else {
522 		RETVAL_TRUE;
523 	}
524 	_php_sasl_freedefs(ctx);
525 }
526 /* }}} */
527 #endif /* HAVE_LDAP_SASL */
528 
529 /* {{{ proto bool ldap_unbind(resource link)
530    Unbind from LDAP directory */
PHP_FUNCTION(ldap_unbind)531 PHP_FUNCTION(ldap_unbind)
532 {
533 	zval *link;
534 	ldap_linkdata *ld;
535 
536 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &link) != SUCCESS) {
537 		RETURN_FALSE;
538 	}
539 
540 	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
541 
542 	zend_list_delete(Z_LVAL_P(link));
543 	RETURN_TRUE;
544 }
545 /* }}} */
546 
547 /* {{{ php_set_opts
548  */
php_set_opts(LDAP * ldap,int sizelimit,int timelimit,int deref,int * old_sizelimit,int * old_timelimit,int * old_deref)549 static void php_set_opts(LDAP *ldap, int sizelimit, int timelimit, int deref, int *old_sizelimit, int *old_timelimit, int *old_deref)
550 {
551 	/* sizelimit */
552 	if (sizelimit > -1) {
553 #if (LDAP_API_VERSION >= 2004) || HAVE_NSLDAP || HAVE_ORALDAP_10
554 		ldap_get_option(ldap, LDAP_OPT_SIZELIMIT, old_sizelimit);
555 		ldap_set_option(ldap, LDAP_OPT_SIZELIMIT, &sizelimit);
556 #else
557 		*old_sizelimit = ldap->ld_sizelimit;
558 		ldap->ld_sizelimit = sizelimit;
559 #endif
560 	}
561 
562 	/* timelimit */
563 	if (timelimit > -1) {
564 #if (LDAP_API_VERSION >= 2004) || HAVE_NSLDAP || HAVE_ORALDAP_10
565 		ldap_get_option(ldap, LDAP_OPT_SIZELIMIT, old_timelimit);
566 		ldap_set_option(ldap, LDAP_OPT_TIMELIMIT, &timelimit);
567 #else
568 		*old_timelimit = ldap->ld_timelimit;
569 		ldap->ld_timelimit = timelimit;
570 #endif
571 	}
572 
573 	/* deref */
574 	if (deref > -1) {
575 #if (LDAP_API_VERSION >= 2004) || HAVE_NSLDAP || HAVE_ORALDAP_10
576 		ldap_get_option(ldap, LDAP_OPT_SIZELIMIT, old_deref);
577 		ldap_set_option(ldap, LDAP_OPT_DEREF, &deref);
578 #else
579 		*old_deref = ldap->ld_deref;
580 		ldap->ld_deref = deref;
581 #endif
582 	}
583 }
584 /* }}} */
585 
586 /* {{{ php_ldap_do_search
587  */
php_ldap_do_search(INTERNAL_FUNCTION_PARAMETERS,int scope)588 static void php_ldap_do_search(INTERNAL_FUNCTION_PARAMETERS, int scope)
589 {
590 	zval *link, *base_dn, **filter, *attrs, **attr;
591 	long attrsonly, sizelimit, timelimit, deref;
592 	char *ldap_base_dn = NULL, *ldap_filter = NULL, **ldap_attrs = NULL;
593 	ldap_linkdata *ld = NULL;
594 	LDAPMessage *ldap_res;
595 	int ldap_attrsonly = 0, ldap_sizelimit = -1, ldap_timelimit = -1, ldap_deref = -1;
596 	int old_ldap_sizelimit = -1, old_ldap_timelimit = -1, old_ldap_deref = -1;
597 	int num_attribs = 0, ret = 1, i, errno, argcount = ZEND_NUM_ARGS();
598 
599 	if (zend_parse_parameters(argcount TSRMLS_CC, "zzZ|allll", &link, &base_dn, &filter, &attrs, &attrsonly,
600 		&sizelimit, &timelimit, &deref) == FAILURE) {
601 		return;
602 	}
603 
604 	/* Reverse -> fall through */
605 	switch (argcount) {
606 		case 8:
607 			ldap_deref = deref;
608 		case 7:
609 			ldap_timelimit = timelimit;
610 		case 6:
611 			ldap_sizelimit = sizelimit;
612 		case 5:
613 			ldap_attrsonly = attrsonly;
614 		case 4:
615 			num_attribs = zend_hash_num_elements(Z_ARRVAL_P(attrs));
616 			ldap_attrs = safe_emalloc((num_attribs+1), sizeof(char *), 0);
617 
618 			for (i = 0; i<num_attribs; i++) {
619 				if (zend_hash_index_find(Z_ARRVAL_P(attrs), i, (void **) &attr) != SUCCESS) {
620 					php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array initialization wrong");
621 					ret = 0;
622 					goto cleanup;
623 				}
624 
625 				SEPARATE_ZVAL(attr);
626 				convert_to_string_ex(attr);
627 				ldap_attrs[i] = Z_STRVAL_PP(attr);
628 			}
629 			ldap_attrs[num_attribs] = NULL;
630 		default:
631 			break;
632 	}
633 
634 	/* parallel search? */
635 	if (Z_TYPE_P(link) == IS_ARRAY) {
636 		int i, nlinks, nbases, nfilters, *rcs;
637 		ldap_linkdata **lds;
638 		zval **entry, *resource;
639 
640 		nlinks = zend_hash_num_elements(Z_ARRVAL_P(link));
641 		if (nlinks == 0) {
642 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "No links in link array");
643 			ret = 0;
644 			goto cleanup;
645 		}
646 
647 		if (Z_TYPE_P(base_dn) == IS_ARRAY) {
648 			nbases = zend_hash_num_elements(Z_ARRVAL_P(base_dn));
649 			if (nbases != nlinks) {
650 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Base must either be a string, or an array with the same number of elements as the links array");
651 				ret = 0;
652 				goto cleanup;
653 			}
654 			zend_hash_internal_pointer_reset(Z_ARRVAL_P(base_dn));
655 		} else {
656 			nbases = 0; /* this means string, not array */
657 			/* If anything else than string is passed, ldap_base_dn = NULL */
658 			if (Z_TYPE_P(base_dn) == IS_STRING) {
659 				ldap_base_dn = Z_STRVAL_P(base_dn);
660 			} else {
661 				ldap_base_dn = NULL;
662 			}
663 		}
664 
665 		if (Z_TYPE_PP(filter) == IS_ARRAY) {
666 			nfilters = zend_hash_num_elements(Z_ARRVAL_PP(filter));
667 			if (nfilters != nlinks) {
668 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Filter must either be a string, or an array with the same number of elements as the links array");
669 				ret = 0;
670 				goto cleanup;
671 			}
672 			zend_hash_internal_pointer_reset(Z_ARRVAL_PP(filter));
673 		} else {
674 			nfilters = 0; /* this means string, not array */
675 			convert_to_string_ex(filter);
676 			ldap_filter = Z_STRVAL_PP(filter);
677 		}
678 
679 		lds = safe_emalloc(nlinks, sizeof(ldap_linkdata), 0);
680 		rcs = safe_emalloc(nlinks, sizeof(*rcs), 0);
681 
682 		zend_hash_internal_pointer_reset(Z_ARRVAL_P(link));
683 		for (i=0; i<nlinks; i++) {
684 			zend_hash_get_current_data(Z_ARRVAL_P(link), (void **)&entry);
685 
686 			ld = (ldap_linkdata *) zend_fetch_resource(entry TSRMLS_CC, -1, "ldap link", NULL, 1, le_link);
687 			if (ld == NULL) {
688 				ret = 0;
689 				goto cleanup_parallel;
690 			}
691 			if (nbases != 0) { /* base_dn an array? */
692 				zend_hash_get_current_data(Z_ARRVAL_P(base_dn), (void **)&entry);
693 				zend_hash_move_forward(Z_ARRVAL_P(base_dn));
694 
695 				/* If anything else than string is passed, ldap_base_dn = NULL */
696 				if (Z_TYPE_PP(entry) == IS_STRING) {
697 					ldap_base_dn = Z_STRVAL_PP(entry);
698 				} else {
699 					ldap_base_dn = NULL;
700 				}
701 			}
702 			if (nfilters != 0) { /* filter an array? */
703 				zend_hash_get_current_data(Z_ARRVAL_PP(filter), (void **)&entry);
704 				zend_hash_move_forward(Z_ARRVAL_PP(filter));
705 				convert_to_string_ex(entry);
706 				ldap_filter = Z_STRVAL_PP(entry);
707 			}
708 
709 			php_set_opts(ld->link, ldap_sizelimit, ldap_timelimit, ldap_deref, &old_ldap_sizelimit, &old_ldap_timelimit, &old_ldap_deref);
710 
711 			/* Run the actual search */
712 			rcs[i] = ldap_search(ld->link, ldap_base_dn, scope, ldap_filter, ldap_attrs, ldap_attrsonly);
713 			lds[i] = ld;
714 			zend_hash_move_forward(Z_ARRVAL_P(link));
715 		}
716 
717 		array_init(return_value);
718 
719 		/* Collect results from the searches */
720 		for (i=0; i<nlinks; i++) {
721 			MAKE_STD_ZVAL(resource);
722 			if (rcs[i] != -1) {
723 				rcs[i] = ldap_result(lds[i]->link, LDAP_RES_ANY, 1 /* LDAP_MSG_ALL */, NULL, &ldap_res);
724 			}
725 			if (rcs[i] != -1) {
726 				ZEND_REGISTER_RESOURCE(resource, ldap_res, le_result);
727 				add_next_index_zval(return_value, resource);
728 			} else {
729 				add_next_index_bool(return_value, 0);
730 			}
731 		}
732 
733 cleanup_parallel:
734 		efree(lds);
735 		efree(rcs);
736 	} else {
737 		convert_to_string_ex(filter);
738 		ldap_filter = Z_STRVAL_PP(filter);
739 
740 		/* If anything else than string is passed, ldap_base_dn = NULL */
741 		if (Z_TYPE_P(base_dn) == IS_STRING) {
742 			ldap_base_dn = Z_STRVAL_P(base_dn);
743 		}
744 
745 		ld = (ldap_linkdata *) zend_fetch_resource(&link TSRMLS_CC, -1, "ldap link", NULL, 1, le_link);
746 		if (ld == NULL) {
747 			ret = 0;
748 			goto cleanup;
749 		}
750 
751 		php_set_opts(ld->link, ldap_sizelimit, ldap_timelimit, ldap_deref, &old_ldap_sizelimit, &old_ldap_timelimit, &old_ldap_deref);
752 
753 		/* Run the actual search */
754 		errno = ldap_search_s(ld->link, ldap_base_dn, scope, ldap_filter, ldap_attrs, ldap_attrsonly, &ldap_res);
755 
756 		if (errno != LDAP_SUCCESS
757 			&& errno != LDAP_SIZELIMIT_EXCEEDED
758 #ifdef LDAP_ADMINLIMIT_EXCEEDED
759 			&& errno != LDAP_ADMINLIMIT_EXCEEDED
760 #endif
761 #ifdef LDAP_REFERRAL
762 			&& errno != LDAP_REFERRAL
763 #endif
764 		) {
765 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Search: %s", ldap_err2string(errno));
766 			ret = 0;
767 		} else {
768 			if (errno == LDAP_SIZELIMIT_EXCEEDED) {
769 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Partial search results returned: Sizelimit exceeded");
770 			}
771 #ifdef LDAP_ADMINLIMIT_EXCEEDED
772 			else if (errno == LDAP_ADMINLIMIT_EXCEEDED) {
773 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Partial search results returned: Adminlimit exceeded");
774 			}
775 #endif
776 
777 			ZEND_REGISTER_RESOURCE(return_value, ldap_res, le_result);
778 		}
779 	}
780 
781 cleanup:
782 	if (ld) {
783 		/* Restoring previous options */
784 		php_set_opts(ld->link, old_ldap_sizelimit, old_ldap_timelimit, old_ldap_deref, &ldap_sizelimit, &ldap_timelimit, &ldap_deref);
785 	}
786 	if (ldap_attrs != NULL) {
787 		efree(ldap_attrs);
788 	}
789 	if (!ret) {
790 		RETVAL_BOOL(ret);
791 	}
792 }
793 /* }}} */
794 
795 /* {{{ proto resource ldap_read(resource|array link, string base_dn, string filter [, array attrs [, int attrsonly [, int sizelimit [, int timelimit [, int deref]]]]])
796    Read an entry */
PHP_FUNCTION(ldap_read)797 PHP_FUNCTION(ldap_read)
798 {
799 	php_ldap_do_search(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_SCOPE_BASE);
800 }
801 /* }}} */
802 
803 /* {{{ proto resource ldap_list(resource|array link, string base_dn, string filter [, array attrs [, int attrsonly [, int sizelimit [, int timelimit [, int deref]]]]])
804    Single-level search */
PHP_FUNCTION(ldap_list)805 PHP_FUNCTION(ldap_list)
806 {
807 	php_ldap_do_search(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_SCOPE_ONELEVEL);
808 }
809 /* }}} */
810 
811 /* {{{ proto resource ldap_search(resource|array link, string base_dn, string filter [, array attrs [, int attrsonly [, int sizelimit [, int timelimit [, int deref]]]]])
812    Search LDAP tree under base_dn */
PHP_FUNCTION(ldap_search)813 PHP_FUNCTION(ldap_search)
814 {
815 	php_ldap_do_search(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_SCOPE_SUBTREE);
816 }
817 /* }}} */
818 
819 /* {{{ proto bool ldap_free_result(resource result)
820    Free result memory */
PHP_FUNCTION(ldap_free_result)821 PHP_FUNCTION(ldap_free_result)
822 {
823 	zval *result;
824 	LDAPMessage *ldap_result;
825 
826 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &result) != SUCCESS) {
827 		return;
828 	}
829 
830 	ZEND_FETCH_RESOURCE(ldap_result, LDAPMessage *, &result, -1, "ldap result", le_result);
831 
832 	zend_list_delete(Z_LVAL_P(result));  /* Delete list entry */
833 	RETVAL_TRUE;
834 }
835 /* }}} */
836 
837 /* {{{ proto int ldap_count_entries(resource link, resource result)
838    Count the number of entries in a search result */
PHP_FUNCTION(ldap_count_entries)839 PHP_FUNCTION(ldap_count_entries)
840 {
841 	zval *link, *result;
842 	ldap_linkdata *ld;
843 	LDAPMessage *ldap_result;
844 
845 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &link, &result) != SUCCESS) {
846 		return;
847 	}
848 
849 	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
850 	ZEND_FETCH_RESOURCE(ldap_result, LDAPMessage *, &result, -1, "ldap result", le_result);
851 
852 	RETURN_LONG(ldap_count_entries(ld->link, ldap_result));
853 }
854 /* }}} */
855 
856 /* {{{ proto resource ldap_first_entry(resource link, resource result)
857    Return first result id */
PHP_FUNCTION(ldap_first_entry)858 PHP_FUNCTION(ldap_first_entry)
859 {
860 	zval *link, *result;
861 	ldap_linkdata *ld;
862 	ldap_resultentry *resultentry;
863 	LDAPMessage *ldap_result, *entry;
864 
865 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &link, &result) != SUCCESS) {
866 		return;
867 	}
868 
869 	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
870 	ZEND_FETCH_RESOURCE(ldap_result, LDAPMessage *, &result, -1, "ldap result", le_result);
871 
872 	if ((entry = ldap_first_entry(ld->link, ldap_result)) == NULL) {
873 		RETVAL_FALSE;
874 	} else {
875 		resultentry = emalloc(sizeof(ldap_resultentry));
876 		ZEND_REGISTER_RESOURCE(return_value, resultentry, le_result_entry);
877 		resultentry->id = Z_LVAL_P(result);
878 		zend_list_addref(resultentry->id);
879 		resultentry->data = entry;
880 		resultentry->ber = NULL;
881 	}
882 }
883 /* }}} */
884 
885 /* {{{ proto resource ldap_next_entry(resource link, resource result_entry)
886    Get next result entry */
PHP_FUNCTION(ldap_next_entry)887 PHP_FUNCTION(ldap_next_entry)
888 {
889 	zval *link, *result_entry;
890 	ldap_linkdata *ld;
891 	ldap_resultentry *resultentry, *resultentry_next;
892 	LDAPMessage *entry_next;
893 
894 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &link, &result_entry) != SUCCESS) {
895 		return;
896 	}
897 
898 	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
899 	ZEND_FETCH_RESOURCE(resultentry, ldap_resultentry *, &result_entry, -1, "ldap result entry", le_result_entry);
900 
901 	if ((entry_next = ldap_next_entry(ld->link, resultentry->data)) == NULL) {
902 		RETVAL_FALSE;
903 	} else {
904 		resultentry_next = emalloc(sizeof(ldap_resultentry));
905 		ZEND_REGISTER_RESOURCE(return_value, resultentry_next, le_result_entry);
906 		resultentry_next->id = resultentry->id;
907 		zend_list_addref(resultentry->id);
908 		resultentry_next->data = entry_next;
909 		resultentry_next->ber = NULL;
910 	}
911 }
912 /* }}} */
913 
914 /* {{{ proto array ldap_get_entries(resource link, resource result)
915    Get all result entries */
PHP_FUNCTION(ldap_get_entries)916 PHP_FUNCTION(ldap_get_entries)
917 {
918 	zval *link, *result;
919 	LDAPMessage *ldap_result, *ldap_result_entry;
920 	zval *tmp1, *tmp2;
921 	ldap_linkdata *ld;
922 	LDAP *ldap;
923 	int num_entries, num_attrib, num_values, i;
924 	BerElement *ber;
925 	char *attribute;
926 	size_t attr_len;
927 	struct berval **ldap_value;
928 	char *dn;
929 
930 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &link, &result) != SUCCESS) {
931 		return;
932 	}
933 
934 	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
935 	ZEND_FETCH_RESOURCE(ldap_result, LDAPMessage *, &result, -1, "ldap result", le_result);
936 
937 	ldap = ld->link;
938 	num_entries = ldap_count_entries(ldap, ldap_result);
939 
940 	array_init(return_value);
941 	add_assoc_long(return_value, "count", num_entries);
942 
943 	if (num_entries == 0) {
944 		return;
945 	}
946 
947 	ldap_result_entry = ldap_first_entry(ldap, ldap_result);
948 	if (ldap_result_entry == NULL) {
949 		zval_dtor(return_value);
950 		RETURN_FALSE;
951 	}
952 
953 	num_entries = 0;
954 	while (ldap_result_entry != NULL) {
955 		MAKE_STD_ZVAL(tmp1);
956 		array_init(tmp1);
957 
958 		num_attrib = 0;
959 		attribute = ldap_first_attribute(ldap, ldap_result_entry, &ber);
960 
961 		while (attribute != NULL) {
962 			ldap_value = ldap_get_values_len(ldap, ldap_result_entry, attribute);
963 			num_values = ldap_count_values_len(ldap_value);
964 
965 			MAKE_STD_ZVAL(tmp2);
966 			array_init(tmp2);
967 			add_assoc_long(tmp2, "count", num_values);
968 			for (i = 0; i < num_values; i++) {
969 				add_index_stringl(tmp2, i, ldap_value[i]->bv_val, ldap_value[i]->bv_len, 1);
970 			}
971 			ldap_value_free_len(ldap_value);
972 
973 			attr_len = strlen(attribute);
974 			zend_hash_update(Z_ARRVAL_P(tmp1), php_strtolower(attribute, attr_len), attr_len+1, (void *) &tmp2, sizeof(zval *), NULL);
975 			add_index_string(tmp1, num_attrib, attribute, 1);
976 
977 			num_attrib++;
978 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10 || WINDOWS
979 			ldap_memfree(attribute);
980 #endif
981 			attribute = ldap_next_attribute(ldap, ldap_result_entry, ber);
982 		}
983 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10 || WINDOWS
984 		if (ber != NULL) {
985 			ber_free(ber, 0);
986 		}
987 #endif
988 
989 		add_assoc_long(tmp1, "count", num_attrib);
990 		dn = ldap_get_dn(ldap, ldap_result_entry);
991 		add_assoc_string(tmp1, "dn", dn, 1);
992 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10 || WINDOWS
993 		ldap_memfree(dn);
994 #else
995 		free(dn);
996 #endif
997 
998 		zend_hash_index_update(Z_ARRVAL_P(return_value), num_entries, (void *) &tmp1, sizeof(zval *), NULL);
999 
1000 		num_entries++;
1001 		ldap_result_entry = ldap_next_entry(ldap, ldap_result_entry);
1002 	}
1003 
1004 	add_assoc_long(return_value, "count", num_entries);
1005 
1006 }
1007 /* }}} */
1008 
1009 /* {{{ proto string ldap_first_attribute(resource link, resource result_entry)
1010    Return first attribute */
PHP_FUNCTION(ldap_first_attribute)1011 PHP_FUNCTION(ldap_first_attribute)
1012 {
1013 	zval *link, *result_entry;
1014 	ldap_linkdata *ld;
1015 	ldap_resultentry *resultentry;
1016 	char *attribute;
1017 	long dummy_ber;
1018 
1019 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr|l", &link, &result_entry, &dummy_ber) != SUCCESS) {
1020 		return;
1021 	}
1022 
1023 	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
1024 	ZEND_FETCH_RESOURCE(resultentry, ldap_resultentry *, &result_entry, -1, "ldap result entry", le_result_entry);
1025 
1026 	if ((attribute = ldap_first_attribute(ld->link, resultentry->data, &resultentry->ber)) == NULL) {
1027 		RETURN_FALSE;
1028 	} else {
1029 		RETVAL_STRING(attribute, 1);
1030 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10 || WINDOWS
1031 		ldap_memfree(attribute);
1032 #endif
1033 	}
1034 }
1035 /* }}} */
1036 
1037 /* {{{ proto string ldap_next_attribute(resource link, resource result_entry)
1038    Get the next attribute in result */
PHP_FUNCTION(ldap_next_attribute)1039 PHP_FUNCTION(ldap_next_attribute)
1040 {
1041 	zval *link, *result_entry;
1042 	ldap_linkdata *ld;
1043 	ldap_resultentry *resultentry;
1044 	char *attribute;
1045 	long dummy_ber;
1046 
1047 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr|l", &link, &result_entry, &dummy_ber) != SUCCESS) {
1048 		return;
1049 	}
1050 
1051 	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
1052 	ZEND_FETCH_RESOURCE(resultentry, ldap_resultentry *, &result_entry, -1, "ldap result entry", le_result_entry);
1053 
1054 	if (resultentry->ber == NULL) {
1055 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "called before calling ldap_first_attribute() or no attributes found in result entry");
1056 		RETURN_FALSE;
1057 	}
1058 
1059 	if ((attribute = ldap_next_attribute(ld->link, resultentry->data, resultentry->ber)) == NULL) {
1060 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10 || WINDOWS
1061 		if (resultentry->ber != NULL) {
1062 			ber_free(resultentry->ber, 0);
1063 			resultentry->ber = NULL;
1064 		}
1065 #endif
1066 		RETURN_FALSE;
1067 	} else {
1068 		RETVAL_STRING(attribute, 1);
1069 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10 || WINDOWS
1070 		ldap_memfree(attribute);
1071 #endif
1072 	}
1073 }
1074 /* }}} */
1075 
1076 /* {{{ proto array ldap_get_attributes(resource link, resource result_entry)
1077    Get attributes from a search result entry */
PHP_FUNCTION(ldap_get_attributes)1078 PHP_FUNCTION(ldap_get_attributes)
1079 {
1080 	zval *link, *result_entry;
1081 	zval *tmp;
1082 	ldap_linkdata *ld;
1083 	ldap_resultentry *resultentry;
1084 	char *attribute;
1085 	struct berval **ldap_value;
1086 	int i, num_values, num_attrib;
1087 	BerElement *ber;
1088 
1089 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &link, &result_entry) != SUCCESS) {
1090 		return;
1091 	}
1092 
1093 	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
1094 	ZEND_FETCH_RESOURCE(resultentry, ldap_resultentry *, &result_entry, -1, "ldap result entry", le_result_entry);
1095 
1096 	array_init(return_value);
1097 	num_attrib = 0;
1098 
1099 	attribute = ldap_first_attribute(ld->link, resultentry->data, &ber);
1100 	while (attribute != NULL) {
1101 		ldap_value = ldap_get_values_len(ld->link, resultentry->data, attribute);
1102 		num_values = ldap_count_values_len(ldap_value);
1103 
1104 		MAKE_STD_ZVAL(tmp);
1105 		array_init(tmp);
1106 		add_assoc_long(tmp, "count", num_values);
1107 		for (i = 0; i < num_values; i++) {
1108 			add_index_stringl(tmp, i, ldap_value[i]->bv_val, ldap_value[i]->bv_len, 1);
1109 		}
1110 		ldap_value_free_len(ldap_value);
1111 
1112 		zend_hash_update(Z_ARRVAL_P(return_value), attribute, strlen(attribute)+1, (void *) &tmp, sizeof(zval *), NULL);
1113 		add_index_string(return_value, num_attrib, attribute, 1);
1114 
1115 		num_attrib++;
1116 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10 || WINDOWS
1117 		ldap_memfree(attribute);
1118 #endif
1119 		attribute = ldap_next_attribute(ld->link, resultentry->data, ber);
1120 	}
1121 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10 || WINDOWS
1122 	if (ber != NULL) {
1123 		ber_free(ber, 0);
1124 	}
1125 #endif
1126 
1127 	add_assoc_long(return_value, "count", num_attrib);
1128 }
1129 /* }}} */
1130 
1131 /* {{{ proto array ldap_get_values_len(resource link, resource result_entry, string attribute)
1132    Get all values with lengths from a result entry */
PHP_FUNCTION(ldap_get_values_len)1133 PHP_FUNCTION(ldap_get_values_len)
1134 {
1135 	zval *link, *result_entry;
1136 	ldap_linkdata *ld;
1137 	ldap_resultentry *resultentry;
1138 	char *attr;
1139 	struct berval **ldap_value_len;
1140 	int i, num_values, attr_len;
1141 
1142 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rrs", &link, &result_entry, &attr, &attr_len) != SUCCESS) {
1143 		return;
1144 	}
1145 
1146 	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
1147 	ZEND_FETCH_RESOURCE(resultentry, ldap_resultentry *, &result_entry, -1, "ldap result entry", le_result_entry);
1148 
1149 	if ((ldap_value_len = ldap_get_values_len(ld->link, resultentry->data, attr)) == NULL) {
1150 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot get the value(s) of attribute %s", ldap_err2string(_get_lderrno(ld->link)));
1151 		RETURN_FALSE;
1152 	}
1153 
1154 	num_values = ldap_count_values_len(ldap_value_len);
1155 	array_init(return_value);
1156 
1157 	for (i=0; i<num_values; i++) {
1158 		add_next_index_stringl(return_value, ldap_value_len[i]->bv_val, ldap_value_len[i]->bv_len, 1);
1159 	}
1160 
1161 	add_assoc_long(return_value, "count", num_values);
1162 	ldap_value_free_len(ldap_value_len);
1163 
1164 }
1165 /* }}} */
1166 
1167 /* {{{ proto string ldap_get_dn(resource link, resource result_entry)
1168    Get the DN of a result entry */
PHP_FUNCTION(ldap_get_dn)1169 PHP_FUNCTION(ldap_get_dn)
1170 {
1171 	zval *link, *result_entry;
1172 	ldap_linkdata *ld;
1173 	ldap_resultentry *resultentry;
1174 	char *text;
1175 
1176 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &link, &result_entry) != SUCCESS) {
1177 		return;
1178 	}
1179 
1180 	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
1181 	ZEND_FETCH_RESOURCE(resultentry, ldap_resultentry *, &result_entry, -1, "ldap result entry", le_result_entry);
1182 
1183 	text = ldap_get_dn(ld->link, resultentry->data);
1184 	if (text != NULL) {
1185 		RETVAL_STRING(text, 1);
1186 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10 || WINDOWS
1187 		ldap_memfree(text);
1188 #else
1189 		free(text);
1190 #endif
1191 	} else {
1192 		RETURN_FALSE;
1193 	}
1194 }
1195 /* }}} */
1196 
1197 /* {{{ proto array ldap_explode_dn(string dn, int with_attrib)
1198    Splits DN into its component parts */
PHP_FUNCTION(ldap_explode_dn)1199 PHP_FUNCTION(ldap_explode_dn)
1200 {
1201 	long with_attrib;
1202 	char *dn, **ldap_value;
1203 	int i, count, dn_len;
1204 
1205 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &dn, &dn_len, &with_attrib) != SUCCESS) {
1206 		return;
1207 	}
1208 
1209 	if (!(ldap_value = ldap_explode_dn(dn, with_attrib))) {
1210 		/* Invalid parameters were passed to ldap_explode_dn */
1211 		RETURN_FALSE;
1212 	}
1213 
1214 	i=0;
1215 	while (ldap_value[i] != NULL) i++;
1216 	count = i;
1217 
1218 	array_init(return_value);
1219 
1220 	add_assoc_long(return_value, "count", count);
1221 	for (i = 0; i<count; i++) {
1222 		add_index_string(return_value, i, ldap_value[i], 1);
1223 	}
1224 
1225 	ldap_value_free(ldap_value);
1226 }
1227 /* }}} */
1228 
1229 /* {{{ proto string ldap_dn2ufn(string dn)
1230    Convert DN to User Friendly Naming format */
PHP_FUNCTION(ldap_dn2ufn)1231 PHP_FUNCTION(ldap_dn2ufn)
1232 {
1233 	char *dn, *ufn;
1234 	int dn_len;
1235 
1236 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &dn, &dn_len) != SUCCESS) {
1237 		return;
1238 	}
1239 
1240 	ufn = ldap_dn2ufn(dn);
1241 
1242 	if (ufn != NULL) {
1243 		RETVAL_STRING(ufn, 1);
1244 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10 || WINDOWS
1245 		ldap_memfree(ufn);
1246 #endif
1247 	} else {
1248 		RETURN_FALSE;
1249 	}
1250 }
1251 /* }}} */
1252 
1253 
1254 /* added to fix use of ldap_modify_add for doing an ldap_add, gerrit thomson. */
1255 #define PHP_LD_FULL_ADD 0xff
1256 /* {{{ php_ldap_do_modify
1257  */
php_ldap_do_modify(INTERNAL_FUNCTION_PARAMETERS,int oper)1258 static void php_ldap_do_modify(INTERNAL_FUNCTION_PARAMETERS, int oper)
1259 {
1260 	zval *link, *entry, **value, **ivalue;
1261 	ldap_linkdata *ld;
1262 	char *dn;
1263 	LDAPMod **ldap_mods;
1264 	int i, j, num_attribs, num_values, dn_len;
1265 	int *num_berval;
1266 	char *attribute;
1267 	ulong index;
1268 	int is_full_add=0; /* flag for full add operation so ldap_mod_add can be put back into oper, gerrit THomson */
1269 
1270 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsa", &link, &dn, &dn_len, &entry) != SUCCESS) {
1271 		return;
1272 	}
1273 
1274 	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
1275 
1276 	num_attribs = zend_hash_num_elements(Z_ARRVAL_P(entry));
1277 	ldap_mods = safe_emalloc((num_attribs+1), sizeof(LDAPMod *), 0);
1278 	num_berval = safe_emalloc(num_attribs, sizeof(int), 0);
1279 	zend_hash_internal_pointer_reset(Z_ARRVAL_P(entry));
1280 
1281 	/* added by gerrit thomson to fix ldap_add using ldap_mod_add */
1282 	if (oper == PHP_LD_FULL_ADD) {
1283 		oper = LDAP_MOD_ADD;
1284 		is_full_add = 1;
1285 	}
1286 	/* end additional , gerrit thomson */
1287 
1288 	for (i = 0; i < num_attribs; i++) {
1289 		ldap_mods[i] = emalloc(sizeof(LDAPMod));
1290 		ldap_mods[i]->mod_op = oper | LDAP_MOD_BVALUES;
1291 		ldap_mods[i]->mod_type = NULL;
1292 
1293 		if (zend_hash_get_current_key(Z_ARRVAL_P(entry), &attribute, &index, 0) == HASH_KEY_IS_STRING) {
1294 			ldap_mods[i]->mod_type = estrdup(attribute);
1295 		} else {
1296 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown attribute in the data");
1297 			/* Free allocated memory */
1298 			while (i >= 0) {
1299 				if (ldap_mods[i]->mod_type) {
1300 					efree(ldap_mods[i]->mod_type);
1301 				}
1302 				efree(ldap_mods[i]);
1303 				i--;
1304 			}
1305 			efree(num_berval);
1306 			efree(ldap_mods);
1307 			RETURN_FALSE;
1308 		}
1309 
1310 		zend_hash_get_current_data(Z_ARRVAL_P(entry), (void **)&value);
1311 
1312 		if (Z_TYPE_PP(value) != IS_ARRAY) {
1313 			num_values = 1;
1314 		} else {
1315 			num_values = zend_hash_num_elements(Z_ARRVAL_PP(value));
1316 		}
1317 
1318 		num_berval[i] = num_values;
1319 		ldap_mods[i]->mod_bvalues = safe_emalloc((num_values + 1), sizeof(struct berval *), 0);
1320 
1321 /* allow for arrays with one element, no allowance for arrays with none but probably not required, gerrit thomson. */
1322 		if ((num_values == 1) && (Z_TYPE_PP(value) != IS_ARRAY)) {
1323 			convert_to_string_ex(value);
1324 			ldap_mods[i]->mod_bvalues[0] = (struct berval *) emalloc (sizeof(struct berval));
1325 			ldap_mods[i]->mod_bvalues[0]->bv_len = Z_STRLEN_PP(value);
1326 			ldap_mods[i]->mod_bvalues[0]->bv_val = Z_STRVAL_PP(value);
1327 		} else {
1328 			for (j = 0; j < num_values; j++) {
1329 				if (zend_hash_index_find(Z_ARRVAL_PP(value), j, (void **) &ivalue) != SUCCESS) {
1330 					php_error_docref(NULL TSRMLS_CC, E_WARNING, "Value array must have consecutive indices 0, 1, ...");
1331 					num_berval[i] = j;
1332 					num_attribs = i + 1;
1333 					RETVAL_FALSE;
1334 					goto errexit;
1335 				}
1336 				convert_to_string_ex(ivalue);
1337 				ldap_mods[i]->mod_bvalues[j] = (struct berval *) emalloc (sizeof(struct berval));
1338 				ldap_mods[i]->mod_bvalues[j]->bv_len = Z_STRLEN_PP(ivalue);
1339 				ldap_mods[i]->mod_bvalues[j]->bv_val = Z_STRVAL_PP(ivalue);
1340 			}
1341 		}
1342 		ldap_mods[i]->mod_bvalues[num_values] = NULL;
1343 		zend_hash_move_forward(Z_ARRVAL_P(entry));
1344 	}
1345 	ldap_mods[num_attribs] = NULL;
1346 
1347 /* check flag to see if do_mod was called to perform full add , gerrit thomson */
1348 	if (is_full_add == 1) {
1349 		if ((i = ldap_add_s(ld->link, dn, ldap_mods)) != LDAP_SUCCESS) {
1350 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Add: %s", ldap_err2string(i));
1351 			RETVAL_FALSE;
1352 		} else RETVAL_TRUE;
1353 	} else {
1354 		if ((i = ldap_modify_ext_s(ld->link, dn, ldap_mods, NULL, NULL)) != LDAP_SUCCESS) {
1355 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Modify: %s", ldap_err2string(i));
1356 			RETVAL_FALSE;
1357 		} else RETVAL_TRUE;
1358 	}
1359 
1360 errexit:
1361 	for (i = 0; i < num_attribs; i++) {
1362 		efree(ldap_mods[i]->mod_type);
1363 		for (j = 0; j < num_berval[i]; j++) {
1364 			efree(ldap_mods[i]->mod_bvalues[j]);
1365 		}
1366 		efree(ldap_mods[i]->mod_bvalues);
1367 		efree(ldap_mods[i]);
1368 	}
1369 	efree(num_berval);
1370 	efree(ldap_mods);
1371 
1372 	return;
1373 }
1374 /* }}} */
1375 
1376 /* {{{ proto bool ldap_add(resource link, string dn, array entry)
1377    Add entries to LDAP directory */
PHP_FUNCTION(ldap_add)1378 PHP_FUNCTION(ldap_add)
1379 {
1380 	/* use a newly define parameter into the do_modify so ldap_mod_add can be used the way it is supposed to be used , Gerrit THomson */
1381 	php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_LD_FULL_ADD);
1382 }
1383 /* }}} */
1384 
1385 /* three functions for attribute base modifications, gerrit Thomson */
1386 
1387 /* {{{ proto bool ldap_mod_replace(resource link, string dn, array entry)
1388    Replace attribute values with new ones */
PHP_FUNCTION(ldap_mod_replace)1389 PHP_FUNCTION(ldap_mod_replace)
1390 {
1391 	php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_REPLACE);
1392 }
1393 /* }}} */
1394 
1395 /* {{{ proto bool ldap_mod_add(resource link, string dn, array entry)
1396    Add attribute values to current */
PHP_FUNCTION(ldap_mod_add)1397 PHP_FUNCTION(ldap_mod_add)
1398 {
1399 	php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_ADD);
1400 }
1401 /* }}} */
1402 
1403 /* {{{ proto bool ldap_mod_del(resource link, string dn, array entry)
1404    Delete attribute values */
PHP_FUNCTION(ldap_mod_del)1405 PHP_FUNCTION(ldap_mod_del)
1406 {
1407 	php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_DELETE);
1408 }
1409 /* }}} */
1410 
1411 /* {{{ proto bool ldap_delete(resource link, string dn)
1412    Delete an entry from a directory */
PHP_FUNCTION(ldap_delete)1413 PHP_FUNCTION(ldap_delete)
1414 {
1415 	zval *link;
1416 	ldap_linkdata *ld;
1417 	char *dn;
1418 	int rc, dn_len;
1419 
1420 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &link, &dn, &dn_len) != SUCCESS) {
1421 		return;
1422 	}
1423 
1424 	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
1425 
1426 	if ((rc = ldap_delete_s(ld->link, dn)) != LDAP_SUCCESS) {
1427 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Delete: %s", ldap_err2string(rc));
1428 		RETURN_FALSE;
1429 	}
1430 
1431 	RETURN_TRUE;
1432 }
1433 /* }}} */
1434 
1435 /* {{{ proto int ldap_errno(resource link)
1436    Get the current ldap error number */
PHP_FUNCTION(ldap_errno)1437 PHP_FUNCTION(ldap_errno)
1438 {
1439 	zval *link;
1440 	ldap_linkdata *ld;
1441 
1442 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &link) != SUCCESS) {
1443 		return;
1444 	}
1445 
1446 	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
1447 
1448 	RETURN_LONG(_get_lderrno(ld->link));
1449 }
1450 /* }}} */
1451 
1452 /* {{{ proto string ldap_err2str(int errno)
1453    Convert error number to error string */
PHP_FUNCTION(ldap_err2str)1454 PHP_FUNCTION(ldap_err2str)
1455 {
1456 	long perrno;
1457 
1458 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &perrno) != SUCCESS) {
1459 		return;
1460 	}
1461 
1462 	RETURN_STRING(ldap_err2string(perrno), 1);
1463 }
1464 /* }}} */
1465 
1466 /* {{{ proto string ldap_error(resource link)
1467    Get the current ldap error string */
PHP_FUNCTION(ldap_error)1468 PHP_FUNCTION(ldap_error)
1469 {
1470 	zval *link;
1471 	ldap_linkdata *ld;
1472 	int ld_errno;
1473 
1474 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &link) != SUCCESS) {
1475 		return;
1476 	}
1477 
1478 	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
1479 
1480 	ld_errno = _get_lderrno(ld->link);
1481 
1482 	RETURN_STRING(ldap_err2string(ld_errno), 1);
1483 }
1484 /* }}} */
1485 
1486 /* {{{ proto bool ldap_compare(resource link, string dn, string attr, string value)
1487    Determine if an entry has a specific value for one of its attributes */
PHP_FUNCTION(ldap_compare)1488 PHP_FUNCTION(ldap_compare)
1489 {
1490 	zval *link;
1491 	char *dn, *attr, *value;
1492 	int dn_len, attr_len, value_len;
1493 	ldap_linkdata *ld;
1494 	int errno;
1495 
1496 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsss", &link, &dn, &dn_len, &attr, &attr_len, &value, &value_len) != SUCCESS) {
1497 		return;
1498 	}
1499 
1500 	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
1501 
1502 	errno = ldap_compare_s(ld->link, dn, attr, value);
1503 
1504 	switch (errno) {
1505 		case LDAP_COMPARE_TRUE:
1506 			RETURN_TRUE;
1507 			break;
1508 
1509 		case LDAP_COMPARE_FALSE:
1510 			RETURN_FALSE;
1511 			break;
1512 	}
1513 
1514 	php_error_docref(NULL TSRMLS_CC, E_WARNING, "Compare: %s", ldap_err2string(errno));
1515 	RETURN_LONG(-1);
1516 }
1517 /* }}} */
1518 
1519 /* {{{ proto bool ldap_sort(resource link, resource result, string sortfilter)
1520    Sort LDAP result entries */
PHP_FUNCTION(ldap_sort)1521 PHP_FUNCTION(ldap_sort)
1522 {
1523 	zval *link, *result;
1524 	ldap_linkdata *ld;
1525 	char *sortfilter;
1526 	int sflen;
1527 	zend_rsrc_list_entry *le;
1528 
1529 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rrs", &link, &result, &sortfilter, &sflen) != SUCCESS) {
1530 		RETURN_FALSE;
1531 	}
1532 
1533 	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
1534 
1535 	if (zend_hash_index_find(&EG(regular_list), Z_LVAL_P(result), (void **) &le) != SUCCESS || le->type != le_result) {
1536 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Supplied resource is not a valid ldap result resource");
1537 		RETURN_FALSE;
1538 	}
1539 
1540 	if (ldap_sort_entries(ld->link, (LDAPMessage **) &le->ptr, sflen ? sortfilter : NULL, strcmp) != LDAP_SUCCESS) {
1541 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", ldap_err2string(errno));
1542 		RETURN_FALSE;
1543 	}
1544 
1545 	RETURN_TRUE;
1546 }
1547 /* }}} */
1548 
1549 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10
1550 /* {{{ proto bool ldap_get_option(resource link, int option, mixed retval)
1551    Get the current value of various session-wide parameters */
PHP_FUNCTION(ldap_get_option)1552 PHP_FUNCTION(ldap_get_option)
1553 {
1554 	zval *link, *retval;
1555 	ldap_linkdata *ld;
1556 	long option;
1557 
1558 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlz", &link, &option, &retval) != SUCCESS) {
1559 		return;
1560 	}
1561 
1562 	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
1563 
1564 	switch (option) {
1565 	/* options with int value */
1566 	case LDAP_OPT_DEREF:
1567 	case LDAP_OPT_SIZELIMIT:
1568 	case LDAP_OPT_TIMELIMIT:
1569 	case LDAP_OPT_PROTOCOL_VERSION:
1570 	case LDAP_OPT_ERROR_NUMBER:
1571 	case LDAP_OPT_REFERRALS:
1572 #ifdef LDAP_OPT_RESTART
1573 	case LDAP_OPT_RESTART:
1574 #endif
1575 		{
1576 			int val;
1577 
1578 			if (ldap_get_option(ld->link, option, &val)) {
1579 				RETURN_FALSE;
1580 			}
1581 			zval_dtor(retval);
1582 			ZVAL_LONG(retval, val);
1583 		} break;
1584 #ifdef LDAP_OPT_NETWORK_TIMEOUT
1585 	case LDAP_OPT_NETWORK_TIMEOUT:
1586 		{
1587 			struct timeval *timeout = NULL;
1588 
1589 			if (ldap_get_option(ld->link, LDAP_OPT_NETWORK_TIMEOUT, (void *) &timeout)) {
1590 				if (timeout) {
1591 					ldap_memfree(timeout);
1592 				}
1593 				RETURN_FALSE;
1594 			}
1595 			if (!timeout) {
1596 				RETURN_FALSE;
1597 			}
1598 			zval_dtor(retval);
1599 			ZVAL_LONG(retval, timeout->tv_sec);
1600 			ldap_memfree(timeout);
1601 		} break;
1602 #elif defined(LDAP_X_OPT_CONNECT_TIMEOUT)
1603 	case LDAP_X_OPT_CONNECT_TIMEOUT:
1604 		{
1605 			int timeout;
1606 
1607 			if (ldap_get_option(ld->link, LDAP_X_OPT_CONNECT_TIMEOUT, &timeout)) {
1608 				RETURN_FALSE;
1609 			}
1610 			zval_dtor(retval);
1611 			ZVAL_LONG(retval, (timeout / 1000));
1612 		} break;
1613 #endif
1614 	/* options with string value */
1615 	case LDAP_OPT_ERROR_STRING:
1616 #ifdef LDAP_OPT_HOST_NAME
1617 	case LDAP_OPT_HOST_NAME:
1618 #endif
1619 #ifdef HAVE_LDAP_SASL
1620 	case LDAP_OPT_X_SASL_MECH:
1621 	case LDAP_OPT_X_SASL_REALM:
1622 	case LDAP_OPT_X_SASL_AUTHCID:
1623 	case LDAP_OPT_X_SASL_AUTHZID:
1624 #endif
1625 #ifdef LDAP_OPT_MATCHED_DN
1626 	case LDAP_OPT_MATCHED_DN:
1627 #endif
1628 		{
1629 			char *val = NULL;
1630 
1631 			if (ldap_get_option(ld->link, option, &val) || val == NULL || *val == '\0') {
1632 				if (val) {
1633 					ldap_memfree(val);
1634 				}
1635 				RETURN_FALSE;
1636 			}
1637 			zval_dtor(retval);
1638 			ZVAL_STRING(retval, val, 1);
1639 			ldap_memfree(val);
1640 		} break;
1641 /* options not implemented
1642 	case LDAP_OPT_SERVER_CONTROLS:
1643 	case LDAP_OPT_CLIENT_CONTROLS:
1644 	case LDAP_OPT_API_INFO:
1645 	case LDAP_OPT_API_FEATURE_INFO:
1646 */
1647 	default:
1648 		RETURN_FALSE;
1649 	}
1650 	RETURN_TRUE;
1651 }
1652 /* }}} */
1653 
1654 /* {{{ proto bool ldap_set_option(resource link, int option, mixed newval)
1655    Set the value of various session-wide parameters */
PHP_FUNCTION(ldap_set_option)1656 PHP_FUNCTION(ldap_set_option)
1657 {
1658 	zval *link, **newval;
1659 	ldap_linkdata *ld;
1660 	LDAP *ldap;
1661 	long option;
1662 
1663 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zlZ", &link, &option, &newval) != SUCCESS) {
1664 		return;
1665 	}
1666 
1667 	if (Z_TYPE_P(link) == IS_NULL) {
1668 		ldap = NULL;
1669 	} else {
1670 		ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
1671 		ldap = ld->link;
1672 	}
1673 
1674 	switch (option) {
1675 	/* options with int value */
1676 	case LDAP_OPT_DEREF:
1677 	case LDAP_OPT_SIZELIMIT:
1678 	case LDAP_OPT_TIMELIMIT:
1679 	case LDAP_OPT_PROTOCOL_VERSION:
1680 	case LDAP_OPT_ERROR_NUMBER:
1681 #ifdef LDAP_OPT_DEBUG_LEVEL
1682 	case LDAP_OPT_DEBUG_LEVEL:
1683 #endif
1684 		{
1685 			int val;
1686 
1687 			convert_to_long_ex(newval);
1688 			val = Z_LVAL_PP(newval);
1689 			if (ldap_set_option(ldap, option, &val)) {
1690 				RETURN_FALSE;
1691 			}
1692 		} break;
1693 #ifdef LDAP_OPT_NETWORK_TIMEOUT
1694 	case LDAP_OPT_NETWORK_TIMEOUT:
1695 		{
1696 			struct timeval timeout;
1697 
1698 			convert_to_long_ex(newval);
1699 			timeout.tv_sec = Z_LVAL_PP(newval);
1700 			timeout.tv_usec = 0;
1701 			if (ldap_set_option(ldap, LDAP_OPT_NETWORK_TIMEOUT, (void *) &timeout)) {
1702 				RETURN_FALSE;
1703 			}
1704 		} break;
1705 #elif defined(LDAP_X_OPT_CONNECT_TIMEOUT)
1706 	case LDAP_X_OPT_CONNECT_TIMEOUT:
1707 		{
1708 			int timeout;
1709 
1710 			convert_to_long_ex(newval);
1711 			timeout = 1000 * Z_LVAL_PP(newval); /* Convert to milliseconds */
1712 			if (ldap_set_option(ldap, LDAP_X_OPT_CONNECT_TIMEOUT, &timeout)) {
1713 				RETURN_FALSE;
1714 			}
1715 		} break;
1716 #endif
1717 		/* options with string value */
1718 	case LDAP_OPT_ERROR_STRING:
1719 #ifdef LDAP_OPT_HOST_NAME
1720 	case LDAP_OPT_HOST_NAME:
1721 #endif
1722 #ifdef HAVE_LDAP_SASL
1723 	case LDAP_OPT_X_SASL_MECH:
1724 	case LDAP_OPT_X_SASL_REALM:
1725 	case LDAP_OPT_X_SASL_AUTHCID:
1726 	case LDAP_OPT_X_SASL_AUTHZID:
1727 #endif
1728 #ifdef LDAP_OPT_MATCHED_DN
1729 	case LDAP_OPT_MATCHED_DN:
1730 #endif
1731 		{
1732 			char *val;
1733 			convert_to_string_ex(newval);
1734 			val = Z_STRVAL_PP(newval);
1735 			if (ldap_set_option(ldap, option, val)) {
1736 				RETURN_FALSE;
1737 			}
1738 		} break;
1739 		/* options with boolean value */
1740 	case LDAP_OPT_REFERRALS:
1741 #ifdef LDAP_OPT_RESTART
1742 	case LDAP_OPT_RESTART:
1743 #endif
1744 		{
1745 			void *val;
1746 			convert_to_boolean_ex(newval);
1747 			val = Z_LVAL_PP(newval)
1748 				? LDAP_OPT_ON : LDAP_OPT_OFF;
1749 			if (ldap_set_option(ldap, option, val)) {
1750 				RETURN_FALSE;
1751 			}
1752 		} break;
1753 		/* options with control list value */
1754 	case LDAP_OPT_SERVER_CONTROLS:
1755 	case LDAP_OPT_CLIENT_CONTROLS:
1756 		{
1757 			LDAPControl *ctrl, **ctrls, **ctrlp;
1758 			zval **ctrlval, **val;
1759 			int ncontrols;
1760 			char error=0;
1761 
1762 			if ((Z_TYPE_PP(newval) != IS_ARRAY) || !(ncontrols = zend_hash_num_elements(Z_ARRVAL_PP(newval)))) {
1763 				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected non-empty array value for this option");
1764 				RETURN_FALSE;
1765 			}
1766 			ctrls = safe_emalloc((1 + ncontrols), sizeof(*ctrls), 0);
1767 			*ctrls = NULL;
1768 			ctrlp = ctrls;
1769 			zend_hash_internal_pointer_reset(Z_ARRVAL_PP(newval));
1770 			while (zend_hash_get_current_data(Z_ARRVAL_PP(newval), (void**)&ctrlval) == SUCCESS) {
1771 				if (Z_TYPE_PP(ctrlval) != IS_ARRAY) {
1772 					php_error_docref(NULL TSRMLS_CC, E_WARNING, "The array value must contain only arrays, where each array is a control");
1773 					error = 1;
1774 					break;
1775 				}
1776 				if (zend_hash_find(Z_ARRVAL_PP(ctrlval), "oid", sizeof("oid"), (void **) &val) != SUCCESS) {
1777 					php_error_docref(NULL TSRMLS_CC, E_WARNING, "Control must have an oid key");
1778 					error = 1;
1779 					break;
1780 				}
1781 				ctrl = *ctrlp = emalloc(sizeof(**ctrlp));
1782 				convert_to_string_ex(val);
1783 				ctrl->ldctl_oid = Z_STRVAL_PP(val);
1784 				if (zend_hash_find(Z_ARRVAL_PP(ctrlval), "value", sizeof("value"), (void **) &val) == SUCCESS) {
1785 					convert_to_string_ex(val);
1786 					ctrl->ldctl_value.bv_val = Z_STRVAL_PP(val);
1787 					ctrl->ldctl_value.bv_len = Z_STRLEN_PP(val);
1788 				} else {
1789 					ctrl->ldctl_value.bv_val = NULL;
1790 					ctrl->ldctl_value.bv_len = 0;
1791 				}
1792 				if (zend_hash_find(Z_ARRVAL_PP(ctrlval), "iscritical", sizeof("iscritical"), (void **) &val) == SUCCESS) {
1793 					convert_to_boolean_ex(val);
1794 					ctrl->ldctl_iscritical = Z_BVAL_PP(val);
1795 				} else {
1796 					ctrl->ldctl_iscritical = 0;
1797 				}
1798 
1799 				++ctrlp;
1800 				*ctrlp = NULL;
1801 				zend_hash_move_forward(Z_ARRVAL_PP(newval));
1802 			}
1803 			if (!error) {
1804 				error = ldap_set_option(ldap, option, ctrls);
1805 			}
1806 			ctrlp = ctrls;
1807 			while (*ctrlp) {
1808 				efree(*ctrlp);
1809 				ctrlp++;
1810 			}
1811 			efree(ctrls);
1812 			if (error) {
1813 				RETURN_FALSE;
1814 			}
1815 		} break;
1816 	default:
1817 		RETURN_FALSE;
1818 	}
1819 	RETURN_TRUE;
1820 }
1821 /* }}} */
1822 
1823 #ifdef HAVE_LDAP_PARSE_RESULT
1824 /* {{{ proto bool ldap_parse_result(resource link, resource result, int errcode, string matcheddn, string errmsg, array referrals)
1825    Extract information from result */
PHP_FUNCTION(ldap_parse_result)1826 PHP_FUNCTION(ldap_parse_result)
1827 {
1828 	zval *link, *result, *errcode, *matcheddn, *errmsg, *referrals;
1829 	ldap_linkdata *ld;
1830 	LDAPMessage *ldap_result;
1831 	char **lreferrals, **refp;
1832 	char *lmatcheddn, *lerrmsg;
1833 	int rc, lerrcode, myargcount = ZEND_NUM_ARGS();
1834 
1835 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rrz|zzz", &link, &result, &errcode, &matcheddn, &errmsg, &referrals) != SUCCESS) {
1836 		return;
1837 	}
1838 
1839 	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
1840 	ZEND_FETCH_RESOURCE(ldap_result, LDAPMessage *, &result, -1, "ldap result", le_result);
1841 
1842 	rc = ldap_parse_result(ld->link, ldap_result, &lerrcode,
1843 				myargcount > 3 ? &lmatcheddn : NULL,
1844 				myargcount > 4 ? &lerrmsg : NULL,
1845 				myargcount > 5 ? &lreferrals : NULL,
1846 				NULL /* &serverctrls */,
1847 				0);
1848 	if (rc != LDAP_SUCCESS) {
1849 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to parse result: %s", ldap_err2string(rc));
1850 		RETURN_FALSE;
1851 	}
1852 
1853 	zval_dtor(errcode);
1854 	ZVAL_LONG(errcode, lerrcode);
1855 
1856 	/* Reverse -> fall through */
1857 	switch (myargcount) {
1858 		case 6:
1859 			zval_dtor(referrals);
1860 			array_init(referrals);
1861 			if (lreferrals != NULL) {
1862 				refp = lreferrals;
1863 				while (*refp) {
1864 					add_next_index_string(referrals, *refp, 1);
1865 					refp++;
1866 				}
1867 				ldap_value_free(lreferrals);
1868 			}
1869 		case 5:
1870 			zval_dtor(errmsg);
1871 			if (lerrmsg == NULL) {
1872 				ZVAL_EMPTY_STRING(errmsg);
1873 			} else {
1874 				ZVAL_STRING(errmsg, lerrmsg, 1);
1875 				ldap_memfree(lerrmsg);
1876 			}
1877 		case 4:
1878 			zval_dtor(matcheddn);
1879 			if (lmatcheddn == NULL) {
1880 				ZVAL_EMPTY_STRING(matcheddn);
1881 			} else {
1882 				ZVAL_STRING(matcheddn, lmatcheddn, 1);
1883 				ldap_memfree(lmatcheddn);
1884 			}
1885 	}
1886 	RETURN_TRUE;
1887 }
1888 /* }}} */
1889 #endif
1890 
1891 /* {{{ proto resource ldap_first_reference(resource link, resource result)
1892    Return first reference */
PHP_FUNCTION(ldap_first_reference)1893 PHP_FUNCTION(ldap_first_reference)
1894 {
1895 	zval *link, *result;
1896 	ldap_linkdata *ld;
1897 	ldap_resultentry *resultentry;
1898 	LDAPMessage *ldap_result, *entry;
1899 
1900 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &link, &result) != SUCCESS) {
1901 		return;
1902 	}
1903 
1904 	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
1905 	ZEND_FETCH_RESOURCE(ldap_result, LDAPMessage *, &result, -1, "ldap result", le_result);
1906 
1907 	if ((entry = ldap_first_reference(ld->link, ldap_result)) == NULL) {
1908 		RETVAL_FALSE;
1909 	} else {
1910 		resultentry = emalloc(sizeof(ldap_resultentry));
1911 		ZEND_REGISTER_RESOURCE(return_value, resultentry, le_result_entry);
1912 		resultentry->id = Z_LVAL_P(result);
1913 		zend_list_addref(resultentry->id);
1914 		resultentry->data = entry;
1915 		resultentry->ber = NULL;
1916 	}
1917 }
1918 /* }}} */
1919 
1920 /* {{{ proto resource ldap_next_reference(resource link, resource reference_entry)
1921    Get next reference */
PHP_FUNCTION(ldap_next_reference)1922 PHP_FUNCTION(ldap_next_reference)
1923 {
1924 	zval *link, *result_entry;
1925 	ldap_linkdata *ld;
1926 	ldap_resultentry *resultentry, *resultentry_next;
1927 	LDAPMessage *entry_next;
1928 
1929 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &link, &result_entry) != SUCCESS) {
1930 		return;
1931 	}
1932 
1933 	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
1934 	ZEND_FETCH_RESOURCE(resultentry, ldap_resultentry *, &result_entry, -1, "ldap result entry", le_result_entry);
1935 
1936 	if ((entry_next = ldap_next_reference(ld->link, resultentry->data)) == NULL) {
1937 		RETVAL_FALSE;
1938 	} else {
1939 		resultentry_next = emalloc(sizeof(ldap_resultentry));
1940 		ZEND_REGISTER_RESOURCE(return_value, resultentry_next, le_result_entry);
1941 		resultentry_next->id = resultentry->id;
1942 		zend_list_addref(resultentry->id);
1943 		resultentry_next->data = entry_next;
1944 		resultentry_next->ber = NULL;
1945 	}
1946 }
1947 /* }}} */
1948 
1949 #ifdef HAVE_LDAP_PARSE_REFERENCE
1950 /* {{{ proto bool ldap_parse_reference(resource link, resource reference_entry, array referrals)
1951    Extract information from reference entry */
PHP_FUNCTION(ldap_parse_reference)1952 PHP_FUNCTION(ldap_parse_reference)
1953 {
1954 	zval *link, *result_entry, *referrals;
1955 	ldap_linkdata *ld;
1956 	ldap_resultentry *resultentry;
1957 	char **lreferrals, **refp;
1958 
1959 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rrz", &link, &result_entry, &referrals) != SUCCESS) {
1960 		return;
1961 	}
1962 
1963 	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
1964 	ZEND_FETCH_RESOURCE(resultentry, ldap_resultentry *, &result_entry, -1, "ldap result entry", le_result_entry);
1965 
1966 	if (ldap_parse_reference(ld->link, resultentry->data, &lreferrals, NULL /* &serverctrls */, 0) != LDAP_SUCCESS) {
1967 		RETURN_FALSE;
1968 	}
1969 
1970 	zval_dtor(referrals);
1971 	array_init(referrals);
1972 	if (lreferrals != NULL) {
1973 		refp = lreferrals;
1974 		while (*refp) {
1975 			add_next_index_string(referrals, *refp, 1);
1976 			refp++;
1977 		}
1978 		ldap_value_free(lreferrals);
1979 	}
1980 	RETURN_TRUE;
1981 }
1982 /* }}} */
1983 #endif
1984 
1985 /* {{{ proto bool ldap_rename(resource link, string dn, string newrdn, string newparent, bool deleteoldrdn);
1986    Modify the name of an entry */
PHP_FUNCTION(ldap_rename)1987 PHP_FUNCTION(ldap_rename)
1988 {
1989 	zval *link;
1990 	ldap_linkdata *ld;
1991 	int rc;
1992 	char *dn, *newrdn, *newparent;
1993 	int dn_len, newrdn_len, newparent_len;
1994 	zend_bool deleteoldrdn;
1995 
1996 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsssb", &link, &dn, &dn_len, &newrdn, &newrdn_len, &newparent, &newparent_len, &deleteoldrdn) != SUCCESS) {
1997 		return;
1998 	}
1999 
2000 	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
2001 
2002 	if (newparent_len == 0) {
2003 		newparent = NULL;
2004 	}
2005 
2006 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10
2007 	rc = ldap_rename_s(ld->link, dn, newrdn, newparent, deleteoldrdn, NULL, NULL);
2008 #else
2009 	if (newparent_len != 0) {
2010 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "You are using old LDAP API, newparent must be the empty string, can only modify RDN");
2011 		RETURN_FALSE;
2012 	}
2013 /* could support old APIs but need check for ldap_modrdn2()/ldap_modrdn() */
2014 	rc = ldap_modrdn2_s(ld->link, dn, newrdn, deleteoldrdn);
2015 #endif
2016 
2017 	if (rc == LDAP_SUCCESS) {
2018 		RETURN_TRUE;
2019 	}
2020 	RETURN_FALSE;
2021 }
2022 /* }}} */
2023 
2024 #ifdef HAVE_LDAP_START_TLS_S
2025 /* {{{ proto bool ldap_start_tls(resource link)
2026    Start TLS */
PHP_FUNCTION(ldap_start_tls)2027 PHP_FUNCTION(ldap_start_tls)
2028 {
2029 	zval *link;
2030 	ldap_linkdata *ld;
2031 	int rc, protocol = LDAP_VERSION3;
2032 
2033 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &link) != SUCCESS) {
2034 		return;
2035 	}
2036 
2037 	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
2038 
2039 	if (((rc = ldap_set_option(ld->link, LDAP_OPT_PROTOCOL_VERSION, &protocol)) != LDAP_SUCCESS) ||
2040 		((rc = ldap_start_tls_s(ld->link, NULL, NULL)) != LDAP_SUCCESS)
2041 	) {
2042 		php_error_docref(NULL TSRMLS_CC, E_WARNING,"Unable to start TLS: %s", ldap_err2string(rc));
2043 		RETURN_FALSE;
2044 	} else {
2045 		RETURN_TRUE;
2046 	}
2047 }
2048 /* }}} */
2049 #endif
2050 #endif /* (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10 */
2051 
2052 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)
2053 /* {{{ _ldap_rebind_proc()
2054 */
_ldap_rebind_proc(LDAP * ldap,const char * url,ber_tag_t req,ber_int_t msgid,void * params)2055 int _ldap_rebind_proc(LDAP *ldap, const char *url, ber_tag_t req, ber_int_t msgid, void *params)
2056 {
2057 	ldap_linkdata *ld;
2058 	int retval;
2059 	zval *cb_url;
2060 	zval **cb_args[2];
2061 	zval *cb_retval;
2062 	zval *cb_link = (zval *) params;
2063 	TSRMLS_FETCH();
2064 
2065 	ld = (ldap_linkdata *) zend_fetch_resource(&cb_link TSRMLS_CC, -1, "ldap link", NULL, 1, le_link);
2066 
2067 	/* link exists and callback set? */
2068 	if (ld == NULL || ld->rebindproc == NULL) {
2069 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Link not found or no callback set");
2070 		return LDAP_OTHER;
2071 	}
2072 
2073 	/* callback */
2074 	MAKE_STD_ZVAL(cb_url);
2075 	ZVAL_STRING(cb_url, estrdup(url), 0);
2076 	cb_args[0] = &cb_link;
2077 	cb_args[1] = &cb_url;
2078 	if (call_user_function_ex(EG(function_table), NULL, ld->rebindproc, &cb_retval, 2, cb_args, 0, NULL TSRMLS_CC) == SUCCESS && cb_retval) {
2079 		convert_to_long_ex(&cb_retval);
2080 		retval = Z_LVAL_P(cb_retval);
2081 		zval_ptr_dtor(&cb_retval);
2082 	} else {
2083 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "rebind_proc PHP callback failed");
2084 		retval = LDAP_OTHER;
2085 	}
2086 	zval_dtor(cb_url);
2087 	FREE_ZVAL(cb_url);
2088 	return retval;
2089 }
2090 /* }}} */
2091 
2092 /* {{{ proto bool ldap_set_rebind_proc(resource link, string callback)
2093    Set a callback function to do re-binds on referral chasing. */
PHP_FUNCTION(ldap_set_rebind_proc)2094 PHP_FUNCTION(ldap_set_rebind_proc)
2095 {
2096 	zval *link, *callback;
2097 	ldap_linkdata *ld;
2098 	char *callback_name;
2099 
2100 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz", &link, &callback) != SUCCESS) {
2101 		RETURN_FALSE;
2102 	}
2103 
2104 	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
2105 
2106 	if (Z_TYPE_P(callback) == IS_STRING && Z_STRLEN_P(callback) == 0) {
2107 		/* unregister rebind procedure */
2108 		if (ld->rebindproc != NULL) {
2109 			zval_dtor(ld->rebindproc);
2110 			ld->rebindproc = NULL;
2111 			ldap_set_rebind_proc(ld->link, NULL, NULL);
2112 		}
2113 		RETURN_TRUE;
2114 	}
2115 
2116 	/* callable? */
2117 	if (!zend_is_callable(callback, 0, &callback_name TSRMLS_CC)) {
2118 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Two arguments expected for '%s' to be a valid callback", callback_name);
2119 		efree(callback_name);
2120 		RETURN_FALSE;
2121 	}
2122 	efree(callback_name);
2123 
2124 	/* register rebind procedure */
2125 	if (ld->rebindproc == NULL) {
2126 		ldap_set_rebind_proc(ld->link, _ldap_rebind_proc, (void *) link);
2127 	} else {
2128 		zval_dtor(ld->rebindproc);
2129 	}
2130 
2131 	ALLOC_ZVAL(ld->rebindproc);
2132 	*ld->rebindproc = *callback;
2133 	zval_copy_ctor(ld->rebindproc);
2134 	RETURN_TRUE;
2135 }
2136 /* }}} */
2137 #endif
2138 
2139 #ifdef STR_TRANSLATION
2140 /* {{{ php_ldap_do_translate
2141  */
php_ldap_do_translate(INTERNAL_FUNCTION_PARAMETERS,int way)2142 static void php_ldap_do_translate(INTERNAL_FUNCTION_PARAMETERS, int way)
2143 {
2144 	char *value;
2145 	int result, ldap_len;
2146 
2147 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &value, &value_len) != SUCCESS) {
2148 		return;
2149 	}
2150 
2151 	if (value_len == 0) {
2152 		RETURN_FALSE;
2153 	}
2154 
2155 	if (way == 1) {
2156 		result = ldap_8859_to_t61(&value, &value_len, 0);
2157 	} else {
2158 		result = ldap_t61_to_8859(&value, &value_len, 0);
2159 	}
2160 
2161 	if (result == LDAP_SUCCESS) {
2162 		RETVAL_STRINGL(value, value_len, 1);
2163 		free(value);
2164 	} else {
2165 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Conversion from iso-8859-1 to t61 failed: %s", ldap_err2string(result));
2166 		RETVAL_FALSE;
2167 	}
2168 }
2169 /* }}} */
2170 
2171 /* {{{ proto string ldap_t61_to_8859(string value)
2172    Translate t61 characters to 8859 characters */
PHP_FUNCTION(ldap_t61_to_8859)2173 PHP_FUNCTION(ldap_t61_to_8859)
2174 {
2175 	php_ldap_do_translate(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
2176 }
2177 /* }}} */
2178 
2179 /* {{{ proto string ldap_8859_to_t61(string value)
2180    Translate 8859 characters to t61 characters */
PHP_FUNCTION(ldap_8859_to_t61)2181 PHP_FUNCTION(ldap_8859_to_t61)
2182 {
2183 	php_ldap_do_translate(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
2184 }
2185 /* }}} */
2186 #endif
2187 
2188 /* {{{ arginfo */
2189 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_connect, 0, 0, 0)
2190 	ZEND_ARG_INFO(0, hostname)
2191 	ZEND_ARG_INFO(0, port)
2192 #ifdef HAVE_ORALDAP
2193 	ZEND_ARG_INFO(0, wallet)
2194 	ZEND_ARG_INFO(0, wallet_passwd)
2195 	ZEND_ARG_INFO(0, authmode)
2196 #endif
2197 ZEND_END_ARG_INFO()
2198 
2199 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_resource, 0, 0, 1)
2200 	ZEND_ARG_INFO(0, link_identifier)
2201 ZEND_END_ARG_INFO()
2202 
2203 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_bind, 0, 0, 1)
2204 	ZEND_ARG_INFO(0, link_identifier)
2205 	ZEND_ARG_INFO(0, bind_rdn)
2206 	ZEND_ARG_INFO(0, bind_password)
2207 ZEND_END_ARG_INFO()
2208 
2209 #ifdef HAVE_LDAP_SASL
2210 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_sasl_bind, 0, 0, 1)
2211 	ZEND_ARG_INFO(0, link)
2212 	ZEND_ARG_INFO(0, binddn)
2213 	ZEND_ARG_INFO(0, password)
2214 	ZEND_ARG_INFO(0, sasl_mech)
2215 	ZEND_ARG_INFO(0, sasl_realm)
2216 	ZEND_ARG_INFO(0, sasl_authz_id)
2217 	ZEND_ARG_INFO(0, props)
2218 ZEND_END_ARG_INFO()
2219 #endif
2220 
2221 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_read, 0, 0, 3)
2222 	ZEND_ARG_INFO(0, link_identifier)
2223 	ZEND_ARG_INFO(0, base_dn)
2224 	ZEND_ARG_INFO(0, filter)
2225 	ZEND_ARG_INFO(0, attributes)
2226 	ZEND_ARG_INFO(0, attrsonly)
2227 	ZEND_ARG_INFO(0, sizelimit)
2228 	ZEND_ARG_INFO(0, timelimit)
2229 	ZEND_ARG_INFO(0, deref)
2230 ZEND_END_ARG_INFO()
2231 
2232 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_list, 0, 0, 3)
2233 	ZEND_ARG_INFO(0, link_identifier)
2234 	ZEND_ARG_INFO(0, base_dn)
2235 	ZEND_ARG_INFO(0, filter)
2236 	ZEND_ARG_INFO(0, attributes)
2237 	ZEND_ARG_INFO(0, attrsonly)
2238 	ZEND_ARG_INFO(0, sizelimit)
2239 	ZEND_ARG_INFO(0, timelimit)
2240 	ZEND_ARG_INFO(0, deref)
2241 ZEND_END_ARG_INFO()
2242 
2243 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_search, 0, 0, 3)
2244 	ZEND_ARG_INFO(0, link_identifier)
2245 	ZEND_ARG_INFO(0, base_dn)
2246 	ZEND_ARG_INFO(0, filter)
2247 	ZEND_ARG_INFO(0, attributes)
2248 	ZEND_ARG_INFO(0, attrsonly)
2249 	ZEND_ARG_INFO(0, sizelimit)
2250 	ZEND_ARG_INFO(0, timelimit)
2251 	ZEND_ARG_INFO(0, deref)
2252 ZEND_END_ARG_INFO()
2253 
2254 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_count_entries, 0, 0, 2)
2255 	ZEND_ARG_INFO(0, link_identifier)
2256 	ZEND_ARG_INFO(0, result_identifier)
2257 ZEND_END_ARG_INFO()
2258 
2259 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_first_entry, 0, 0, 2)
2260 	ZEND_ARG_INFO(0, link_identifier)
2261 	ZEND_ARG_INFO(0, result_identifier)
2262 ZEND_END_ARG_INFO()
2263 
2264 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_next_entry, 0, 0, 2)
2265 	ZEND_ARG_INFO(0, link_identifier)
2266 	ZEND_ARG_INFO(0, result_identifier)
2267 ZEND_END_ARG_INFO()
2268 
2269 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_get_entries, 0, 0, 2)
2270 	ZEND_ARG_INFO(0, link_identifier)
2271 	ZEND_ARG_INFO(0, result_identifier)
2272 ZEND_END_ARG_INFO()
2273 
2274 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_first_attribute, 0, 0, 2)
2275 	ZEND_ARG_INFO(0, link_identifier)
2276 	ZEND_ARG_INFO(0, result_entry_identifier)
2277 ZEND_END_ARG_INFO()
2278 
2279 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_next_attribute, 0, 0, 2)
2280 	ZEND_ARG_INFO(0, link_identifier)
2281 	ZEND_ARG_INFO(0, result_entry_identifier)
2282 ZEND_END_ARG_INFO()
2283 
2284 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_get_attributes, 0, 0, 2)
2285 	ZEND_ARG_INFO(0, link_identifier)
2286 	ZEND_ARG_INFO(0, result_entry_identifier)
2287 ZEND_END_ARG_INFO()
2288 
2289 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_get_values, 0, 0, 3)
2290 	ZEND_ARG_INFO(0, link_identifier)
2291 	ZEND_ARG_INFO(0, result_entry_identifier)
2292 	ZEND_ARG_INFO(0, attribute)
2293 ZEND_END_ARG_INFO()
2294 
2295 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_get_values_len, 0, 0, 3)
2296 	ZEND_ARG_INFO(0, link_identifier)
2297 	ZEND_ARG_INFO(0, result_entry_identifier)
2298 	ZEND_ARG_INFO(0, attribute)
2299 ZEND_END_ARG_INFO()
2300 
2301 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_get_dn, 0, 0, 2)
2302 	ZEND_ARG_INFO(0, link_identifier)
2303 	ZEND_ARG_INFO(0, result_entry_identifier)
2304 ZEND_END_ARG_INFO()
2305 
2306 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_explode_dn, 0, 0, 2)
2307 	ZEND_ARG_INFO(0, dn)
2308 	ZEND_ARG_INFO(0, with_attrib)
2309 ZEND_END_ARG_INFO()
2310 
2311 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_dn2ufn, 0, 0, 1)
2312 	ZEND_ARG_INFO(0, dn)
2313 ZEND_END_ARG_INFO()
2314 
2315 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_add, 0, 0, 3)
2316 	ZEND_ARG_INFO(0, link_identifier)
2317 	ZEND_ARG_INFO(0, dn)
2318 	ZEND_ARG_INFO(0, entry)
2319 ZEND_END_ARG_INFO()
2320 
2321 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_delete, 0, 0, 2)
2322 	ZEND_ARG_INFO(0, link_identifier)
2323 	ZEND_ARG_INFO(0, dn)
2324 ZEND_END_ARG_INFO()
2325 
2326 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_modify, 0, 0, 3)
2327 	ZEND_ARG_INFO(0, link_identifier)
2328 	ZEND_ARG_INFO(0, dn)
2329 	ZEND_ARG_INFO(0, entry)
2330 ZEND_END_ARG_INFO()
2331 
2332 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_mod_add, 0, 0, 3)
2333 	ZEND_ARG_INFO(0, link_identifier)
2334 	ZEND_ARG_INFO(0, dn)
2335 	ZEND_ARG_INFO(0, entry)
2336 ZEND_END_ARG_INFO()
2337 
2338 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_mod_replace, 0, 0, 3)
2339 	ZEND_ARG_INFO(0, link_identifier)
2340 	ZEND_ARG_INFO(0, dn)
2341 	ZEND_ARG_INFO(0, entry)
2342 ZEND_END_ARG_INFO()
2343 
2344 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_mod_del, 0, 0, 3)
2345 	ZEND_ARG_INFO(0, link_identifier)
2346 	ZEND_ARG_INFO(0, dn)
2347 	ZEND_ARG_INFO(0, entry)
2348 ZEND_END_ARG_INFO()
2349 
2350 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_err2str, 0, 0, 1)
2351 	ZEND_ARG_INFO(0, errno)
2352 ZEND_END_ARG_INFO()
2353 
2354 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_compare, 0, 0, 4)
2355 	ZEND_ARG_INFO(0, link_identifier)
2356 	ZEND_ARG_INFO(0, dn)
2357 	ZEND_ARG_INFO(0, attribute)
2358 	ZEND_ARG_INFO(0, value)
2359 ZEND_END_ARG_INFO()
2360 
2361 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_sort, 0, 0, 3)
2362 	ZEND_ARG_INFO(0, link)
2363 	ZEND_ARG_INFO(0, result)
2364 	ZEND_ARG_INFO(0, sortfilter)
2365 ZEND_END_ARG_INFO()
2366 
2367 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10
2368 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_rename, 0, 0, 5)
2369 	ZEND_ARG_INFO(0, link_identifier)
2370 	ZEND_ARG_INFO(0, dn)
2371 	ZEND_ARG_INFO(0, newrdn)
2372 	ZEND_ARG_INFO(0, newparent)
2373 	ZEND_ARG_INFO(0, deleteoldrdn)
2374 ZEND_END_ARG_INFO()
2375 
2376 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_get_option, 0, 0, 3)
2377 	ZEND_ARG_INFO(0, link_identifier)
2378 	ZEND_ARG_INFO(0, option)
2379 	ZEND_ARG_INFO(1, retval)
2380 ZEND_END_ARG_INFO()
2381 
2382 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_set_option, 0, 0, 3)
2383 	ZEND_ARG_INFO(0, link_identifier)
2384 	ZEND_ARG_INFO(0, option)
2385 	ZEND_ARG_INFO(0, newval)
2386 ZEND_END_ARG_INFO()
2387 
2388 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_first_reference, 0, 0, 2)
2389 	ZEND_ARG_INFO(0, link)
2390 	ZEND_ARG_INFO(0, result)
2391 ZEND_END_ARG_INFO()
2392 
2393 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_next_reference, 0, 0, 2)
2394 	ZEND_ARG_INFO(0, link)
2395 	ZEND_ARG_INFO(0, entry)
2396 ZEND_END_ARG_INFO()
2397 
2398 #ifdef HAVE_LDAP_PARSE_REFERENCE
2399 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_parse_reference, 0, 0, 3)
2400 	ZEND_ARG_INFO(0, link)
2401 	ZEND_ARG_INFO(0, entry)
2402 	ZEND_ARG_INFO(1, referrals)
2403 ZEND_END_ARG_INFO()
2404 #endif
2405 
2406 
2407 #ifdef HAVE_LDAP_PARSE_RESULT
2408 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_parse_result, 0, 0, 3)
2409 	ZEND_ARG_INFO(0, link)
2410 	ZEND_ARG_INFO(0, result)
2411 	ZEND_ARG_INFO(1, errcode)
2412 	ZEND_ARG_INFO(1, matcheddn)
2413 	ZEND_ARG_INFO(1, errmsg)
2414 	ZEND_ARG_INFO(1, referrals)
2415 ZEND_END_ARG_INFO()
2416 #endif
2417 #endif
2418 
2419 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)
2420 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_set_rebind_proc, 0, 0, 2)
2421 	ZEND_ARG_INFO(0, link)
2422 	ZEND_ARG_INFO(0, callback)
2423 ZEND_END_ARG_INFO()
2424 #endif
2425 
2426 #ifdef STR_TRANSLATION
2427 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_t61_to_8859, 0, 0, 1)
2428 	ZEND_ARG_INFO(0, value)
2429 ZEND_END_ARG_INFO()
2430 
2431 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_8859_to_t61, 0, 0, 1)
2432 	ZEND_ARG_INFO(0, value)
2433 ZEND_END_ARG_INFO()
2434 #endif
2435 /* }}} */
2436 
2437 /*
2438 	This is just a small subset of the functionality provided by the LDAP library. All the
2439 	operations are synchronous. Referrals are not handled automatically.
2440 */
2441 /* {{{ ldap_functions[]
2442  */
2443 const zend_function_entry ldap_functions[] = {
2444 	PHP_FE(ldap_connect,								arginfo_ldap_connect)
2445 	PHP_FALIAS(ldap_close,		ldap_unbind,			arginfo_ldap_resource)
2446 	PHP_FE(ldap_bind,									arginfo_ldap_bind)
2447 #ifdef HAVE_LDAP_SASL
2448 	PHP_FE(ldap_sasl_bind,								arginfo_ldap_sasl_bind)
2449 #endif
2450 	PHP_FE(ldap_unbind,									arginfo_ldap_resource)
2451 	PHP_FE(ldap_read,									arginfo_ldap_read)
2452 	PHP_FE(ldap_list,									arginfo_ldap_list)
2453 	PHP_FE(ldap_search,									arginfo_ldap_search)
2454 	PHP_FE(ldap_free_result,							arginfo_ldap_resource)
2455 	PHP_FE(ldap_count_entries,							arginfo_ldap_count_entries)
2456 	PHP_FE(ldap_first_entry,							arginfo_ldap_first_entry)
2457 	PHP_FE(ldap_next_entry,								arginfo_ldap_next_entry)
2458 	PHP_FE(ldap_get_entries,							arginfo_ldap_get_entries)
2459 	PHP_FE(ldap_first_attribute,						arginfo_ldap_first_attribute)
2460 	PHP_FE(ldap_next_attribute,							arginfo_ldap_next_attribute)
2461 	PHP_FE(ldap_get_attributes,							arginfo_ldap_get_attributes)
2462 	PHP_FALIAS(ldap_get_values,	ldap_get_values_len,	arginfo_ldap_get_values)
2463 	PHP_FE(ldap_get_values_len,							arginfo_ldap_get_values_len)
2464 	PHP_FE(ldap_get_dn,									arginfo_ldap_get_dn)
2465 	PHP_FE(ldap_explode_dn,								arginfo_ldap_explode_dn)
2466 	PHP_FE(ldap_dn2ufn,									arginfo_ldap_dn2ufn)
2467 	PHP_FE(ldap_add,									arginfo_ldap_add)
2468 	PHP_FE(ldap_delete,									arginfo_ldap_delete)
2469 	PHP_FALIAS(ldap_modify,		ldap_mod_replace,		arginfo_ldap_modify)
2470 
2471 /* additional functions for attribute based modifications, Gerrit Thomson */
2472 	PHP_FE(ldap_mod_add,								arginfo_ldap_mod_add)
2473 	PHP_FE(ldap_mod_replace,							arginfo_ldap_mod_replace)
2474 	PHP_FE(ldap_mod_del,								arginfo_ldap_mod_del)
2475 /* end gjt mod */
2476 
2477 	PHP_FE(ldap_errno,									arginfo_ldap_resource)
2478 	PHP_FE(ldap_err2str,								arginfo_ldap_err2str)
2479 	PHP_FE(ldap_error,									arginfo_ldap_resource)
2480 	PHP_FE(ldap_compare,								arginfo_ldap_compare)
2481 	PHP_FE(ldap_sort,									arginfo_ldap_sort)
2482 
2483 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10
2484 	PHP_FE(ldap_rename,									arginfo_ldap_rename)
2485 	PHP_FE(ldap_get_option,								arginfo_ldap_get_option)
2486 	PHP_FE(ldap_set_option,								arginfo_ldap_set_option)
2487 	PHP_FE(ldap_first_reference,						arginfo_ldap_first_reference)
2488 	PHP_FE(ldap_next_reference,							arginfo_ldap_next_reference)
2489 #ifdef HAVE_LDAP_PARSE_REFERENCE
2490 	PHP_FE(ldap_parse_reference,						arginfo_ldap_parse_reference)
2491 #endif
2492 #ifdef HAVE_LDAP_PARSE_RESULT
2493 	PHP_FE(ldap_parse_result,							arginfo_ldap_parse_result)
2494 #endif
2495 #ifdef HAVE_LDAP_START_TLS_S
2496 	PHP_FE(ldap_start_tls,								arginfo_ldap_resource)
2497 #endif
2498 #endif
2499 
2500 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)
2501 	PHP_FE(ldap_set_rebind_proc,						arginfo_ldap_set_rebind_proc)
2502 #endif
2503 
2504 #ifdef STR_TRANSLATION
2505 	PHP_FE(ldap_t61_to_8859,							arginfo_ldap_t61_to_8859)
2506 	PHP_FE(ldap_8859_to_t61,							arginfo_ldap_8859_to_t61)
2507 #endif
2508 
2509 	PHP_FE_END
2510 };
2511 /* }}} */
2512 
2513 zend_module_entry ldap_module_entry = { /* {{{ */
2514 	STANDARD_MODULE_HEADER,
2515 	"ldap",
2516 	ldap_functions,
2517 	PHP_MINIT(ldap),
2518 	PHP_MSHUTDOWN(ldap),
2519 	NULL,
2520 	NULL,
2521 	PHP_MINFO(ldap),
2522 	NO_VERSION_YET,
2523 	PHP_MODULE_GLOBALS(ldap),
2524 	PHP_GINIT(ldap),
2525 	NULL,
2526 	NULL,
2527 	STANDARD_MODULE_PROPERTIES_EX
2528 };
2529 /* }}} */
2530 
2531 /*
2532  * Local variables:
2533  * tab-width: 4
2534  * c-basic-offset: 4
2535  * End:
2536  * vim600: sw=4 ts=4 fdm=marker
2537  * vim<600: sw=4 ts=4
2538  */
2539