xref: /PHP-7.1/ext/ldap/ldap.c (revision 49782c54)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2018 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: 5f1913de8e05a346da913956f81e0c0d8991c7cb $ */
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 #define PHP_LDAP_ESCAPE_FILTER 0x01
71 #define PHP_LDAP_ESCAPE_DN     0x02
72 
73 #if defined(LDAP_CONTROL_PAGEDRESULTS) && !defined(HAVE_LDAP_CONTROL_FIND)
ldap_control_find(const char * oid,LDAPControl ** ctrls,LDAPControl *** nextctrlp)74 LDAPControl *ldap_control_find( const char *oid, LDAPControl **ctrls, LDAPControl ***nextctrlp)
75 {
76 	assert(nextctrlp == NULL);
77 	return ldap_find_control(oid, ctrls);
78 }
79 #endif
80 
81 #if !defined(LDAP_API_FEATURE_X_OPENLDAP)
ldap_memvfree(void ** v)82 void ldap_memvfree(void **v)
83 {
84 	ldap_value_free((char **)v);
85 }
86 #endif
87 
88 typedef struct {
89 	LDAP *link;
90 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)
91 	zval rebindproc;
92 #endif
93 } ldap_linkdata;
94 
95 typedef struct {
96 	LDAPMessage *data;
97 	BerElement  *ber;
98 	zval         res;
99 } ldap_resultentry;
100 
101 ZEND_DECLARE_MODULE_GLOBALS(ldap)
102 static PHP_GINIT_FUNCTION(ldap);
103 
104 static int le_link, le_result, le_result_entry;
105 
106 #ifdef COMPILE_DL_LDAP
ZEND_GET_MODULE(ldap)107 ZEND_GET_MODULE(ldap)
108 #endif
109 
110 static void _close_ldap_link(zend_resource *rsrc) /* {{{ */
111 {
112 	ldap_linkdata *ld = (ldap_linkdata *)rsrc->ptr;
113 
114 	ldap_unbind_ext(ld->link, NULL, NULL);
115 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)
116 	zval_ptr_dtor(&ld->rebindproc);
117 #endif
118 
119 	efree(ld);
120 	LDAPG(num_links)--;
121 }
122 /* }}} */
123 
_free_ldap_result(zend_resource * rsrc)124 static void _free_ldap_result(zend_resource *rsrc) /* {{{ */
125 {
126 	LDAPMessage *result = (LDAPMessage *)rsrc->ptr;
127 	ldap_msgfree(result);
128 }
129 /* }}} */
130 
_free_ldap_result_entry(zend_resource * rsrc)131 static void _free_ldap_result_entry(zend_resource *rsrc) /* {{{ */
132 {
133 	ldap_resultentry *entry = (ldap_resultentry *)rsrc->ptr;
134 
135 	if (entry->ber != NULL) {
136 		ber_free(entry->ber, 0);
137 		entry->ber = NULL;
138 	}
139 	zval_ptr_dtor(&entry->res);
140 	efree(entry);
141 }
142 /* }}} */
143 
144 /* {{{ PHP_INI_BEGIN
145  */
146 PHP_INI_BEGIN()
147 	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()148 PHP_INI_END()
149 /* }}} */
150 
151 /* {{{ PHP_GINIT_FUNCTION
152  */
153 static PHP_GINIT_FUNCTION(ldap)
154 {
155 	ldap_globals->num_links = 0;
156 }
157 /* }}} */
158 
159 /* {{{ PHP_MINIT_FUNCTION
160  */
PHP_MINIT_FUNCTION(ldap)161 PHP_MINIT_FUNCTION(ldap)
162 {
163 	REGISTER_INI_ENTRIES();
164 
165 	/* Constants to be used with deref-parameter in php_ldap_do_search() */
166 	REGISTER_LONG_CONSTANT("LDAP_DEREF_NEVER", LDAP_DEREF_NEVER, CONST_PERSISTENT | CONST_CS);
167 	REGISTER_LONG_CONSTANT("LDAP_DEREF_SEARCHING", LDAP_DEREF_SEARCHING, CONST_PERSISTENT | CONST_CS);
168 	REGISTER_LONG_CONSTANT("LDAP_DEREF_FINDING", LDAP_DEREF_FINDING, CONST_PERSISTENT | CONST_CS);
169 	REGISTER_LONG_CONSTANT("LDAP_DEREF_ALWAYS", LDAP_DEREF_ALWAYS, CONST_PERSISTENT | CONST_CS);
170 
171 	/* Constants to be used with ldap_modify_batch() */
172 	REGISTER_LONG_CONSTANT("LDAP_MODIFY_BATCH_ADD", LDAP_MODIFY_BATCH_ADD, CONST_PERSISTENT | CONST_CS);
173 	REGISTER_LONG_CONSTANT("LDAP_MODIFY_BATCH_REMOVE", LDAP_MODIFY_BATCH_REMOVE, CONST_PERSISTENT | CONST_CS);
174 	REGISTER_LONG_CONSTANT("LDAP_MODIFY_BATCH_REMOVE_ALL", LDAP_MODIFY_BATCH_REMOVE_ALL, CONST_PERSISTENT | CONST_CS);
175 	REGISTER_LONG_CONSTANT("LDAP_MODIFY_BATCH_REPLACE", LDAP_MODIFY_BATCH_REPLACE, CONST_PERSISTENT | CONST_CS);
176 	REGISTER_STRING_CONSTANT("LDAP_MODIFY_BATCH_ATTRIB", LDAP_MODIFY_BATCH_ATTRIB, CONST_PERSISTENT | CONST_CS);
177 	REGISTER_STRING_CONSTANT("LDAP_MODIFY_BATCH_MODTYPE", LDAP_MODIFY_BATCH_MODTYPE, CONST_PERSISTENT | CONST_CS);
178 	REGISTER_STRING_CONSTANT("LDAP_MODIFY_BATCH_VALUES", LDAP_MODIFY_BATCH_VALUES, CONST_PERSISTENT | CONST_CS);
179 
180 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP
181 	/* LDAP options */
182 	REGISTER_LONG_CONSTANT("LDAP_OPT_DEREF", LDAP_OPT_DEREF, CONST_PERSISTENT | CONST_CS);
183 	REGISTER_LONG_CONSTANT("LDAP_OPT_SIZELIMIT", LDAP_OPT_SIZELIMIT, CONST_PERSISTENT | CONST_CS);
184 	REGISTER_LONG_CONSTANT("LDAP_OPT_TIMELIMIT", LDAP_OPT_TIMELIMIT, CONST_PERSISTENT | CONST_CS);
185 #ifdef LDAP_OPT_NETWORK_TIMEOUT
186 	REGISTER_LONG_CONSTANT("LDAP_OPT_NETWORK_TIMEOUT", LDAP_OPT_NETWORK_TIMEOUT, CONST_PERSISTENT | CONST_CS);
187 #elif defined (LDAP_X_OPT_CONNECT_TIMEOUT)
188 	REGISTER_LONG_CONSTANT("LDAP_OPT_NETWORK_TIMEOUT", LDAP_X_OPT_CONNECT_TIMEOUT, CONST_PERSISTENT | CONST_CS);
189 #endif
190 #ifdef LDAP_OPT_TIMEOUT
191 	REGISTER_LONG_CONSTANT("LDAP_OPT_TIMEOUT", LDAP_OPT_TIMEOUT, CONST_PERSISTENT | CONST_CS);
192 #endif
193 	REGISTER_LONG_CONSTANT("LDAP_OPT_PROTOCOL_VERSION", LDAP_OPT_PROTOCOL_VERSION, CONST_PERSISTENT | CONST_CS);
194 	REGISTER_LONG_CONSTANT("LDAP_OPT_ERROR_NUMBER", LDAP_OPT_ERROR_NUMBER, CONST_PERSISTENT | CONST_CS);
195 	REGISTER_LONG_CONSTANT("LDAP_OPT_REFERRALS", LDAP_OPT_REFERRALS, CONST_PERSISTENT | CONST_CS);
196 #ifdef LDAP_OPT_RESTART
197 	REGISTER_LONG_CONSTANT("LDAP_OPT_RESTART", LDAP_OPT_RESTART, CONST_PERSISTENT | CONST_CS);
198 #endif
199 #ifdef LDAP_OPT_HOST_NAME
200 	REGISTER_LONG_CONSTANT("LDAP_OPT_HOST_NAME", LDAP_OPT_HOST_NAME, CONST_PERSISTENT | CONST_CS);
201 #endif
202 	REGISTER_LONG_CONSTANT("LDAP_OPT_ERROR_STRING", LDAP_OPT_ERROR_STRING, CONST_PERSISTENT | CONST_CS);
203 #ifdef LDAP_OPT_MATCHED_DN
204 	REGISTER_LONG_CONSTANT("LDAP_OPT_MATCHED_DN", LDAP_OPT_MATCHED_DN, CONST_PERSISTENT | CONST_CS);
205 #endif
206 	REGISTER_LONG_CONSTANT("LDAP_OPT_SERVER_CONTROLS", LDAP_OPT_SERVER_CONTROLS, CONST_PERSISTENT | CONST_CS);
207 	REGISTER_LONG_CONSTANT("LDAP_OPT_CLIENT_CONTROLS", LDAP_OPT_CLIENT_CONTROLS, CONST_PERSISTENT | CONST_CS);
208 #endif
209 #ifdef LDAP_OPT_DEBUG_LEVEL
210 	REGISTER_LONG_CONSTANT("LDAP_OPT_DEBUG_LEVEL", LDAP_OPT_DEBUG_LEVEL, CONST_PERSISTENT | CONST_CS);
211 #endif
212 
213 #ifdef LDAP_OPT_DIAGNOSTIC_MESSAGE
214 	REGISTER_LONG_CONSTANT("LDAP_OPT_DIAGNOSTIC_MESSAGE", LDAP_OPT_DIAGNOSTIC_MESSAGE, CONST_PERSISTENT | CONST_CS);
215 #endif
216 
217 #ifdef HAVE_LDAP_SASL
218 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_SASL_MECH", LDAP_OPT_X_SASL_MECH, CONST_PERSISTENT | CONST_CS);
219 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_SASL_REALM", LDAP_OPT_X_SASL_REALM, CONST_PERSISTENT | CONST_CS);
220 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_SASL_AUTHCID", LDAP_OPT_X_SASL_AUTHCID, CONST_PERSISTENT | CONST_CS);
221 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_SASL_AUTHZID", LDAP_OPT_X_SASL_AUTHZID, CONST_PERSISTENT | CONST_CS);
222 #endif
223 #ifdef LDAP_OPT_X_SASL_NOCANON
224 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_SASL_NOCANON", LDAP_OPT_X_SASL_NOCANON, CONST_PERSISTENT | CONST_CS);
225 #endif
226 #ifdef LDAP_OPT_X_SASL_USERNAME
227 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_SASL_USERNAME", LDAP_OPT_X_SASL_USERNAME, CONST_PERSISTENT | CONST_CS);
228 #endif
229 
230 #ifdef ORALDAP
231 	REGISTER_LONG_CONSTANT("GSLC_SSL_NO_AUTH", GSLC_SSL_NO_AUTH, CONST_PERSISTENT | CONST_CS);
232 	REGISTER_LONG_CONSTANT("GSLC_SSL_ONEWAY_AUTH", GSLC_SSL_ONEWAY_AUTH, CONST_PERSISTENT | CONST_CS);
233 	REGISTER_LONG_CONSTANT("GSLC_SSL_TWOWAY_AUTH", GSLC_SSL_TWOWAY_AUTH, CONST_PERSISTENT | CONST_CS);
234 #endif
235 
236 #if (LDAP_API_VERSION > 2000)
237 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_REQUIRE_CERT", LDAP_OPT_X_TLS_REQUIRE_CERT, CONST_PERSISTENT | CONST_CS);
238 
239 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_NEVER", LDAP_OPT_X_TLS_NEVER, CONST_PERSISTENT | CONST_CS);
240 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_HARD", LDAP_OPT_X_TLS_HARD, CONST_PERSISTENT | CONST_CS);
241 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_DEMAND", LDAP_OPT_X_TLS_DEMAND, CONST_PERSISTENT | CONST_CS);
242 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_ALLOW", LDAP_OPT_X_TLS_ALLOW, CONST_PERSISTENT | CONST_CS);
243 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_TRY", LDAP_OPT_X_TLS_TRY, CONST_PERSISTENT | CONST_CS);
244 
245 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_CACERTDIR", LDAP_OPT_X_TLS_CACERTDIR, CONST_PERSISTENT | CONST_CS);
246 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_CACERTFILE", LDAP_OPT_X_TLS_CACERTFILE, CONST_PERSISTENT | CONST_CS);
247 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_CERTFILE", LDAP_OPT_X_TLS_CERTFILE, CONST_PERSISTENT | CONST_CS);
248 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_CIPHER_SUITE", LDAP_OPT_X_TLS_CIPHER_SUITE, CONST_PERSISTENT | CONST_CS);
249 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_KEYFILE", LDAP_OPT_X_TLS_KEYFILE, CONST_PERSISTENT | CONST_CS);
250 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_RANDOM_FILE", LDAP_OPT_X_TLS_RANDOM_FILE, CONST_PERSISTENT | CONST_CS);
251 #endif
252 
253 #ifdef LDAP_OPT_X_TLS_CRLCHECK
254 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_CRLCHECK", LDAP_OPT_X_TLS_CRLCHECK, CONST_PERSISTENT | CONST_CS);
255 
256 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_CRL_NONE", LDAP_OPT_X_TLS_CRL_NONE, CONST_PERSISTENT | CONST_CS);
257 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_CRL_PEER", LDAP_OPT_X_TLS_CRL_PEER, CONST_PERSISTENT | CONST_CS);
258 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_CRL_ALL", LDAP_OPT_X_TLS_CRL_ALL, CONST_PERSISTENT | CONST_CS);
259 #endif
260 
261 #ifdef LDAP_OPT_X_TLS_DHFILE
262 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_DHFILE", LDAP_OPT_X_TLS_DHFILE, CONST_PERSISTENT | CONST_CS);
263 #endif
264 
265 #ifdef LDAP_OPT_X_TLS_CRLFILE
266 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_CRLFILE", LDAP_OPT_X_TLS_CRLFILE, CONST_PERSISTENT | CONST_CS);
267 #endif
268 
269 #ifdef LDAP_OPT_X_TLS_PROTOCOL_MIN
270 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_PROTOCOL_MIN", LDAP_OPT_X_TLS_PROTOCOL_MIN, CONST_PERSISTENT | CONST_CS);
271 
272 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_PROTOCOL_SSL2", LDAP_OPT_X_TLS_PROTOCOL_SSL2, CONST_PERSISTENT | CONST_CS);
273 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_PROTOCOL_SSL3", LDAP_OPT_X_TLS_PROTOCOL_SSL3, CONST_PERSISTENT | CONST_CS);
274 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_PROTOCOL_TLS1_0", LDAP_OPT_X_TLS_PROTOCOL_TLS1_0, CONST_PERSISTENT | CONST_CS);
275 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_PROTOCOL_TLS1_1", LDAP_OPT_X_TLS_PROTOCOL_TLS1_1, CONST_PERSISTENT | CONST_CS);
276 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_PROTOCOL_TLS1_2", LDAP_OPT_X_TLS_PROTOCOL_TLS1_2, CONST_PERSISTENT | CONST_CS);
277 #endif
278 
279 #ifdef LDAP_OPT_X_TLS_PACKAGE
280 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_PACKAGE", LDAP_OPT_X_TLS_PACKAGE, CONST_PERSISTENT | CONST_CS);
281 #endif
282 
283 #ifdef LDAP_OPT_X_KEEPALIVE_IDLE
284 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_KEEPALIVE_IDLE", LDAP_OPT_X_KEEPALIVE_IDLE, CONST_PERSISTENT | CONST_CS);
285 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_KEEPALIVE_PROBES", LDAP_OPT_X_KEEPALIVE_PROBES, CONST_PERSISTENT | CONST_CS);
286 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_KEEPALIVE_INTERVAL", LDAP_OPT_X_KEEPALIVE_INTERVAL, CONST_PERSISTENT | CONST_CS);
287 #endif
288 
289 	REGISTER_LONG_CONSTANT("LDAP_ESCAPE_FILTER", PHP_LDAP_ESCAPE_FILTER, CONST_PERSISTENT | CONST_CS);
290 	REGISTER_LONG_CONSTANT("LDAP_ESCAPE_DN", PHP_LDAP_ESCAPE_DN, CONST_PERSISTENT | CONST_CS);
291 
292 	le_link = zend_register_list_destructors_ex(_close_ldap_link, NULL, "ldap link", module_number);
293 	le_result = zend_register_list_destructors_ex(_free_ldap_result, NULL, "ldap result", module_number);
294 	le_result_entry = zend_register_list_destructors_ex(_free_ldap_result_entry, NULL, "ldap result entry", module_number);
295 
296 	ldap_module_entry.type = type;
297 
298 	return SUCCESS;
299 }
300 /* }}} */
301 
302 /* {{{ PHP_MSHUTDOWN_FUNCTION
303  */
PHP_MSHUTDOWN_FUNCTION(ldap)304 PHP_MSHUTDOWN_FUNCTION(ldap)
305 {
306 	UNREGISTER_INI_ENTRIES();
307 	return SUCCESS;
308 }
309 /* }}} */
310 
311 /* {{{ PHP_MINFO_FUNCTION
312  */
PHP_MINFO_FUNCTION(ldap)313 PHP_MINFO_FUNCTION(ldap)
314 {
315 	char tmp[32];
316 #if HAVE_NSLDAP
317 	LDAPVersion ver;
318 	double SDKVersion;
319 #endif
320 
321 	php_info_print_table_start();
322 	php_info_print_table_row(2, "LDAP Support", "enabled");
323 	php_info_print_table_row(2, "RCS Version", "$Id: 5f1913de8e05a346da913956f81e0c0d8991c7cb $");
324 
325 	if (LDAPG(max_links) == -1) {
326 		snprintf(tmp, 31, ZEND_LONG_FMT "/unlimited", LDAPG(num_links));
327 	} else {
328 		snprintf(tmp, 31, ZEND_LONG_FMT "/" ZEND_LONG_FMT, LDAPG(num_links), LDAPG(max_links));
329 	}
330 	php_info_print_table_row(2, "Total Links", tmp);
331 
332 #ifdef LDAP_API_VERSION
333 	snprintf(tmp, 31, "%d", LDAP_API_VERSION);
334 	php_info_print_table_row(2, "API Version", tmp);
335 #endif
336 
337 #ifdef LDAP_VENDOR_NAME
338 	php_info_print_table_row(2, "Vendor Name", LDAP_VENDOR_NAME);
339 #endif
340 
341 #ifdef LDAP_VENDOR_VERSION
342 	snprintf(tmp, 31, "%d", LDAP_VENDOR_VERSION);
343 	php_info_print_table_row(2, "Vendor Version", tmp);
344 #endif
345 
346 #if HAVE_NSLDAP
347 	SDKVersion = ldap_version(&ver);
348 	snprintf(tmp, 31, "%F", SDKVersion/100.0);
349 	php_info_print_table_row(2, "SDK Version", tmp);
350 
351 	snprintf(tmp, 31, "%F", ver.protocol_version/100.0);
352 	php_info_print_table_row(2, "Highest LDAP Protocol Supported", tmp);
353 
354 	snprintf(tmp, 31, "%F", ver.SSL_version/100.0);
355 	php_info_print_table_row(2, "SSL Level Supported", tmp);
356 
357 	if (ver.security_level != LDAP_SECURITY_NONE) {
358 		snprintf(tmp, 31, "%d", ver.security_level);
359 	} else {
360 		strcpy(tmp, "SSL not enabled");
361 	}
362 	php_info_print_table_row(2, "Level of Encryption", tmp);
363 #endif
364 
365 #ifdef HAVE_LDAP_SASL
366 	php_info_print_table_row(2, "SASL Support", "Enabled");
367 #endif
368 
369 	php_info_print_table_end();
370 	DISPLAY_INI_ENTRIES();
371 }
372 /* }}} */
373 
374 /* {{{ proto resource ldap_connect([string host [, int port [, string wallet [, string wallet_passwd [, int authmode]]]]])
375    Connect to an LDAP server */
PHP_FUNCTION(ldap_connect)376 PHP_FUNCTION(ldap_connect)
377 {
378 	char *host = NULL;
379 	size_t hostlen = 0;
380 	zend_long port = LDAP_PORT;
381 #ifdef HAVE_ORALDAP
382 	char *wallet = NULL, *walletpasswd = NULL;
383 	size_t walletlen = 0, walletpasswdlen = 0;
384 	zend_long authmode = GSLC_SSL_NO_AUTH;
385 	int ssl=0;
386 #endif
387 	ldap_linkdata *ld;
388 	LDAP *ldap = NULL;
389 
390 #ifdef HAVE_ORALDAP
391 	if (ZEND_NUM_ARGS() == 3 || ZEND_NUM_ARGS() == 4) {
392 		WRONG_PARAM_COUNT;
393 	}
394 
395 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|slssl", &host, &hostlen, &port, &wallet, &walletlen, &walletpasswd, &walletpasswdlen, &authmode) != SUCCESS) {
396 		RETURN_FALSE;
397 	}
398 
399 	if (ZEND_NUM_ARGS() == 5) {
400 		ssl = 1;
401 	}
402 #else
403 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|sl", &host, &hostlen, &port) != SUCCESS) {
404 		RETURN_FALSE;
405 	}
406 #endif
407 
408 	if (LDAPG(max_links) != -1 && LDAPG(num_links) >= LDAPG(max_links)) {
409 		php_error_docref(NULL, E_WARNING, "Too many open links (" ZEND_LONG_FMT ")", LDAPG(num_links));
410 		RETURN_FALSE;
411 	}
412 
413 	ld = ecalloc(1, sizeof(ldap_linkdata));
414 
415 	{
416 		int rc = LDAP_SUCCESS;
417 		char	*url = host;
418 		if (url && !ldap_is_ldap_url(url)) {
419 			int	urllen = hostlen + sizeof( "ldap://:65535" );
420 
421 			if (port <= 0 || port > 65535) {
422 				efree(ld);
423 				php_error_docref(NULL, E_WARNING, "invalid port number: " ZEND_LONG_FMT, port);
424 				RETURN_FALSE;
425 			}
426 
427 			url = emalloc(urllen);
428 			snprintf( url, urllen, "ldap://%s:" ZEND_LONG_FMT, host, port );
429 		}
430 
431 #ifdef LDAP_API_FEATURE_X_OPENLDAP
432 		/* ldap_init() is deprecated, use ldap_initialize() instead.
433 		 */
434 		rc = ldap_initialize(&ldap, url);
435 #else /* ! LDAP_API_FEATURE_X_OPENLDAP */
436 		/* ldap_init does not support URLs.
437 		 * We must try the original host and port information.
438 		 */
439 		ldap = ldap_init(host, port);
440 		if (ldap == NULL) {
441 			efree(ld);
442 			php_error_docref(NULL, E_WARNING, "Could not create session handle");
443 			RETURN_FALSE;
444 		}
445 #endif /* ! LDAP_API_FEATURE_X_OPENLDAP */
446 		if (url != host) {
447 			efree(url);
448 		}
449 		if (rc != LDAP_SUCCESS) {
450 			efree(ld);
451 			php_error_docref(NULL, E_WARNING, "Could not create session handle: %s", ldap_err2string(rc));
452 			RETURN_FALSE;
453 		}
454 	}
455 
456 	if (ldap == NULL) {
457 		efree(ld);
458 		RETURN_FALSE;
459 	} else {
460 #ifdef HAVE_ORALDAP
461 		if (ssl) {
462 			if (ldap_init_SSL(&ldap->ld_sb, wallet, walletpasswd, authmode)) {
463 				efree(ld);
464 				php_error_docref(NULL, E_WARNING, "SSL init failed");
465 				RETURN_FALSE;
466 			}
467 		}
468 #endif
469 		LDAPG(num_links)++;
470 		ld->link = ldap;
471 		RETURN_RES(zend_register_resource(ld, le_link));
472 	}
473 
474 }
475 /* }}} */
476 
477 /* {{{ _get_lderrno
478  */
_get_lderrno(LDAP * ldap)479 static int _get_lderrno(LDAP *ldap)
480 {
481 #if !HAVE_NSLDAP
482 #if LDAP_API_VERSION > 2000 || HAVE_ORALDAP
483 	int lderr;
484 
485 	/* New versions of OpenLDAP do it this way */
486 	ldap_get_option(ldap, LDAP_OPT_ERROR_NUMBER, &lderr);
487 	return lderr;
488 #else
489 	return ldap->ld_errno;
490 #endif
491 #else
492 	return ldap_get_lderrno(ldap, NULL, NULL);
493 #endif
494 }
495 /* }}} */
496 
497 /* {{{ _set_lderrno
498  */
_set_lderrno(LDAP * ldap,int lderr)499 static void _set_lderrno(LDAP *ldap, int lderr)
500 {
501 #if !HAVE_NSLDAP
502 #if LDAP_API_VERSION > 2000 || HAVE_ORALDAP
503 	/* New versions of OpenLDAP do it this way */
504 	ldap_set_option(ldap, LDAP_OPT_ERROR_NUMBER, &lderr);
505 #else
506 	ldap->ld_errno = lderr;
507 #endif
508 #else
509 	ldap_set_lderrno(ldap, lderr, NULL, NULL);
510 #endif
511 }
512 /* }}} */
513 
514 /* {{{ proto bool ldap_bind(resource link [, string dn [, string password]])
515    Bind to LDAP directory */
PHP_FUNCTION(ldap_bind)516 PHP_FUNCTION(ldap_bind)
517 {
518 	zval *link;
519 	char *ldap_bind_dn = NULL, *ldap_bind_pw = NULL;
520 	size_t ldap_bind_dnlen, ldap_bind_pwlen;
521 	ldap_linkdata *ld;
522 	int rc;
523 
524 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|ss", &link, &ldap_bind_dn, &ldap_bind_dnlen, &ldap_bind_pw, &ldap_bind_pwlen) != SUCCESS) {
525 		RETURN_FALSE;
526 	}
527 
528 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
529 		RETURN_FALSE;
530 	}
531 
532 	if (ldap_bind_dn != NULL && memchr(ldap_bind_dn, '\0', ldap_bind_dnlen) != NULL) {
533 		_set_lderrno(ld->link, LDAP_INVALID_CREDENTIALS);
534 		php_error_docref(NULL, E_WARNING, "DN contains a null byte");
535 		RETURN_FALSE;
536 	}
537 
538 	if (ldap_bind_pw != NULL && memchr(ldap_bind_pw, '\0', ldap_bind_pwlen) != NULL) {
539 		_set_lderrno(ld->link, LDAP_INVALID_CREDENTIALS);
540 		php_error_docref(NULL, E_WARNING, "Password contains a null byte");
541 		RETURN_FALSE;
542 	}
543 
544 	{
545 #ifdef LDAP_API_FEATURE_X_OPENLDAP
546 		/* ldap_simple_bind_s() is deprecated, use ldap_sasl_bind_s() instead.
547 		 */
548 		struct berval   cred;
549 
550 		cred.bv_val = ldap_bind_pw;
551 		cred.bv_len = ldap_bind_pw ? ldap_bind_pwlen : 0;
552 		rc = ldap_sasl_bind_s(ld->link, ldap_bind_dn, LDAP_SASL_SIMPLE, &cred,
553 				NULL, NULL,     /* no controls right now */
554 				NULL);	  /* we don't care about the server's credentials */
555 #else /* ! LDAP_API_FEATURE_X_OPENLDAP */
556 		rc = ldap_simple_bind_s(ld->link, ldap_bind_dn, ldap_bind_pw);
557 #endif /* ! LDAP_API_FEATURE_X_OPENLDAP */
558 	}
559 	if ( rc != LDAP_SUCCESS) {
560 		php_error_docref(NULL, E_WARNING, "Unable to bind to server: %s", ldap_err2string(rc));
561 		RETURN_FALSE;
562 	} else {
563 		RETURN_TRUE;
564 	}
565 }
566 /* }}} */
567 
568 #ifdef HAVE_LDAP_SASL
569 typedef struct {
570 	char *mech;
571 	char *realm;
572 	char *authcid;
573 	char *passwd;
574 	char *authzid;
575 } php_ldap_bictx;
576 
577 /* {{{ _php_sasl_setdefs
578  */
_php_sasl_setdefs(LDAP * ld,char * sasl_mech,char * sasl_realm,char * sasl_authc_id,char * passwd,char * sasl_authz_id)579 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)
580 {
581 	php_ldap_bictx *ctx;
582 
583 	ctx = ber_memalloc(sizeof(php_ldap_bictx));
584 	ctx->mech    = (sasl_mech) ? ber_strdup(sasl_mech) : NULL;
585 	ctx->realm   = (sasl_realm) ? ber_strdup(sasl_realm) : NULL;
586 	ctx->authcid = (sasl_authc_id) ? ber_strdup(sasl_authc_id) : NULL;
587 	ctx->passwd  = (passwd) ? ber_strdup(passwd) : NULL;
588 	ctx->authzid = (sasl_authz_id) ? ber_strdup(sasl_authz_id) : NULL;
589 
590 	if (ctx->mech == NULL) {
591 		ldap_get_option(ld, LDAP_OPT_X_SASL_MECH, &ctx->mech);
592 	}
593 	if (ctx->realm == NULL) {
594 		ldap_get_option(ld, LDAP_OPT_X_SASL_REALM, &ctx->realm);
595 	}
596 	if (ctx->authcid == NULL) {
597 		ldap_get_option(ld, LDAP_OPT_X_SASL_AUTHCID, &ctx->authcid);
598 	}
599 	if (ctx->authzid == NULL) {
600 		ldap_get_option(ld, LDAP_OPT_X_SASL_AUTHZID, &ctx->authzid);
601 	}
602 
603 	return ctx;
604 }
605 /* }}} */
606 
607 /* {{{ _php_sasl_freedefs
608  */
_php_sasl_freedefs(php_ldap_bictx * ctx)609 static void _php_sasl_freedefs(php_ldap_bictx *ctx)
610 {
611 	if (ctx->mech) ber_memfree(ctx->mech);
612 	if (ctx->realm) ber_memfree(ctx->realm);
613 	if (ctx->authcid) ber_memfree(ctx->authcid);
614 	if (ctx->passwd) ber_memfree(ctx->passwd);
615 	if (ctx->authzid) ber_memfree(ctx->authzid);
616 	ber_memfree(ctx);
617 }
618 /* }}} */
619 
620 /* {{{ _php_sasl_interact
621    Internal interact function for SASL */
_php_sasl_interact(LDAP * ld,unsigned flags,void * defaults,void * in)622 static int _php_sasl_interact(LDAP *ld, unsigned flags, void *defaults, void *in)
623 {
624 	sasl_interact_t *interact = in;
625 	const char *p;
626 	php_ldap_bictx *ctx = defaults;
627 
628 	for (;interact->id != SASL_CB_LIST_END;interact++) {
629 		p = NULL;
630 		switch(interact->id) {
631 			case SASL_CB_GETREALM:
632 				p = ctx->realm;
633 				break;
634 			case SASL_CB_AUTHNAME:
635 				p = ctx->authcid;
636 				break;
637 			case SASL_CB_USER:
638 				p = ctx->authzid;
639 				break;
640 			case SASL_CB_PASS:
641 				p = ctx->passwd;
642 				break;
643 		}
644 		if (p) {
645 			interact->result = p;
646 			interact->len = strlen(interact->result);
647 		}
648 	}
649 	return LDAP_SUCCESS;
650 }
651 /* }}} */
652 
653 /* {{{ 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]]]]]]])
654    Bind to LDAP directory using SASL */
PHP_FUNCTION(ldap_sasl_bind)655 PHP_FUNCTION(ldap_sasl_bind)
656 {
657 	zval *link;
658 	ldap_linkdata *ld;
659 	char *binddn = NULL;
660 	char *passwd = NULL;
661 	char *sasl_mech = NULL;
662 	char *sasl_realm = NULL;
663 	char *sasl_authz_id = NULL;
664 	char *sasl_authc_id = NULL;
665 	char *props = NULL;
666 	size_t rc, dn_len, passwd_len, mech_len, realm_len, authc_id_len, authz_id_len, props_len;
667 	php_ldap_bictx *ctx;
668 
669 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "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) {
670 		RETURN_FALSE;
671 	}
672 
673 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
674 		RETURN_FALSE;
675 	}
676 
677 	ctx = _php_sasl_setdefs(ld->link, sasl_mech, sasl_realm, sasl_authc_id, passwd, sasl_authz_id);
678 
679 	if (props) {
680 		ldap_set_option(ld->link, LDAP_OPT_X_SASL_SECPROPS, props);
681 	}
682 
683 	rc = ldap_sasl_interactive_bind_s(ld->link, binddn, ctx->mech, NULL, NULL, LDAP_SASL_QUIET, _php_sasl_interact, ctx);
684 	if (rc != LDAP_SUCCESS) {
685 		php_error_docref(NULL, E_WARNING, "Unable to bind to server: %s", ldap_err2string(rc));
686 		RETVAL_FALSE;
687 	} else {
688 		RETVAL_TRUE;
689 	}
690 	_php_sasl_freedefs(ctx);
691 }
692 /* }}} */
693 #endif /* HAVE_LDAP_SASL */
694 
695 /* {{{ proto bool ldap_unbind(resource link)
696    Unbind from LDAP directory */
PHP_FUNCTION(ldap_unbind)697 PHP_FUNCTION(ldap_unbind)
698 {
699 	zval *link;
700 	ldap_linkdata *ld;
701 
702 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &link) != SUCCESS) {
703 		RETURN_FALSE;
704 	}
705 
706 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
707 		RETURN_FALSE;
708 	}
709 
710 	zend_list_close(Z_RES_P(link));
711 	RETURN_TRUE;
712 }
713 /* }}} */
714 
715 /* {{{ php_set_opts
716  */
php_set_opts(LDAP * ldap,int sizelimit,int timelimit,int deref,int * old_sizelimit,int * old_timelimit,int * old_deref)717 static void php_set_opts(LDAP *ldap, int sizelimit, int timelimit, int deref, int *old_sizelimit, int *old_timelimit, int *old_deref)
718 {
719 	/* sizelimit */
720 	if (sizelimit > -1) {
721 #if (LDAP_API_VERSION >= 2004) || HAVE_NSLDAP || HAVE_ORALDAP
722 		ldap_get_option(ldap, LDAP_OPT_SIZELIMIT, old_sizelimit);
723 		ldap_set_option(ldap, LDAP_OPT_SIZELIMIT, &sizelimit);
724 #else
725 		*old_sizelimit = ldap->ld_sizelimit;
726 		ldap->ld_sizelimit = sizelimit;
727 #endif
728 	}
729 
730 	/* timelimit */
731 	if (timelimit > -1) {
732 #if (LDAP_API_VERSION >= 2004) || HAVE_NSLDAP || HAVE_ORALDAP
733 		ldap_get_option(ldap, LDAP_OPT_TIMELIMIT, old_timelimit);
734 		ldap_set_option(ldap, LDAP_OPT_TIMELIMIT, &timelimit);
735 #else
736 		*old_timelimit = ldap->ld_timelimit;
737 		ldap->ld_timelimit = timelimit;
738 #endif
739 	}
740 
741 	/* deref */
742 	if (deref > -1) {
743 #if (LDAP_API_VERSION >= 2004) || HAVE_NSLDAP || HAVE_ORALDAP
744 		ldap_get_option(ldap, LDAP_OPT_DEREF, old_deref);
745 		ldap_set_option(ldap, LDAP_OPT_DEREF, &deref);
746 #else
747 		*old_deref = ldap->ld_deref;
748 		ldap->ld_deref = deref;
749 #endif
750 	}
751 }
752 /* }}} */
753 
754 /* {{{ php_ldap_do_search
755  */
php_ldap_do_search(INTERNAL_FUNCTION_PARAMETERS,int scope)756 static void php_ldap_do_search(INTERNAL_FUNCTION_PARAMETERS, int scope)
757 {
758 	zval *link, *base_dn, *filter, *attrs = NULL, *attr;
759 	zend_long attrsonly, sizelimit, timelimit, deref;
760 	char *ldap_base_dn = NULL, *ldap_filter = NULL, **ldap_attrs = NULL;
761 	ldap_linkdata *ld = NULL;
762 	LDAPMessage *ldap_res;
763 	int ldap_attrsonly = 0, ldap_sizelimit = -1, ldap_timelimit = -1, ldap_deref = -1;
764 	int old_ldap_sizelimit = -1, old_ldap_timelimit = -1, old_ldap_deref = -1;
765 	int num_attribs = 0, ret = 1, i, errno, argcount = ZEND_NUM_ARGS();
766 
767 	if (zend_parse_parameters(argcount, "zzz|allll", &link, &base_dn, &filter, &attrs, &attrsonly,
768 		&sizelimit, &timelimit, &deref) == FAILURE) {
769 		return;
770 	}
771 
772 	/* Reverse -> fall through */
773 	switch (argcount) {
774 		case 8:
775 			ldap_deref = deref;
776 		case 7:
777 			ldap_timelimit = timelimit;
778 		case 6:
779 			ldap_sizelimit = sizelimit;
780 		case 5:
781 			ldap_attrsonly = attrsonly;
782 		case 4:
783 			num_attribs = zend_hash_num_elements(Z_ARRVAL_P(attrs));
784 			ldap_attrs = safe_emalloc((num_attribs+1), sizeof(char *), 0);
785 
786 			for (i = 0; i<num_attribs; i++) {
787 				if ((attr = zend_hash_index_find(Z_ARRVAL_P(attrs), i)) == NULL) {
788 					php_error_docref(NULL, E_WARNING, "Array initialization wrong");
789 					ret = 0;
790 					goto cleanup;
791 				}
792 
793 				convert_to_string_ex(attr);
794 				ldap_attrs[i] = Z_STRVAL_P(attr);
795 			}
796 			ldap_attrs[num_attribs] = NULL;
797 		default:
798 			break;
799 	}
800 
801 	/* parallel search? */
802 	if (Z_TYPE_P(link) == IS_ARRAY) {
803 		int i, nlinks, nbases, nfilters, *rcs;
804 		ldap_linkdata **lds;
805 		zval *entry, resource;
806 
807 		nlinks = zend_hash_num_elements(Z_ARRVAL_P(link));
808 		if (nlinks == 0) {
809 			php_error_docref(NULL, E_WARNING, "No links in link array");
810 			ret = 0;
811 			goto cleanup;
812 		}
813 
814 		if (Z_TYPE_P(base_dn) == IS_ARRAY) {
815 			nbases = zend_hash_num_elements(Z_ARRVAL_P(base_dn));
816 			if (nbases != nlinks) {
817 				php_error_docref(NULL, E_WARNING, "Base must either be a string, or an array with the same number of elements as the links array");
818 				ret = 0;
819 				goto cleanup;
820 			}
821 			zend_hash_internal_pointer_reset(Z_ARRVAL_P(base_dn));
822 		} else {
823 			nbases = 0; /* this means string, not array */
824 			/* If anything else than string is passed, ldap_base_dn = NULL */
825 			if (Z_TYPE_P(base_dn) == IS_STRING) {
826 				ldap_base_dn = Z_STRVAL_P(base_dn);
827 			} else {
828 				ldap_base_dn = NULL;
829 			}
830 		}
831 
832 		if (Z_TYPE_P(filter) == IS_ARRAY) {
833 			nfilters = zend_hash_num_elements(Z_ARRVAL_P(filter));
834 			if (nfilters != nlinks) {
835 				php_error_docref(NULL, E_WARNING, "Filter must either be a string, or an array with the same number of elements as the links array");
836 				ret = 0;
837 				goto cleanup;
838 			}
839 			zend_hash_internal_pointer_reset(Z_ARRVAL_P(filter));
840 		} else {
841 			nfilters = 0; /* this means string, not array */
842 			convert_to_string_ex(filter);
843 			ldap_filter = Z_STRVAL_P(filter);
844 		}
845 
846 		lds = safe_emalloc(nlinks, sizeof(ldap_linkdata), 0);
847 		rcs = safe_emalloc(nlinks, sizeof(*rcs), 0);
848 
849 		zend_hash_internal_pointer_reset(Z_ARRVAL_P(link));
850 		for (i=0; i<nlinks; i++) {
851 			entry = zend_hash_get_current_data(Z_ARRVAL_P(link));
852 
853 			ld = (ldap_linkdata *) zend_fetch_resource_ex(entry, "ldap link", le_link);
854 			if (ld == NULL) {
855 				ret = 0;
856 				goto cleanup_parallel;
857 			}
858 			if (nbases != 0) { /* base_dn an array? */
859 				entry = zend_hash_get_current_data(Z_ARRVAL_P(base_dn));
860 				zend_hash_move_forward(Z_ARRVAL_P(base_dn));
861 
862 				/* If anything else than string is passed, ldap_base_dn = NULL */
863 				if (Z_TYPE_P(entry) == IS_STRING) {
864 					ldap_base_dn = Z_STRVAL_P(entry);
865 				} else {
866 					ldap_base_dn = NULL;
867 				}
868 			}
869 			if (nfilters != 0) { /* filter an array? */
870 				entry = zend_hash_get_current_data(Z_ARRVAL_P(filter));
871 				zend_hash_move_forward(Z_ARRVAL_P(filter));
872 				convert_to_string_ex(entry);
873 				ldap_filter = Z_STRVAL_P(entry);
874 			}
875 
876 			php_set_opts(ld->link, ldap_sizelimit, ldap_timelimit, ldap_deref, &old_ldap_sizelimit, &old_ldap_timelimit, &old_ldap_deref);
877 
878 			/* Run the actual search */
879 			ldap_search_ext(ld->link, ldap_base_dn, scope, ldap_filter, ldap_attrs, ldap_attrsonly, NULL, NULL, NULL, ldap_sizelimit, &rcs[i]);
880 			lds[i] = ld;
881 			zend_hash_move_forward(Z_ARRVAL_P(link));
882 		}
883 
884 		array_init(return_value);
885 
886 		/* Collect results from the searches */
887 		for (i=0; i<nlinks; i++) {
888 			if (rcs[i] != -1) {
889 				rcs[i] = ldap_result(lds[i]->link, LDAP_RES_ANY, 1 /* LDAP_MSG_ALL */, NULL, &ldap_res);
890 			}
891 			if (rcs[i] != -1) {
892 				ZVAL_RES(&resource, zend_register_resource(ldap_res, le_result));
893 				add_next_index_zval(return_value, &resource);
894 			} else {
895 				add_next_index_bool(return_value, 0);
896 			}
897 		}
898 
899 cleanup_parallel:
900 		efree(lds);
901 		efree(rcs);
902 	} else {
903 		convert_to_string_ex(filter);
904 		ldap_filter = Z_STRVAL_P(filter);
905 
906 		/* If anything else than string is passed, ldap_base_dn = NULL */
907 		if (Z_TYPE_P(base_dn) == IS_STRING) {
908 			ldap_base_dn = Z_STRVAL_P(base_dn);
909 		}
910 
911 		ld = (ldap_linkdata *) zend_fetch_resource_ex(link, "ldap link", le_link);
912 		if (ld == NULL) {
913 			ret = 0;
914 			goto cleanup;
915 		}
916 
917 		php_set_opts(ld->link, ldap_sizelimit, ldap_timelimit, ldap_deref, &old_ldap_sizelimit, &old_ldap_timelimit, &old_ldap_deref);
918 
919 		/* Run the actual search */
920 		errno = ldap_search_ext_s(ld->link, ldap_base_dn, scope, ldap_filter, ldap_attrs, ldap_attrsonly, NULL, NULL, NULL, ldap_sizelimit, &ldap_res);
921 
922 		if (errno != LDAP_SUCCESS
923 			&& errno != LDAP_SIZELIMIT_EXCEEDED
924 #ifdef LDAP_ADMINLIMIT_EXCEEDED
925 			&& errno != LDAP_ADMINLIMIT_EXCEEDED
926 #endif
927 #ifdef LDAP_REFERRAL
928 			&& errno != LDAP_REFERRAL
929 #endif
930 		) {
931 			php_error_docref(NULL, E_WARNING, "Search: %s", ldap_err2string(errno));
932 			ret = 0;
933 		} else {
934 			if (errno == LDAP_SIZELIMIT_EXCEEDED) {
935 				php_error_docref(NULL, E_WARNING, "Partial search results returned: Sizelimit exceeded");
936 			}
937 #ifdef LDAP_ADMINLIMIT_EXCEEDED
938 			else if (errno == LDAP_ADMINLIMIT_EXCEEDED) {
939 				php_error_docref(NULL, E_WARNING, "Partial search results returned: Adminlimit exceeded");
940 			}
941 #endif
942 
943 			RETVAL_RES(zend_register_resource(ldap_res, le_result));
944 		}
945 	}
946 
947 cleanup:
948 	if (ld) {
949 		/* Restoring previous options */
950 		php_set_opts(ld->link, old_ldap_sizelimit, old_ldap_timelimit, old_ldap_deref, &ldap_sizelimit, &ldap_timelimit, &ldap_deref);
951 	}
952 	if (ldap_attrs != NULL) {
953 		efree(ldap_attrs);
954 	}
955 	if (!ret) {
956 		RETVAL_BOOL(ret);
957 	}
958 }
959 /* }}} */
960 
961 /* {{{ proto resource ldap_read(resource|array link, string base_dn, string filter [, array attrs [, int attrsonly [, int sizelimit [, int timelimit [, int deref]]]]])
962    Read an entry */
PHP_FUNCTION(ldap_read)963 PHP_FUNCTION(ldap_read)
964 {
965 	php_ldap_do_search(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_SCOPE_BASE);
966 }
967 /* }}} */
968 
969 /* {{{ proto resource ldap_list(resource|array link, string base_dn, string filter [, array attrs [, int attrsonly [, int sizelimit [, int timelimit [, int deref]]]]])
970    Single-level search */
PHP_FUNCTION(ldap_list)971 PHP_FUNCTION(ldap_list)
972 {
973 	php_ldap_do_search(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_SCOPE_ONELEVEL);
974 }
975 /* }}} */
976 
977 /* {{{ proto resource ldap_search(resource|array link, string base_dn, string filter [, array attrs [, int attrsonly [, int sizelimit [, int timelimit [, int deref]]]]])
978    Search LDAP tree under base_dn */
PHP_FUNCTION(ldap_search)979 PHP_FUNCTION(ldap_search)
980 {
981 	php_ldap_do_search(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_SCOPE_SUBTREE);
982 }
983 /* }}} */
984 
985 /* {{{ proto bool ldap_free_result(resource result)
986    Free result memory */
PHP_FUNCTION(ldap_free_result)987 PHP_FUNCTION(ldap_free_result)
988 {
989 	zval *result;
990 	LDAPMessage *ldap_result;
991 
992 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &result) != SUCCESS) {
993 		return;
994 	}
995 
996 	if ((ldap_result = (LDAPMessage *)zend_fetch_resource(Z_RES_P(result), "ldap result", le_result)) == NULL) {
997 		RETURN_FALSE;
998 	}
999 
1000 	zend_list_close(Z_RES_P(result));  /* Delete list entry */
1001 	RETVAL_TRUE;
1002 }
1003 /* }}} */
1004 
1005 /* {{{ proto int ldap_count_entries(resource link, resource result)
1006    Count the number of entries in a search result */
PHP_FUNCTION(ldap_count_entries)1007 PHP_FUNCTION(ldap_count_entries)
1008 {
1009 	zval *link, *result;
1010 	ldap_linkdata *ld;
1011 	LDAPMessage *ldap_result;
1012 
1013 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rr", &link, &result) != SUCCESS) {
1014 		return;
1015 	}
1016 
1017 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
1018 		RETURN_FALSE;
1019 	}
1020 
1021 	if ((ldap_result = (LDAPMessage *)zend_fetch_resource(Z_RES_P(result), "ldap result", le_result)) == NULL) {
1022 		RETURN_FALSE;
1023 	}
1024 
1025 	RETURN_LONG(ldap_count_entries(ld->link, ldap_result));
1026 }
1027 /* }}} */
1028 
1029 /* {{{ proto resource ldap_first_entry(resource link, resource result)
1030    Return first result id */
PHP_FUNCTION(ldap_first_entry)1031 PHP_FUNCTION(ldap_first_entry)
1032 {
1033 	zval *link, *result;
1034 	ldap_linkdata *ld;
1035 	ldap_resultentry *resultentry;
1036 	LDAPMessage *ldap_result, *entry;
1037 
1038 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rr", &link, &result) != SUCCESS) {
1039 		return;
1040 	}
1041 
1042 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
1043 		RETURN_FALSE;
1044 	}
1045 
1046 	if ((ldap_result = (LDAPMessage *)zend_fetch_resource(Z_RES_P(result), "ldap result", le_result)) == NULL) {
1047 		RETURN_FALSE;
1048 	}
1049 
1050 	if ((entry = ldap_first_entry(ld->link, ldap_result)) == NULL) {
1051 		RETVAL_FALSE;
1052 	} else {
1053 		resultentry = emalloc(sizeof(ldap_resultentry));
1054 		RETVAL_RES(zend_register_resource(resultentry, le_result_entry));
1055 		ZVAL_COPY(&resultentry->res, result);
1056 		resultentry->data = entry;
1057 		resultentry->ber = NULL;
1058 	}
1059 }
1060 /* }}} */
1061 
1062 /* {{{ proto resource ldap_next_entry(resource link, resource result_entry)
1063    Get next result entry */
PHP_FUNCTION(ldap_next_entry)1064 PHP_FUNCTION(ldap_next_entry)
1065 {
1066 	zval *link, *result_entry;
1067 	ldap_linkdata *ld;
1068 	ldap_resultentry *resultentry, *resultentry_next;
1069 	LDAPMessage *entry_next;
1070 
1071 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rr", &link, &result_entry) != SUCCESS) {
1072 		return;
1073 	}
1074 
1075 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
1076 		RETURN_FALSE;
1077 	}
1078 	if ((resultentry = (ldap_resultentry *)zend_fetch_resource(Z_RES_P(result_entry), "ldap result entry", le_result_entry)) == NULL) {
1079 		RETURN_FALSE;
1080 	}
1081 
1082 	if ((entry_next = ldap_next_entry(ld->link, resultentry->data)) == NULL) {
1083 		RETVAL_FALSE;
1084 	} else {
1085 		resultentry_next = emalloc(sizeof(ldap_resultentry));
1086 		RETVAL_RES(zend_register_resource(resultentry_next, le_result_entry));
1087 		ZVAL_COPY(&resultentry_next->res, &resultentry->res);
1088 		resultentry_next->data = entry_next;
1089 		resultentry_next->ber = NULL;
1090 	}
1091 }
1092 /* }}} */
1093 
1094 /* {{{ proto array ldap_get_entries(resource link, resource result)
1095    Get all result entries */
PHP_FUNCTION(ldap_get_entries)1096 PHP_FUNCTION(ldap_get_entries)
1097 {
1098 	zval *link, *result;
1099 	LDAPMessage *ldap_result, *ldap_result_entry;
1100 	zval tmp1, tmp2;
1101 	ldap_linkdata *ld;
1102 	LDAP *ldap;
1103 	int num_entries, num_attrib, num_values, i;
1104 	BerElement *ber;
1105 	char *attribute;
1106 	size_t attr_len;
1107 	struct berval **ldap_value;
1108 	char *dn;
1109 
1110 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rr", &link, &result) != SUCCESS) {
1111 		return;
1112 	}
1113 
1114 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
1115 		RETURN_FALSE;
1116 	}
1117 	if ((ldap_result = (LDAPMessage *)zend_fetch_resource(Z_RES_P(result), "ldap result", le_result)) == NULL) {
1118 		RETURN_FALSE;
1119 	}
1120 
1121 	ldap = ld->link;
1122 	num_entries = ldap_count_entries(ldap, ldap_result);
1123 
1124 	array_init(return_value);
1125 	add_assoc_long(return_value, "count", num_entries);
1126 
1127 	if (num_entries == 0) {
1128 		return;
1129 	}
1130 
1131 	ldap_result_entry = ldap_first_entry(ldap, ldap_result);
1132 	if (ldap_result_entry == NULL) {
1133 		zval_dtor(return_value);
1134 		RETURN_FALSE;
1135 	}
1136 
1137 	num_entries = 0;
1138 	while (ldap_result_entry != NULL) {
1139 		array_init(&tmp1);
1140 
1141 		num_attrib = 0;
1142 		attribute = ldap_first_attribute(ldap, ldap_result_entry, &ber);
1143 
1144 		while (attribute != NULL) {
1145 			ldap_value = ldap_get_values_len(ldap, ldap_result_entry, attribute);
1146 			num_values = ldap_count_values_len(ldap_value);
1147 
1148 			array_init(&tmp2);
1149 			add_assoc_long(&tmp2, "count", num_values);
1150 			for (i = 0; i < num_values; i++) {
1151 				add_index_stringl(&tmp2, i, ldap_value[i]->bv_val, ldap_value[i]->bv_len);
1152 			}
1153 			ldap_value_free_len(ldap_value);
1154 
1155 			attr_len = strlen(attribute);
1156 			zend_hash_str_update(Z_ARRVAL(tmp1), php_strtolower(attribute, attr_len), attr_len, &tmp2);
1157 			add_index_string(&tmp1, num_attrib, attribute);
1158 
1159 			num_attrib++;
1160 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP || WINDOWS
1161 			ldap_memfree(attribute);
1162 #endif
1163 			attribute = ldap_next_attribute(ldap, ldap_result_entry, ber);
1164 		}
1165 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP || WINDOWS
1166 		if (ber != NULL) {
1167 			ber_free(ber, 0);
1168 		}
1169 #endif
1170 
1171 		add_assoc_long(&tmp1, "count", num_attrib);
1172 		dn = ldap_get_dn(ldap, ldap_result_entry);
1173 		if (dn) {
1174 			add_assoc_string(&tmp1, "dn", dn);
1175 		} else {
1176 			add_assoc_null(&tmp1, "dn");
1177 		}
1178 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP || WINDOWS
1179 		ldap_memfree(dn);
1180 #else
1181 		free(dn);
1182 #endif
1183 
1184 		zend_hash_index_update(Z_ARRVAL_P(return_value), num_entries, &tmp1);
1185 
1186 		num_entries++;
1187 		ldap_result_entry = ldap_next_entry(ldap, ldap_result_entry);
1188 	}
1189 
1190 	add_assoc_long(return_value, "count", num_entries);
1191 
1192 }
1193 /* }}} */
1194 
1195 /* {{{ proto string ldap_first_attribute(resource link, resource result_entry)
1196    Return first attribute */
PHP_FUNCTION(ldap_first_attribute)1197 PHP_FUNCTION(ldap_first_attribute)
1198 {
1199 	zval *link, *result_entry;
1200 	ldap_linkdata *ld;
1201 	ldap_resultentry *resultentry;
1202 	char *attribute;
1203 	zend_long dummy_ber;
1204 
1205 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rr|l", &link, &result_entry, &dummy_ber) != SUCCESS) {
1206 		return;
1207 	}
1208 
1209 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
1210 		RETURN_FALSE;
1211 	}
1212 
1213 	if ((resultentry = (ldap_resultentry *)zend_fetch_resource(Z_RES_P(result_entry), "ldap result entry", le_result_entry)) == NULL) {
1214 		RETURN_FALSE;
1215 	}
1216 
1217 	if ((attribute = ldap_first_attribute(ld->link, resultentry->data, &resultentry->ber)) == NULL) {
1218 		RETURN_FALSE;
1219 	} else {
1220 		RETVAL_STRING(attribute);
1221 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP || WINDOWS
1222 		ldap_memfree(attribute);
1223 #endif
1224 	}
1225 }
1226 /* }}} */
1227 
1228 /* {{{ proto string ldap_next_attribute(resource link, resource result_entry)
1229    Get the next attribute in result */
PHP_FUNCTION(ldap_next_attribute)1230 PHP_FUNCTION(ldap_next_attribute)
1231 {
1232 	zval *link, *result_entry;
1233 	ldap_linkdata *ld;
1234 	ldap_resultentry *resultentry;
1235 	char *attribute;
1236 	zend_long dummy_ber;
1237 
1238 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rr|l", &link, &result_entry, &dummy_ber) != SUCCESS) {
1239 		return;
1240 	}
1241 
1242 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
1243 		RETURN_FALSE;
1244 	}
1245 
1246 	if ((resultentry = (ldap_resultentry *)zend_fetch_resource(Z_RES_P(result_entry), "ldap result entry", le_result_entry)) == NULL) {
1247 		RETURN_FALSE;
1248 	}
1249 
1250 	if (resultentry->ber == NULL) {
1251 		php_error_docref(NULL, E_WARNING, "called before calling ldap_first_attribute() or no attributes found in result entry");
1252 		RETURN_FALSE;
1253 	}
1254 
1255 	if ((attribute = ldap_next_attribute(ld->link, resultentry->data, resultentry->ber)) == NULL) {
1256 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP || WINDOWS
1257 		if (resultentry->ber != NULL) {
1258 			ber_free(resultentry->ber, 0);
1259 			resultentry->ber = NULL;
1260 		}
1261 #endif
1262 		RETURN_FALSE;
1263 	} else {
1264 		RETVAL_STRING(attribute);
1265 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP || WINDOWS
1266 		ldap_memfree(attribute);
1267 #endif
1268 	}
1269 }
1270 /* }}} */
1271 
1272 /* {{{ proto array ldap_get_attributes(resource link, resource result_entry)
1273    Get attributes from a search result entry */
PHP_FUNCTION(ldap_get_attributes)1274 PHP_FUNCTION(ldap_get_attributes)
1275 {
1276 	zval *link, *result_entry;
1277 	zval tmp;
1278 	ldap_linkdata *ld;
1279 	ldap_resultentry *resultentry;
1280 	char *attribute;
1281 	struct berval **ldap_value;
1282 	int i, num_values, num_attrib;
1283 	BerElement *ber;
1284 
1285 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rr", &link, &result_entry) != SUCCESS) {
1286 		return;
1287 	}
1288 
1289 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
1290 		RETURN_FALSE;
1291 	}
1292 
1293 	if ((resultentry = (ldap_resultentry *)zend_fetch_resource(Z_RES_P(result_entry), "ldap result entry", le_result_entry)) == NULL) {
1294 		RETURN_FALSE;
1295 	}
1296 
1297 	array_init(return_value);
1298 	num_attrib = 0;
1299 
1300 	attribute = ldap_first_attribute(ld->link, resultentry->data, &ber);
1301 	while (attribute != NULL) {
1302 		ldap_value = ldap_get_values_len(ld->link, resultentry->data, attribute);
1303 		num_values = ldap_count_values_len(ldap_value);
1304 
1305 		array_init(&tmp);
1306 		add_assoc_long(&tmp, "count", num_values);
1307 		for (i = 0; i < num_values; i++) {
1308 			add_index_stringl(&tmp, i, ldap_value[i]->bv_val, ldap_value[i]->bv_len);
1309 		}
1310 		ldap_value_free_len(ldap_value);
1311 
1312 		zend_hash_str_update(Z_ARRVAL_P(return_value), attribute, strlen(attribute), &tmp);
1313 		add_index_string(return_value, num_attrib, attribute);
1314 
1315 		num_attrib++;
1316 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP || WINDOWS
1317 		ldap_memfree(attribute);
1318 #endif
1319 		attribute = ldap_next_attribute(ld->link, resultentry->data, ber);
1320 	}
1321 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP || WINDOWS
1322 	if (ber != NULL) {
1323 		ber_free(ber, 0);
1324 	}
1325 #endif
1326 
1327 	add_assoc_long(return_value, "count", num_attrib);
1328 }
1329 /* }}} */
1330 
1331 /* {{{ proto array ldap_get_values_len(resource link, resource result_entry, string attribute)
1332    Get all values with lengths from a result entry */
PHP_FUNCTION(ldap_get_values_len)1333 PHP_FUNCTION(ldap_get_values_len)
1334 {
1335 	zval *link, *result_entry;
1336 	ldap_linkdata *ld;
1337 	ldap_resultentry *resultentry;
1338 	char *attr;
1339 	struct berval **ldap_value_len;
1340 	int i, num_values;
1341 	size_t attr_len;
1342 
1343 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rrs", &link, &result_entry, &attr, &attr_len) != SUCCESS) {
1344 		return;
1345 	}
1346 
1347 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
1348 		RETURN_FALSE;
1349 	}
1350 
1351 	if ((resultentry = (ldap_resultentry *)zend_fetch_resource(Z_RES_P(result_entry), "ldap result entry", le_result_entry)) == NULL) {
1352 		RETURN_FALSE;
1353 	}
1354 
1355 	if ((ldap_value_len = ldap_get_values_len(ld->link, resultentry->data, attr)) == NULL) {
1356 		php_error_docref(NULL, E_WARNING, "Cannot get the value(s) of attribute %s", ldap_err2string(_get_lderrno(ld->link)));
1357 		RETURN_FALSE;
1358 	}
1359 
1360 	num_values = ldap_count_values_len(ldap_value_len);
1361 	array_init(return_value);
1362 
1363 	for (i=0; i<num_values; i++) {
1364 		add_next_index_stringl(return_value, ldap_value_len[i]->bv_val, ldap_value_len[i]->bv_len);
1365 	}
1366 
1367 	add_assoc_long(return_value, "count", num_values);
1368 	ldap_value_free_len(ldap_value_len);
1369 
1370 }
1371 /* }}} */
1372 
1373 /* {{{ proto string ldap_get_dn(resource link, resource result_entry)
1374    Get the DN of a result entry */
PHP_FUNCTION(ldap_get_dn)1375 PHP_FUNCTION(ldap_get_dn)
1376 {
1377 	zval *link, *result_entry;
1378 	ldap_linkdata *ld;
1379 	ldap_resultentry *resultentry;
1380 	char *text;
1381 
1382 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rr", &link, &result_entry) != SUCCESS) {
1383 		return;
1384 	}
1385 
1386 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
1387 		RETURN_FALSE;
1388 	}
1389 
1390 	if ((resultentry = (ldap_resultentry *)zend_fetch_resource(Z_RES_P(result_entry), "ldap result entry", le_result_entry)) == NULL) {
1391 		RETURN_FALSE;
1392 	}
1393 
1394 	text = ldap_get_dn(ld->link, resultentry->data);
1395 	if (text != NULL) {
1396 		RETVAL_STRING(text);
1397 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP || WINDOWS
1398 		ldap_memfree(text);
1399 #else
1400 		free(text);
1401 #endif
1402 	} else {
1403 		RETURN_FALSE;
1404 	}
1405 }
1406 /* }}} */
1407 
1408 /* {{{ proto array ldap_explode_dn(string dn, int with_attrib)
1409    Splits DN into its component parts */
PHP_FUNCTION(ldap_explode_dn)1410 PHP_FUNCTION(ldap_explode_dn)
1411 {
1412 	zend_long with_attrib;
1413 	char *dn, **ldap_value;
1414 	int i, count;
1415 	size_t dn_len;
1416 
1417 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl", &dn, &dn_len, &with_attrib) != SUCCESS) {
1418 		return;
1419 	}
1420 
1421 	if (!(ldap_value = ldap_explode_dn(dn, with_attrib))) {
1422 		/* Invalid parameters were passed to ldap_explode_dn */
1423 		RETURN_FALSE;
1424 	}
1425 
1426 	i=0;
1427 	while (ldap_value[i] != NULL) i++;
1428 	count = i;
1429 
1430 	array_init(return_value);
1431 
1432 	add_assoc_long(return_value, "count", count);
1433 	for (i = 0; i<count; i++) {
1434 		add_index_string(return_value, i, ldap_value[i]);
1435 	}
1436 
1437 	ldap_memvfree((void **)ldap_value);
1438 }
1439 /* }}} */
1440 
1441 /* {{{ proto string ldap_dn2ufn(string dn)
1442    Convert DN to User Friendly Naming format */
PHP_FUNCTION(ldap_dn2ufn)1443 PHP_FUNCTION(ldap_dn2ufn)
1444 {
1445 	char *dn, *ufn;
1446 	size_t dn_len;
1447 
1448 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &dn, &dn_len) != SUCCESS) {
1449 		return;
1450 	}
1451 
1452 	ufn = ldap_dn2ufn(dn);
1453 
1454 	if (ufn != NULL) {
1455 		RETVAL_STRING(ufn);
1456 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP || WINDOWS
1457 		ldap_memfree(ufn);
1458 #endif
1459 	} else {
1460 		RETURN_FALSE;
1461 	}
1462 }
1463 /* }}} */
1464 
1465 
1466 /* added to fix use of ldap_modify_add for doing an ldap_add, gerrit thomson. */
1467 #define PHP_LD_FULL_ADD 0xff
1468 /* {{{ php_ldap_do_modify
1469  */
php_ldap_do_modify(INTERNAL_FUNCTION_PARAMETERS,int oper)1470 static void php_ldap_do_modify(INTERNAL_FUNCTION_PARAMETERS, int oper)
1471 {
1472 	zval *link, *entry, *value, *ivalue;
1473 	ldap_linkdata *ld;
1474 	char *dn;
1475 	LDAPMod **ldap_mods;
1476 	int i, j, num_attribs, num_values;
1477 	size_t dn_len;
1478 	int *num_berval;
1479 	zend_string *attribute;
1480 	zend_ulong index;
1481 	int is_full_add=0; /* flag for full add operation so ldap_mod_add can be put back into oper, gerrit THomson */
1482 
1483 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsa/", &link, &dn, &dn_len, &entry) != SUCCESS) {
1484 		return;
1485 	}
1486 
1487 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
1488 		RETURN_FALSE;
1489 	}
1490 
1491 	num_attribs = zend_hash_num_elements(Z_ARRVAL_P(entry));
1492 	ldap_mods = safe_emalloc((num_attribs+1), sizeof(LDAPMod *), 0);
1493 	num_berval = safe_emalloc(num_attribs, sizeof(int), 0);
1494 	zend_hash_internal_pointer_reset(Z_ARRVAL_P(entry));
1495 
1496 	/* added by gerrit thomson to fix ldap_add using ldap_mod_add */
1497 	if (oper == PHP_LD_FULL_ADD) {
1498 		oper = LDAP_MOD_ADD;
1499 		is_full_add = 1;
1500 	}
1501 	/* end additional , gerrit thomson */
1502 
1503 	for (i = 0; i < num_attribs; i++) {
1504 		ldap_mods[i] = emalloc(sizeof(LDAPMod));
1505 		ldap_mods[i]->mod_op = oper | LDAP_MOD_BVALUES;
1506 		ldap_mods[i]->mod_type = NULL;
1507 
1508 		if (zend_hash_get_current_key(Z_ARRVAL_P(entry), &attribute, &index) == HASH_KEY_IS_STRING) {
1509 			ldap_mods[i]->mod_type = estrndup(ZSTR_VAL(attribute), ZSTR_LEN(attribute));
1510 		} else {
1511 			php_error_docref(NULL, E_WARNING, "Unknown attribute in the data");
1512 			/* Free allocated memory */
1513 			while (i >= 0) {
1514 				if (ldap_mods[i]->mod_type) {
1515 					efree(ldap_mods[i]->mod_type);
1516 				}
1517 				efree(ldap_mods[i]);
1518 				i--;
1519 			}
1520 			efree(num_berval);
1521 			efree(ldap_mods);
1522 			RETURN_FALSE;
1523 		}
1524 
1525 		value = zend_hash_get_current_data(Z_ARRVAL_P(entry));
1526 
1527 		ZVAL_DEREF(value);
1528 		if (Z_TYPE_P(value) != IS_ARRAY) {
1529 			num_values = 1;
1530 		} else {
1531 			SEPARATE_ARRAY(value);
1532 			num_values = zend_hash_num_elements(Z_ARRVAL_P(value));
1533 		}
1534 
1535 		num_berval[i] = num_values;
1536 		ldap_mods[i]->mod_bvalues = safe_emalloc((num_values + 1), sizeof(struct berval *), 0);
1537 
1538 /* allow for arrays with one element, no allowance for arrays with none but probably not required, gerrit thomson. */
1539 		if ((num_values == 1) && (Z_TYPE_P(value) != IS_ARRAY)) {
1540 			convert_to_string_ex(value);
1541 			ldap_mods[i]->mod_bvalues[0] = (struct berval *) emalloc (sizeof(struct berval));
1542 			ldap_mods[i]->mod_bvalues[0]->bv_len = Z_STRLEN_P(value);
1543 			ldap_mods[i]->mod_bvalues[0]->bv_val = Z_STRVAL_P(value);
1544 		} else {
1545 			for (j = 0; j < num_values; j++) {
1546 				if ((ivalue = zend_hash_index_find(Z_ARRVAL_P(value), j)) == NULL) {
1547 					php_error_docref(NULL, E_WARNING, "Value array must have consecutive indices 0, 1, ...");
1548 					num_berval[i] = j;
1549 					num_attribs = i + 1;
1550 					RETVAL_FALSE;
1551 					goto errexit;
1552 				}
1553 				convert_to_string_ex(ivalue);
1554 				ldap_mods[i]->mod_bvalues[j] = (struct berval *) emalloc (sizeof(struct berval));
1555 				ldap_mods[i]->mod_bvalues[j]->bv_len = Z_STRLEN_P(ivalue);
1556 				ldap_mods[i]->mod_bvalues[j]->bv_val = Z_STRVAL_P(ivalue);
1557 			}
1558 		}
1559 		ldap_mods[i]->mod_bvalues[num_values] = NULL;
1560 		zend_hash_move_forward(Z_ARRVAL_P(entry));
1561 	}
1562 	ldap_mods[num_attribs] = NULL;
1563 
1564 /* check flag to see if do_mod was called to perform full add , gerrit thomson */
1565 	if (is_full_add == 1) {
1566 		if ((i = ldap_add_ext_s(ld->link, dn, ldap_mods, NULL, NULL)) != LDAP_SUCCESS) {
1567 			php_error_docref(NULL, E_WARNING, "Add: %s", ldap_err2string(i));
1568 			RETVAL_FALSE;
1569 		} else RETVAL_TRUE;
1570 	} else {
1571 		if ((i = ldap_modify_ext_s(ld->link, dn, ldap_mods, NULL, NULL)) != LDAP_SUCCESS) {
1572 			php_error_docref(NULL, E_WARNING, "Modify: %s", ldap_err2string(i));
1573 			RETVAL_FALSE;
1574 		} else RETVAL_TRUE;
1575 	}
1576 
1577 errexit:
1578 	for (i = 0; i < num_attribs; i++) {
1579 		efree(ldap_mods[i]->mod_type);
1580 		for (j = 0; j < num_berval[i]; j++) {
1581 			efree(ldap_mods[i]->mod_bvalues[j]);
1582 		}
1583 		efree(ldap_mods[i]->mod_bvalues);
1584 		efree(ldap_mods[i]);
1585 	}
1586 	efree(num_berval);
1587 	efree(ldap_mods);
1588 
1589 	return;
1590 }
1591 /* }}} */
1592 
1593 /* {{{ proto bool ldap_add(resource link, string dn, array entry)
1594    Add entries to LDAP directory */
PHP_FUNCTION(ldap_add)1595 PHP_FUNCTION(ldap_add)
1596 {
1597 	/* 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 */
1598 	php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_LD_FULL_ADD);
1599 }
1600 /* }}} */
1601 
1602 /* three functions for attribute base modifications, gerrit Thomson */
1603 
1604 /* {{{ proto bool ldap_mod_replace(resource link, string dn, array entry)
1605    Replace attribute values with new ones */
PHP_FUNCTION(ldap_mod_replace)1606 PHP_FUNCTION(ldap_mod_replace)
1607 {
1608 	php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_REPLACE);
1609 }
1610 /* }}} */
1611 
1612 /* {{{ proto bool ldap_mod_add(resource link, string dn, array entry)
1613    Add attribute values to current */
PHP_FUNCTION(ldap_mod_add)1614 PHP_FUNCTION(ldap_mod_add)
1615 {
1616 	php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_ADD);
1617 }
1618 /* }}} */
1619 
1620 /* {{{ proto bool ldap_mod_del(resource link, string dn, array entry)
1621    Delete attribute values */
PHP_FUNCTION(ldap_mod_del)1622 PHP_FUNCTION(ldap_mod_del)
1623 {
1624 	php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_DELETE);
1625 }
1626 /* }}} */
1627 
1628 /* {{{ proto bool ldap_delete(resource link, string dn)
1629    Delete an entry from a directory */
PHP_FUNCTION(ldap_delete)1630 PHP_FUNCTION(ldap_delete)
1631 {
1632 	zval *link;
1633 	ldap_linkdata *ld;
1634 	char *dn;
1635 	int rc;
1636 	size_t dn_len;
1637 
1638 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &link, &dn, &dn_len) != SUCCESS) {
1639 		return;
1640 	}
1641 
1642 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
1643 		RETURN_FALSE;
1644 	}
1645 
1646 	if ((rc = ldap_delete_ext_s(ld->link, dn, NULL, NULL)) != LDAP_SUCCESS) {
1647 		php_error_docref(NULL, E_WARNING, "Delete: %s", ldap_err2string(rc));
1648 		RETURN_FALSE;
1649 	}
1650 
1651 	RETURN_TRUE;
1652 }
1653 /* }}} */
1654 
1655 /* {{{ _ldap_str_equal_to_const
1656  */
_ldap_str_equal_to_const(const char * str,uint str_len,const char * cstr)1657 static int _ldap_str_equal_to_const(const char *str, uint str_len, const char *cstr)
1658 {
1659 	uint i;
1660 
1661 	if (strlen(cstr) != str_len)
1662 		return 0;
1663 
1664 	for (i = 0; i < str_len; ++i) {
1665 		if (str[i] != cstr[i]) {
1666 			return 0;
1667 		}
1668 	}
1669 
1670 	return 1;
1671 }
1672 /* }}} */
1673 
1674 /* {{{ _ldap_strlen_max
1675  */
_ldap_strlen_max(const char * str,uint max_len)1676 static int _ldap_strlen_max(const char *str, uint max_len)
1677 {
1678 	uint i;
1679 
1680 	for (i = 0; i < max_len; ++i) {
1681 		if (str[i] == '\0') {
1682 			return i;
1683 		}
1684 	}
1685 
1686 	return max_len;
1687 }
1688 /* }}} */
1689 
1690 /* {{{ _ldap_hash_fetch
1691  */
_ldap_hash_fetch(zval * hashTbl,const char * key,zval ** out)1692 static void _ldap_hash_fetch(zval *hashTbl, const char *key, zval **out)
1693 {
1694 	*out = zend_hash_str_find(Z_ARRVAL_P(hashTbl), key, strlen(key));
1695 }
1696 /* }}} */
1697 
1698 /* {{{ proto bool ldap_modify_batch(resource link, string dn, array modifs)
1699    Perform multiple modifications as part of one operation */
PHP_FUNCTION(ldap_modify_batch)1700 PHP_FUNCTION(ldap_modify_batch)
1701 {
1702 	ldap_linkdata *ld;
1703 	zval *link, *mods, *mod, *modinfo, *modval;
1704 	zval *attrib, *modtype, *vals;
1705 	zval *fetched;
1706 	char *dn;
1707 	size_t dn_len;
1708 	int i, j, k;
1709 	int num_mods, num_modprops, num_modvals;
1710 	LDAPMod **ldap_mods;
1711 	uint oper;
1712 
1713 	/*
1714 	$mods = array(
1715 		array(
1716 			"attrib" => "unicodePwd",
1717 			"modtype" => LDAP_MODIFY_BATCH_REMOVE,
1718 			"values" => array($oldpw)
1719 		),
1720 		array(
1721 			"attrib" => "unicodePwd",
1722 			"modtype" => LDAP_MODIFY_BATCH_ADD,
1723 			"values" => array($newpw)
1724 		),
1725 		array(
1726 			"attrib" => "userPrincipalName",
1727 			"modtype" => LDAP_MODIFY_BATCH_REPLACE,
1728 			"values" => array("janitor@corp.contoso.com")
1729 		),
1730 		array(
1731 			"attrib" => "userCert",
1732 			"modtype" => LDAP_MODIFY_BATCH_REMOVE_ALL
1733 		)
1734 	);
1735 	*/
1736 
1737 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsa/", &link, &dn, &dn_len, &mods) != SUCCESS) {
1738 		return;
1739 	}
1740 
1741 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
1742 		RETURN_FALSE;
1743 	}
1744 
1745 	/* perform validation */
1746 	{
1747 		zend_string *modkey;
1748 		zend_long modtype;
1749 
1750 		/* to store the wrongly-typed keys */
1751 		zend_ulong tmpUlong;
1752 
1753 		/* make sure the DN contains no NUL bytes */
1754 		if ((size_t)_ldap_strlen_max(dn, dn_len) != dn_len) {
1755 			php_error_docref(NULL, E_WARNING, "DN must not contain NUL bytes");
1756 			RETURN_FALSE;
1757 		}
1758 
1759 		/* make sure the top level is a normal array */
1760 		zend_hash_internal_pointer_reset(Z_ARRVAL_P(mods));
1761 		if (zend_hash_get_current_key_type(Z_ARRVAL_P(mods)) != HASH_KEY_IS_LONG) {
1762 			php_error_docref(NULL, E_WARNING, "Modifications array must not be string-indexed");
1763 			RETURN_FALSE;
1764 		}
1765 
1766 		num_mods = zend_hash_num_elements(Z_ARRVAL_P(mods));
1767 
1768 		for (i = 0; i < num_mods; i++) {
1769 			/* is the numbering consecutive? */
1770 			if ((fetched = zend_hash_index_find(Z_ARRVAL_P(mods), i)) == NULL) {
1771 				php_error_docref(NULL, E_WARNING, "Modifications array must have consecutive indices 0, 1, ...");
1772 				RETURN_FALSE;
1773 			}
1774 			mod = fetched;
1775 
1776 			/* is it an array? */
1777 			if (Z_TYPE_P(mod) != IS_ARRAY) {
1778 				php_error_docref(NULL, E_WARNING, "Each entry of modifications array must be an array itself");
1779 				RETURN_FALSE;
1780 			}
1781 
1782 			SEPARATE_ARRAY(mod);
1783 			/* for the modification hashtable... */
1784 			zend_hash_internal_pointer_reset(Z_ARRVAL_P(mod));
1785 			num_modprops = zend_hash_num_elements(Z_ARRVAL_P(mod));
1786 
1787 			for (j = 0; j < num_modprops; j++) {
1788 				/* are the keys strings? */
1789 				if (zend_hash_get_current_key(Z_ARRVAL_P(mod), &modkey, &tmpUlong) != HASH_KEY_IS_STRING) {
1790 					php_error_docref(NULL, E_WARNING, "Each entry of modifications array must be string-indexed");
1791 					RETURN_FALSE;
1792 				}
1793 
1794 				/* is this a valid entry? */
1795 				if (
1796 					!_ldap_str_equal_to_const(ZSTR_VAL(modkey), ZSTR_LEN(modkey), LDAP_MODIFY_BATCH_ATTRIB) &&
1797 					!_ldap_str_equal_to_const(ZSTR_VAL(modkey), ZSTR_LEN(modkey), LDAP_MODIFY_BATCH_MODTYPE) &&
1798 					!_ldap_str_equal_to_const(ZSTR_VAL(modkey), ZSTR_LEN(modkey), LDAP_MODIFY_BATCH_VALUES)
1799 				) {
1800 					php_error_docref(NULL, E_WARNING, "The only allowed keys in entries of the modifications array are '" LDAP_MODIFY_BATCH_ATTRIB "', '" LDAP_MODIFY_BATCH_MODTYPE "' and '" LDAP_MODIFY_BATCH_VALUES "'");
1801 					RETURN_FALSE;
1802 				}
1803 
1804 				fetched = zend_hash_get_current_data(Z_ARRVAL_P(mod));
1805 				modinfo = fetched;
1806 
1807 				/* does the value type match the key? */
1808 				if (_ldap_str_equal_to_const(ZSTR_VAL(modkey), ZSTR_LEN(modkey), LDAP_MODIFY_BATCH_ATTRIB)) {
1809 					if (Z_TYPE_P(modinfo) != IS_STRING) {
1810 						php_error_docref(NULL, E_WARNING, "A '" LDAP_MODIFY_BATCH_ATTRIB "' value must be a string");
1811 						RETURN_FALSE;
1812 					}
1813 
1814 					if (Z_STRLEN_P(modinfo) != (size_t)_ldap_strlen_max(Z_STRVAL_P(modinfo), Z_STRLEN_P(modinfo))) {
1815 						php_error_docref(NULL, E_WARNING, "A '" LDAP_MODIFY_BATCH_ATTRIB "' value must not contain NUL bytes");
1816 						RETURN_FALSE;
1817 					}
1818 				}
1819 				else if (_ldap_str_equal_to_const(ZSTR_VAL(modkey), ZSTR_LEN(modkey), LDAP_MODIFY_BATCH_MODTYPE)) {
1820 					if (Z_TYPE_P(modinfo) != IS_LONG) {
1821 						php_error_docref(NULL, E_WARNING, "A '" LDAP_MODIFY_BATCH_MODTYPE "' value must be a long");
1822 						RETURN_FALSE;
1823 					}
1824 
1825 					/* is the value in range? */
1826 					modtype = Z_LVAL_P(modinfo);
1827 					if (
1828 						modtype != LDAP_MODIFY_BATCH_ADD &&
1829 						modtype != LDAP_MODIFY_BATCH_REMOVE &&
1830 						modtype != LDAP_MODIFY_BATCH_REPLACE &&
1831 						modtype != LDAP_MODIFY_BATCH_REMOVE_ALL
1832 					) {
1833 						php_error_docref(NULL, E_WARNING, "The '" LDAP_MODIFY_BATCH_MODTYPE "' value must match one of the LDAP_MODIFY_BATCH_* constants");
1834 						RETURN_FALSE;
1835 					}
1836 
1837 					/* if it's REMOVE_ALL, there must not be a values array; otherwise, there must */
1838 					if (modtype == LDAP_MODIFY_BATCH_REMOVE_ALL) {
1839 						if (zend_hash_str_exists(Z_ARRVAL_P(mod), LDAP_MODIFY_BATCH_VALUES, strlen(LDAP_MODIFY_BATCH_VALUES))) {
1840 							php_error_docref(NULL, E_WARNING, "If '" LDAP_MODIFY_BATCH_MODTYPE "' is LDAP_MODIFY_BATCH_REMOVE_ALL, a '" LDAP_MODIFY_BATCH_VALUES "' array must not be provided");
1841 							RETURN_FALSE;
1842 						}
1843 					}
1844 					else {
1845 						if (!zend_hash_str_exists(Z_ARRVAL_P(mod), LDAP_MODIFY_BATCH_VALUES, strlen(LDAP_MODIFY_BATCH_VALUES))) {
1846 							php_error_docref(NULL, E_WARNING, "If '" LDAP_MODIFY_BATCH_MODTYPE "' is not LDAP_MODIFY_BATCH_REMOVE_ALL, a '" LDAP_MODIFY_BATCH_VALUES "' array must be provided");
1847 							RETURN_FALSE;
1848 						}
1849 					}
1850 				}
1851 				else if (_ldap_str_equal_to_const(ZSTR_VAL(modkey), ZSTR_LEN(modkey), LDAP_MODIFY_BATCH_VALUES)) {
1852 					if (Z_TYPE_P(modinfo) != IS_ARRAY) {
1853 						php_error_docref(NULL, E_WARNING, "A '" LDAP_MODIFY_BATCH_VALUES "' value must be an array");
1854 						RETURN_FALSE;
1855 					}
1856 
1857 					SEPARATE_ARRAY(modinfo);
1858 					/* is the array not empty? */
1859 					zend_hash_internal_pointer_reset(Z_ARRVAL_P(modinfo));
1860 					num_modvals = zend_hash_num_elements(Z_ARRVAL_P(modinfo));
1861 					if (num_modvals == 0) {
1862 						php_error_docref(NULL, E_WARNING, "A '" LDAP_MODIFY_BATCH_VALUES "' array must have at least one element");
1863 						RETURN_FALSE;
1864 					}
1865 
1866 					/* are its keys integers? */
1867 					if (zend_hash_get_current_key_type(Z_ARRVAL_P(modinfo)) != HASH_KEY_IS_LONG) {
1868 						php_error_docref(NULL, E_WARNING, "A '" LDAP_MODIFY_BATCH_VALUES "' array must not be string-indexed");
1869 						RETURN_FALSE;
1870 					}
1871 
1872 					/* are the keys consecutive? */
1873 					for (k = 0; k < num_modvals; k++) {
1874 						if ((fetched = zend_hash_index_find(Z_ARRVAL_P(modinfo), k)) == NULL) {
1875 							php_error_docref(NULL, E_WARNING, "A '" LDAP_MODIFY_BATCH_VALUES "' array must have consecutive indices 0, 1, ...");
1876 							RETURN_FALSE;
1877 						}
1878 						modval = fetched;
1879 
1880 						/* is the data element a string? */
1881 						if (Z_TYPE_P(modval) != IS_STRING) {
1882 							php_error_docref(NULL, E_WARNING, "Each element of a '" LDAP_MODIFY_BATCH_VALUES "' array must be a string");
1883 							RETURN_FALSE;
1884 						}
1885 					}
1886 				}
1887 
1888 				zend_hash_move_forward(Z_ARRVAL_P(mod));
1889 			}
1890 		}
1891 	}
1892 	/* validation was successful */
1893 
1894 	/* allocate array of modifications */
1895 	ldap_mods = safe_emalloc((num_mods+1), sizeof(LDAPMod *), 0);
1896 
1897 	/* for each modification */
1898 	for (i = 0; i < num_mods; i++) {
1899 		/* allocate the modification struct */
1900 		ldap_mods[i] = safe_emalloc(1, sizeof(LDAPMod), 0);
1901 
1902 		/* fetch the relevant data */
1903 		fetched = zend_hash_index_find(Z_ARRVAL_P(mods), i);
1904 		mod = fetched;
1905 
1906 		_ldap_hash_fetch(mod, LDAP_MODIFY_BATCH_ATTRIB, &attrib);
1907 		_ldap_hash_fetch(mod, LDAP_MODIFY_BATCH_MODTYPE, &modtype);
1908 		_ldap_hash_fetch(mod, LDAP_MODIFY_BATCH_VALUES, &vals);
1909 
1910 		/* map the modification type */
1911 		switch (Z_LVAL_P(modtype)) {
1912 			case LDAP_MODIFY_BATCH_ADD:
1913 				oper = LDAP_MOD_ADD;
1914 				break;
1915 			case LDAP_MODIFY_BATCH_REMOVE:
1916 			case LDAP_MODIFY_BATCH_REMOVE_ALL:
1917 				oper = LDAP_MOD_DELETE;
1918 				break;
1919 			case LDAP_MODIFY_BATCH_REPLACE:
1920 				oper = LDAP_MOD_REPLACE;
1921 				break;
1922 			default:
1923 				zend_throw_error(NULL, "Unknown and uncaught modification type.");
1924 				RETVAL_FALSE;
1925 				efree(ldap_mods[i]);
1926 				num_mods = i;
1927 				goto cleanup;
1928 		}
1929 
1930 		/* fill in the basic info */
1931 		ldap_mods[i]->mod_op = oper | LDAP_MOD_BVALUES;
1932 		ldap_mods[i]->mod_type = estrndup(Z_STRVAL_P(attrib), Z_STRLEN_P(attrib));
1933 
1934 		if (Z_LVAL_P(modtype) == LDAP_MODIFY_BATCH_REMOVE_ALL) {
1935 			/* no values */
1936 			ldap_mods[i]->mod_bvalues = NULL;
1937 		}
1938 		else {
1939 			/* allocate space for the values as part of this modification */
1940 			num_modvals = zend_hash_num_elements(Z_ARRVAL_P(vals));
1941 			ldap_mods[i]->mod_bvalues = safe_emalloc((num_modvals+1), sizeof(struct berval *), 0);
1942 
1943 			/* for each value */
1944 			for (j = 0; j < num_modvals; j++) {
1945 				/* fetch it */
1946 				fetched = zend_hash_index_find(Z_ARRVAL_P(vals), j);
1947 				modval = fetched;
1948 
1949 				/* allocate the data struct */
1950 				ldap_mods[i]->mod_bvalues[j] = safe_emalloc(1, sizeof(struct berval), 0);
1951 
1952 				/* fill it */
1953 				ldap_mods[i]->mod_bvalues[j]->bv_len = Z_STRLEN_P(modval);
1954 				ldap_mods[i]->mod_bvalues[j]->bv_val = estrndup(Z_STRVAL_P(modval), Z_STRLEN_P(modval));
1955 			}
1956 
1957 			/* NULL-terminate values */
1958 			ldap_mods[i]->mod_bvalues[num_modvals] = NULL;
1959 		}
1960 	}
1961 
1962 	/* NULL-terminate modifications */
1963 	ldap_mods[num_mods] = NULL;
1964 
1965 	/* perform (finally) */
1966 	if ((i = ldap_modify_ext_s(ld->link, dn, ldap_mods, NULL, NULL)) != LDAP_SUCCESS) {
1967 		php_error_docref(NULL, E_WARNING, "Batch Modify: %s", ldap_err2string(i));
1968 		RETVAL_FALSE;
1969 	} else RETVAL_TRUE;
1970 
1971 	/* clean up */
1972 	cleanup: {
1973 		for (i = 0; i < num_mods; i++) {
1974 			/* attribute */
1975 			efree(ldap_mods[i]->mod_type);
1976 
1977 			if (ldap_mods[i]->mod_bvalues != NULL) {
1978 				/* each BER value */
1979 				for (j = 0; ldap_mods[i]->mod_bvalues[j] != NULL; j++) {
1980 					/* free the data bytes */
1981 					efree(ldap_mods[i]->mod_bvalues[j]->bv_val);
1982 
1983 					/* free the bvalue struct */
1984 					efree(ldap_mods[i]->mod_bvalues[j]);
1985 				}
1986 
1987 				/* the BER value array */
1988 				efree(ldap_mods[i]->mod_bvalues);
1989 			}
1990 
1991 			/* the modification */
1992 			efree(ldap_mods[i]);
1993 		}
1994 
1995 		/* the modifications array */
1996 		efree(ldap_mods);
1997 	}
1998 }
1999 /* }}} */
2000 
2001 /* {{{ proto int ldap_errno(resource link)
2002    Get the current ldap error number */
PHP_FUNCTION(ldap_errno)2003 PHP_FUNCTION(ldap_errno)
2004 {
2005 	zval *link;
2006 	ldap_linkdata *ld;
2007 
2008 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &link) != SUCCESS) {
2009 		return;
2010 	}
2011 
2012 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
2013 		RETURN_FALSE;
2014 	}
2015 
2016 	RETURN_LONG(_get_lderrno(ld->link));
2017 }
2018 /* }}} */
2019 
2020 /* {{{ proto string ldap_err2str(int errno)
2021    Convert error number to error string */
PHP_FUNCTION(ldap_err2str)2022 PHP_FUNCTION(ldap_err2str)
2023 {
2024 	zend_long perrno;
2025 
2026 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &perrno) != SUCCESS) {
2027 		return;
2028 	}
2029 
2030 	RETURN_STRING(ldap_err2string(perrno));
2031 }
2032 /* }}} */
2033 
2034 /* {{{ proto string ldap_error(resource link)
2035    Get the current ldap error string */
PHP_FUNCTION(ldap_error)2036 PHP_FUNCTION(ldap_error)
2037 {
2038 	zval *link;
2039 	ldap_linkdata *ld;
2040 	int ld_errno;
2041 
2042 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &link) != SUCCESS) {
2043 		return;
2044 	}
2045 
2046 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
2047 		RETURN_FALSE;
2048 	}
2049 
2050 	ld_errno = _get_lderrno(ld->link);
2051 
2052 	RETURN_STRING(ldap_err2string(ld_errno));
2053 }
2054 /* }}} */
2055 
2056 /* {{{ proto bool ldap_compare(resource link, string dn, string attr, string value)
2057    Determine if an entry has a specific value for one of its attributes */
PHP_FUNCTION(ldap_compare)2058 PHP_FUNCTION(ldap_compare)
2059 {
2060 	zval *link;
2061 	char *dn, *attr, *value;
2062 	size_t dn_len, attr_len, value_len;
2063 	ldap_linkdata *ld;
2064 	int errno;
2065 	struct berval lvalue;
2066 
2067 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsss", &link, &dn, &dn_len, &attr, &attr_len, &value, &value_len) != SUCCESS) {
2068 		return;
2069 	}
2070 
2071 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
2072 		RETURN_FALSE;
2073 	}
2074 
2075 	lvalue.bv_val = value;
2076 	lvalue.bv_len = value_len;
2077 
2078 	errno = ldap_compare_ext_s(ld->link, dn, attr, &lvalue, NULL, NULL);
2079 
2080 	switch (errno) {
2081 		case LDAP_COMPARE_TRUE:
2082 			RETURN_TRUE;
2083 			break;
2084 
2085 		case LDAP_COMPARE_FALSE:
2086 			RETURN_FALSE;
2087 			break;
2088 	}
2089 
2090 	php_error_docref(NULL, E_WARNING, "Compare: %s", ldap_err2string(errno));
2091 	RETURN_LONG(-1);
2092 }
2093 /* }}} */
2094 
2095 /* {{{ proto bool ldap_sort(resource link, resource result, string sortfilter)
2096    Sort LDAP result entries */
PHP_FUNCTION(ldap_sort)2097 PHP_FUNCTION(ldap_sort)
2098 {
2099 	zval *link, *result;
2100 	ldap_linkdata *ld;
2101 	char *sortfilter;
2102 	size_t sflen;
2103 	zend_resource *le;
2104 
2105 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rrs", &link, &result, &sortfilter, &sflen) != SUCCESS) {
2106 		RETURN_FALSE;
2107 	}
2108 
2109 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
2110 		RETURN_FALSE;
2111 	}
2112 
2113 	le = Z_RES_P(result);
2114 	if (le->type != le_result) {
2115 		php_error_docref(NULL, E_WARNING, "Supplied resource is not a valid ldap result resource");
2116 		RETURN_FALSE;
2117 	}
2118 
2119 	if (ldap_sort_entries(ld->link, (LDAPMessage **) &le->ptr, sflen ? sortfilter : NULL, strcmp) != LDAP_SUCCESS) {
2120 		php_error_docref(NULL, E_WARNING, "%s", ldap_err2string(errno));
2121 		RETURN_FALSE;
2122 	}
2123 
2124 	RETURN_TRUE;
2125 }
2126 /* }}} */
2127 
2128 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP
2129 /* {{{ proto bool ldap_get_option(resource link, int option, mixed retval)
2130    Get the current value of various session-wide parameters */
PHP_FUNCTION(ldap_get_option)2131 PHP_FUNCTION(ldap_get_option)
2132 {
2133 	zval *link, *retval;
2134 	ldap_linkdata *ld;
2135 	zend_long option;
2136 
2137 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rlz/", &link, &option, &retval) != SUCCESS) {
2138 		return;
2139 	}
2140 
2141 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
2142 		RETURN_FALSE;
2143 	}
2144 
2145 	switch (option) {
2146 	/* options with int value */
2147 	case LDAP_OPT_DEREF:
2148 	case LDAP_OPT_SIZELIMIT:
2149 	case LDAP_OPT_TIMELIMIT:
2150 	case LDAP_OPT_PROTOCOL_VERSION:
2151 	case LDAP_OPT_ERROR_NUMBER:
2152 	case LDAP_OPT_REFERRALS:
2153 #ifdef LDAP_OPT_RESTART
2154 	case LDAP_OPT_RESTART:
2155 #endif
2156 #ifdef LDAP_OPT_X_SASL_NOCANON
2157 	case LDAP_OPT_X_SASL_NOCANON:
2158 #endif
2159 #ifdef LDAP_OPT_X_TLS_REQUIRE_CERT
2160 	case LDAP_OPT_X_TLS_REQUIRE_CERT:
2161 #endif
2162 #ifdef LDAP_OPT_X_TLS_CRLCHECK
2163 	case LDAP_OPT_X_TLS_CRLCHECK:
2164 #endif
2165 #ifdef LDAP_OPT_X_TLS_PROTOCOL_MIN
2166 	case LDAP_OPT_X_TLS_PROTOCOL_MIN:
2167 #endif
2168 #ifdef LDAP_OPT_X_KEEPALIVE_IDLE
2169 	case LDAP_OPT_X_KEEPALIVE_IDLE:
2170 	case LDAP_OPT_X_KEEPALIVE_PROBES:
2171 	case LDAP_OPT_X_KEEPALIVE_INTERVAL:
2172 #endif
2173 		{
2174 			int val;
2175 
2176 			if (ldap_get_option(ld->link, option, &val)) {
2177 				RETURN_FALSE;
2178 			}
2179 			zval_ptr_dtor(retval);
2180 			ZVAL_LONG(retval, val);
2181 		} break;
2182 #ifdef LDAP_OPT_NETWORK_TIMEOUT
2183 	case LDAP_OPT_NETWORK_TIMEOUT:
2184 		{
2185 			struct timeval *timeout = NULL;
2186 
2187 			if (ldap_get_option(ld->link, LDAP_OPT_NETWORK_TIMEOUT, (void *) &timeout)) {
2188 				if (timeout) {
2189 					ldap_memfree(timeout);
2190 				}
2191 				RETURN_FALSE;
2192 			}
2193 			if (!timeout) {
2194 				RETURN_FALSE;
2195 			}
2196 			zval_ptr_dtor(retval);
2197 			ZVAL_LONG(retval, timeout->tv_sec);
2198 			ldap_memfree(timeout);
2199 		} break;
2200 #elif defined(LDAP_X_OPT_CONNECT_TIMEOUT)
2201 	case LDAP_X_OPT_CONNECT_TIMEOUT:
2202 		{
2203 			int timeout;
2204 
2205 			if (ldap_get_option(ld->link, LDAP_X_OPT_CONNECT_TIMEOUT, &timeout)) {
2206 				RETURN_FALSE;
2207 			}
2208 			zval_ptr_dtor(retval);
2209 			ZVAL_LONG(retval, (timeout / 1000));
2210 		} break;
2211 #endif
2212 #ifdef LDAP_OPT_TIMEOUT
2213 	case LDAP_OPT_TIMEOUT:
2214 		{
2215 			struct timeval *timeout = NULL;
2216 
2217 			if (ldap_get_option(ld->link, LDAP_OPT_TIMEOUT, (void *) &timeout)) {
2218 				if (timeout) {
2219 					ldap_memfree(timeout);
2220 				}
2221 				RETURN_FALSE;
2222 			}
2223 			if (!timeout) {
2224 				RETURN_FALSE;
2225 			}
2226 			zval_dtor(retval);
2227 			ZVAL_LONG(retval, timeout->tv_sec);
2228 			ldap_memfree(timeout);
2229 		} break;
2230 #endif
2231 	/* options with string value */
2232 	case LDAP_OPT_ERROR_STRING:
2233 #ifdef LDAP_OPT_HOST_NAME
2234 	case LDAP_OPT_HOST_NAME:
2235 #endif
2236 #ifdef HAVE_LDAP_SASL
2237 	case LDAP_OPT_X_SASL_MECH:
2238 	case LDAP_OPT_X_SASL_REALM:
2239 	case LDAP_OPT_X_SASL_AUTHCID:
2240 	case LDAP_OPT_X_SASL_AUTHZID:
2241 #endif
2242 #ifdef LDAP_OPT_X_SASL_USERNAME
2243 	case LDAP_OPT_X_SASL_USERNAME:
2244 #endif
2245 #if (LDAP_API_VERSION > 2000)
2246 	case LDAP_OPT_X_TLS_CACERTDIR:
2247 	case LDAP_OPT_X_TLS_CACERTFILE:
2248 	case LDAP_OPT_X_TLS_CERTFILE:
2249 	case LDAP_OPT_X_TLS_CIPHER_SUITE:
2250 	case LDAP_OPT_X_TLS_KEYFILE:
2251 	case LDAP_OPT_X_TLS_RANDOM_FILE:
2252 #endif
2253 #ifdef LDAP_OPT_X_TLS_PACKAGE
2254 	case LDAP_OPT_X_TLS_PACKAGE:
2255 #endif
2256 #ifdef LDAP_OPT_X_TLS_CRLFILE
2257 	case LDAP_OPT_X_TLS_CRLFILE:
2258 #endif
2259 #ifdef LDAP_OPT_X_TLS_DHFILE
2260 	case LDAP_OPT_X_TLS_DHFILE:
2261 #endif
2262 #ifdef LDAP_OPT_MATCHED_DN
2263 	case LDAP_OPT_MATCHED_DN:
2264 #endif
2265 		{
2266 			char *val = NULL;
2267 
2268 			if (ldap_get_option(ld->link, option, &val) || val == NULL || *val == '\0') {
2269 				if (val) {
2270 					ldap_memfree(val);
2271 				}
2272 				RETURN_FALSE;
2273 			}
2274 			zval_ptr_dtor(retval);
2275 			ZVAL_STRING(retval, val);
2276 			ldap_memfree(val);
2277 		} break;
2278 /* options not implemented
2279 	case LDAP_OPT_SERVER_CONTROLS:
2280 	case LDAP_OPT_CLIENT_CONTROLS:
2281 	case LDAP_OPT_API_INFO:
2282 	case LDAP_OPT_API_FEATURE_INFO:
2283 */
2284 	default:
2285 		RETURN_FALSE;
2286 	}
2287 	RETURN_TRUE;
2288 }
2289 /* }}} */
2290 
2291 /* {{{ proto bool ldap_set_option(resource link, int option, mixed newval)
2292    Set the value of various session-wide parameters */
PHP_FUNCTION(ldap_set_option)2293 PHP_FUNCTION(ldap_set_option)
2294 {
2295 	zval *link, *newval;
2296 	ldap_linkdata *ld;
2297 	LDAP *ldap;
2298 	zend_long option;
2299 
2300 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "zlz", &link, &option, &newval) != SUCCESS) {
2301 		return;
2302 	}
2303 
2304 	if (Z_TYPE_P(link) == IS_NULL) {
2305 		ldap = NULL;
2306 	} else {
2307 		if ((ld = (ldap_linkdata *)zend_fetch_resource_ex(link, "ldap link", le_link)) == NULL) {
2308 			RETURN_FALSE;
2309 		}
2310 		ldap = ld->link;
2311 	}
2312 
2313 	switch (option) {
2314 	/* options with int value */
2315 	case LDAP_OPT_DEREF:
2316 	case LDAP_OPT_SIZELIMIT:
2317 	case LDAP_OPT_TIMELIMIT:
2318 	case LDAP_OPT_PROTOCOL_VERSION:
2319 	case LDAP_OPT_ERROR_NUMBER:
2320 #ifdef LDAP_OPT_DEBUG_LEVEL
2321 	case LDAP_OPT_DEBUG_LEVEL:
2322 #endif
2323 #ifdef LDAP_OPT_X_TLS_REQUIRE_CERT
2324 	case LDAP_OPT_X_TLS_REQUIRE_CERT:
2325 #endif
2326 #ifdef LDAP_OPT_X_TLS_CRLCHECK
2327 	case LDAP_OPT_X_TLS_CRLCHECK:
2328 #endif
2329 #ifdef LDAP_OPT_X_TLS_PROTOCOL_MIN
2330 	case LDAP_OPT_X_TLS_PROTOCOL_MIN:
2331 #endif
2332 #ifdef LDAP_OPT_X_KEEPALIVE_IDLE
2333 	case LDAP_OPT_X_KEEPALIVE_IDLE:
2334 	case LDAP_OPT_X_KEEPALIVE_PROBES:
2335 	case LDAP_OPT_X_KEEPALIVE_INTERVAL:
2336 #endif
2337 		{
2338 			int val;
2339 
2340 			convert_to_long_ex(newval);
2341 			val = Z_LVAL_P(newval);
2342 			if (ldap_set_option(ldap, option, &val)) {
2343 				RETURN_FALSE;
2344 			}
2345 		} break;
2346 #ifdef LDAP_OPT_NETWORK_TIMEOUT
2347 	case LDAP_OPT_NETWORK_TIMEOUT:
2348 		{
2349 			struct timeval timeout;
2350 
2351 			convert_to_long_ex(newval);
2352 			timeout.tv_sec = Z_LVAL_P(newval);
2353 			timeout.tv_usec = 0;
2354 			if (ldap_set_option(ldap, LDAP_OPT_NETWORK_TIMEOUT, (void *) &timeout)) {
2355 				RETURN_FALSE;
2356 			}
2357 		} break;
2358 #elif defined(LDAP_X_OPT_CONNECT_TIMEOUT)
2359 	case LDAP_X_OPT_CONNECT_TIMEOUT:
2360 		{
2361 			int timeout;
2362 
2363 			convert_to_long_ex(newval);
2364 			timeout = 1000 * Z_LVAL_P(newval); /* Convert to milliseconds */
2365 			if (ldap_set_option(ldap, LDAP_X_OPT_CONNECT_TIMEOUT, &timeout)) {
2366 				RETURN_FALSE;
2367 			}
2368 		} break;
2369 #endif
2370 #ifdef LDAP_OPT_TIMEOUT
2371 	case LDAP_OPT_TIMEOUT:
2372 		{
2373 			struct timeval timeout;
2374 
2375 			convert_to_long_ex(newval);
2376 			timeout.tv_sec = Z_LVAL_P(newval);
2377 			timeout.tv_usec = 0;
2378 			if (ldap_set_option(ldap, LDAP_OPT_TIMEOUT, (void *) &timeout)) {
2379 				RETURN_FALSE;
2380 			}
2381 		} break;
2382 #endif
2383 		/* options with string value */
2384 	case LDAP_OPT_ERROR_STRING:
2385 #ifdef LDAP_OPT_HOST_NAME
2386 	case LDAP_OPT_HOST_NAME:
2387 #endif
2388 #ifdef HAVE_LDAP_SASL
2389 	case LDAP_OPT_X_SASL_MECH:
2390 	case LDAP_OPT_X_SASL_REALM:
2391 	case LDAP_OPT_X_SASL_AUTHCID:
2392 	case LDAP_OPT_X_SASL_AUTHZID:
2393 #endif
2394 #if (LDAP_API_VERSION > 2000)
2395 	case LDAP_OPT_X_TLS_CACERTDIR:
2396 	case LDAP_OPT_X_TLS_CACERTFILE:
2397 	case LDAP_OPT_X_TLS_CERTFILE:
2398 	case LDAP_OPT_X_TLS_CIPHER_SUITE:
2399 	case LDAP_OPT_X_TLS_KEYFILE:
2400 	case LDAP_OPT_X_TLS_RANDOM_FILE:
2401 #endif
2402 #ifdef LDAP_OPT_X_TLS_CRLFILE
2403 	case LDAP_OPT_X_TLS_CRLFILE:
2404 #endif
2405 #ifdef LDAP_OPT_X_TLS_DHFILE
2406 	case LDAP_OPT_X_TLS_DHFILE:
2407 #endif
2408 #ifdef LDAP_OPT_MATCHED_DN
2409 	case LDAP_OPT_MATCHED_DN:
2410 #endif
2411 		{
2412 			char *val;
2413 			convert_to_string_ex(newval);
2414 			val = Z_STRVAL_P(newval);
2415 			if (ldap_set_option(ldap, option, val)) {
2416 				RETURN_FALSE;
2417 			}
2418 		} break;
2419 		/* options with boolean value */
2420 	case LDAP_OPT_REFERRALS:
2421 #ifdef LDAP_OPT_RESTART
2422 	case LDAP_OPT_RESTART:
2423 #endif
2424 #ifdef LDAP_OPT_X_SASL_NOCANON
2425 	case LDAP_OPT_X_SASL_NOCANON:
2426 #endif
2427 		{
2428 			void *val;
2429 			convert_to_boolean_ex(newval);
2430 			val = Z_TYPE_P(newval) == IS_TRUE
2431 				? LDAP_OPT_ON : LDAP_OPT_OFF;
2432 			if (ldap_set_option(ldap, option, val)) {
2433 				RETURN_FALSE;
2434 			}
2435 		} break;
2436 		/* options with control list value */
2437 	case LDAP_OPT_SERVER_CONTROLS:
2438 	case LDAP_OPT_CLIENT_CONTROLS:
2439 		{
2440 			LDAPControl *ctrl, **ctrls, **ctrlp;
2441 			zval *ctrlval, *val;
2442 			int ncontrols;
2443 			char error=0;
2444 
2445 			if ((Z_TYPE_P(newval) != IS_ARRAY) || !(ncontrols = zend_hash_num_elements(Z_ARRVAL_P(newval)))) {
2446 				php_error_docref(NULL, E_WARNING, "Expected non-empty array value for this option");
2447 				RETURN_FALSE;
2448 			}
2449 			ctrls = safe_emalloc((1 + ncontrols), sizeof(*ctrls), 0);
2450 			*ctrls = NULL;
2451 			ctrlp = ctrls;
2452 			ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(newval), ctrlval) {
2453 				if (Z_TYPE_P(ctrlval) != IS_ARRAY) {
2454 					php_error_docref(NULL, E_WARNING, "The array value must contain only arrays, where each array is a control");
2455 					error = 1;
2456 					break;
2457 				}
2458 				if ((val = zend_hash_str_find(Z_ARRVAL_P(ctrlval), "oid", sizeof("oid") - 1)) == NULL) {
2459 					php_error_docref(NULL, E_WARNING, "Control must have an oid key");
2460 					error = 1;
2461 					break;
2462 				}
2463 				ctrl = *ctrlp = emalloc(sizeof(**ctrlp));
2464 				convert_to_string_ex(val);
2465 				ctrl->ldctl_oid = Z_STRVAL_P(val);
2466 				if ((val = zend_hash_str_find(Z_ARRVAL_P(ctrlval), "value", sizeof("value") - 1)) != NULL) {
2467 					convert_to_string_ex(val);
2468 					ctrl->ldctl_value.bv_val = Z_STRVAL_P(val);
2469 					ctrl->ldctl_value.bv_len = Z_STRLEN_P(val);
2470 				} else {
2471 					ctrl->ldctl_value.bv_val = NULL;
2472 					ctrl->ldctl_value.bv_len = 0;
2473 				}
2474 				if ((val = zend_hash_str_find(Z_ARRVAL_P(ctrlval), "iscritical", sizeof("iscritical") - 1)) != NULL) {
2475 					convert_to_boolean_ex(val);
2476 					ctrl->ldctl_iscritical = Z_TYPE_P(val) == IS_TRUE;
2477 				} else {
2478 					ctrl->ldctl_iscritical = 0;
2479 				}
2480 
2481 				++ctrlp;
2482 				*ctrlp = NULL;
2483 			} ZEND_HASH_FOREACH_END();
2484 			if (!error) {
2485 				error = ldap_set_option(ldap, option, ctrls);
2486 			}
2487 			ctrlp = ctrls;
2488 			while (*ctrlp) {
2489 				efree(*ctrlp);
2490 				ctrlp++;
2491 			}
2492 			efree(ctrls);
2493 			if (error) {
2494 				RETURN_FALSE;
2495 			}
2496 		} break;
2497 	default:
2498 		RETURN_FALSE;
2499 	}
2500 	RETURN_TRUE;
2501 }
2502 /* }}} */
2503 
2504 #ifdef HAVE_LDAP_PARSE_RESULT
2505 /* {{{ proto bool ldap_parse_result(resource link, resource result, int errcode, string matcheddn, string errmsg, array referrals)
2506    Extract information from result */
PHP_FUNCTION(ldap_parse_result)2507 PHP_FUNCTION(ldap_parse_result)
2508 {
2509 	zval *link, *result, *errcode, *matcheddn, *errmsg, *referrals;
2510 	ldap_linkdata *ld;
2511 	LDAPMessage *ldap_result;
2512 	char **lreferrals, **refp;
2513 	char *lmatcheddn, *lerrmsg;
2514 	int rc, lerrcode, myargcount = ZEND_NUM_ARGS();
2515 
2516 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rrz/|z/z/z/", &link, &result, &errcode, &matcheddn, &errmsg, &referrals) != SUCCESS) {
2517 		return;
2518 	}
2519 
2520 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
2521 		RETURN_FALSE;
2522 	}
2523 
2524 	if ((ldap_result = (LDAPMessage *)zend_fetch_resource(Z_RES_P(result), "ldap result", le_result)) == NULL) {
2525 		RETURN_FALSE;
2526 	}
2527 
2528 	rc = ldap_parse_result(ld->link, ldap_result, &lerrcode,
2529 				myargcount > 3 ? &lmatcheddn : NULL,
2530 				myargcount > 4 ? &lerrmsg : NULL,
2531 				myargcount > 5 ? &lreferrals : NULL,
2532 				NULL /* &serverctrls */,
2533 				0);
2534 	if (rc != LDAP_SUCCESS) {
2535 		php_error_docref(NULL, E_WARNING, "Unable to parse result: %s", ldap_err2string(rc));
2536 		RETURN_FALSE;
2537 	}
2538 
2539 	zval_ptr_dtor(errcode);
2540 	ZVAL_LONG(errcode, lerrcode);
2541 
2542 	/* Reverse -> fall through */
2543 	switch (myargcount) {
2544 		case 6:
2545 			zval_ptr_dtor(referrals);
2546 			array_init(referrals);
2547 			if (lreferrals != NULL) {
2548 				refp = lreferrals;
2549 				while (*refp) {
2550 					add_next_index_string(referrals, *refp);
2551 					refp++;
2552 				}
2553 				ldap_memvfree((void**)lreferrals);
2554 			}
2555 		case 5:
2556 			zval_ptr_dtor(errmsg);
2557 			if (lerrmsg == NULL) {
2558 				ZVAL_EMPTY_STRING(errmsg);
2559 			} else {
2560 				ZVAL_STRING(errmsg, lerrmsg);
2561 				ldap_memfree(lerrmsg);
2562 			}
2563 		case 4:
2564 			zval_ptr_dtor(matcheddn);
2565 			if (lmatcheddn == NULL) {
2566 				ZVAL_EMPTY_STRING(matcheddn);
2567 			} else {
2568 				ZVAL_STRING(matcheddn, lmatcheddn);
2569 				ldap_memfree(lmatcheddn);
2570 			}
2571 	}
2572 	RETURN_TRUE;
2573 }
2574 /* }}} */
2575 #endif
2576 
2577 /* {{{ proto resource ldap_first_reference(resource link, resource result)
2578    Return first reference */
PHP_FUNCTION(ldap_first_reference)2579 PHP_FUNCTION(ldap_first_reference)
2580 {
2581 	zval *link, *result;
2582 	ldap_linkdata *ld;
2583 	ldap_resultentry *resultentry;
2584 	LDAPMessage *ldap_result, *entry;
2585 
2586 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rr", &link, &result) != SUCCESS) {
2587 		return;
2588 	}
2589 
2590 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
2591 		RETURN_FALSE;
2592 	}
2593 
2594 	if ((ldap_result = (LDAPMessage *)zend_fetch_resource(Z_RES_P(result), "ldap result", le_result)) == NULL) {
2595 		RETURN_FALSE;
2596 	}
2597 
2598 	if ((entry = ldap_first_reference(ld->link, ldap_result)) == NULL) {
2599 		RETVAL_FALSE;
2600 	} else {
2601 		resultentry = emalloc(sizeof(ldap_resultentry));
2602 		RETVAL_RES(zend_register_resource(resultentry, le_result_entry));
2603 		ZVAL_COPY(&resultentry->res, result);
2604 		resultentry->data = entry;
2605 		resultentry->ber = NULL;
2606 	}
2607 }
2608 /* }}} */
2609 
2610 /* {{{ proto resource ldap_next_reference(resource link, resource reference_entry)
2611    Get next reference */
PHP_FUNCTION(ldap_next_reference)2612 PHP_FUNCTION(ldap_next_reference)
2613 {
2614 	zval *link, *result_entry;
2615 	ldap_linkdata *ld;
2616 	ldap_resultentry *resultentry, *resultentry_next;
2617 	LDAPMessage *entry_next;
2618 
2619 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rr", &link, &result_entry) != SUCCESS) {
2620 		return;
2621 	}
2622 
2623 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
2624 		RETURN_FALSE;
2625 	}
2626 
2627 	if ((resultentry = (ldap_resultentry *)zend_fetch_resource(Z_RES_P(result_entry), "ldap result entry", le_result_entry)) == NULL) {
2628 		RETURN_FALSE;
2629 	}
2630 
2631 	if ((entry_next = ldap_next_reference(ld->link, resultentry->data)) == NULL) {
2632 		RETVAL_FALSE;
2633 	} else {
2634 		resultentry_next = emalloc(sizeof(ldap_resultentry));
2635 		RETVAL_RES(zend_register_resource(resultentry_next, le_result_entry));
2636 		ZVAL_COPY(&resultentry_next->res, &resultentry->res);
2637 		resultentry_next->data = entry_next;
2638 		resultentry_next->ber = NULL;
2639 	}
2640 }
2641 /* }}} */
2642 
2643 #ifdef HAVE_LDAP_PARSE_REFERENCE
2644 /* {{{ proto bool ldap_parse_reference(resource link, resource reference_entry, array referrals)
2645    Extract information from reference entry */
PHP_FUNCTION(ldap_parse_reference)2646 PHP_FUNCTION(ldap_parse_reference)
2647 {
2648 	zval *link, *result_entry, *referrals;
2649 	ldap_linkdata *ld;
2650 	ldap_resultentry *resultentry;
2651 	char **lreferrals, **refp;
2652 
2653 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rrz/", &link, &result_entry, &referrals) != SUCCESS) {
2654 		return;
2655 	}
2656 
2657 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
2658 		RETURN_FALSE;
2659 	}
2660 
2661 	if ((resultentry = (ldap_resultentry *)zend_fetch_resource(Z_RES_P(result_entry), "ldap result entry", le_result_entry)) == NULL) {
2662 		RETURN_FALSE;
2663 	}
2664 
2665 	if (ldap_parse_reference(ld->link, resultentry->data, &lreferrals, NULL /* &serverctrls */, 0) != LDAP_SUCCESS) {
2666 		RETURN_FALSE;
2667 	}
2668 
2669 	zval_ptr_dtor(referrals);
2670 	array_init(referrals);
2671 	if (lreferrals != NULL) {
2672 		refp = lreferrals;
2673 		while (*refp) {
2674 			add_next_index_string(referrals, *refp);
2675 			refp++;
2676 		}
2677 		ldap_memvfree((void**)lreferrals);
2678 	}
2679 	RETURN_TRUE;
2680 }
2681 /* }}} */
2682 #endif
2683 
2684 /* {{{ proto bool ldap_rename(resource link, string dn, string newrdn, string newparent, bool deleteoldrdn)
2685    Modify the name of an entry */
PHP_FUNCTION(ldap_rename)2686 PHP_FUNCTION(ldap_rename)
2687 {
2688 	zval *link;
2689 	ldap_linkdata *ld;
2690 	int rc;
2691 	char *dn, *newrdn, *newparent;
2692 	size_t dn_len, newrdn_len, newparent_len;
2693 	zend_bool deleteoldrdn;
2694 
2695 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsssb", &link, &dn, &dn_len, &newrdn, &newrdn_len, &newparent, &newparent_len, &deleteoldrdn) != SUCCESS) {
2696 		return;
2697 	}
2698 
2699 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
2700 		RETURN_FALSE;
2701 	}
2702 
2703 	if (newparent_len == 0) {
2704 		newparent = NULL;
2705 	}
2706 
2707 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP
2708 	rc = ldap_rename_s(ld->link, dn, newrdn, newparent, deleteoldrdn, NULL, NULL);
2709 #else
2710 	if (newparent_len != 0) {
2711 		php_error_docref(NULL, E_WARNING, "You are using old LDAP API, newparent must be the empty string, can only modify RDN");
2712 		RETURN_FALSE;
2713 	}
2714 /* could support old APIs but need check for ldap_modrdn2()/ldap_modrdn() */
2715 	rc = ldap_modrdn2_s(ld->link, dn, newrdn, deleteoldrdn);
2716 #endif
2717 
2718 	if (rc == LDAP_SUCCESS) {
2719 		RETURN_TRUE;
2720 	}
2721 	RETURN_FALSE;
2722 }
2723 /* }}} */
2724 
2725 #ifdef HAVE_LDAP_START_TLS_S
2726 /* {{{ proto bool ldap_start_tls(resource link)
2727    Start TLS */
PHP_FUNCTION(ldap_start_tls)2728 PHP_FUNCTION(ldap_start_tls)
2729 {
2730 	zval *link;
2731 	ldap_linkdata *ld;
2732 	int rc, protocol = LDAP_VERSION3;
2733 
2734 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &link) != SUCCESS) {
2735 		return;
2736 	}
2737 
2738 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
2739 		RETURN_FALSE;
2740 	}
2741 
2742 	if (((rc = ldap_set_option(ld->link, LDAP_OPT_PROTOCOL_VERSION, &protocol)) != LDAP_SUCCESS) ||
2743 		((rc = ldap_start_tls_s(ld->link, NULL, NULL)) != LDAP_SUCCESS)
2744 	) {
2745 		php_error_docref(NULL, E_WARNING,"Unable to start TLS: %s", ldap_err2string(rc));
2746 		RETURN_FALSE;
2747 	} else {
2748 		RETURN_TRUE;
2749 	}
2750 }
2751 /* }}} */
2752 #endif
2753 #endif /* (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP */
2754 
2755 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)
2756 /* {{{ _ldap_rebind_proc()
2757 */
_ldap_rebind_proc(LDAP * ldap,const char * url,ber_tag_t req,ber_int_t msgid,void * params)2758 int _ldap_rebind_proc(LDAP *ldap, const char *url, ber_tag_t req, ber_int_t msgid, void *params)
2759 {
2760 	ldap_linkdata *ld;
2761 	int retval;
2762 	zval cb_args[2];
2763 	zval cb_retval;
2764 	zval *cb_link = (zval *) params;
2765 
2766 	ld = (ldap_linkdata *) zend_fetch_resource_ex(cb_link, "ldap link", le_link);
2767 
2768 	/* link exists and callback set? */
2769 	if (ld == NULL || Z_ISUNDEF(ld->rebindproc)) {
2770 		php_error_docref(NULL, E_WARNING, "Link not found or no callback set");
2771 		return LDAP_OTHER;
2772 	}
2773 
2774 	/* callback */
2775 	ZVAL_COPY_VALUE(&cb_args[0], cb_link);
2776 	ZVAL_STRING(&cb_args[1], url);
2777 	if (call_user_function_ex(EG(function_table), NULL, &ld->rebindproc, &cb_retval, 2, cb_args, 0, NULL) == SUCCESS && !Z_ISUNDEF(cb_retval)) {
2778 		convert_to_long_ex(&cb_retval);
2779 		retval = Z_LVAL(cb_retval);
2780 		zval_ptr_dtor(&cb_retval);
2781 	} else {
2782 		php_error_docref(NULL, E_WARNING, "rebind_proc PHP callback failed");
2783 		retval = LDAP_OTHER;
2784 	}
2785 	zval_ptr_dtor(&cb_args[1]);
2786 	return retval;
2787 }
2788 /* }}} */
2789 
2790 /* {{{ proto bool ldap_set_rebind_proc(resource link, string callback)
2791    Set a callback function to do re-binds on referral chasing. */
PHP_FUNCTION(ldap_set_rebind_proc)2792 PHP_FUNCTION(ldap_set_rebind_proc)
2793 {
2794 	zval *link, *callback;
2795 	ldap_linkdata *ld;
2796 	zend_string *callback_name;
2797 
2798 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz", &link, &callback) != SUCCESS) {
2799 		RETURN_FALSE;
2800 	}
2801 
2802 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
2803 		RETURN_FALSE;
2804 	}
2805 
2806 	if (Z_TYPE_P(callback) == IS_STRING && Z_STRLEN_P(callback) == 0) {
2807 		/* unregister rebind procedure */
2808 		if (!Z_ISUNDEF(ld->rebindproc)) {
2809 			zval_ptr_dtor(&ld->rebindproc);
2810 			ZVAL_UNDEF(&ld->rebindproc);
2811 			ldap_set_rebind_proc(ld->link, NULL, NULL);
2812 		}
2813 		RETURN_TRUE;
2814 	}
2815 
2816 	/* callable? */
2817 	if (!zend_is_callable(callback, 0, &callback_name)) {
2818 		php_error_docref(NULL, E_WARNING, "Two arguments expected for '%s' to be a valid callback", ZSTR_VAL(callback_name));
2819 		zend_string_release(callback_name);
2820 		RETURN_FALSE;
2821 	}
2822 	zend_string_release(callback_name);
2823 
2824 	/* register rebind procedure */
2825 	if (Z_ISUNDEF(ld->rebindproc)) {
2826 		ldap_set_rebind_proc(ld->link, _ldap_rebind_proc, (void *) link);
2827 	} else {
2828 		zval_ptr_dtor(&ld->rebindproc);
2829 	}
2830 
2831 	ZVAL_COPY(&ld->rebindproc, callback);
2832 	RETURN_TRUE;
2833 }
2834 /* }}} */
2835 #endif
2836 
php_ldap_do_escape(const zend_bool * map,const char * value,size_t valuelen,zend_long flags)2837 static zend_string* php_ldap_do_escape(const zend_bool *map, const char *value, size_t valuelen, zend_long flags)
2838 {
2839 	char hex[] = "0123456789abcdef";
2840 	size_t i, p = 0;
2841 	size_t len = 0;
2842 	zend_string *ret;
2843 
2844 	for (i = 0; i < valuelen; i++) {
2845 		len += (map[(unsigned char) value[i]]) ? 3 : 1;
2846 	}
2847 	/* Per RFC 4514, a leading and trailing space must be escaped */
2848 	if ((flags & PHP_LDAP_ESCAPE_DN) && (value[0] == ' ')) {
2849 		len += 2;
2850 	}
2851 	if ((flags & PHP_LDAP_ESCAPE_DN) && ((valuelen > 1) && (value[valuelen - 1] == ' '))) {
2852 		len += 2;
2853 	}
2854 
2855 	ret =  zend_string_alloc(len, 0);
2856 
2857 	for (i = 0; i < valuelen; i++) {
2858 		unsigned char v = (unsigned char) value[i];
2859 
2860 		if (map[v] || ((flags & PHP_LDAP_ESCAPE_DN) && ((i == 0) || (i + 1 == valuelen)) && (v == ' '))) {
2861 			ZSTR_VAL(ret)[p++] = '\\';
2862 			ZSTR_VAL(ret)[p++] = hex[v >> 4];
2863 			ZSTR_VAL(ret)[p++] = hex[v & 0x0f];
2864 		} else {
2865 			ZSTR_VAL(ret)[p++] = v;
2866 		}
2867 	}
2868 
2869 	ZSTR_VAL(ret)[p] = '\0';
2870 	ZSTR_LEN(ret) = p;
2871 	return ret;
2872 }
2873 
php_ldap_escape_map_set_chars(zend_bool * map,const char * chars,const int charslen,char escape)2874 static void php_ldap_escape_map_set_chars(zend_bool *map, const char *chars, const int charslen, char escape)
2875 {
2876 	int i = 0;
2877 	while (i < charslen) {
2878 		map[(unsigned char) chars[i++]] = escape;
2879 	}
2880 }
2881 
PHP_FUNCTION(ldap_escape)2882 PHP_FUNCTION(ldap_escape)
2883 {
2884 	char *value, *ignores;
2885 	size_t valuelen = 0, ignoreslen = 0;
2886 	int i;
2887 	zend_long flags = 0;
2888 	zend_bool map[256] = {0}, havecharlist = 0;
2889 
2890 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|sl", &value, &valuelen, &ignores, &ignoreslen, &flags) != SUCCESS) {
2891 		return;
2892 	}
2893 
2894 	if (!valuelen) {
2895 		RETURN_EMPTY_STRING();
2896 	}
2897 
2898 	if (flags & PHP_LDAP_ESCAPE_FILTER) {
2899 		havecharlist = 1;
2900 		php_ldap_escape_map_set_chars(map, "\\*()\0", sizeof("\\*()\0") - 1, 1);
2901 	}
2902 
2903 	if (flags & PHP_LDAP_ESCAPE_DN) {
2904 		havecharlist = 1;
2905 		php_ldap_escape_map_set_chars(map, "\\,=+<>;\"#\r", sizeof("\\,=+<>;\"#\r") - 1, 1);
2906 	}
2907 
2908 	if (!havecharlist) {
2909 		for (i = 0; i < 256; i++) {
2910 			map[i] = 1;
2911 		}
2912 	}
2913 
2914 	if (ignoreslen) {
2915 		php_ldap_escape_map_set_chars(map, ignores, ignoreslen, 0);
2916 	}
2917 
2918 	RETURN_NEW_STR(php_ldap_do_escape(map, value, valuelen, flags));
2919 }
2920 
2921 #ifdef STR_TRANSLATION
2922 /* {{{ php_ldap_do_translate
2923  */
php_ldap_do_translate(INTERNAL_FUNCTION_PARAMETERS,int way)2924 static void php_ldap_do_translate(INTERNAL_FUNCTION_PARAMETERS, int way)
2925 {
2926 	char *value;
2927 	size_t value_len;
2928 	int result;
2929 
2930 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &value, &value_len) != SUCCESS) {
2931 		return;
2932 	}
2933 
2934 	if (value_len == 0) {
2935 		RETURN_FALSE;
2936 	}
2937 
2938 	if (way == 1) {
2939 		result = ldap_8859_to_t61(&value, &value_len, 0);
2940 	} else {
2941 		result = ldap_t61_to_8859(&value, &value_len, 0);
2942 	}
2943 
2944 	if (result == LDAP_SUCCESS) {
2945 		RETVAL_STRINGL(value, value_len);
2946 		free(value);
2947 	} else {
2948 		php_error_docref(NULL, E_WARNING, "Conversion from iso-8859-1 to t61 failed: %s", ldap_err2string(result));
2949 		RETVAL_FALSE;
2950 	}
2951 }
2952 /* }}} */
2953 
2954 /* {{{ proto string ldap_t61_to_8859(string value)
2955    Translate t61 characters to 8859 characters */
PHP_FUNCTION(ldap_t61_to_8859)2956 PHP_FUNCTION(ldap_t61_to_8859)
2957 {
2958 	php_ldap_do_translate(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
2959 }
2960 /* }}} */
2961 
2962 /* {{{ proto string ldap_8859_to_t61(string value)
2963    Translate 8859 characters to t61 characters */
PHP_FUNCTION(ldap_8859_to_t61)2964 PHP_FUNCTION(ldap_8859_to_t61)
2965 {
2966 	php_ldap_do_translate(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
2967 }
2968 /* }}} */
2969 #endif
2970 
2971 #ifdef LDAP_CONTROL_PAGEDRESULTS
2972 /* {{{ proto mixed ldap_control_paged_result(resource link, int pagesize [, bool iscritical [, string cookie]])
2973    Inject paged results control*/
PHP_FUNCTION(ldap_control_paged_result)2974 PHP_FUNCTION(ldap_control_paged_result)
2975 {
2976 	zend_long pagesize;
2977 	zend_bool iscritical;
2978 	zval *link;
2979 	char *cookie = NULL;
2980 	size_t cookie_len = 0;
2981 	struct berval lcookie = { 0, NULL };
2982 	ldap_linkdata *ld;
2983 	LDAP *ldap;
2984 	BerElement *ber = NULL;
2985 	LDAPControl	ctrl, *ctrlsp[2];
2986 	int rc, myargcount = ZEND_NUM_ARGS();
2987 
2988 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl|bs", &link, &pagesize, &iscritical, &cookie, &cookie_len) != SUCCESS) {
2989 		return;
2990 	}
2991 
2992 	if (Z_TYPE_P(link) == IS_NULL) {
2993 		ldap = NULL;
2994 	} else {
2995 		if ((ld = (ldap_linkdata *)zend_fetch_resource_ex(link, "ldap link", le_link)) == NULL) {
2996 			RETURN_FALSE;
2997 		}
2998 		ldap = ld->link;
2999 	}
3000 
3001 	ber = ber_alloc_t(LBER_USE_DER);
3002 	if (ber == NULL) {
3003 		php_error_docref(NULL, E_WARNING, "Unable to alloc BER encoding resources for paged results control");
3004 		RETURN_FALSE;
3005 	}
3006 
3007 	ctrl.ldctl_iscritical = 0;
3008 
3009 	switch (myargcount) {
3010 		case 4:
3011 			lcookie.bv_val = cookie;
3012 			lcookie.bv_len = cookie_len;
3013 			/* fallthru */
3014 		case 3:
3015 			ctrl.ldctl_iscritical = (int)iscritical;
3016 			/* fallthru */
3017 	}
3018 
3019 	if (ber_printf(ber, "{iO}", (int)pagesize, &lcookie) == LBER_ERROR) {
3020 		php_error_docref(NULL, E_WARNING, "Unable to BER printf paged results control");
3021 		RETVAL_FALSE;
3022 		goto lcpr_error_out;
3023 	}
3024 	rc = ber_flatten2(ber, &ctrl.ldctl_value, 0);
3025 	if (rc == LBER_ERROR) {
3026 		php_error_docref(NULL, E_WARNING, "Unable to BER encode paged results control");
3027 		RETVAL_FALSE;
3028 		goto lcpr_error_out;
3029 	}
3030 
3031 	ctrl.ldctl_oid = LDAP_CONTROL_PAGEDRESULTS;
3032 
3033 	if (ldap) {
3034 		/* directly set the option */
3035 		ctrlsp[0] = &ctrl;
3036 		ctrlsp[1] = NULL;
3037 
3038 		rc = ldap_set_option(ldap, LDAP_OPT_SERVER_CONTROLS, ctrlsp);
3039 		if (rc != LDAP_SUCCESS) {
3040 			php_error_docref(NULL, E_WARNING, "Unable to set paged results control: %s (%d)", ldap_err2string(rc), rc);
3041 			RETVAL_FALSE;
3042 			goto lcpr_error_out;
3043 		}
3044 		RETVAL_TRUE;
3045 	} else {
3046 		/* return a PHP control object */
3047 		array_init(return_value);
3048 
3049 		add_assoc_string(return_value, "oid", ctrl.ldctl_oid);
3050 		if (ctrl.ldctl_value.bv_len) {
3051 			add_assoc_stringl(return_value, "value", ctrl.ldctl_value.bv_val, ctrl.ldctl_value.bv_len);
3052 		}
3053 		if (ctrl.ldctl_iscritical) {
3054 			add_assoc_bool(return_value, "iscritical", ctrl.ldctl_iscritical);
3055 		}
3056 	}
3057 
3058 lcpr_error_out:
3059 	if (ber != NULL) {
3060 		ber_free(ber, 1);
3061 	}
3062 	return;
3063 }
3064 /* }}} */
3065 
3066 /* {{{ proto bool ldap_control_paged_result_response(resource link, resource result [, string &cookie [, int &estimated]])
3067    Extract paged results control response */
PHP_FUNCTION(ldap_control_paged_result_response)3068 PHP_FUNCTION(ldap_control_paged_result_response)
3069 {
3070 	zval *link, *result, *cookie, *estimated;
3071 	struct berval lcookie;
3072 	int lestimated;
3073 	ldap_linkdata *ld;
3074 	LDAPMessage *ldap_result;
3075 	LDAPControl **lserverctrls, *lctrl;
3076 	BerElement *ber;
3077 	ber_tag_t tag;
3078 	int rc, lerrcode, myargcount = ZEND_NUM_ARGS();
3079 
3080 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rr|z/z/", &link, &result, &cookie, &estimated) != SUCCESS) {
3081 		return;
3082 	}
3083 
3084 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
3085 		RETURN_FALSE;
3086 	}
3087 
3088 	if ((ldap_result = (LDAPMessage *)zend_fetch_resource(Z_RES_P(result), "ldap result", le_result)) == NULL) {
3089 		RETURN_FALSE;
3090 	}
3091 
3092 	rc = ldap_parse_result(ld->link,
3093 				ldap_result,
3094 				&lerrcode,
3095 				NULL,		/* matcheddn */
3096 				NULL,		/* errmsg */
3097 				NULL,		/* referrals */
3098 				&lserverctrls,
3099 				0);
3100 
3101 	if (rc != LDAP_SUCCESS) {
3102 		php_error_docref(NULL, E_WARNING, "Unable to parse result: %s (%d)", ldap_err2string(rc), rc);
3103 		RETURN_FALSE;
3104 	}
3105 
3106 	if (lerrcode != LDAP_SUCCESS) {
3107 		php_error_docref(NULL, E_WARNING, "Result is: %s (%d)", ldap_err2string(lerrcode), lerrcode);
3108 		RETURN_FALSE;
3109 	}
3110 
3111 	if (lserverctrls == NULL) {
3112 		php_error_docref(NULL, E_WARNING, "No server controls in result");
3113 		RETURN_FALSE;
3114 	}
3115 
3116 	lctrl = ldap_control_find(LDAP_CONTROL_PAGEDRESULTS, lserverctrls, NULL);
3117 	if (lctrl == NULL) {
3118 		ldap_controls_free(lserverctrls);
3119 		php_error_docref(NULL, E_WARNING, "No paged results control response in result");
3120 		RETURN_FALSE;
3121 	}
3122 
3123 	ber = ber_init(&lctrl->ldctl_value);
3124 	if (ber == NULL) {
3125 		ldap_controls_free(lserverctrls);
3126 		php_error_docref(NULL, E_WARNING, "Unable to alloc BER decoding resources for paged results control response");
3127 		RETURN_FALSE;
3128 	}
3129 
3130 	tag = ber_scanf(ber, "{io}", &lestimated, &lcookie);
3131 	(void)ber_free(ber, 1);
3132 
3133 	if (tag == LBER_ERROR) {
3134 		ldap_controls_free(lserverctrls);
3135 		php_error_docref(NULL, E_WARNING, "Unable to decode paged results control response");
3136 		RETURN_FALSE;
3137 	}
3138 
3139 	if (lestimated < 0) {
3140 		ldap_controls_free(lserverctrls);
3141 		php_error_docref(NULL, E_WARNING, "Invalid paged results control response value");
3142 		RETURN_FALSE;
3143 	}
3144 
3145 	ldap_controls_free(lserverctrls);
3146 	if (myargcount == 4) {
3147 		zval_dtor(estimated);
3148 		ZVAL_LONG(estimated, lestimated);
3149 	}
3150 
3151 	zval_ptr_dtor(cookie);
3152  	if (lcookie.bv_len == 0) {
3153 		ZVAL_EMPTY_STRING(cookie);
3154  	} else {
3155 		ZVAL_STRINGL(cookie, lcookie.bv_val, lcookie.bv_len);
3156  	}
3157  	ldap_memfree(lcookie.bv_val);
3158 
3159 	RETURN_TRUE;
3160 }
3161 /* }}} */
3162 #endif
3163 
3164 /* {{{ arginfo */
3165 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_connect, 0, 0, 0)
3166 	ZEND_ARG_INFO(0, hostname)
3167 	ZEND_ARG_INFO(0, port)
3168 #ifdef HAVE_ORALDAP
3169 	ZEND_ARG_INFO(0, wallet)
3170 	ZEND_ARG_INFO(0, wallet_passwd)
3171 	ZEND_ARG_INFO(0, authmode)
3172 #endif
3173 ZEND_END_ARG_INFO()
3174 
3175 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_resource, 0, 0, 1)
3176 	ZEND_ARG_INFO(0, link_identifier)
3177 ZEND_END_ARG_INFO()
3178 
3179 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_bind, 0, 0, 1)
3180 	ZEND_ARG_INFO(0, link_identifier)
3181 	ZEND_ARG_INFO(0, bind_rdn)
3182 	ZEND_ARG_INFO(0, bind_password)
3183 ZEND_END_ARG_INFO()
3184 
3185 #ifdef HAVE_LDAP_SASL
3186 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_sasl_bind, 0, 0, 1)
3187 	ZEND_ARG_INFO(0, link)
3188 	ZEND_ARG_INFO(0, binddn)
3189 	ZEND_ARG_INFO(0, password)
3190 	ZEND_ARG_INFO(0, sasl_mech)
3191 	ZEND_ARG_INFO(0, sasl_realm)
3192 	ZEND_ARG_INFO(0, sasl_authz_id)
3193 	ZEND_ARG_INFO(0, props)
3194 ZEND_END_ARG_INFO()
3195 #endif
3196 
3197 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_read, 0, 0, 3)
3198 	ZEND_ARG_INFO(0, link_identifier)
3199 	ZEND_ARG_INFO(0, base_dn)
3200 	ZEND_ARG_INFO(0, filter)
3201 	ZEND_ARG_INFO(0, attributes)
3202 	ZEND_ARG_INFO(0, attrsonly)
3203 	ZEND_ARG_INFO(0, sizelimit)
3204 	ZEND_ARG_INFO(0, timelimit)
3205 	ZEND_ARG_INFO(0, deref)
3206 ZEND_END_ARG_INFO()
3207 
3208 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_list, 0, 0, 3)
3209 	ZEND_ARG_INFO(0, link_identifier)
3210 	ZEND_ARG_INFO(0, base_dn)
3211 	ZEND_ARG_INFO(0, filter)
3212 	ZEND_ARG_INFO(0, attributes)
3213 	ZEND_ARG_INFO(0, attrsonly)
3214 	ZEND_ARG_INFO(0, sizelimit)
3215 	ZEND_ARG_INFO(0, timelimit)
3216 	ZEND_ARG_INFO(0, deref)
3217 ZEND_END_ARG_INFO()
3218 
3219 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_search, 0, 0, 3)
3220 	ZEND_ARG_INFO(0, link_identifier)
3221 	ZEND_ARG_INFO(0, base_dn)
3222 	ZEND_ARG_INFO(0, filter)
3223 	ZEND_ARG_INFO(0, attributes)
3224 	ZEND_ARG_INFO(0, attrsonly)
3225 	ZEND_ARG_INFO(0, sizelimit)
3226 	ZEND_ARG_INFO(0, timelimit)
3227 	ZEND_ARG_INFO(0, deref)
3228 ZEND_END_ARG_INFO()
3229 
3230 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_count_entries, 0, 0, 2)
3231 	ZEND_ARG_INFO(0, link_identifier)
3232 	ZEND_ARG_INFO(0, result_identifier)
3233 ZEND_END_ARG_INFO()
3234 
3235 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_first_entry, 0, 0, 2)
3236 	ZEND_ARG_INFO(0, link_identifier)
3237 	ZEND_ARG_INFO(0, result_identifier)
3238 ZEND_END_ARG_INFO()
3239 
3240 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_next_entry, 0, 0, 2)
3241 	ZEND_ARG_INFO(0, link_identifier)
3242 	ZEND_ARG_INFO(0, result_identifier)
3243 ZEND_END_ARG_INFO()
3244 
3245 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_get_entries, 0, 0, 2)
3246 	ZEND_ARG_INFO(0, link_identifier)
3247 	ZEND_ARG_INFO(0, result_identifier)
3248 ZEND_END_ARG_INFO()
3249 
3250 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_first_attribute, 0, 0, 2)
3251 	ZEND_ARG_INFO(0, link_identifier)
3252 	ZEND_ARG_INFO(0, result_entry_identifier)
3253 ZEND_END_ARG_INFO()
3254 
3255 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_next_attribute, 0, 0, 2)
3256 	ZEND_ARG_INFO(0, link_identifier)
3257 	ZEND_ARG_INFO(0, result_entry_identifier)
3258 ZEND_END_ARG_INFO()
3259 
3260 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_get_attributes, 0, 0, 2)
3261 	ZEND_ARG_INFO(0, link_identifier)
3262 	ZEND_ARG_INFO(0, result_entry_identifier)
3263 ZEND_END_ARG_INFO()
3264 
3265 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_get_values, 0, 0, 3)
3266 	ZEND_ARG_INFO(0, link_identifier)
3267 	ZEND_ARG_INFO(0, result_entry_identifier)
3268 	ZEND_ARG_INFO(0, attribute)
3269 ZEND_END_ARG_INFO()
3270 
3271 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_get_values_len, 0, 0, 3)
3272 	ZEND_ARG_INFO(0, link_identifier)
3273 	ZEND_ARG_INFO(0, result_entry_identifier)
3274 	ZEND_ARG_INFO(0, attribute)
3275 ZEND_END_ARG_INFO()
3276 
3277 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_get_dn, 0, 0, 2)
3278 	ZEND_ARG_INFO(0, link_identifier)
3279 	ZEND_ARG_INFO(0, result_entry_identifier)
3280 ZEND_END_ARG_INFO()
3281 
3282 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_explode_dn, 0, 0, 2)
3283 	ZEND_ARG_INFO(0, dn)
3284 	ZEND_ARG_INFO(0, with_attrib)
3285 ZEND_END_ARG_INFO()
3286 
3287 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_dn2ufn, 0, 0, 1)
3288 	ZEND_ARG_INFO(0, dn)
3289 ZEND_END_ARG_INFO()
3290 
3291 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_add, 0, 0, 3)
3292 	ZEND_ARG_INFO(0, link_identifier)
3293 	ZEND_ARG_INFO(0, dn)
3294 	ZEND_ARG_INFO(0, entry)
3295 ZEND_END_ARG_INFO()
3296 
3297 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_delete, 0, 0, 2)
3298 	ZEND_ARG_INFO(0, link_identifier)
3299 	ZEND_ARG_INFO(0, dn)
3300 ZEND_END_ARG_INFO()
3301 
3302 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_modify, 0, 0, 3)
3303 	ZEND_ARG_INFO(0, link_identifier)
3304 	ZEND_ARG_INFO(0, dn)
3305 	ZEND_ARG_INFO(0, entry)
3306 ZEND_END_ARG_INFO()
3307 
3308 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_modify_batch, 0, 0, 3)
3309 	ZEND_ARG_INFO(0, link_identifier)
3310 	ZEND_ARG_INFO(0, dn)
3311 	ZEND_ARG_ARRAY_INFO(0, modifications_info, 0)
3312 ZEND_END_ARG_INFO()
3313 
3314 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_mod_add, 0, 0, 3)
3315 	ZEND_ARG_INFO(0, link_identifier)
3316 	ZEND_ARG_INFO(0, dn)
3317 	ZEND_ARG_INFO(0, entry)
3318 ZEND_END_ARG_INFO()
3319 
3320 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_mod_replace, 0, 0, 3)
3321 	ZEND_ARG_INFO(0, link_identifier)
3322 	ZEND_ARG_INFO(0, dn)
3323 	ZEND_ARG_INFO(0, entry)
3324 ZEND_END_ARG_INFO()
3325 
3326 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_mod_del, 0, 0, 3)
3327 	ZEND_ARG_INFO(0, link_identifier)
3328 	ZEND_ARG_INFO(0, dn)
3329 	ZEND_ARG_INFO(0, entry)
3330 ZEND_END_ARG_INFO()
3331 
3332 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_err2str, 0, 0, 1)
3333 	ZEND_ARG_INFO(0, errno)
3334 ZEND_END_ARG_INFO()
3335 
3336 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_compare, 0, 0, 4)
3337 	ZEND_ARG_INFO(0, link_identifier)
3338 	ZEND_ARG_INFO(0, dn)
3339 	ZEND_ARG_INFO(0, attribute)
3340 	ZEND_ARG_INFO(0, value)
3341 ZEND_END_ARG_INFO()
3342 
3343 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_sort, 0, 0, 3)
3344 	ZEND_ARG_INFO(0, link)
3345 	ZEND_ARG_INFO(0, result)
3346 	ZEND_ARG_INFO(0, sortfilter)
3347 ZEND_END_ARG_INFO()
3348 
3349 #ifdef LDAP_CONTROL_PAGEDRESULTS
3350 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_control_paged_result, 0, 0, 2)
3351 	ZEND_ARG_INFO(0, link)
3352 	ZEND_ARG_INFO(0, pagesize)
3353 	ZEND_ARG_INFO(0, iscritical)
3354 	ZEND_ARG_INFO(0, cookie)
3355 ZEND_END_ARG_INFO();
3356 
3357 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_control_paged_result_response, 0, 0, 2)
3358 	ZEND_ARG_INFO(0, link)
3359 	ZEND_ARG_INFO(0, result)
3360 	ZEND_ARG_INFO(1, cookie)
3361 	ZEND_ARG_INFO(1, estimated)
3362 ZEND_END_ARG_INFO();
3363 #endif
3364 
3365 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP
3366 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_rename, 0, 0, 5)
3367 	ZEND_ARG_INFO(0, link_identifier)
3368 	ZEND_ARG_INFO(0, dn)
3369 	ZEND_ARG_INFO(0, newrdn)
3370 	ZEND_ARG_INFO(0, newparent)
3371 	ZEND_ARG_INFO(0, deleteoldrdn)
3372 ZEND_END_ARG_INFO()
3373 
3374 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_get_option, 0, 0, 3)
3375 	ZEND_ARG_INFO(0, link_identifier)
3376 	ZEND_ARG_INFO(0, option)
3377 	ZEND_ARG_INFO(1, retval)
3378 ZEND_END_ARG_INFO()
3379 
3380 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_set_option, 0, 0, 3)
3381 	ZEND_ARG_INFO(0, link_identifier)
3382 	ZEND_ARG_INFO(0, option)
3383 	ZEND_ARG_INFO(0, newval)
3384 ZEND_END_ARG_INFO()
3385 
3386 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_first_reference, 0, 0, 2)
3387 	ZEND_ARG_INFO(0, link)
3388 	ZEND_ARG_INFO(0, result)
3389 ZEND_END_ARG_INFO()
3390 
3391 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_next_reference, 0, 0, 2)
3392 	ZEND_ARG_INFO(0, link)
3393 	ZEND_ARG_INFO(0, entry)
3394 ZEND_END_ARG_INFO()
3395 
3396 #ifdef HAVE_LDAP_PARSE_REFERENCE
3397 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_parse_reference, 0, 0, 3)
3398 	ZEND_ARG_INFO(0, link)
3399 	ZEND_ARG_INFO(0, entry)
3400 	ZEND_ARG_INFO(1, referrals)
3401 ZEND_END_ARG_INFO()
3402 #endif
3403 
3404 
3405 #ifdef HAVE_LDAP_PARSE_RESULT
3406 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_parse_result, 0, 0, 3)
3407 	ZEND_ARG_INFO(0, link)
3408 	ZEND_ARG_INFO(0, result)
3409 	ZEND_ARG_INFO(1, errcode)
3410 	ZEND_ARG_INFO(1, matcheddn)
3411 	ZEND_ARG_INFO(1, errmsg)
3412 	ZEND_ARG_INFO(1, referrals)
3413 ZEND_END_ARG_INFO()
3414 #endif
3415 #endif
3416 
3417 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)
3418 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_set_rebind_proc, 0, 0, 2)
3419 	ZEND_ARG_INFO(0, link)
3420 	ZEND_ARG_INFO(0, callback)
3421 ZEND_END_ARG_INFO()
3422 #endif
3423 
3424 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_escape, 0, 0, 1)
3425 	ZEND_ARG_INFO(0, value)
3426 	ZEND_ARG_INFO(0, ignore)
3427 	ZEND_ARG_INFO(0, flags)
3428 ZEND_END_ARG_INFO()
3429 
3430 #ifdef STR_TRANSLATION
3431 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_t61_to_8859, 0, 0, 1)
3432 	ZEND_ARG_INFO(0, value)
3433 ZEND_END_ARG_INFO()
3434 
3435 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_8859_to_t61, 0, 0, 1)
3436 	ZEND_ARG_INFO(0, value)
3437 ZEND_END_ARG_INFO()
3438 #endif
3439 /* }}} */
3440 
3441 /*
3442 	This is just a small subset of the functionality provided by the LDAP library. All the
3443 	operations are synchronous. Referrals are not handled automatically.
3444 */
3445 /* {{{ ldap_functions[]
3446  */
3447 const zend_function_entry ldap_functions[] = {
3448 	PHP_FE(ldap_connect,								arginfo_ldap_connect)
3449 	PHP_FALIAS(ldap_close,		ldap_unbind,			arginfo_ldap_resource)
3450 	PHP_FE(ldap_bind,									arginfo_ldap_bind)
3451 #ifdef HAVE_LDAP_SASL
3452 	PHP_FE(ldap_sasl_bind,								arginfo_ldap_sasl_bind)
3453 #endif
3454 	PHP_FE(ldap_unbind,									arginfo_ldap_resource)
3455 	PHP_FE(ldap_read,									arginfo_ldap_read)
3456 	PHP_FE(ldap_list,									arginfo_ldap_list)
3457 	PHP_FE(ldap_search,									arginfo_ldap_search)
3458 	PHP_FE(ldap_free_result,							arginfo_ldap_resource)
3459 	PHP_FE(ldap_count_entries,							arginfo_ldap_count_entries)
3460 	PHP_FE(ldap_first_entry,							arginfo_ldap_first_entry)
3461 	PHP_FE(ldap_next_entry,								arginfo_ldap_next_entry)
3462 	PHP_FE(ldap_get_entries,							arginfo_ldap_get_entries)
3463 	PHP_FE(ldap_first_attribute,						arginfo_ldap_first_attribute)
3464 	PHP_FE(ldap_next_attribute,							arginfo_ldap_next_attribute)
3465 	PHP_FE(ldap_get_attributes,							arginfo_ldap_get_attributes)
3466 	PHP_FALIAS(ldap_get_values,	ldap_get_values_len,	arginfo_ldap_get_values)
3467 	PHP_FE(ldap_get_values_len,							arginfo_ldap_get_values_len)
3468 	PHP_FE(ldap_get_dn,									arginfo_ldap_get_dn)
3469 	PHP_FE(ldap_explode_dn,								arginfo_ldap_explode_dn)
3470 	PHP_FE(ldap_dn2ufn,									arginfo_ldap_dn2ufn)
3471 	PHP_FE(ldap_add,									arginfo_ldap_add)
3472 	PHP_FE(ldap_delete,									arginfo_ldap_delete)
3473 	PHP_FE(ldap_modify_batch,							arginfo_ldap_modify_batch)
3474 	PHP_FALIAS(ldap_modify,		ldap_mod_replace,		arginfo_ldap_modify)
3475 
3476 /* additional functions for attribute based modifications, Gerrit Thomson */
3477 	PHP_FE(ldap_mod_add,								arginfo_ldap_mod_add)
3478 	PHP_FE(ldap_mod_replace,							arginfo_ldap_mod_replace)
3479 	PHP_FE(ldap_mod_del,								arginfo_ldap_mod_del)
3480 /* end gjt mod */
3481 
3482 	PHP_FE(ldap_errno,									arginfo_ldap_resource)
3483 	PHP_FE(ldap_err2str,								arginfo_ldap_err2str)
3484 	PHP_FE(ldap_error,									arginfo_ldap_resource)
3485 	PHP_FE(ldap_compare,								arginfo_ldap_compare)
3486 	PHP_DEP_FE(ldap_sort,									arginfo_ldap_sort)
3487 
3488 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP
3489 	PHP_FE(ldap_rename,									arginfo_ldap_rename)
3490 	PHP_FE(ldap_get_option,								arginfo_ldap_get_option)
3491 	PHP_FE(ldap_set_option,								arginfo_ldap_set_option)
3492 	PHP_FE(ldap_first_reference,						arginfo_ldap_first_reference)
3493 	PHP_FE(ldap_next_reference,							arginfo_ldap_next_reference)
3494 #ifdef HAVE_LDAP_PARSE_REFERENCE
3495 	PHP_FE(ldap_parse_reference,						arginfo_ldap_parse_reference)
3496 #endif
3497 #ifdef HAVE_LDAP_PARSE_RESULT
3498 	PHP_FE(ldap_parse_result,							arginfo_ldap_parse_result)
3499 #endif
3500 #ifdef HAVE_LDAP_START_TLS_S
3501 	PHP_FE(ldap_start_tls,								arginfo_ldap_resource)
3502 #endif
3503 #endif
3504 
3505 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)
3506 	PHP_FE(ldap_set_rebind_proc,						arginfo_ldap_set_rebind_proc)
3507 #endif
3508 
3509 	PHP_FE(ldap_escape,									arginfo_ldap_escape)
3510 
3511 #ifdef STR_TRANSLATION
3512 	PHP_FE(ldap_t61_to_8859,							arginfo_ldap_t61_to_8859)
3513 	PHP_FE(ldap_8859_to_t61,							arginfo_ldap_8859_to_t61)
3514 #endif
3515 
3516 #ifdef LDAP_CONTROL_PAGEDRESULTS
3517 	PHP_FE(ldap_control_paged_result,							arginfo_ldap_control_paged_result)
3518 	PHP_FE(ldap_control_paged_result_response,		arginfo_ldap_control_paged_result_response)
3519 #endif
3520 	PHP_FE_END
3521 };
3522 /* }}} */
3523 
3524 zend_module_entry ldap_module_entry = { /* {{{ */
3525 	STANDARD_MODULE_HEADER,
3526 	"ldap",
3527 	ldap_functions,
3528 	PHP_MINIT(ldap),
3529 	PHP_MSHUTDOWN(ldap),
3530 	NULL,
3531 	NULL,
3532 	PHP_MINFO(ldap),
3533 	PHP_LDAP_VERSION,
3534 	PHP_MODULE_GLOBALS(ldap),
3535 	PHP_GINIT(ldap),
3536 	NULL,
3537 	NULL,
3538 	STANDARD_MODULE_PROPERTIES_EX
3539 };
3540 /* }}} */
3541 
3542 /*
3543  * Local variables:
3544  * tab-width: 4
3545  * c-basic-offset: 4
3546  * End:
3547  * vim600: sw=4 ts=4 fdm=marker
3548  * vim<600: sw=4 ts=4
3549  */
3550