xref: /PHP-7.3/ext/ldap/ldap.c (revision efe6d96b)
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    |          Côme Chilliet  <mcmic@php.net>                              |
23    | PHP 4.0 updates:  Zeev Suraski <zeev@php.net>                        |
24    +----------------------------------------------------------------------+
25  */
26 
27 #define IS_EXT_MODULE
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 
33 #include "php.h"
34 #include "php_ini.h"
35 
36 #include <stddef.h>
37 
38 #include "ext/standard/dl.h"
39 #include "php_ldap.h"
40 
41 #ifdef PHP_WIN32
42 #include <string.h>
43 #include "config.w32.h"
44 #if HAVE_NSLDAP
45 #include <winsock2.h>
46 #endif
47 #define strdup _strdup
48 #undef WINDOWS
49 #undef strcasecmp
50 #undef strncasecmp
51 #define WINSOCK 1
52 #define __STDC__ 1
53 #endif
54 
55 #include "ext/standard/php_string.h"
56 #include "ext/standard/info.h"
57 
58 #ifdef HAVE_LDAP_SASL_H
59 #include <sasl.h>
60 #elif defined(HAVE_LDAP_SASL_SASL_H)
61 #include <sasl/sasl.h>
62 #endif
63 
64 #define PHP_LDAP_ESCAPE_FILTER 0x01
65 #define PHP_LDAP_ESCAPE_DN     0x02
66 
67 #if defined(LDAP_CONTROL_PAGEDRESULTS) && !defined(HAVE_LDAP_CONTROL_FIND)
ldap_control_find(const char * oid,LDAPControl ** ctrls,LDAPControl *** nextctrlp)68 LDAPControl *ldap_control_find( const char *oid, LDAPControl **ctrls, LDAPControl ***nextctrlp)
69 {
70 	assert(nextctrlp == NULL);
71 	return ldap_find_control(oid, ctrls);
72 }
73 #endif
74 
75 #if !defined(LDAP_API_FEATURE_X_OPENLDAP)
ldap_memvfree(void ** v)76 void ldap_memvfree(void **v)
77 {
78 	ldap_value_free((char **)v);
79 }
80 #endif
81 
82 typedef struct {
83 	LDAP *link;
84 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)
85 	zval rebindproc;
86 #endif
87 } ldap_linkdata;
88 
89 typedef struct {
90 	LDAPMessage *data;
91 	BerElement  *ber;
92 	zval         res;
93 } ldap_resultentry;
94 
95 ZEND_DECLARE_MODULE_GLOBALS(ldap)
96 static PHP_GINIT_FUNCTION(ldap);
97 
98 static int le_link, le_result, le_result_entry;
99 
100 #ifdef COMPILE_DL_LDAP
ZEND_GET_MODULE(ldap)101 ZEND_GET_MODULE(ldap)
102 #endif
103 
104 static void _close_ldap_link(zend_resource *rsrc) /* {{{ */
105 {
106 	ldap_linkdata *ld = (ldap_linkdata *)rsrc->ptr;
107 
108 	ldap_unbind_ext(ld->link, NULL, NULL);
109 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)
110 	zval_ptr_dtor(&ld->rebindproc);
111 #endif
112 
113 	efree(ld);
114 	LDAPG(num_links)--;
115 }
116 /* }}} */
117 
_free_ldap_result(zend_resource * rsrc)118 static void _free_ldap_result(zend_resource *rsrc) /* {{{ */
119 {
120 	LDAPMessage *result = (LDAPMessage *)rsrc->ptr;
121 	ldap_msgfree(result);
122 }
123 /* }}} */
124 
_free_ldap_result_entry(zend_resource * rsrc)125 static void _free_ldap_result_entry(zend_resource *rsrc) /* {{{ */
126 {
127 	ldap_resultentry *entry = (ldap_resultentry *)rsrc->ptr;
128 
129 	if (entry->ber != NULL) {
130 		ber_free(entry->ber, 0);
131 		entry->ber = NULL;
132 	}
133 	zval_ptr_dtor(&entry->res);
134 	efree(entry);
135 }
136 /* }}} */
137 
138 /* {{{ Parse controls from and to arrays */
_php_ldap_control_to_array(LDAP * ld,LDAPControl * ctrl,zval * array,int request)139 static void _php_ldap_control_to_array(LDAP *ld, LDAPControl* ctrl, zval* array, int request)
140 {
141 	array_init(array);
142 
143 	add_assoc_string(array, "oid", ctrl->ldctl_oid);
144 	if (request) {
145 		/* iscritical field only makes sense in request controls (which may be obtained by ldap_get_option) */
146 		add_assoc_bool(array, "iscritical", (ctrl->ldctl_iscritical != 0));
147 	}
148 
149 	/* If it is a known oid, parse to values */
150 	if (strcmp(ctrl->ldctl_oid, LDAP_CONTROL_PASSWORDPOLICYRESPONSE) == 0) {
151 		int expire = 0, grace = 0, rc;
152 		LDAPPasswordPolicyError pperr;
153 		zval value;
154 
155 		rc = ldap_parse_passwordpolicy_control(ld, ctrl, &expire, &grace, &pperr);
156 		if ( rc == LDAP_SUCCESS ) {
157 			array_init(&value);
158 			add_assoc_long(&value, "expire", expire);
159 			add_assoc_long(&value, "grace", grace);
160 
161 			if ( pperr != PP_noError ) {
162 				add_assoc_long(&value, "error", pperr);
163 			}
164 			add_assoc_zval(array, "value", &value);
165 		} else {
166 			add_assoc_null(array, "value");
167 		}
168 	} else if (strcmp(ctrl->ldctl_oid, LDAP_CONTROL_PAGEDRESULTS) == 0) {
169 		int lestimated, rc;
170 		struct berval lcookie = { 0L, NULL };
171 		zval value;
172 
173 		if (ctrl->ldctl_value.bv_len) {
174 			/* ldap_parse_pageresponse_control() allocates lcookie.bv_val */
175 			rc = ldap_parse_pageresponse_control(ld, ctrl, &lestimated, &lcookie);
176 		} else {
177 			/* ldap_parse_pageresponse_control will crash if value is empty */
178 			rc = -1;
179 		}
180 
181 		if ( rc == LDAP_SUCCESS ) {
182 			array_init(&value);
183 			add_assoc_long(&value, "size", lestimated);
184 			add_assoc_stringl(&value, "cookie", lcookie.bv_val, lcookie.bv_len);
185 			add_assoc_zval(array, "value", &value);
186 		} else {
187 			add_assoc_null(array, "value");
188 		}
189 
190 		if (lcookie.bv_val) {
191 			ldap_memfree(lcookie.bv_val);
192 		}
193 	} else if ((strcmp(ctrl->ldctl_oid, LDAP_CONTROL_PRE_READ) == 0) || (strcmp(ctrl->ldctl_oid, LDAP_CONTROL_POST_READ) == 0)) {
194 		BerElement *ber;
195 		struct berval bv;
196 
197 		ber = ber_init(&ctrl->ldctl_value);
198 		if (ber == NULL) {
199 			add_assoc_null(array, "value");
200 		} else if (ber_scanf(ber, "{m{" /*}}*/, &bv) == LBER_ERROR) {
201 			add_assoc_null(array, "value");
202 		} else {
203 			zval value;
204 
205 			array_init(&value);
206 			add_assoc_stringl(&value, "dn", bv.bv_val, bv.bv_len);
207 
208 			while (ber_scanf(ber, "{m" /*}*/, &bv) != LBER_ERROR) {
209 				int	 i;
210 				BerVarray vals = NULL;
211 				zval tmp;
212 
213 				if (ber_scanf(ber, "[W]", &vals) == LBER_ERROR || vals == NULL)
214 				{
215 					break;
216 				}
217 
218 				array_init(&tmp);
219 				for (i = 0; vals[i].bv_val != NULL; i++) {
220 					add_next_index_stringl(&tmp, vals[i].bv_val, vals[i].bv_len);
221 				}
222 				add_assoc_zval(&value, bv.bv_val, &tmp);
223 
224 				ber_bvarray_free(vals);
225 			}
226 			add_assoc_zval(array, "value", &value);
227 		}
228 
229 		if (ber != NULL) {
230 			ber_free(ber, 1);
231 		}
232 	} else if (strcmp(ctrl->ldctl_oid, LDAP_CONTROL_SORTRESPONSE) == 0) {
233 		zval value;
234 		int errcode, rc;
235 		char* attribute;
236 
237 		if (ctrl->ldctl_value.bv_len) {
238 			rc = ldap_parse_sortresponse_control(ld, ctrl, &errcode, &attribute);
239 		} else {
240 			rc = -1;
241 		}
242 		if ( rc == LDAP_SUCCESS ) {
243 			array_init(&value);
244 			add_assoc_long(&value, "errcode", errcode);
245 			if (attribute) {
246 				add_assoc_string(&value, "attribute", attribute);
247 				ldap_memfree(attribute);
248 			}
249 			add_assoc_zval(array, "value", &value);
250 		} else {
251 			add_assoc_null(array, "value");
252 		}
253 	} else if (strcmp(ctrl->ldctl_oid, LDAP_CONTROL_VLVRESPONSE) == 0) {
254 		int target, count, errcode, rc;
255 		struct berval *context;
256 		zval value;
257 
258 		if (ctrl->ldctl_value.bv_len) {
259 			rc = ldap_parse_vlvresponse_control(ld, ctrl, &target, &count, &context, &errcode);
260 		} else {
261 			rc = -1;
262 		}
263 		if ( rc == LDAP_SUCCESS ) {
264 			array_init(&value);
265 			add_assoc_long(&value, "target", target);
266 			add_assoc_long(&value, "count", count);
267 			add_assoc_long(&value, "errcode", errcode);
268 			if ( context && (context->bv_len >= 0) ) {
269 				add_assoc_stringl(&value, "context", context->bv_val, context->bv_len);
270 			}
271 			add_assoc_zval(array, "value", &value);
272 		} else {
273 			add_assoc_null(array, "value");
274 		}
275 		ber_bvfree(context);
276 	} else {
277 		if (ctrl->ldctl_value.bv_len) {
278 			add_assoc_stringl(array, "value", ctrl->ldctl_value.bv_val, ctrl->ldctl_value.bv_len);
279 		} else {
280 			add_assoc_null(array, "value");
281 		}
282 	}
283 }
284 
_php_ldap_control_from_array(LDAP * ld,LDAPControl ** ctrl,zval * array)285 static int _php_ldap_control_from_array(LDAP *ld, LDAPControl** ctrl, zval* array)
286 {
287 	zval* val;
288 	zend_string *control_oid;
289 	int control_iscritical = 0, rc = LDAP_SUCCESS;
290 	char** ldap_attrs = NULL;
291 	LDAPSortKey** sort_keys = NULL;
292 	zend_string *tmpstring = NULL, **tmpstrings1 = NULL, **tmpstrings2 = NULL;
293 	size_t num_tmpstrings1 = 0, num_tmpstrings2 = 0;
294 
295 	if ((val = zend_hash_str_find(Z_ARRVAL_P(array), "oid", sizeof("oid") - 1)) == NULL) {
296 		php_error_docref(NULL, E_WARNING, "Control must have an oid key");
297 		return -1;
298 	}
299 
300 	control_oid = zval_get_string(val);
301 	if (EG(exception)) {
302 		return -1;
303 	}
304 
305 	if ((val = zend_hash_str_find(Z_ARRVAL_P(array), "iscritical", sizeof("iscritical") - 1)) != NULL) {
306 		control_iscritical = zend_is_true(val);
307 	} else {
308 		control_iscritical = 0;
309 	}
310 
311 	BerElement *ber = NULL;
312 	struct berval control_value = { 0L, NULL };
313 	int control_value_alloc = 0;
314 
315 	if ((val = zend_hash_str_find(Z_ARRVAL_P(array), "value", sizeof("value") - 1)) != NULL) {
316 		if (Z_TYPE_P(val) != IS_ARRAY) {
317 			tmpstring = zval_get_string(val);
318 			if (EG(exception)) {
319 				rc = -1;
320 				goto failure;
321 			}
322 			control_value.bv_val = ZSTR_VAL(tmpstring);
323 			control_value.bv_len = ZSTR_LEN(tmpstring);
324 		} else if (strcmp(ZSTR_VAL(control_oid), LDAP_CONTROL_PAGEDRESULTS) == 0) {
325 			zval* tmp;
326 			int pagesize = 1;
327 			struct berval cookie = { 0L, NULL };
328 			if ((tmp = zend_hash_str_find(Z_ARRVAL_P(val), "size", sizeof("size") - 1)) != NULL) {
329 				pagesize = zval_get_long(tmp);
330 			}
331 			if ((tmp = zend_hash_str_find(Z_ARRVAL_P(val), "cookie", sizeof("cookie") - 1)) != NULL) {
332 				tmpstring = zval_get_string(tmp);
333 				if (EG(exception)) {
334 					rc = -1;
335 					goto failure;
336 				}
337 				cookie.bv_val = ZSTR_VAL(tmpstring);
338 				cookie.bv_len = ZSTR_LEN(tmpstring);
339 			}
340 			/* ldap_create_page_control_value() allocates memory for control_value.bv_val */
341 			control_value_alloc = 1;
342 			rc = ldap_create_page_control_value(ld, pagesize, &cookie, &control_value);
343 			if (rc != LDAP_SUCCESS) {
344 				php_error_docref(NULL, E_WARNING, "Failed to create paged result control value: %s (%d)", ldap_err2string(rc), rc);
345 			}
346 		} else if (strcmp(ZSTR_VAL(control_oid), LDAP_CONTROL_ASSERT) == 0) {
347 			zval* tmp;
348 			zend_string* assert;
349 			if ((tmp = zend_hash_str_find(Z_ARRVAL_P(val), "filter", sizeof("filter") - 1)) == NULL) {
350 				rc = -1;
351 				php_error_docref(NULL, E_WARNING, "Filter missing from assert control value array");
352 			} else {
353 				assert = zval_get_string(tmp);
354 				if (EG(exception)) {
355 					rc = -1;
356 					goto failure;
357 				}
358 				/* ldap_create_assertion_control_value does not reset ld_errno, we need to do it ourselves
359 					 See http://www.openldap.org/its/index.cgi/Incoming?id=8674 */
360 				int success = LDAP_SUCCESS;
361 				ldap_set_option(ld, LDAP_OPT_RESULT_CODE, &success);
362 				/* ldap_create_assertion_control_value() allocates memory for control_value.bv_val */
363 				control_value_alloc = 1;
364 				rc = ldap_create_assertion_control_value(ld, ZSTR_VAL(assert), &control_value);
365 				if (rc != LDAP_SUCCESS) {
366 					php_error_docref(NULL, E_WARNING, "Failed to create assert control value: %s (%d)", ldap_err2string(rc), rc);
367 				}
368 				zend_string_release(assert);
369 			}
370 		} else if (strcmp(ZSTR_VAL(control_oid), LDAP_CONTROL_VALUESRETURNFILTER) == 0) {
371 			zval* tmp;
372 			if ((tmp = zend_hash_str_find(Z_ARRVAL_P(val), "filter", sizeof("filter") - 1)) == NULL) {
373 				rc = -1;
374 				php_error_docref(NULL, E_WARNING, "Filter missing from control value array");
375 			} else {
376 				ber = ber_alloc_t(LBER_USE_DER);
377 				if (ber == NULL) {
378 					rc = -1;
379 					php_error_docref(NULL, E_WARNING, "Failed to allocate control value");
380 				} else {
381 					tmpstring = zval_get_string(tmp);
382 					if (EG(exception)) {
383 						rc = -1;
384 						goto failure;
385 					}
386 					if (ldap_put_vrFilter(ber, ZSTR_VAL(tmpstring)) == -1) {
387 						rc = -1;
388 						php_error_docref(NULL, E_WARNING, "Failed to create control value: Bad ValuesReturnFilter: %s", ZSTR_VAL(tmpstring));
389 					} else if (ber_flatten2(ber, &control_value, control_value_alloc) == -1) {
390 						rc = -1;
391 					}
392 				}
393 			}
394 		} else if ((strcmp(ZSTR_VAL(control_oid), LDAP_CONTROL_PRE_READ) == 0) || (strcmp(ZSTR_VAL(control_oid), LDAP_CONTROL_POST_READ) == 0)) {
395 			zval* tmp;
396 			if ((tmp = zend_hash_str_find(Z_ARRVAL_P(val), "attrs", sizeof("attrs") - 1)) == NULL) {
397 				rc = -1;
398 				php_error_docref(NULL, E_WARNING, "Attributes list missing from control value array");
399 			} else {
400 				ber = ber_alloc_t(LBER_USE_DER);
401 
402 				if (ber == NULL) {
403 					rc = -1;
404 					php_error_docref(NULL, E_WARNING, "Failed to allocate control value");
405 				} else {
406 					int num_attribs, i;
407 					zval* attr;
408 
409 					num_attribs = zend_hash_num_elements(Z_ARRVAL_P(tmp));
410 					ldap_attrs = safe_emalloc((num_attribs+1), sizeof(char *), 0);
411 					tmpstrings1 = safe_emalloc(num_attribs, sizeof(zend_string*), 0);
412 					num_tmpstrings1 = 0;
413 
414 					for (i = 0; i<num_attribs; i++) {
415 						if ((attr = zend_hash_index_find(Z_ARRVAL_P(tmp), i)) == NULL) {
416 							rc = -1;
417 							php_error_docref(NULL, E_WARNING, "Failed to encode attribute list");
418 							goto failure;
419 						}
420 
421 						tmpstrings1[num_tmpstrings1] = zval_get_string(attr);
422 						if (EG(exception)) {
423 							rc = -1;
424 							goto failure;
425 						}
426 						ldap_attrs[i] = ZSTR_VAL(tmpstrings1[num_tmpstrings1]);
427 						++num_tmpstrings1;
428 					}
429 					ldap_attrs[num_attribs] = NULL;
430 
431 					ber_init2( ber, NULL, LBER_USE_DER );
432 
433 					if (ber_printf(ber, "{v}", ldap_attrs) == -1) {
434 						rc = -1;
435 						php_error_docref(NULL, E_WARNING, "Failed to encode attribute list");
436 					} else {
437 						int err;
438 						err = ber_flatten2(ber, &control_value, control_value_alloc);
439 						if (err < 0) {
440 							rc = -1;
441 							php_error_docref(NULL, E_WARNING, "Failed to encode control value (%d)", err);
442 						}
443 					}
444 				}
445 			}
446 		} else if (strcmp(ZSTR_VAL(control_oid), LDAP_CONTROL_SORTREQUEST) == 0) {
447 			int num_keys, i;
448 			zval *sortkey, *tmp;
449 
450 			num_keys = zend_hash_num_elements(Z_ARRVAL_P(val));
451 			sort_keys = safe_emalloc((num_keys+1), sizeof(LDAPSortKey*), 0);
452 			tmpstrings1 = safe_emalloc(num_keys, sizeof(zend_string*), 0);
453 			tmpstrings2 = safe_emalloc(num_keys, sizeof(zend_string*), 0);
454 			num_tmpstrings1 = 0;
455 			num_tmpstrings2 = 0;
456 
457 			for (i = 0; i<num_keys; i++) {
458 				if ((sortkey = zend_hash_index_find(Z_ARRVAL_P(val), i)) == NULL) {
459 					rc = -1;
460 					php_error_docref(NULL, E_WARNING, "Failed to encode sort keys list");
461 					goto failure;
462 				}
463 
464 				if ((tmp = zend_hash_str_find(Z_ARRVAL_P(sortkey), "attr", sizeof("attr") - 1)) == NULL) {
465 					rc = -1;
466 					php_error_docref(NULL, E_WARNING, "Sort key list missing field");
467 					goto failure;
468 				}
469 				sort_keys[i] = emalloc(sizeof(LDAPSortKey));
470 				tmpstrings1[num_tmpstrings1] = zval_get_string(tmp);
471 				if (EG(exception)) {
472 					rc = -1;
473 					goto failure;
474 				}
475 				sort_keys[i]->attributeType = ZSTR_VAL(tmpstrings1[num_tmpstrings1]);
476 				++num_tmpstrings1;
477 
478 				if ((tmp = zend_hash_str_find(Z_ARRVAL_P(sortkey), "oid", sizeof("oid") - 1)) != NULL) {
479 					tmpstrings2[num_tmpstrings2] = zval_get_string(tmp);
480 					if (EG(exception)) {
481 						rc = -1;
482 						goto failure;
483 					}
484 					sort_keys[i]->orderingRule = ZSTR_VAL(tmpstrings2[num_tmpstrings2]);
485 					++num_tmpstrings2;
486 				} else {
487 					sort_keys[i]->orderingRule = NULL;
488 				}
489 
490 				if ((tmp = zend_hash_str_find(Z_ARRVAL_P(sortkey), "reverse", sizeof("reverse") - 1)) != NULL) {
491 					sort_keys[i]->reverseOrder = zend_is_true(tmp);
492 				} else {
493 					sort_keys[i]->reverseOrder = 0;
494 				}
495 			}
496 			sort_keys[num_keys] = NULL;
497 			/* ldap_create_sort_control_value() allocates memory for control_value.bv_val */
498 			control_value_alloc = 1;
499 			rc = ldap_create_sort_control_value(ld, sort_keys, &control_value);
500 			if (rc != LDAP_SUCCESS) {
501 				php_error_docref(NULL, E_WARNING, "Failed to create sort control value: %s (%d)", ldap_err2string(rc), rc);
502 			}
503 		} else if (strcmp(ZSTR_VAL(control_oid), LDAP_CONTROL_VLVREQUEST) == 0) {
504 			zval* tmp;
505 			LDAPVLVInfo vlvInfo;
506 			struct berval attrValue;
507 			struct berval context;
508 
509 			if ((tmp = zend_hash_str_find(Z_ARRVAL_P(val), "before", sizeof("before") - 1)) != NULL) {
510 				vlvInfo.ldvlv_before_count = zval_get_long(tmp);
511 			} else {
512 				rc = -1;
513 				php_error_docref(NULL, E_WARNING, "Before key missing from array value for VLV control");
514 				goto failure;
515 			}
516 
517 			if ((tmp = zend_hash_str_find(Z_ARRVAL_P(val), "after", sizeof("after") - 1)) != NULL) {
518 				vlvInfo.ldvlv_after_count = zval_get_long(tmp);
519 			} else {
520 				rc = -1;
521 				php_error_docref(NULL, E_WARNING, "After key missing from array value for VLV control");
522 				goto failure;
523 			}
524 
525 			if ((tmp = zend_hash_str_find(Z_ARRVAL_P(val), "attrvalue", sizeof("attrvalue") - 1)) != NULL) {
526 				tmpstring = zval_get_string(tmp);
527 				if (EG(exception)) {
528 					rc = -1;
529 					goto failure;
530 				}
531 				attrValue.bv_val = ZSTR_VAL(tmpstring);
532 				attrValue.bv_len = ZSTR_LEN(tmpstring);
533 				vlvInfo.ldvlv_attrvalue = &attrValue;
534 			} else if ((tmp = zend_hash_str_find(Z_ARRVAL_P(val), "offset", sizeof("offset") - 1)) != NULL) {
535 				vlvInfo.ldvlv_attrvalue = NULL;
536 				vlvInfo.ldvlv_offset = zval_get_long(tmp);
537 				if ((tmp = zend_hash_str_find(Z_ARRVAL_P(val), "count", sizeof("count") - 1)) != NULL) {
538 					vlvInfo.ldvlv_count = zval_get_long(tmp);
539 				} else {
540 					rc = -1;
541 					php_error_docref(NULL, E_WARNING, "Count key missing from array value for VLV control");
542 					goto failure;
543 				}
544 			} else {
545 				rc = -1;
546 				php_error_docref(NULL, E_WARNING, "Missing either attrvalue or offset key from array value for VLV control");
547 				goto failure;
548 			}
549 
550 			if ((tmp = zend_hash_str_find(Z_ARRVAL_P(val), "context", sizeof("context") - 1)) != NULL) {
551 				tmpstring = zval_get_string(tmp);
552 				if (EG(exception)) {
553 					rc = -1;
554 					goto failure;
555 				}
556 				context.bv_val = ZSTR_VAL(tmpstring);
557 				context.bv_len = ZSTR_LEN(tmpstring);
558 				vlvInfo.ldvlv_context = &context;
559 			} else {
560 				vlvInfo.ldvlv_context = NULL;
561 			}
562 
563 			/* ldap_create_vlv_control_value() allocates memory for control_value.bv_val */
564 			control_value_alloc = 1;
565 			rc = ldap_create_vlv_control_value(ld, &vlvInfo, &control_value);
566 			if (rc != LDAP_SUCCESS) {
567 				php_error_docref(NULL, E_WARNING, "Failed to create VLV control value: %s (%d)", ldap_err2string(rc), rc);
568 			}
569 		} else {
570 			php_error_docref(NULL, E_WARNING, "Control OID %s does not expect an array as value", ZSTR_VAL(control_oid));
571 			rc = -1;
572 		}
573 	}
574 
575 	if (rc == LDAP_SUCCESS) {
576 		rc = ldap_control_create(ZSTR_VAL(control_oid), control_iscritical, &control_value, 1, ctrl);
577 	}
578 
579 failure:
580 	zend_string_release(control_oid);
581 	if (tmpstring != NULL) {
582 		zend_string_release(tmpstring);
583 	}
584 	if (tmpstrings1 != NULL) {
585 		int i;
586 		for (i = 0; i < num_tmpstrings1; ++i) {
587 			zend_string_release(tmpstrings1[i]);
588 		}
589 		efree(tmpstrings1);
590 	}
591 	if (tmpstrings2 != NULL) {
592 		int i;
593 		for (i = 0; i < num_tmpstrings2; ++i) {
594 			zend_string_release(tmpstrings2[i]);
595 		}
596 		efree(tmpstrings2);
597 	}
598 	if (control_value.bv_val != NULL && control_value_alloc != 0) {
599 		ber_memfree(control_value.bv_val);
600 	}
601 	if (ber != NULL) {
602 		ber_free(ber, 1);
603 	}
604 	if (ldap_attrs != NULL) {
605 		efree(ldap_attrs);
606 	}
607 	if (sort_keys != NULL) {
608 		LDAPSortKey** sortp = sort_keys;
609 		while (*sortp) {
610 			efree(*sortp);
611 			sortp++;
612 		}
613 		efree(sort_keys);
614 		sort_keys = NULL;
615 	}
616 
617 	if (rc == LDAP_SUCCESS) {
618 		return LDAP_SUCCESS;
619 	}
620 
621 	/* Failed */
622 	*ctrl = NULL;
623 	return -1;
624 }
625 
_php_ldap_controls_to_array(LDAP * ld,LDAPControl ** ctrls,zval * array,int request)626 static void _php_ldap_controls_to_array(LDAP *ld, LDAPControl** ctrls, zval* array, int request)
627 {
628 	zval tmp1;
629 	LDAPControl **ctrlp;
630 
631 	array_init(array);
632 	if (ctrls == NULL) {
633 		return;
634 	}
635 	ctrlp = ctrls;
636 	while (*ctrlp != NULL) {
637 		_php_ldap_control_to_array(ld, *ctrlp, &tmp1, request);
638 		add_assoc_zval(array, (*ctrlp)->ldctl_oid, &tmp1);
639 		ctrlp++;
640 	}
641 	ldap_controls_free(ctrls);
642 }
643 
_php_ldap_controls_from_array(LDAP * ld,zval * array)644 static LDAPControl** _php_ldap_controls_from_array(LDAP *ld, zval* array)
645 {
646 	int ncontrols;
647 	LDAPControl** ctrlp, **ctrls = NULL;
648 	zval* ctrlarray;
649 	int error = 0;
650 
651 	ncontrols = zend_hash_num_elements(Z_ARRVAL_P(array));
652 	ctrls = safe_emalloc((1 + ncontrols), sizeof(*ctrls), 0);
653 	*ctrls = NULL;
654 	ctrlp = ctrls;
655 	ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(array), ctrlarray) {
656 		if (Z_TYPE_P(ctrlarray) != IS_ARRAY) {
657 			php_error_docref(NULL, E_WARNING, "The array value must contain only arrays, where each array is a control");
658 			error = 1;
659 			break;
660 		}
661 
662 		if (_php_ldap_control_from_array(ld, ctrlp, ctrlarray) == LDAP_SUCCESS) {
663 			++ctrlp;
664 		} else {
665 			error = 1;
666 			break;
667 		}
668 
669 		*ctrlp = NULL;
670 	} ZEND_HASH_FOREACH_END();
671 
672 	if (error) {
673 		ctrlp = ctrls;
674 		while (*ctrlp) {
675 			ldap_control_free(*ctrlp);
676 			ctrlp++;
677 		}
678 		efree(ctrls);
679 		ctrls = NULL;
680 	}
681 
682 	return ctrls;
683 }
684 
_php_ldap_controls_free(LDAPControl *** ctrls)685 static void _php_ldap_controls_free (LDAPControl*** ctrls)
686 {
687 	LDAPControl **ctrlp;
688 
689 	if (*ctrls) {
690 		ctrlp = *ctrls;
691 		while (*ctrlp) {
692 			ldap_control_free(*ctrlp);
693 			ctrlp++;
694 		}
695 		efree(*ctrls);
696 		*ctrls = NULL;
697 	}
698 }
699 /* }}} */
700 
701 /* {{{ PHP_INI_BEGIN
702  */
703 PHP_INI_BEGIN()
704 	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()705 PHP_INI_END()
706 /* }}} */
707 
708 /* {{{ PHP_GINIT_FUNCTION
709  */
710 static PHP_GINIT_FUNCTION(ldap)
711 {
712 	ldap_globals->num_links = 0;
713 }
714 /* }}} */
715 
716 /* {{{ PHP_MINIT_FUNCTION
717  */
PHP_MINIT_FUNCTION(ldap)718 PHP_MINIT_FUNCTION(ldap)
719 {
720 	REGISTER_INI_ENTRIES();
721 
722 	/* Constants to be used with deref-parameter in php_ldap_do_search() */
723 	REGISTER_LONG_CONSTANT("LDAP_DEREF_NEVER", LDAP_DEREF_NEVER, CONST_PERSISTENT | CONST_CS);
724 	REGISTER_LONG_CONSTANT("LDAP_DEREF_SEARCHING", LDAP_DEREF_SEARCHING, CONST_PERSISTENT | CONST_CS);
725 	REGISTER_LONG_CONSTANT("LDAP_DEREF_FINDING", LDAP_DEREF_FINDING, CONST_PERSISTENT | CONST_CS);
726 	REGISTER_LONG_CONSTANT("LDAP_DEREF_ALWAYS", LDAP_DEREF_ALWAYS, CONST_PERSISTENT | CONST_CS);
727 
728 	/* Constants to be used with ldap_modify_batch() */
729 	REGISTER_LONG_CONSTANT("LDAP_MODIFY_BATCH_ADD", LDAP_MODIFY_BATCH_ADD, CONST_PERSISTENT | CONST_CS);
730 	REGISTER_LONG_CONSTANT("LDAP_MODIFY_BATCH_REMOVE", LDAP_MODIFY_BATCH_REMOVE, CONST_PERSISTENT | CONST_CS);
731 	REGISTER_LONG_CONSTANT("LDAP_MODIFY_BATCH_REMOVE_ALL", LDAP_MODIFY_BATCH_REMOVE_ALL, CONST_PERSISTENT | CONST_CS);
732 	REGISTER_LONG_CONSTANT("LDAP_MODIFY_BATCH_REPLACE", LDAP_MODIFY_BATCH_REPLACE, CONST_PERSISTENT | CONST_CS);
733 	REGISTER_STRING_CONSTANT("LDAP_MODIFY_BATCH_ATTRIB", LDAP_MODIFY_BATCH_ATTRIB, CONST_PERSISTENT | CONST_CS);
734 	REGISTER_STRING_CONSTANT("LDAP_MODIFY_BATCH_MODTYPE", LDAP_MODIFY_BATCH_MODTYPE, CONST_PERSISTENT | CONST_CS);
735 	REGISTER_STRING_CONSTANT("LDAP_MODIFY_BATCH_VALUES", LDAP_MODIFY_BATCH_VALUES, CONST_PERSISTENT | CONST_CS);
736 
737 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP
738 	/* LDAP options */
739 	REGISTER_LONG_CONSTANT("LDAP_OPT_DEREF", LDAP_OPT_DEREF, CONST_PERSISTENT | CONST_CS);
740 	REGISTER_LONG_CONSTANT("LDAP_OPT_SIZELIMIT", LDAP_OPT_SIZELIMIT, CONST_PERSISTENT | CONST_CS);
741 	REGISTER_LONG_CONSTANT("LDAP_OPT_TIMELIMIT", LDAP_OPT_TIMELIMIT, CONST_PERSISTENT | CONST_CS);
742 #ifdef LDAP_OPT_NETWORK_TIMEOUT
743 	REGISTER_LONG_CONSTANT("LDAP_OPT_NETWORK_TIMEOUT", LDAP_OPT_NETWORK_TIMEOUT, CONST_PERSISTENT | CONST_CS);
744 #elif defined (LDAP_X_OPT_CONNECT_TIMEOUT)
745 	REGISTER_LONG_CONSTANT("LDAP_OPT_NETWORK_TIMEOUT", LDAP_X_OPT_CONNECT_TIMEOUT, CONST_PERSISTENT | CONST_CS);
746 #endif
747 #ifdef LDAP_OPT_TIMEOUT
748 	REGISTER_LONG_CONSTANT("LDAP_OPT_TIMEOUT", LDAP_OPT_TIMEOUT, CONST_PERSISTENT | CONST_CS);
749 #endif
750 	REGISTER_LONG_CONSTANT("LDAP_OPT_PROTOCOL_VERSION", LDAP_OPT_PROTOCOL_VERSION, CONST_PERSISTENT | CONST_CS);
751 	REGISTER_LONG_CONSTANT("LDAP_OPT_ERROR_NUMBER", LDAP_OPT_ERROR_NUMBER, CONST_PERSISTENT | CONST_CS);
752 	REGISTER_LONG_CONSTANT("LDAP_OPT_REFERRALS", LDAP_OPT_REFERRALS, CONST_PERSISTENT | CONST_CS);
753 #ifdef LDAP_OPT_RESTART
754 	REGISTER_LONG_CONSTANT("LDAP_OPT_RESTART", LDAP_OPT_RESTART, CONST_PERSISTENT | CONST_CS);
755 #endif
756 #ifdef LDAP_OPT_HOST_NAME
757 	REGISTER_LONG_CONSTANT("LDAP_OPT_HOST_NAME", LDAP_OPT_HOST_NAME, CONST_PERSISTENT | CONST_CS);
758 #endif
759 	REGISTER_LONG_CONSTANT("LDAP_OPT_ERROR_STRING", LDAP_OPT_ERROR_STRING, CONST_PERSISTENT | CONST_CS);
760 #ifdef LDAP_OPT_MATCHED_DN
761 	REGISTER_LONG_CONSTANT("LDAP_OPT_MATCHED_DN", LDAP_OPT_MATCHED_DN, CONST_PERSISTENT | CONST_CS);
762 #endif
763 	REGISTER_LONG_CONSTANT("LDAP_OPT_SERVER_CONTROLS", LDAP_OPT_SERVER_CONTROLS, CONST_PERSISTENT | CONST_CS);
764 	REGISTER_LONG_CONSTANT("LDAP_OPT_CLIENT_CONTROLS", LDAP_OPT_CLIENT_CONTROLS, CONST_PERSISTENT | CONST_CS);
765 #endif
766 #ifdef LDAP_OPT_DEBUG_LEVEL
767 	REGISTER_LONG_CONSTANT("LDAP_OPT_DEBUG_LEVEL", LDAP_OPT_DEBUG_LEVEL, CONST_PERSISTENT | CONST_CS);
768 #endif
769 
770 #ifdef LDAP_OPT_DIAGNOSTIC_MESSAGE
771 	REGISTER_LONG_CONSTANT("LDAP_OPT_DIAGNOSTIC_MESSAGE", LDAP_OPT_DIAGNOSTIC_MESSAGE, CONST_PERSISTENT | CONST_CS);
772 #endif
773 
774 #ifdef HAVE_LDAP_SASL
775 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_SASL_MECH", LDAP_OPT_X_SASL_MECH, CONST_PERSISTENT | CONST_CS);
776 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_SASL_REALM", LDAP_OPT_X_SASL_REALM, CONST_PERSISTENT | CONST_CS);
777 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_SASL_AUTHCID", LDAP_OPT_X_SASL_AUTHCID, CONST_PERSISTENT | CONST_CS);
778 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_SASL_AUTHZID", LDAP_OPT_X_SASL_AUTHZID, CONST_PERSISTENT | CONST_CS);
779 #endif
780 #ifdef LDAP_OPT_X_SASL_NOCANON
781 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_SASL_NOCANON", LDAP_OPT_X_SASL_NOCANON, CONST_PERSISTENT | CONST_CS);
782 #endif
783 #ifdef LDAP_OPT_X_SASL_USERNAME
784 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_SASL_USERNAME", LDAP_OPT_X_SASL_USERNAME, CONST_PERSISTENT | CONST_CS);
785 #endif
786 
787 #ifdef ORALDAP
788 	REGISTER_LONG_CONSTANT("GSLC_SSL_NO_AUTH", GSLC_SSL_NO_AUTH, CONST_PERSISTENT | CONST_CS);
789 	REGISTER_LONG_CONSTANT("GSLC_SSL_ONEWAY_AUTH", GSLC_SSL_ONEWAY_AUTH, CONST_PERSISTENT | CONST_CS);
790 	REGISTER_LONG_CONSTANT("GSLC_SSL_TWOWAY_AUTH", GSLC_SSL_TWOWAY_AUTH, CONST_PERSISTENT | CONST_CS);
791 #endif
792 
793 #if (LDAP_API_VERSION > 2000)
794 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_REQUIRE_CERT", LDAP_OPT_X_TLS_REQUIRE_CERT, CONST_PERSISTENT | CONST_CS);
795 
796 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_NEVER", LDAP_OPT_X_TLS_NEVER, CONST_PERSISTENT | CONST_CS);
797 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_HARD", LDAP_OPT_X_TLS_HARD, CONST_PERSISTENT | CONST_CS);
798 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_DEMAND", LDAP_OPT_X_TLS_DEMAND, CONST_PERSISTENT | CONST_CS);
799 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_ALLOW", LDAP_OPT_X_TLS_ALLOW, CONST_PERSISTENT | CONST_CS);
800 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_TRY", LDAP_OPT_X_TLS_TRY, CONST_PERSISTENT | CONST_CS);
801 
802 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_CACERTDIR", LDAP_OPT_X_TLS_CACERTDIR, CONST_PERSISTENT | CONST_CS);
803 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_CACERTFILE", LDAP_OPT_X_TLS_CACERTFILE, CONST_PERSISTENT | CONST_CS);
804 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_CERTFILE", LDAP_OPT_X_TLS_CERTFILE, CONST_PERSISTENT | CONST_CS);
805 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_CIPHER_SUITE", LDAP_OPT_X_TLS_CIPHER_SUITE, CONST_PERSISTENT | CONST_CS);
806 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_KEYFILE", LDAP_OPT_X_TLS_KEYFILE, CONST_PERSISTENT | CONST_CS);
807 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_RANDOM_FILE", LDAP_OPT_X_TLS_RANDOM_FILE, CONST_PERSISTENT | CONST_CS);
808 #endif
809 
810 #ifdef LDAP_OPT_X_TLS_CRLCHECK
811 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_CRLCHECK", LDAP_OPT_X_TLS_CRLCHECK, CONST_PERSISTENT | CONST_CS);
812 
813 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_CRL_NONE", LDAP_OPT_X_TLS_CRL_NONE, CONST_PERSISTENT | CONST_CS);
814 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_CRL_PEER", LDAP_OPT_X_TLS_CRL_PEER, CONST_PERSISTENT | CONST_CS);
815 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_CRL_ALL", LDAP_OPT_X_TLS_CRL_ALL, CONST_PERSISTENT | CONST_CS);
816 #endif
817 
818 #ifdef LDAP_OPT_X_TLS_DHFILE
819 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_DHFILE", LDAP_OPT_X_TLS_DHFILE, CONST_PERSISTENT | CONST_CS);
820 #endif
821 
822 #ifdef LDAP_OPT_X_TLS_CRLFILE
823 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_CRLFILE", LDAP_OPT_X_TLS_CRLFILE, CONST_PERSISTENT | CONST_CS);
824 #endif
825 
826 #ifdef LDAP_OPT_X_TLS_PROTOCOL_MIN
827 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_PROTOCOL_MIN", LDAP_OPT_X_TLS_PROTOCOL_MIN, CONST_PERSISTENT | CONST_CS);
828 
829 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_PROTOCOL_SSL2", LDAP_OPT_X_TLS_PROTOCOL_SSL2, CONST_PERSISTENT | CONST_CS);
830 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_PROTOCOL_SSL3", LDAP_OPT_X_TLS_PROTOCOL_SSL3, CONST_PERSISTENT | CONST_CS);
831 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_PROTOCOL_TLS1_0", LDAP_OPT_X_TLS_PROTOCOL_TLS1_0, CONST_PERSISTENT | CONST_CS);
832 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_PROTOCOL_TLS1_1", LDAP_OPT_X_TLS_PROTOCOL_TLS1_1, CONST_PERSISTENT | CONST_CS);
833 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_PROTOCOL_TLS1_2", LDAP_OPT_X_TLS_PROTOCOL_TLS1_2, CONST_PERSISTENT | CONST_CS);
834 #endif
835 
836 #ifdef LDAP_OPT_X_TLS_PACKAGE
837 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_TLS_PACKAGE", LDAP_OPT_X_TLS_PACKAGE, CONST_PERSISTENT | CONST_CS);
838 #endif
839 
840 #ifdef LDAP_OPT_X_KEEPALIVE_IDLE
841 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_KEEPALIVE_IDLE", LDAP_OPT_X_KEEPALIVE_IDLE, CONST_PERSISTENT | CONST_CS);
842 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_KEEPALIVE_PROBES", LDAP_OPT_X_KEEPALIVE_PROBES, CONST_PERSISTENT | CONST_CS);
843 	REGISTER_LONG_CONSTANT("LDAP_OPT_X_KEEPALIVE_INTERVAL", LDAP_OPT_X_KEEPALIVE_INTERVAL, CONST_PERSISTENT | CONST_CS);
844 #endif
845 
846 	REGISTER_LONG_CONSTANT("LDAP_ESCAPE_FILTER", PHP_LDAP_ESCAPE_FILTER, CONST_PERSISTENT | CONST_CS);
847 	REGISTER_LONG_CONSTANT("LDAP_ESCAPE_DN", PHP_LDAP_ESCAPE_DN, CONST_PERSISTENT | CONST_CS);
848 
849 #ifdef HAVE_LDAP_EXTENDED_OPERATION_S
850 	REGISTER_STRING_CONSTANT("LDAP_EXOP_START_TLS", LDAP_EXOP_START_TLS, CONST_PERSISTENT | CONST_CS);
851 	REGISTER_STRING_CONSTANT("LDAP_EXOP_MODIFY_PASSWD", LDAP_EXOP_MODIFY_PASSWD, CONST_PERSISTENT | CONST_CS);
852 	REGISTER_STRING_CONSTANT("LDAP_EXOP_REFRESH", LDAP_EXOP_REFRESH, CONST_PERSISTENT | CONST_CS);
853 	REGISTER_STRING_CONSTANT("LDAP_EXOP_WHO_AM_I", LDAP_EXOP_WHO_AM_I, CONST_PERSISTENT | CONST_CS);
854 	REGISTER_STRING_CONSTANT("LDAP_EXOP_TURN", LDAP_EXOP_TURN, CONST_PERSISTENT | CONST_CS);
855 #endif
856 
857 /* LDAP Controls */
858 /*	standard track controls */
859 #ifdef LDAP_CONTROL_MANAGEDSAIT
860 	/* RFC 3296 */
861 	REGISTER_STRING_CONSTANT("LDAP_CONTROL_MANAGEDSAIT", LDAP_CONTROL_MANAGEDSAIT, CONST_PERSISTENT | CONST_CS);
862 #endif
863 #ifdef LDAP_CONTROL_PROXY_AUTHZ
864 	/* RFC 4370 */
865 	REGISTER_STRING_CONSTANT("LDAP_CONTROL_PROXY_AUTHZ", LDAP_CONTROL_PROXY_AUTHZ, CONST_PERSISTENT | CONST_CS);
866 #endif
867 #ifdef LDAP_CONTROL_SUBENTRIES
868 	/* RFC 3672 */
869 	REGISTER_STRING_CONSTANT("LDAP_CONTROL_SUBENTRIES", LDAP_CONTROL_SUBENTRIES, CONST_PERSISTENT | CONST_CS);
870 #endif
871 #ifdef LDAP_CONTROL_VALUESRETURNFILTER
872 	/* RFC 3876 */
873 	REGISTER_STRING_CONSTANT("LDAP_CONTROL_VALUESRETURNFILTER", LDAP_CONTROL_VALUESRETURNFILTER, CONST_PERSISTENT | CONST_CS);
874 #endif
875 #ifdef LDAP_CONTROL_ASSERT
876 	/* RFC 4528 */
877 	REGISTER_STRING_CONSTANT("LDAP_CONTROL_ASSERT", LDAP_CONTROL_ASSERT, CONST_PERSISTENT | CONST_CS);
878 	/* RFC 4527 */
879 	REGISTER_STRING_CONSTANT("LDAP_CONTROL_PRE_READ", LDAP_CONTROL_PRE_READ, CONST_PERSISTENT | CONST_CS);
880 	REGISTER_STRING_CONSTANT("LDAP_CONTROL_POST_READ", LDAP_CONTROL_POST_READ, CONST_PERSISTENT | CONST_CS);
881 #endif
882 #ifdef LDAP_CONTROL_SORTREQUEST
883 	/* RFC 2891 */
884 	REGISTER_STRING_CONSTANT("LDAP_CONTROL_SORTREQUEST", LDAP_CONTROL_SORTREQUEST, CONST_PERSISTENT | CONST_CS);
885 	REGISTER_STRING_CONSTANT("LDAP_CONTROL_SORTRESPONSE", LDAP_CONTROL_SORTRESPONSE, CONST_PERSISTENT | CONST_CS);
886 #endif
887 /*	non-standard track controls */
888 #ifdef LDAP_CONTROL_PAGEDRESULTS
889 	/* RFC 2696 */
890 	REGISTER_STRING_CONSTANT("LDAP_CONTROL_PAGEDRESULTS", LDAP_CONTROL_PAGEDRESULTS, CONST_PERSISTENT | CONST_CS);
891 #endif
892 #ifdef LDAP_CONTROL_AUTHZID_REQUEST
893 	/* RFC 3829 */
894 	REGISTER_STRING_CONSTANT("LDAP_CONTROL_AUTHZID_REQUEST", LDAP_CONTROL_AUTHZID_REQUEST, CONST_PERSISTENT | CONST_CS);
895 	REGISTER_STRING_CONSTANT("LDAP_CONTROL_AUTHZID_RESPONSE", LDAP_CONTROL_AUTHZID_RESPONSE, CONST_PERSISTENT | CONST_CS);
896 #endif
897 #ifdef LDAP_CONTROL_SYNC
898 	/* LDAP Content Synchronization Operation -- RFC 4533 */
899 	REGISTER_STRING_CONSTANT("LDAP_CONTROL_SYNC", LDAP_CONTROL_SYNC, CONST_PERSISTENT | CONST_CS);
900 	REGISTER_STRING_CONSTANT("LDAP_CONTROL_SYNC_STATE", LDAP_CONTROL_SYNC_STATE, CONST_PERSISTENT | CONST_CS);
901 	REGISTER_STRING_CONSTANT("LDAP_CONTROL_SYNC_DONE", LDAP_CONTROL_SYNC_DONE, CONST_PERSISTENT | CONST_CS);
902 #endif
903 #ifdef LDAP_CONTROL_DONTUSECOPY
904 	/* LDAP Don't Use Copy Control (RFC 6171) */
905 	REGISTER_STRING_CONSTANT("LDAP_CONTROL_DONTUSECOPY", LDAP_CONTROL_DONTUSECOPY, CONST_PERSISTENT | CONST_CS);
906 #endif
907 #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
908 	/* Password policy Controls */
909 	REGISTER_STRING_CONSTANT("LDAP_CONTROL_PASSWORDPOLICYREQUEST", LDAP_CONTROL_PASSWORDPOLICYREQUEST, CONST_PERSISTENT | CONST_CS);
910 	REGISTER_STRING_CONSTANT("LDAP_CONTROL_PASSWORDPOLICYRESPONSE", LDAP_CONTROL_PASSWORDPOLICYRESPONSE, CONST_PERSISTENT | CONST_CS);
911 #endif
912 #ifdef LDAP_CONTROL_X_INCREMENTAL_VALUES
913 	/* MS Active Directory controls */
914 	REGISTER_STRING_CONSTANT("LDAP_CONTROL_X_INCREMENTAL_VALUES", LDAP_CONTROL_X_INCREMENTAL_VALUES, CONST_PERSISTENT | CONST_CS);
915 	REGISTER_STRING_CONSTANT("LDAP_CONTROL_X_DOMAIN_SCOPE", LDAP_CONTROL_X_DOMAIN_SCOPE, CONST_PERSISTENT | CONST_CS);
916 	REGISTER_STRING_CONSTANT("LDAP_CONTROL_X_PERMISSIVE_MODIFY", LDAP_CONTROL_X_PERMISSIVE_MODIFY, CONST_PERSISTENT | CONST_CS);
917 	REGISTER_STRING_CONSTANT("LDAP_CONTROL_X_SEARCH_OPTIONS", LDAP_CONTROL_X_SEARCH_OPTIONS, CONST_PERSISTENT | CONST_CS);
918 	REGISTER_STRING_CONSTANT("LDAP_CONTROL_X_TREE_DELETE", LDAP_CONTROL_X_TREE_DELETE, CONST_PERSISTENT | CONST_CS);
919 	REGISTER_STRING_CONSTANT("LDAP_CONTROL_X_EXTENDED_DN", LDAP_CONTROL_X_EXTENDED_DN, CONST_PERSISTENT | CONST_CS);
920 #endif
921 #ifdef LDAP_CONTROL_VLVREQUEST
922 	/* LDAP VLV */
923 	REGISTER_STRING_CONSTANT("LDAP_CONTROL_VLVREQUEST", LDAP_CONTROL_VLVREQUEST, CONST_PERSISTENT | CONST_CS);
924 	REGISTER_STRING_CONSTANT("LDAP_CONTROL_VLVRESPONSE", LDAP_CONTROL_VLVRESPONSE, CONST_PERSISTENT | CONST_CS);
925 #endif
926 
927 	le_link = zend_register_list_destructors_ex(_close_ldap_link, NULL, "ldap link", module_number);
928 	le_result = zend_register_list_destructors_ex(_free_ldap_result, NULL, "ldap result", module_number);
929 	le_result_entry = zend_register_list_destructors_ex(_free_ldap_result_entry, NULL, "ldap result entry", module_number);
930 
931 	ldap_module_entry.type = type;
932 
933 	return SUCCESS;
934 }
935 /* }}} */
936 
937 /* {{{ PHP_MSHUTDOWN_FUNCTION
938  */
PHP_MSHUTDOWN_FUNCTION(ldap)939 PHP_MSHUTDOWN_FUNCTION(ldap)
940 {
941 	UNREGISTER_INI_ENTRIES();
942 	return SUCCESS;
943 }
944 /* }}} */
945 
946 /* {{{ PHP_MINFO_FUNCTION
947  */
PHP_MINFO_FUNCTION(ldap)948 PHP_MINFO_FUNCTION(ldap)
949 {
950 	char tmp[32];
951 #if HAVE_NSLDAP
952 	LDAPVersion ver;
953 	double SDKVersion;
954 #endif
955 
956 	php_info_print_table_start();
957 	php_info_print_table_row(2, "LDAP Support", "enabled");
958 
959 	if (LDAPG(max_links) == -1) {
960 		snprintf(tmp, 31, ZEND_LONG_FMT "/unlimited", LDAPG(num_links));
961 	} else {
962 		snprintf(tmp, 31, ZEND_LONG_FMT "/" ZEND_LONG_FMT, LDAPG(num_links), LDAPG(max_links));
963 	}
964 	php_info_print_table_row(2, "Total Links", tmp);
965 
966 #ifdef LDAP_API_VERSION
967 	snprintf(tmp, 31, "%d", LDAP_API_VERSION);
968 	php_info_print_table_row(2, "API Version", tmp);
969 #endif
970 
971 #ifdef LDAP_VENDOR_NAME
972 	php_info_print_table_row(2, "Vendor Name", LDAP_VENDOR_NAME);
973 #endif
974 
975 #ifdef LDAP_VENDOR_VERSION
976 	snprintf(tmp, 31, "%d", LDAP_VENDOR_VERSION);
977 	php_info_print_table_row(2, "Vendor Version", tmp);
978 #endif
979 
980 #if HAVE_NSLDAP
981 	SDKVersion = ldap_version(&ver);
982 	snprintf(tmp, 31, "%F", SDKVersion/100.0);
983 	php_info_print_table_row(2, "SDK Version", tmp);
984 
985 	snprintf(tmp, 31, "%F", ver.protocol_version/100.0);
986 	php_info_print_table_row(2, "Highest LDAP Protocol Supported", tmp);
987 
988 	snprintf(tmp, 31, "%F", ver.SSL_version/100.0);
989 	php_info_print_table_row(2, "SSL Level Supported", tmp);
990 
991 	if (ver.security_level != LDAP_SECURITY_NONE) {
992 		snprintf(tmp, 31, "%d", ver.security_level);
993 	} else {
994 		strcpy(tmp, "SSL not enabled");
995 	}
996 	php_info_print_table_row(2, "Level of Encryption", tmp);
997 #endif
998 
999 #ifdef HAVE_LDAP_SASL
1000 	php_info_print_table_row(2, "SASL Support", "Enabled");
1001 #endif
1002 
1003 	php_info_print_table_end();
1004 	DISPLAY_INI_ENTRIES();
1005 }
1006 /* }}} */
1007 
1008 /* {{{ proto resource ldap_connect([string host [, int port [, string wallet [, string wallet_passwd [, int authmode]]]]])
1009    Connect to an LDAP server */
PHP_FUNCTION(ldap_connect)1010 PHP_FUNCTION(ldap_connect)
1011 {
1012 	char *host = NULL;
1013 	size_t hostlen = 0;
1014 	zend_long port = LDAP_PORT;
1015 #ifdef HAVE_ORALDAP
1016 	char *wallet = NULL, *walletpasswd = NULL;
1017 	size_t walletlen = 0, walletpasswdlen = 0;
1018 	zend_long authmode = GSLC_SSL_NO_AUTH;
1019 	int ssl=0;
1020 #endif
1021 	ldap_linkdata *ld;
1022 	LDAP *ldap = NULL;
1023 
1024 #ifdef HAVE_ORALDAP
1025 	if (ZEND_NUM_ARGS() == 3 || ZEND_NUM_ARGS() == 4) {
1026 		WRONG_PARAM_COUNT;
1027 	}
1028 
1029 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|slssl", &host, &hostlen, &port, &wallet, &walletlen, &walletpasswd, &walletpasswdlen, &authmode) != SUCCESS) {
1030 		RETURN_FALSE;
1031 	}
1032 
1033 	if (ZEND_NUM_ARGS() == 5) {
1034 		ssl = 1;
1035 	}
1036 #else
1037 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|sl", &host, &hostlen, &port) != SUCCESS) {
1038 		RETURN_FALSE;
1039 	}
1040 #endif
1041 
1042 	if (LDAPG(max_links) != -1 && LDAPG(num_links) >= LDAPG(max_links)) {
1043 		php_error_docref(NULL, E_WARNING, "Too many open links (" ZEND_LONG_FMT ")", LDAPG(num_links));
1044 		RETURN_FALSE;
1045 	}
1046 
1047 	ld = ecalloc(1, sizeof(ldap_linkdata));
1048 
1049 	{
1050 		int rc = LDAP_SUCCESS;
1051 		char	*url = host;
1052 		if (url && !ldap_is_ldap_url(url)) {
1053 			size_t urllen = hostlen + sizeof( "ldap://:65535" );
1054 
1055 			if (port <= 0 || port > 65535) {
1056 				efree(ld);
1057 				php_error_docref(NULL, E_WARNING, "invalid port number: " ZEND_LONG_FMT, port);
1058 				RETURN_FALSE;
1059 			}
1060 
1061 			url = emalloc(urllen);
1062 			snprintf( url, urllen, "ldap://%s:" ZEND_LONG_FMT, host, port );
1063 		}
1064 
1065 #ifdef LDAP_API_FEATURE_X_OPENLDAP
1066 		/* ldap_init() is deprecated, use ldap_initialize() instead.
1067 		 */
1068 		rc = ldap_initialize(&ldap, url);
1069 #else /* ! LDAP_API_FEATURE_X_OPENLDAP */
1070 		/* ldap_init does not support URLs.
1071 		 * We must try the original host and port information.
1072 		 */
1073 		ldap = ldap_init(host, port);
1074 		if (ldap == NULL) {
1075 			efree(ld);
1076 			php_error_docref(NULL, E_WARNING, "Could not create session handle");
1077 			RETURN_FALSE;
1078 		}
1079 #endif /* ! LDAP_API_FEATURE_X_OPENLDAP */
1080 		if (url != host) {
1081 			efree(url);
1082 		}
1083 		if (rc != LDAP_SUCCESS) {
1084 			efree(ld);
1085 			php_error_docref(NULL, E_WARNING, "Could not create session handle: %s", ldap_err2string(rc));
1086 			RETURN_FALSE;
1087 		}
1088 	}
1089 
1090 	if (ldap == NULL) {
1091 		efree(ld);
1092 		RETURN_FALSE;
1093 	} else {
1094 #ifdef HAVE_ORALDAP
1095 		if (ssl) {
1096 			if (ldap_init_SSL(&ldap->ld_sb, wallet, walletpasswd, authmode)) {
1097 				efree(ld);
1098 				php_error_docref(NULL, E_WARNING, "SSL init failed");
1099 				RETURN_FALSE;
1100 			}
1101 		}
1102 #endif
1103 		LDAPG(num_links)++;
1104 		ld->link = ldap;
1105 		RETURN_RES(zend_register_resource(ld, le_link));
1106 	}
1107 
1108 }
1109 /* }}} */
1110 
1111 /* {{{ _get_lderrno
1112  */
_get_lderrno(LDAP * ldap)1113 static int _get_lderrno(LDAP *ldap)
1114 {
1115 #if !HAVE_NSLDAP
1116 #if LDAP_API_VERSION > 2000 || HAVE_ORALDAP
1117 	int lderr;
1118 
1119 	/* New versions of OpenLDAP do it this way */
1120 	ldap_get_option(ldap, LDAP_OPT_ERROR_NUMBER, &lderr);
1121 	return lderr;
1122 #else
1123 	return ldap->ld_errno;
1124 #endif
1125 #else
1126 	return ldap_get_lderrno(ldap, NULL, NULL);
1127 #endif
1128 }
1129 /* }}} */
1130 
1131 /* {{{ _set_lderrno
1132  */
_set_lderrno(LDAP * ldap,int lderr)1133 static void _set_lderrno(LDAP *ldap, int lderr)
1134 {
1135 #if !HAVE_NSLDAP
1136 #if LDAP_API_VERSION > 2000 || HAVE_ORALDAP
1137 	/* New versions of OpenLDAP do it this way */
1138 	ldap_set_option(ldap, LDAP_OPT_ERROR_NUMBER, &lderr);
1139 #else
1140 	ldap->ld_errno = lderr;
1141 #endif
1142 #else
1143 	ldap_set_lderrno(ldap, lderr, NULL, NULL);
1144 #endif
1145 }
1146 /* }}} */
1147 
1148 /* {{{ proto bool ldap_bind(resource link [, string dn [, string password]])
1149    Bind to LDAP directory */
PHP_FUNCTION(ldap_bind)1150 PHP_FUNCTION(ldap_bind)
1151 {
1152 	zval *link;
1153 	char *ldap_bind_dn = NULL, *ldap_bind_pw = NULL;
1154 	size_t ldap_bind_dnlen, ldap_bind_pwlen;
1155 	ldap_linkdata *ld;
1156 	int rc;
1157 
1158 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|ss", &link, &ldap_bind_dn, &ldap_bind_dnlen, &ldap_bind_pw, &ldap_bind_pwlen) != SUCCESS) {
1159 		RETURN_FALSE;
1160 	}
1161 
1162 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
1163 		RETURN_FALSE;
1164 	}
1165 
1166 	if (ldap_bind_dn != NULL && memchr(ldap_bind_dn, '\0', ldap_bind_dnlen) != NULL) {
1167 		_set_lderrno(ld->link, LDAP_INVALID_CREDENTIALS);
1168 		php_error_docref(NULL, E_WARNING, "DN contains a null byte");
1169 		RETURN_FALSE;
1170 	}
1171 
1172 	if (ldap_bind_pw != NULL && memchr(ldap_bind_pw, '\0', ldap_bind_pwlen) != NULL) {
1173 		_set_lderrno(ld->link, LDAP_INVALID_CREDENTIALS);
1174 		php_error_docref(NULL, E_WARNING, "Password contains a null byte");
1175 		RETURN_FALSE;
1176 	}
1177 
1178 	{
1179 #ifdef LDAP_API_FEATURE_X_OPENLDAP
1180 		/* ldap_simple_bind_s() is deprecated, use ldap_sasl_bind_s() instead.
1181 		 */
1182 		struct berval   cred;
1183 
1184 		cred.bv_val = ldap_bind_pw;
1185 		cred.bv_len = ldap_bind_pw ? ldap_bind_pwlen : 0;
1186 		rc = ldap_sasl_bind_s(ld->link, ldap_bind_dn, LDAP_SASL_SIMPLE, &cred,
1187 				NULL, NULL,     /* no controls right now */
1188 				NULL);	  /* we don't care about the server's credentials */
1189 #else /* ! LDAP_API_FEATURE_X_OPENLDAP */
1190 		rc = ldap_simple_bind_s(ld->link, ldap_bind_dn, ldap_bind_pw);
1191 #endif /* ! LDAP_API_FEATURE_X_OPENLDAP */
1192 	}
1193 	if ( rc != LDAP_SUCCESS) {
1194 		php_error_docref(NULL, E_WARNING, "Unable to bind to server: %s", ldap_err2string(rc));
1195 		RETURN_FALSE;
1196 	} else {
1197 		RETURN_TRUE;
1198 	}
1199 }
1200 /* }}} */
1201 
1202 /* {{{ proto resource ldap_bind_ext(resource link [, string dn [, string password [, serverctrls]]])
1203    Bind to LDAP directory */
PHP_FUNCTION(ldap_bind_ext)1204 PHP_FUNCTION(ldap_bind_ext)
1205 {
1206 	zval *serverctrls = NULL;
1207 	zval *link;
1208 	char *ldap_bind_dn = NULL, *ldap_bind_pw = NULL;
1209 	size_t ldap_bind_dnlen, ldap_bind_pwlen;
1210 	ldap_linkdata *ld;
1211 	LDAPControl **lserverctrls = NULL;
1212 	LDAPMessage *ldap_res;
1213 	int rc;
1214 
1215 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|ssa", &link, &ldap_bind_dn, &ldap_bind_dnlen, &ldap_bind_pw, &ldap_bind_pwlen, &serverctrls) != SUCCESS) {
1216 		RETURN_FALSE;
1217 	}
1218 
1219 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
1220 		RETURN_FALSE;
1221 	}
1222 
1223 	if (ldap_bind_dn != NULL && memchr(ldap_bind_dn, '\0', ldap_bind_dnlen) != NULL) {
1224 		_set_lderrno(ld->link, LDAP_INVALID_CREDENTIALS);
1225 		php_error_docref(NULL, E_WARNING, "DN contains a null byte");
1226 		RETURN_FALSE;
1227 	}
1228 
1229 	if (ldap_bind_pw != NULL && memchr(ldap_bind_pw, '\0', ldap_bind_pwlen) != NULL) {
1230 		_set_lderrno(ld->link, LDAP_INVALID_CREDENTIALS);
1231 		php_error_docref(NULL, E_WARNING, "Password contains a null byte");
1232 		RETURN_FALSE;
1233 	}
1234 
1235 	if (serverctrls) {
1236 		lserverctrls = _php_ldap_controls_from_array(ld->link, serverctrls);
1237 		if (lserverctrls == NULL) {
1238 			RETVAL_FALSE;
1239 			goto cleanup;
1240 		}
1241 	}
1242 
1243 	{
1244 		/* ldap_simple_bind() is deprecated, use ldap_sasl_bind() instead */
1245 		struct berval   cred;
1246 		int msgid;
1247 
1248 		cred.bv_val = ldap_bind_pw;
1249 		cred.bv_len = ldap_bind_pw ? ldap_bind_pwlen : 0;
1250 		/* asynchronous call */
1251 		rc = ldap_sasl_bind(ld->link, ldap_bind_dn, LDAP_SASL_SIMPLE, &cred,
1252 				lserverctrls, NULL, &msgid);
1253 		if (rc != LDAP_SUCCESS ) {
1254 			php_error_docref(NULL, E_WARNING, "Unable to bind to server: %s (%d)", ldap_err2string(rc), rc);
1255 			RETVAL_FALSE;
1256 			goto cleanup;
1257 		}
1258 
1259 		rc = ldap_result(ld->link, msgid, 1 /* LDAP_MSG_ALL */, NULL, &ldap_res);
1260 		if (rc == -1) {
1261 			php_error_docref(NULL, E_WARNING, "Bind operation failed");
1262 			RETVAL_FALSE;
1263 			goto cleanup;
1264 		}
1265 
1266 		/* return a PHP control object */
1267 		RETVAL_RES(zend_register_resource(ldap_res, le_result));
1268 	}
1269 
1270 cleanup:
1271 	if (lserverctrls) {
1272 		_php_ldap_controls_free(&lserverctrls);
1273 	}
1274 
1275 	return;
1276 }
1277 /* }}} */
1278 
1279 #ifdef HAVE_LDAP_SASL
1280 typedef struct {
1281 	char *mech;
1282 	char *realm;
1283 	char *authcid;
1284 	char *passwd;
1285 	char *authzid;
1286 } php_ldap_bictx;
1287 
1288 /* {{{ _php_sasl_setdefs
1289  */
_php_sasl_setdefs(LDAP * ld,char * sasl_mech,char * sasl_realm,char * sasl_authc_id,char * passwd,char * sasl_authz_id)1290 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)
1291 {
1292 	php_ldap_bictx *ctx;
1293 
1294 	ctx = ber_memalloc(sizeof(php_ldap_bictx));
1295 	ctx->mech    = (sasl_mech) ? ber_strdup(sasl_mech) : NULL;
1296 	ctx->realm   = (sasl_realm) ? ber_strdup(sasl_realm) : NULL;
1297 	ctx->authcid = (sasl_authc_id) ? ber_strdup(sasl_authc_id) : NULL;
1298 	ctx->passwd  = (passwd) ? ber_strdup(passwd) : NULL;
1299 	ctx->authzid = (sasl_authz_id) ? ber_strdup(sasl_authz_id) : NULL;
1300 
1301 	if (ctx->mech == NULL) {
1302 		ldap_get_option(ld, LDAP_OPT_X_SASL_MECH, &ctx->mech);
1303 	}
1304 	if (ctx->realm == NULL) {
1305 		ldap_get_option(ld, LDAP_OPT_X_SASL_REALM, &ctx->realm);
1306 	}
1307 	if (ctx->authcid == NULL) {
1308 		ldap_get_option(ld, LDAP_OPT_X_SASL_AUTHCID, &ctx->authcid);
1309 	}
1310 	if (ctx->authzid == NULL) {
1311 		ldap_get_option(ld, LDAP_OPT_X_SASL_AUTHZID, &ctx->authzid);
1312 	}
1313 
1314 	return ctx;
1315 }
1316 /* }}} */
1317 
1318 /* {{{ _php_sasl_freedefs
1319  */
_php_sasl_freedefs(php_ldap_bictx * ctx)1320 static void _php_sasl_freedefs(php_ldap_bictx *ctx)
1321 {
1322 	if (ctx->mech) ber_memfree(ctx->mech);
1323 	if (ctx->realm) ber_memfree(ctx->realm);
1324 	if (ctx->authcid) ber_memfree(ctx->authcid);
1325 	if (ctx->passwd) ber_memfree(ctx->passwd);
1326 	if (ctx->authzid) ber_memfree(ctx->authzid);
1327 	ber_memfree(ctx);
1328 }
1329 /* }}} */
1330 
1331 /* {{{ _php_sasl_interact
1332    Internal interact function for SASL */
_php_sasl_interact(LDAP * ld,unsigned flags,void * defaults,void * in)1333 static int _php_sasl_interact(LDAP *ld, unsigned flags, void *defaults, void *in)
1334 {
1335 	sasl_interact_t *interact = in;
1336 	const char *p;
1337 	php_ldap_bictx *ctx = defaults;
1338 
1339 	for (;interact->id != SASL_CB_LIST_END;interact++) {
1340 		p = NULL;
1341 		switch(interact->id) {
1342 			case SASL_CB_GETREALM:
1343 				p = ctx->realm;
1344 				break;
1345 			case SASL_CB_AUTHNAME:
1346 				p = ctx->authcid;
1347 				break;
1348 			case SASL_CB_USER:
1349 				p = ctx->authzid;
1350 				break;
1351 			case SASL_CB_PASS:
1352 				p = ctx->passwd;
1353 				break;
1354 		}
1355 		if (p) {
1356 			interact->result = p;
1357 			interact->len = strlen(interact->result);
1358 		}
1359 	}
1360 	return LDAP_SUCCESS;
1361 }
1362 /* }}} */
1363 
1364 /* {{{ 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]]]]]]])
1365    Bind to LDAP directory using SASL */
PHP_FUNCTION(ldap_sasl_bind)1366 PHP_FUNCTION(ldap_sasl_bind)
1367 {
1368 	zval *link;
1369 	ldap_linkdata *ld;
1370 	char *binddn = NULL;
1371 	char *passwd = NULL;
1372 	char *sasl_mech = NULL;
1373 	char *sasl_realm = NULL;
1374 	char *sasl_authz_id = NULL;
1375 	char *sasl_authc_id = NULL;
1376 	char *props = NULL;
1377 	size_t rc, dn_len, passwd_len, mech_len, realm_len, authc_id_len, authz_id_len, props_len;
1378 	php_ldap_bictx *ctx;
1379 
1380 	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) {
1381 		RETURN_FALSE;
1382 	}
1383 
1384 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
1385 		RETURN_FALSE;
1386 	}
1387 
1388 	ctx = _php_sasl_setdefs(ld->link, sasl_mech, sasl_realm, sasl_authc_id, passwd, sasl_authz_id);
1389 
1390 	if (props) {
1391 		ldap_set_option(ld->link, LDAP_OPT_X_SASL_SECPROPS, props);
1392 	}
1393 
1394 	rc = ldap_sasl_interactive_bind_s(ld->link, binddn, ctx->mech, NULL, NULL, LDAP_SASL_QUIET, _php_sasl_interact, ctx);
1395 	if (rc != LDAP_SUCCESS) {
1396 		php_error_docref(NULL, E_WARNING, "Unable to bind to server: %s", ldap_err2string(rc));
1397 		RETVAL_FALSE;
1398 	} else {
1399 		RETVAL_TRUE;
1400 	}
1401 	_php_sasl_freedefs(ctx);
1402 }
1403 /* }}} */
1404 #endif /* HAVE_LDAP_SASL */
1405 
1406 /* {{{ proto bool ldap_unbind(resource link)
1407    Unbind from LDAP directory */
PHP_FUNCTION(ldap_unbind)1408 PHP_FUNCTION(ldap_unbind)
1409 {
1410 	zval *link;
1411 	ldap_linkdata *ld;
1412 
1413 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &link) != SUCCESS) {
1414 		RETURN_FALSE;
1415 	}
1416 
1417 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
1418 		RETURN_FALSE;
1419 	}
1420 
1421 	zend_list_close(Z_RES_P(link));
1422 	RETURN_TRUE;
1423 }
1424 /* }}} */
1425 
1426 /* {{{ php_set_opts
1427  */
php_set_opts(LDAP * ldap,int sizelimit,int timelimit,int deref,int * old_sizelimit,int * old_timelimit,int * old_deref)1428 static void php_set_opts(LDAP *ldap, int sizelimit, int timelimit, int deref, int *old_sizelimit, int *old_timelimit, int *old_deref)
1429 {
1430 	/* sizelimit */
1431 	if (sizelimit > -1) {
1432 #if (LDAP_API_VERSION >= 2004) || HAVE_NSLDAP || HAVE_ORALDAP
1433 		ldap_get_option(ldap, LDAP_OPT_SIZELIMIT, old_sizelimit);
1434 		ldap_set_option(ldap, LDAP_OPT_SIZELIMIT, &sizelimit);
1435 #else
1436 		*old_sizelimit = ldap->ld_sizelimit;
1437 		ldap->ld_sizelimit = sizelimit;
1438 #endif
1439 	}
1440 
1441 	/* timelimit */
1442 	if (timelimit > -1) {
1443 #if (LDAP_API_VERSION >= 2004) || HAVE_NSLDAP || HAVE_ORALDAP
1444 		ldap_get_option(ldap, LDAP_OPT_TIMELIMIT, old_timelimit);
1445 		ldap_set_option(ldap, LDAP_OPT_TIMELIMIT, &timelimit);
1446 #else
1447 		*old_timelimit = ldap->ld_timelimit;
1448 		ldap->ld_timelimit = timelimit;
1449 #endif
1450 	}
1451 
1452 	/* deref */
1453 	if (deref > -1) {
1454 #if (LDAP_API_VERSION >= 2004) || HAVE_NSLDAP || HAVE_ORALDAP
1455 		ldap_get_option(ldap, LDAP_OPT_DEREF, old_deref);
1456 		ldap_set_option(ldap, LDAP_OPT_DEREF, &deref);
1457 #else
1458 		*old_deref = ldap->ld_deref;
1459 		ldap->ld_deref = deref;
1460 #endif
1461 	}
1462 }
1463 /* }}} */
1464 
1465 /* {{{ php_ldap_do_search
1466  */
php_ldap_do_search(INTERNAL_FUNCTION_PARAMETERS,int scope)1467 static void php_ldap_do_search(INTERNAL_FUNCTION_PARAMETERS, int scope)
1468 {
1469 	zval *link, *base_dn, *filter, *attrs = NULL, *attr, *serverctrls = NULL;
1470 	zend_long attrsonly, sizelimit, timelimit, deref;
1471 	zend_string *ldap_filter = NULL, *ldap_base_dn = NULL;
1472 	char **ldap_attrs = NULL;
1473 	ldap_linkdata *ld = NULL;
1474 	LDAPMessage *ldap_res = NULL;
1475 	LDAPControl **lserverctrls = NULL;
1476 	int ldap_attrsonly = 0, ldap_sizelimit = -1, ldap_timelimit = -1, ldap_deref = -1;
1477 	int old_ldap_sizelimit = -1, old_ldap_timelimit = -1, old_ldap_deref = -1;
1478 	int num_attribs = 0, ret = 1, i, errno, argcount = ZEND_NUM_ARGS();
1479 
1480 	if (zend_parse_parameters(argcount, "zzz|alllla/", &link, &base_dn, &filter, &attrs, &attrsonly,
1481 		&sizelimit, &timelimit, &deref, &serverctrls) == FAILURE) {
1482 		return;
1483 	}
1484 
1485 	/* Reverse -> fall through */
1486 	switch (argcount) {
1487 		case 9:
1488 		case 8:
1489 			ldap_deref = deref;
1490 		case 7:
1491 			ldap_timelimit = timelimit;
1492 		case 6:
1493 			ldap_sizelimit = sizelimit;
1494 		case 5:
1495 			ldap_attrsonly = attrsonly;
1496 		case 4:
1497 			num_attribs = zend_hash_num_elements(Z_ARRVAL_P(attrs));
1498 			ldap_attrs = safe_emalloc((num_attribs+1), sizeof(char *), 0);
1499 
1500 			for (i = 0; i<num_attribs; i++) {
1501 				if ((attr = zend_hash_index_find(Z_ARRVAL_P(attrs), i)) == NULL) {
1502 					php_error_docref(NULL, E_WARNING, "Array initialization wrong");
1503 					ret = 0;
1504 					goto cleanup;
1505 				}
1506 
1507 				convert_to_string(attr);
1508 				if (EG(exception)) {
1509 					ret = 0;
1510 					goto cleanup;
1511 				}
1512 				ldap_attrs[i] = Z_STRVAL_P(attr);
1513 			}
1514 			ldap_attrs[num_attribs] = NULL;
1515 		default:
1516 			break;
1517 	}
1518 
1519 	/* parallel search? */
1520 	if (Z_TYPE_P(link) == IS_ARRAY) {
1521 		int i, nlinks, nbases, nfilters, *rcs;
1522 		ldap_linkdata **lds;
1523 		zval *entry, resource;
1524 
1525 		nlinks = zend_hash_num_elements(Z_ARRVAL_P(link));
1526 		if (nlinks == 0) {
1527 			php_error_docref(NULL, E_WARNING, "No links in link array");
1528 			ret = 0;
1529 			goto cleanup;
1530 		}
1531 
1532 		if (Z_TYPE_P(base_dn) == IS_ARRAY) {
1533 			nbases = zend_hash_num_elements(Z_ARRVAL_P(base_dn));
1534 			if (nbases != nlinks) {
1535 				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");
1536 				ret = 0;
1537 				goto cleanup;
1538 			}
1539 			zend_hash_internal_pointer_reset(Z_ARRVAL_P(base_dn));
1540 		} else {
1541 			nbases = 0; /* this means string, not array */
1542 			ldap_base_dn = zval_get_string(base_dn);
1543 			if (EG(exception)) {
1544 				ret = 0;
1545 				goto cleanup;
1546 			}
1547 		}
1548 
1549 		if (Z_TYPE_P(filter) == IS_ARRAY) {
1550 			nfilters = zend_hash_num_elements(Z_ARRVAL_P(filter));
1551 			if (nfilters != nlinks) {
1552 				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");
1553 				ret = 0;
1554 				goto cleanup;
1555 			}
1556 			zend_hash_internal_pointer_reset(Z_ARRVAL_P(filter));
1557 		} else {
1558 			nfilters = 0; /* this means string, not array */
1559 			ldap_filter = zval_get_string(filter);
1560 			if (EG(exception)) {
1561 				ret = 0;
1562 				goto cleanup;
1563 			}
1564 		}
1565 
1566 		lds = safe_emalloc(nlinks, sizeof(ldap_linkdata), 0);
1567 		rcs = safe_emalloc(nlinks, sizeof(*rcs), 0);
1568 
1569 		zend_hash_internal_pointer_reset(Z_ARRVAL_P(link));
1570 		for (i=0; i<nlinks; i++) {
1571 			entry = zend_hash_get_current_data(Z_ARRVAL_P(link));
1572 
1573 			ld = (ldap_linkdata *) zend_fetch_resource_ex(entry, "ldap link", le_link);
1574 			if (ld == NULL) {
1575 				ret = 0;
1576 				goto cleanup_parallel;
1577 			}
1578 			if (nbases != 0) { /* base_dn an array? */
1579 				entry = zend_hash_get_current_data(Z_ARRVAL_P(base_dn));
1580 				zend_hash_move_forward(Z_ARRVAL_P(base_dn));
1581 				ldap_base_dn = zval_get_string(entry);
1582 				if (EG(exception)) {
1583 					ret = 0;
1584 					goto cleanup_parallel;
1585 				}
1586 			}
1587 			if (nfilters != 0) { /* filter an array? */
1588 				entry = zend_hash_get_current_data(Z_ARRVAL_P(filter));
1589 				zend_hash_move_forward(Z_ARRVAL_P(filter));
1590 				ldap_filter = zval_get_string(entry);
1591 				if (EG(exception)) {
1592 					ret = 0;
1593 					goto cleanup_parallel;
1594 				}
1595 			}
1596 
1597 			if (argcount > 8) {
1598 				/* We have to parse controls again for each link as they use it */
1599 				_php_ldap_controls_free(&lserverctrls);
1600 				lserverctrls = _php_ldap_controls_from_array(ld->link, serverctrls);
1601 				if (lserverctrls == NULL) {
1602 					rcs[i] = -1;
1603 					continue;
1604 				}
1605 			}
1606 
1607 			php_set_opts(ld->link, ldap_sizelimit, ldap_timelimit, ldap_deref, &old_ldap_sizelimit, &old_ldap_timelimit, &old_ldap_deref);
1608 
1609 			/* Run the actual search */
1610 			ldap_search_ext(ld->link, ZSTR_VAL(ldap_base_dn), scope, ZSTR_VAL(ldap_filter), ldap_attrs, ldap_attrsonly, lserverctrls, NULL, NULL, ldap_sizelimit, &rcs[i]);
1611 			lds[i] = ld;
1612 			zend_hash_move_forward(Z_ARRVAL_P(link));
1613 		}
1614 
1615 		array_init(return_value);
1616 
1617 		/* Collect results from the searches */
1618 		for (i=0; i<nlinks; i++) {
1619 			if (rcs[i] != -1) {
1620 				rcs[i] = ldap_result(lds[i]->link, LDAP_RES_ANY, 1 /* LDAP_MSG_ALL */, NULL, &ldap_res);
1621 			}
1622 			if (rcs[i] != -1) {
1623 				ZVAL_RES(&resource, zend_register_resource(ldap_res, le_result));
1624 				add_next_index_zval(return_value, &resource);
1625 			} else {
1626 				add_next_index_bool(return_value, 0);
1627 			}
1628 		}
1629 
1630 cleanup_parallel:
1631 		efree(lds);
1632 		efree(rcs);
1633 	} else {
1634 		ldap_filter = zval_get_string(filter);
1635 		if (EG(exception)) {
1636 			ret = 0;
1637 			goto cleanup;
1638 		}
1639 
1640 		ldap_base_dn = zval_get_string(base_dn);
1641 		if (EG(exception)) {
1642 			ret = 0;
1643 			goto cleanup;
1644 		}
1645 
1646 		ld = (ldap_linkdata *) zend_fetch_resource_ex(link, "ldap link", le_link);
1647 		if (ld == NULL) {
1648 			ret = 0;
1649 			goto cleanup;
1650 		}
1651 
1652 		if (argcount > 8) {
1653 			lserverctrls = _php_ldap_controls_from_array(ld->link, serverctrls);
1654 			if (lserverctrls == NULL) {
1655 				ret = 0;
1656 				goto cleanup;
1657 			}
1658 		}
1659 
1660 		php_set_opts(ld->link, ldap_sizelimit, ldap_timelimit, ldap_deref, &old_ldap_sizelimit, &old_ldap_timelimit, &old_ldap_deref);
1661 
1662 		/* Run the actual search */
1663 		errno = ldap_search_ext_s(ld->link, ZSTR_VAL(ldap_base_dn), scope, ZSTR_VAL(ldap_filter), ldap_attrs, ldap_attrsonly, lserverctrls, NULL, NULL, ldap_sizelimit, &ldap_res);
1664 
1665 		if (errno != LDAP_SUCCESS
1666 			&& errno != LDAP_SIZELIMIT_EXCEEDED
1667 #ifdef LDAP_ADMINLIMIT_EXCEEDED
1668 			&& errno != LDAP_ADMINLIMIT_EXCEEDED
1669 #endif
1670 #ifdef LDAP_REFERRAL
1671 			&& errno != LDAP_REFERRAL
1672 #endif
1673 		) {
1674 			/* ldap_res should be freed regardless of return value of ldap_search_ext_s()
1675 			 * see: https://linux.die.net/man/3/ldap_search_ext_s */
1676 			if (ldap_res != NULL) {
1677 				ldap_msgfree(ldap_res);
1678 			}
1679 			php_error_docref(NULL, E_WARNING, "Search: %s", ldap_err2string(errno));
1680 			ret = 0;
1681 		} else {
1682 			if (errno == LDAP_SIZELIMIT_EXCEEDED) {
1683 				php_error_docref(NULL, E_WARNING, "Partial search results returned: Sizelimit exceeded");
1684 			}
1685 #ifdef LDAP_ADMINLIMIT_EXCEEDED
1686 			else if (errno == LDAP_ADMINLIMIT_EXCEEDED) {
1687 				php_error_docref(NULL, E_WARNING, "Partial search results returned: Adminlimit exceeded");
1688 			}
1689 #endif
1690 
1691 			RETVAL_RES(zend_register_resource(ldap_res, le_result));
1692 		}
1693 	}
1694 
1695 cleanup:
1696 	if (ld) {
1697 		/* Restoring previous options */
1698 		php_set_opts(ld->link, old_ldap_sizelimit, old_ldap_timelimit, old_ldap_deref, &ldap_sizelimit, &ldap_timelimit, &ldap_deref);
1699 	}
1700 	if (ldap_filter) {
1701 		zend_string_release(ldap_filter);
1702 	}
1703 	if (ldap_base_dn) {
1704 		zend_string_release(ldap_base_dn);
1705 	}
1706 	if (ldap_attrs != NULL) {
1707 		efree(ldap_attrs);
1708 	}
1709 	if (!ret) {
1710 		RETVAL_BOOL(ret);
1711 	}
1712 	if (lserverctrls) {
1713 		_php_ldap_controls_free(&lserverctrls);
1714 	}
1715 }
1716 /* }}} */
1717 
1718 /* {{{ proto resource ldap_read(resource|array link, string base_dn, string filter [, array attrs [, int attrsonly [, int sizelimit [, int timelimit [, int deref [, array servercontrols]]]]]])
1719    Read an entry */
PHP_FUNCTION(ldap_read)1720 PHP_FUNCTION(ldap_read)
1721 {
1722 	php_ldap_do_search(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_SCOPE_BASE);
1723 }
1724 /* }}} */
1725 
1726 /* {{{ proto resource ldap_list(resource|array link, string base_dn, string filter [, array attrs [, int attrsonly [, int sizelimit [, int timelimit [, int deref [, array servercontrols]]]]]])
1727    Single-level search */
PHP_FUNCTION(ldap_list)1728 PHP_FUNCTION(ldap_list)
1729 {
1730 	php_ldap_do_search(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_SCOPE_ONELEVEL);
1731 }
1732 /* }}} */
1733 
1734 /* {{{ proto resource ldap_search(resource|array link, string base_dn, string filter [, array attrs [, int attrsonly [, int sizelimit [, int timelimit [, int deref [, array servercontrols]]]]]])
1735    Search LDAP tree under base_dn */
PHP_FUNCTION(ldap_search)1736 PHP_FUNCTION(ldap_search)
1737 {
1738 	php_ldap_do_search(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_SCOPE_SUBTREE);
1739 }
1740 /* }}} */
1741 
1742 /* {{{ proto bool ldap_free_result(resource result)
1743    Free result memory */
PHP_FUNCTION(ldap_free_result)1744 PHP_FUNCTION(ldap_free_result)
1745 {
1746 	zval *result;
1747 	LDAPMessage *ldap_result;
1748 
1749 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &result) != SUCCESS) {
1750 		return;
1751 	}
1752 
1753 	if ((ldap_result = (LDAPMessage *)zend_fetch_resource(Z_RES_P(result), "ldap result", le_result)) == NULL) {
1754 		RETURN_FALSE;
1755 	}
1756 
1757 	zend_list_close(Z_RES_P(result));  /* Delete list entry */
1758 	RETVAL_TRUE;
1759 }
1760 /* }}} */
1761 
1762 /* {{{ proto int ldap_count_entries(resource link, resource result)
1763    Count the number of entries in a search result */
PHP_FUNCTION(ldap_count_entries)1764 PHP_FUNCTION(ldap_count_entries)
1765 {
1766 	zval *link, *result;
1767 	ldap_linkdata *ld;
1768 	LDAPMessage *ldap_result;
1769 
1770 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rr", &link, &result) != SUCCESS) {
1771 		return;
1772 	}
1773 
1774 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
1775 		RETURN_FALSE;
1776 	}
1777 
1778 	if ((ldap_result = (LDAPMessage *)zend_fetch_resource(Z_RES_P(result), "ldap result", le_result)) == NULL) {
1779 		RETURN_FALSE;
1780 	}
1781 
1782 	RETURN_LONG(ldap_count_entries(ld->link, ldap_result));
1783 }
1784 /* }}} */
1785 
1786 /* {{{ proto resource ldap_first_entry(resource link, resource result)
1787    Return first result id */
PHP_FUNCTION(ldap_first_entry)1788 PHP_FUNCTION(ldap_first_entry)
1789 {
1790 	zval *link, *result;
1791 	ldap_linkdata *ld;
1792 	ldap_resultentry *resultentry;
1793 	LDAPMessage *ldap_result, *entry;
1794 
1795 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rr", &link, &result) != SUCCESS) {
1796 		return;
1797 	}
1798 
1799 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
1800 		RETURN_FALSE;
1801 	}
1802 
1803 	if ((ldap_result = (LDAPMessage *)zend_fetch_resource(Z_RES_P(result), "ldap result", le_result)) == NULL) {
1804 		RETURN_FALSE;
1805 	}
1806 
1807 	if ((entry = ldap_first_entry(ld->link, ldap_result)) == NULL) {
1808 		RETVAL_FALSE;
1809 	} else {
1810 		resultentry = emalloc(sizeof(ldap_resultentry));
1811 		RETVAL_RES(zend_register_resource(resultentry, le_result_entry));
1812 		ZVAL_COPY(&resultentry->res, result);
1813 		resultentry->data = entry;
1814 		resultentry->ber = NULL;
1815 	}
1816 }
1817 /* }}} */
1818 
1819 /* {{{ proto resource ldap_next_entry(resource link, resource result_entry)
1820    Get next result entry */
PHP_FUNCTION(ldap_next_entry)1821 PHP_FUNCTION(ldap_next_entry)
1822 {
1823 	zval *link, *result_entry;
1824 	ldap_linkdata *ld;
1825 	ldap_resultentry *resultentry, *resultentry_next;
1826 	LDAPMessage *entry_next;
1827 
1828 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rr", &link, &result_entry) != SUCCESS) {
1829 		return;
1830 	}
1831 
1832 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
1833 		RETURN_FALSE;
1834 	}
1835 	if ((resultentry = (ldap_resultentry *)zend_fetch_resource(Z_RES_P(result_entry), "ldap result entry", le_result_entry)) == NULL) {
1836 		RETURN_FALSE;
1837 	}
1838 
1839 	if ((entry_next = ldap_next_entry(ld->link, resultentry->data)) == NULL) {
1840 		RETVAL_FALSE;
1841 	} else {
1842 		resultentry_next = emalloc(sizeof(ldap_resultentry));
1843 		RETVAL_RES(zend_register_resource(resultentry_next, le_result_entry));
1844 		ZVAL_COPY(&resultentry_next->res, &resultentry->res);
1845 		resultentry_next->data = entry_next;
1846 		resultentry_next->ber = NULL;
1847 	}
1848 }
1849 /* }}} */
1850 
1851 /* {{{ proto array ldap_get_entries(resource link, resource result)
1852    Get all result entries */
PHP_FUNCTION(ldap_get_entries)1853 PHP_FUNCTION(ldap_get_entries)
1854 {
1855 	zval *link, *result;
1856 	LDAPMessage *ldap_result, *ldap_result_entry;
1857 	zval tmp1, tmp2;
1858 	ldap_linkdata *ld;
1859 	LDAP *ldap;
1860 	int num_entries, num_attrib, num_values, i;
1861 	BerElement *ber;
1862 	char *attribute;
1863 	size_t attr_len;
1864 	struct berval **ldap_value;
1865 	char *dn;
1866 
1867 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rr", &link, &result) != SUCCESS) {
1868 		return;
1869 	}
1870 
1871 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
1872 		RETURN_FALSE;
1873 	}
1874 	if ((ldap_result = (LDAPMessage *)zend_fetch_resource(Z_RES_P(result), "ldap result", le_result)) == NULL) {
1875 		RETURN_FALSE;
1876 	}
1877 
1878 	ldap = ld->link;
1879 	num_entries = ldap_count_entries(ldap, ldap_result);
1880 
1881 	array_init(return_value);
1882 	add_assoc_long(return_value, "count", num_entries);
1883 
1884 	if (num_entries == 0) {
1885 		return;
1886 	}
1887 
1888 	ldap_result_entry = ldap_first_entry(ldap, ldap_result);
1889 	if (ldap_result_entry == NULL) {
1890 		zend_array_destroy(Z_ARR_P(return_value));
1891 		RETURN_FALSE;
1892 	}
1893 
1894 	num_entries = 0;
1895 	while (ldap_result_entry != NULL) {
1896 		array_init(&tmp1);
1897 
1898 		num_attrib = 0;
1899 		attribute = ldap_first_attribute(ldap, ldap_result_entry, &ber);
1900 
1901 		while (attribute != NULL) {
1902 			ldap_value = ldap_get_values_len(ldap, ldap_result_entry, attribute);
1903 			num_values = ldap_count_values_len(ldap_value);
1904 
1905 			array_init(&tmp2);
1906 			add_assoc_long(&tmp2, "count", num_values);
1907 			for (i = 0; i < num_values; i++) {
1908 				add_index_stringl(&tmp2, i, ldap_value[i]->bv_val, ldap_value[i]->bv_len);
1909 			}
1910 			ldap_value_free_len(ldap_value);
1911 
1912 			attr_len = strlen(attribute);
1913 			zend_hash_str_update(Z_ARRVAL(tmp1), php_strtolower(attribute, attr_len), attr_len, &tmp2);
1914 			add_index_string(&tmp1, num_attrib, attribute);
1915 
1916 			num_attrib++;
1917 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP || WINDOWS
1918 			ldap_memfree(attribute);
1919 #endif
1920 			attribute = ldap_next_attribute(ldap, ldap_result_entry, ber);
1921 		}
1922 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP || WINDOWS
1923 		if (ber != NULL) {
1924 			ber_free(ber, 0);
1925 		}
1926 #endif
1927 
1928 		add_assoc_long(&tmp1, "count", num_attrib);
1929 		dn = ldap_get_dn(ldap, ldap_result_entry);
1930 		if (dn) {
1931 			add_assoc_string(&tmp1, "dn", dn);
1932 		} else {
1933 			add_assoc_null(&tmp1, "dn");
1934 		}
1935 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP || WINDOWS
1936 		ldap_memfree(dn);
1937 #else
1938 		free(dn);
1939 #endif
1940 
1941 		zend_hash_index_update(Z_ARRVAL_P(return_value), num_entries, &tmp1);
1942 
1943 		num_entries++;
1944 		ldap_result_entry = ldap_next_entry(ldap, ldap_result_entry);
1945 	}
1946 
1947 	add_assoc_long(return_value, "count", num_entries);
1948 
1949 }
1950 /* }}} */
1951 
1952 /* {{{ proto string ldap_first_attribute(resource link, resource result_entry)
1953    Return first attribute */
PHP_FUNCTION(ldap_first_attribute)1954 PHP_FUNCTION(ldap_first_attribute)
1955 {
1956 	zval *link, *result_entry;
1957 	ldap_linkdata *ld;
1958 	ldap_resultentry *resultentry;
1959 	char *attribute;
1960 	zend_long dummy_ber;
1961 
1962 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rr|l", &link, &result_entry, &dummy_ber) != SUCCESS) {
1963 		return;
1964 	}
1965 
1966 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
1967 		RETURN_FALSE;
1968 	}
1969 
1970 	if ((resultentry = (ldap_resultentry *)zend_fetch_resource(Z_RES_P(result_entry), "ldap result entry", le_result_entry)) == NULL) {
1971 		RETURN_FALSE;
1972 	}
1973 
1974 	if ((attribute = ldap_first_attribute(ld->link, resultentry->data, &resultentry->ber)) == NULL) {
1975 		RETURN_FALSE;
1976 	} else {
1977 		RETVAL_STRING(attribute);
1978 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP || WINDOWS
1979 		ldap_memfree(attribute);
1980 #endif
1981 	}
1982 }
1983 /* }}} */
1984 
1985 /* {{{ proto string ldap_next_attribute(resource link, resource result_entry)
1986    Get the next attribute in result */
PHP_FUNCTION(ldap_next_attribute)1987 PHP_FUNCTION(ldap_next_attribute)
1988 {
1989 	zval *link, *result_entry;
1990 	ldap_linkdata *ld;
1991 	ldap_resultentry *resultentry;
1992 	char *attribute;
1993 	zend_long dummy_ber;
1994 
1995 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rr|l", &link, &result_entry, &dummy_ber) != SUCCESS) {
1996 		return;
1997 	}
1998 
1999 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
2000 		RETURN_FALSE;
2001 	}
2002 
2003 	if ((resultentry = (ldap_resultentry *)zend_fetch_resource(Z_RES_P(result_entry), "ldap result entry", le_result_entry)) == NULL) {
2004 		RETURN_FALSE;
2005 	}
2006 
2007 	if (resultentry->ber == NULL) {
2008 		php_error_docref(NULL, E_WARNING, "called before calling ldap_first_attribute() or no attributes found in result entry");
2009 		RETURN_FALSE;
2010 	}
2011 
2012 	if ((attribute = ldap_next_attribute(ld->link, resultentry->data, resultentry->ber)) == NULL) {
2013 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP || WINDOWS
2014 		if (resultentry->ber != NULL) {
2015 			ber_free(resultentry->ber, 0);
2016 			resultentry->ber = NULL;
2017 		}
2018 #endif
2019 		RETURN_FALSE;
2020 	} else {
2021 		RETVAL_STRING(attribute);
2022 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP || WINDOWS
2023 		ldap_memfree(attribute);
2024 #endif
2025 	}
2026 }
2027 /* }}} */
2028 
2029 /* {{{ proto array ldap_get_attributes(resource link, resource result_entry)
2030    Get attributes from a search result entry */
PHP_FUNCTION(ldap_get_attributes)2031 PHP_FUNCTION(ldap_get_attributes)
2032 {
2033 	zval *link, *result_entry;
2034 	zval tmp;
2035 	ldap_linkdata *ld;
2036 	ldap_resultentry *resultentry;
2037 	char *attribute;
2038 	struct berval **ldap_value;
2039 	int i, num_values, num_attrib;
2040 	BerElement *ber;
2041 
2042 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rr", &link, &result_entry) != 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 	if ((resultentry = (ldap_resultentry *)zend_fetch_resource(Z_RES_P(result_entry), "ldap result entry", le_result_entry)) == NULL) {
2051 		RETURN_FALSE;
2052 	}
2053 
2054 	array_init(return_value);
2055 	num_attrib = 0;
2056 
2057 	attribute = ldap_first_attribute(ld->link, resultentry->data, &ber);
2058 	while (attribute != NULL) {
2059 		ldap_value = ldap_get_values_len(ld->link, resultentry->data, attribute);
2060 		num_values = ldap_count_values_len(ldap_value);
2061 
2062 		array_init(&tmp);
2063 		add_assoc_long(&tmp, "count", num_values);
2064 		for (i = 0; i < num_values; i++) {
2065 			add_index_stringl(&tmp, i, ldap_value[i]->bv_val, ldap_value[i]->bv_len);
2066 		}
2067 		ldap_value_free_len(ldap_value);
2068 
2069 		zend_hash_str_update(Z_ARRVAL_P(return_value), attribute, strlen(attribute), &tmp);
2070 		add_index_string(return_value, num_attrib, attribute);
2071 
2072 		num_attrib++;
2073 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP || WINDOWS
2074 		ldap_memfree(attribute);
2075 #endif
2076 		attribute = ldap_next_attribute(ld->link, resultentry->data, ber);
2077 	}
2078 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP || WINDOWS
2079 	if (ber != NULL) {
2080 		ber_free(ber, 0);
2081 	}
2082 #endif
2083 
2084 	add_assoc_long(return_value, "count", num_attrib);
2085 }
2086 /* }}} */
2087 
2088 /* {{{ proto array ldap_get_values_len(resource link, resource result_entry, string attribute)
2089    Get all values with lengths from a result entry */
PHP_FUNCTION(ldap_get_values_len)2090 PHP_FUNCTION(ldap_get_values_len)
2091 {
2092 	zval *link, *result_entry;
2093 	ldap_linkdata *ld;
2094 	ldap_resultentry *resultentry;
2095 	char *attr;
2096 	struct berval **ldap_value_len;
2097 	int i, num_values;
2098 	size_t attr_len;
2099 
2100 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rrs", &link, &result_entry, &attr, &attr_len) != SUCCESS) {
2101 		return;
2102 	}
2103 
2104 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
2105 		RETURN_FALSE;
2106 	}
2107 
2108 	if ((resultentry = (ldap_resultentry *)zend_fetch_resource(Z_RES_P(result_entry), "ldap result entry", le_result_entry)) == NULL) {
2109 		RETURN_FALSE;
2110 	}
2111 
2112 	if ((ldap_value_len = ldap_get_values_len(ld->link, resultentry->data, attr)) == NULL) {
2113 		php_error_docref(NULL, E_WARNING, "Cannot get the value(s) of attribute %s", ldap_err2string(_get_lderrno(ld->link)));
2114 		RETURN_FALSE;
2115 	}
2116 
2117 	num_values = ldap_count_values_len(ldap_value_len);
2118 	array_init(return_value);
2119 
2120 	for (i=0; i<num_values; i++) {
2121 		add_next_index_stringl(return_value, ldap_value_len[i]->bv_val, ldap_value_len[i]->bv_len);
2122 	}
2123 
2124 	add_assoc_long(return_value, "count", num_values);
2125 	ldap_value_free_len(ldap_value_len);
2126 
2127 }
2128 /* }}} */
2129 
2130 /* {{{ proto string ldap_get_dn(resource link, resource result_entry)
2131    Get the DN of a result entry */
PHP_FUNCTION(ldap_get_dn)2132 PHP_FUNCTION(ldap_get_dn)
2133 {
2134 	zval *link, *result_entry;
2135 	ldap_linkdata *ld;
2136 	ldap_resultentry *resultentry;
2137 	char *text;
2138 
2139 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rr", &link, &result_entry) != SUCCESS) {
2140 		return;
2141 	}
2142 
2143 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
2144 		RETURN_FALSE;
2145 	}
2146 
2147 	if ((resultentry = (ldap_resultentry *)zend_fetch_resource(Z_RES_P(result_entry), "ldap result entry", le_result_entry)) == NULL) {
2148 		RETURN_FALSE;
2149 	}
2150 
2151 	text = ldap_get_dn(ld->link, resultentry->data);
2152 	if (text != NULL) {
2153 		RETVAL_STRING(text);
2154 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP || WINDOWS
2155 		ldap_memfree(text);
2156 #else
2157 		free(text);
2158 #endif
2159 	} else {
2160 		RETURN_FALSE;
2161 	}
2162 }
2163 /* }}} */
2164 
2165 /* {{{ proto array ldap_explode_dn(string dn, int with_attrib)
2166    Splits DN into its component parts */
PHP_FUNCTION(ldap_explode_dn)2167 PHP_FUNCTION(ldap_explode_dn)
2168 {
2169 	zend_long with_attrib;
2170 	char *dn, **ldap_value;
2171 	int i, count;
2172 	size_t dn_len;
2173 
2174 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl", &dn, &dn_len, &with_attrib) != SUCCESS) {
2175 		return;
2176 	}
2177 
2178 	if (!(ldap_value = ldap_explode_dn(dn, with_attrib))) {
2179 		/* Invalid parameters were passed to ldap_explode_dn */
2180 		RETURN_FALSE;
2181 	}
2182 
2183 	i=0;
2184 	while (ldap_value[i] != NULL) i++;
2185 	count = i;
2186 
2187 	array_init(return_value);
2188 
2189 	add_assoc_long(return_value, "count", count);
2190 	for (i = 0; i<count; i++) {
2191 		add_index_string(return_value, i, ldap_value[i]);
2192 	}
2193 
2194 	ldap_memvfree((void **)ldap_value);
2195 }
2196 /* }}} */
2197 
2198 /* {{{ proto string ldap_dn2ufn(string dn)
2199    Convert DN to User Friendly Naming format */
PHP_FUNCTION(ldap_dn2ufn)2200 PHP_FUNCTION(ldap_dn2ufn)
2201 {
2202 	char *dn, *ufn;
2203 	size_t dn_len;
2204 
2205 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &dn, &dn_len) != SUCCESS) {
2206 		return;
2207 	}
2208 
2209 	ufn = ldap_dn2ufn(dn);
2210 
2211 	if (ufn != NULL) {
2212 		RETVAL_STRING(ufn);
2213 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP || WINDOWS
2214 		ldap_memfree(ufn);
2215 #endif
2216 	} else {
2217 		RETURN_FALSE;
2218 	}
2219 }
2220 /* }}} */
2221 
2222 
2223 /* added to fix use of ldap_modify_add for doing an ldap_add, gerrit thomson. */
2224 #define PHP_LD_FULL_ADD 0xff
2225 /* {{{ php_ldap_do_modify
2226  */
php_ldap_do_modify(INTERNAL_FUNCTION_PARAMETERS,int oper,int ext)2227 static void php_ldap_do_modify(INTERNAL_FUNCTION_PARAMETERS, int oper, int ext)
2228 {
2229 	zval *serverctrls = NULL;
2230 	zval *link, *entry, *value, *ivalue;
2231 	ldap_linkdata *ld;
2232 	char *dn;
2233 	LDAPMod **ldap_mods;
2234 	LDAPControl **lserverctrls = NULL;
2235 	LDAPMessage *ldap_res;
2236 	int i, j, num_attribs, num_values, msgid;
2237 	size_t dn_len;
2238 	int *num_berval;
2239 	zend_string *attribute;
2240 	zend_ulong index;
2241 	int is_full_add=0; /* flag for full add operation so ldap_mod_add can be put back into oper, gerrit THomson */
2242 
2243 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsa/|a", &link, &dn, &dn_len, &entry, &serverctrls) != SUCCESS) {
2244 		return;
2245 	}
2246 
2247 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
2248 		RETURN_FALSE;
2249 	}
2250 
2251 	num_attribs = zend_hash_num_elements(Z_ARRVAL_P(entry));
2252 	ldap_mods = safe_emalloc((num_attribs+1), sizeof(LDAPMod *), 0);
2253 	num_berval = safe_emalloc(num_attribs, sizeof(int), 0);
2254 	zend_hash_internal_pointer_reset(Z_ARRVAL_P(entry));
2255 
2256 	/* added by gerrit thomson to fix ldap_add using ldap_mod_add */
2257 	if (oper == PHP_LD_FULL_ADD) {
2258 		oper = LDAP_MOD_ADD;
2259 		is_full_add = 1;
2260 	}
2261 	/* end additional , gerrit thomson */
2262 
2263 	for (i = 0; i < num_attribs; i++) {
2264 		ldap_mods[i] = emalloc(sizeof(LDAPMod));
2265 		ldap_mods[i]->mod_op = oper | LDAP_MOD_BVALUES;
2266 		ldap_mods[i]->mod_type = NULL;
2267 
2268 		if (zend_hash_get_current_key(Z_ARRVAL_P(entry), &attribute, &index) == HASH_KEY_IS_STRING) {
2269 			ldap_mods[i]->mod_type = estrndup(ZSTR_VAL(attribute), ZSTR_LEN(attribute));
2270 		} else {
2271 			php_error_docref(NULL, E_WARNING, "Unknown attribute in the data");
2272 			/* Free allocated memory */
2273 			while (i >= 0) {
2274 				if (ldap_mods[i]->mod_type) {
2275 					efree(ldap_mods[i]->mod_type);
2276 				}
2277 				efree(ldap_mods[i]);
2278 				i--;
2279 			}
2280 			efree(num_berval);
2281 			efree(ldap_mods);
2282 			RETURN_FALSE;
2283 		}
2284 
2285 		value = zend_hash_get_current_data(Z_ARRVAL_P(entry));
2286 
2287 		ZVAL_DEREF(value);
2288 		if (Z_TYPE_P(value) != IS_ARRAY) {
2289 			num_values = 1;
2290 		} else {
2291 			SEPARATE_ARRAY(value);
2292 			num_values = zend_hash_num_elements(Z_ARRVAL_P(value));
2293 		}
2294 
2295 		num_berval[i] = num_values;
2296 		ldap_mods[i]->mod_bvalues = safe_emalloc((num_values + 1), sizeof(struct berval *), 0);
2297 
2298 /* allow for arrays with one element, no allowance for arrays with none but probably not required, gerrit thomson. */
2299 		if ((num_values == 1) && (Z_TYPE_P(value) != IS_ARRAY)) {
2300 			convert_to_string(value);
2301 			if (EG(exception)) {
2302 				RETVAL_FALSE;
2303 				goto cleanup;
2304 			}
2305 			ldap_mods[i]->mod_bvalues[0] = (struct berval *) emalloc (sizeof(struct berval));
2306 			ldap_mods[i]->mod_bvalues[0]->bv_val = Z_STRVAL_P(value);
2307 			ldap_mods[i]->mod_bvalues[0]->bv_len = Z_STRLEN_P(value);
2308 		} else {
2309 			for (j = 0; j < num_values; j++) {
2310 				if ((ivalue = zend_hash_index_find(Z_ARRVAL_P(value), j)) == NULL) {
2311 					php_error_docref(NULL, E_WARNING, "Value array must have consecutive indices 0, 1, ...");
2312 					num_berval[i] = j;
2313 					num_attribs = i + 1;
2314 					RETVAL_FALSE;
2315 					goto cleanup;
2316 				}
2317 				convert_to_string(ivalue);
2318 				if (EG(exception)) {
2319 					RETVAL_FALSE;
2320 					goto cleanup;
2321 				}
2322 				ldap_mods[i]->mod_bvalues[j] = (struct berval *) emalloc (sizeof(struct berval));
2323 				ldap_mods[i]->mod_bvalues[j]->bv_val = Z_STRVAL_P(ivalue);
2324 				ldap_mods[i]->mod_bvalues[j]->bv_len = Z_STRLEN_P(ivalue);
2325 			}
2326 		}
2327 		ldap_mods[i]->mod_bvalues[num_values] = NULL;
2328 		zend_hash_move_forward(Z_ARRVAL_P(entry));
2329 	}
2330 	ldap_mods[num_attribs] = NULL;
2331 
2332 	if (serverctrls) {
2333 		lserverctrls = _php_ldap_controls_from_array(ld->link, serverctrls);
2334 		if (lserverctrls == NULL) {
2335 			RETVAL_FALSE;
2336 			goto cleanup;
2337 		}
2338 	}
2339 
2340 /* check flag to see if do_mod was called to perform full add , gerrit thomson */
2341 	if (is_full_add == 1) {
2342 		if (ext) {
2343 			i = ldap_add_ext(ld->link, dn, ldap_mods, lserverctrls, NULL, &msgid);
2344 		} else {
2345 			i = ldap_add_ext_s(ld->link, dn, ldap_mods, lserverctrls, NULL);
2346 		}
2347 		if (i != LDAP_SUCCESS) {
2348 			php_error_docref(NULL, E_WARNING, "Add: %s", ldap_err2string(i));
2349 			RETVAL_FALSE;
2350 		} else if (ext) {
2351 			i = ldap_result(ld->link, msgid, 1 /* LDAP_MSG_ALL */, NULL, &ldap_res);
2352 			if (i == -1) {
2353 				php_error_docref(NULL, E_WARNING, "Add operation failed");
2354 				RETVAL_FALSE;
2355 				goto cleanup;
2356 			}
2357 
2358 			/* return a PHP control object */
2359 			RETVAL_RES(zend_register_resource(ldap_res, le_result));
2360 		} else RETVAL_TRUE;
2361 	} else {
2362 		if (ext) {
2363 			i = ldap_modify_ext(ld->link, dn, ldap_mods, lserverctrls, NULL, &msgid);
2364 		} else {
2365 			i = ldap_modify_ext_s(ld->link, dn, ldap_mods, lserverctrls, NULL);
2366 		}
2367 		if (i != LDAP_SUCCESS) {
2368 			php_error_docref(NULL, E_WARNING, "Modify: %s", ldap_err2string(i));
2369 			RETVAL_FALSE;
2370 		} else if (ext) {
2371 			i = ldap_result(ld->link, msgid, 1 /* LDAP_MSG_ALL */, NULL, &ldap_res);
2372 			if (i == -1) {
2373 				php_error_docref(NULL, E_WARNING, "Modify operation failed");
2374 				RETVAL_FALSE;
2375 				goto cleanup;
2376 			}
2377 
2378 			/* return a PHP control object */
2379 			RETVAL_RES(zend_register_resource(ldap_res, le_result));
2380 		} else RETVAL_TRUE;
2381 	}
2382 
2383 cleanup:
2384 	for (i = 0; i < num_attribs; i++) {
2385 		efree(ldap_mods[i]->mod_type);
2386 		for (j = 0; j < num_berval[i]; j++) {
2387 			efree(ldap_mods[i]->mod_bvalues[j]);
2388 		}
2389 		efree(ldap_mods[i]->mod_bvalues);
2390 		efree(ldap_mods[i]);
2391 	}
2392 	efree(num_berval);
2393 	efree(ldap_mods);
2394 
2395 	if (lserverctrls) {
2396 		_php_ldap_controls_free(&lserverctrls);
2397 	}
2398 
2399 	return;
2400 }
2401 /* }}} */
2402 
2403 /* {{{ proto bool ldap_add(resource link, string dn, array entry [, array servercontrols])
2404    Add entries to LDAP directory */
PHP_FUNCTION(ldap_add)2405 PHP_FUNCTION(ldap_add)
2406 {
2407 	/* 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 */
2408 	php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_LD_FULL_ADD, 0);
2409 }
2410 /* }}} */
2411 
2412 /* {{{ proto resource ldap_add_ext(resource link, string dn, array entry [, array servercontrols])
2413    Add entries to LDAP directory */
PHP_FUNCTION(ldap_add_ext)2414 PHP_FUNCTION(ldap_add_ext)
2415 {
2416 	php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_LD_FULL_ADD, 1);
2417 }
2418 /* }}} */
2419 
2420 /* three functions for attribute base modifications, gerrit Thomson */
2421 
2422 /* {{{ proto bool ldap_mod_replace(resource link, string dn, array entry [, array servercontrols])
2423    Replace attribute values with new ones */
PHP_FUNCTION(ldap_mod_replace)2424 PHP_FUNCTION(ldap_mod_replace)
2425 {
2426 	php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_REPLACE, 0);
2427 }
2428 /* }}} */
2429 
2430 /* {{{ proto resource ldap_mod_replace_ext(resource link, string dn, array entry [, array servercontrols])
2431    Replace attribute values with new ones */
PHP_FUNCTION(ldap_mod_replace_ext)2432 PHP_FUNCTION(ldap_mod_replace_ext)
2433 {
2434 	php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_REPLACE, 1);
2435 }
2436 /* }}} */
2437 
2438 /* {{{ proto bool ldap_mod_add(resource link, string dn, array entry [, array servercontrols])
2439    Add attribute values to current */
PHP_FUNCTION(ldap_mod_add)2440 PHP_FUNCTION(ldap_mod_add)
2441 {
2442 	php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_ADD, 0);
2443 }
2444 /* }}} */
2445 
2446 /* {{{ proto resource ldap_mod_add(resource link, string dn, array entry [, array servercontrols])
2447    Add attribute values to current */
PHP_FUNCTION(ldap_mod_add_ext)2448 PHP_FUNCTION(ldap_mod_add_ext)
2449 {
2450 	php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_ADD, 1);
2451 }
2452 /* }}} */
2453 
2454 /* {{{ proto bool ldap_mod_del(resource link, string dn, array entry [, array servercontrols])
2455    Delete attribute values */
PHP_FUNCTION(ldap_mod_del)2456 PHP_FUNCTION(ldap_mod_del)
2457 {
2458 	php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_DELETE, 0);
2459 }
2460 /* }}} */
2461 
2462 /* {{{ proto resource ldap_mod_del_ext(resource link, string dn, array entry [, array servercontrols])
2463    Delete attribute values */
PHP_FUNCTION(ldap_mod_del_ext)2464 PHP_FUNCTION(ldap_mod_del_ext)
2465 {
2466 	php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_DELETE, 1);
2467 }
2468 /* }}} */
2469 
2470 /* {{{ php_ldap_do_delete
2471  */
php_ldap_do_delete(INTERNAL_FUNCTION_PARAMETERS,int ext)2472 static void php_ldap_do_delete(INTERNAL_FUNCTION_PARAMETERS, int ext)
2473 {
2474 	zval *serverctrls = NULL;
2475 	zval *link;
2476 	ldap_linkdata *ld;
2477 	LDAPControl **lserverctrls = NULL;
2478 	LDAPMessage *ldap_res;
2479 	char *dn;
2480 	int rc, msgid;
2481 	size_t dn_len;
2482 
2483 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs|a", &link, &dn, &dn_len, &serverctrls) != SUCCESS) {
2484 		return;
2485 	}
2486 
2487 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
2488 		RETURN_FALSE;
2489 	}
2490 
2491 	if (serverctrls) {
2492 		lserverctrls = _php_ldap_controls_from_array(ld->link, serverctrls);
2493 		if (lserverctrls == NULL) {
2494 			RETVAL_FALSE;
2495 			goto cleanup;
2496 		}
2497 	}
2498 
2499 	if (ext) {
2500 		rc = ldap_delete_ext(ld->link, dn, lserverctrls, NULL, &msgid);
2501 	} else {
2502 		rc = ldap_delete_ext_s(ld->link, dn, lserverctrls, NULL);
2503 	}
2504 	if (rc != LDAP_SUCCESS) {
2505 		php_error_docref(NULL, E_WARNING, "Delete: %s", ldap_err2string(rc));
2506 		RETVAL_FALSE;
2507 		goto cleanup;
2508 	} else if (ext) {
2509 		rc = ldap_result(ld->link, msgid, 1 /* LDAP_MSG_ALL */, NULL, &ldap_res);
2510 		if (rc == -1) {
2511 			php_error_docref(NULL, E_WARNING, "Delete operation failed");
2512 			RETVAL_FALSE;
2513 			goto cleanup;
2514 		}
2515 
2516 		/* return a PHP control object */
2517 		RETVAL_RES(zend_register_resource(ldap_res, le_result));
2518 	} else {
2519 		RETVAL_TRUE;
2520 	}
2521 
2522 cleanup:
2523 	if (lserverctrls) {
2524 		_php_ldap_controls_free(&lserverctrls);
2525 	}
2526 
2527 	return;
2528 }
2529 /* }}} */
2530 
2531 /* {{{ proto bool ldap_delete(resource link, string dn [, array servercontrols])
2532    Delete an entry from a directory */
PHP_FUNCTION(ldap_delete)2533 PHP_FUNCTION(ldap_delete)
2534 {
2535 	php_ldap_do_delete(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
2536 }
2537 /* }}} */
2538 
2539 /* {{{ proto resource ldap_delete_ext(resource link, string dn [, array servercontrols])
2540    Delete an entry from a directory */
PHP_FUNCTION(ldap_delete_ext)2541 PHP_FUNCTION(ldap_delete_ext)
2542 {
2543 	php_ldap_do_delete(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
2544 }
2545 /* }}} */
2546 
2547 /* {{{ _ldap_str_equal_to_const
2548  */
_ldap_str_equal_to_const(const char * str,size_t str_len,const char * cstr)2549 static size_t _ldap_str_equal_to_const(const char *str, size_t str_len, const char *cstr)
2550 {
2551 	size_t i;
2552 
2553 	if (strlen(cstr) != str_len)
2554 		return 0;
2555 
2556 	for (i = 0; i < str_len; ++i) {
2557 		if (str[i] != cstr[i]) {
2558 			return 0;
2559 		}
2560 	}
2561 
2562 	return 1;
2563 }
2564 /* }}} */
2565 
2566 /* {{{ _ldap_strlen_max
2567  */
_ldap_strlen_max(const char * str,size_t max_len)2568 static size_t _ldap_strlen_max(const char *str, size_t max_len)
2569 {
2570 	size_t i;
2571 
2572 	for (i = 0; i < max_len; ++i) {
2573 		if (str[i] == '\0') {
2574 			return i;
2575 		}
2576 	}
2577 
2578 	return max_len;
2579 }
2580 /* }}} */
2581 
2582 /* {{{ _ldap_hash_fetch
2583  */
_ldap_hash_fetch(zval * hashTbl,const char * key,zval ** out)2584 static void _ldap_hash_fetch(zval *hashTbl, const char *key, zval **out)
2585 {
2586 	*out = zend_hash_str_find(Z_ARRVAL_P(hashTbl), key, strlen(key));
2587 }
2588 /* }}} */
2589 
2590 /* {{{ proto bool ldap_modify_batch(resource link, string dn, array modifs [, array servercontrols])
2591    Perform multiple modifications as part of one operation */
PHP_FUNCTION(ldap_modify_batch)2592 PHP_FUNCTION(ldap_modify_batch)
2593 {
2594 	zval *serverctrls = NULL;
2595 	ldap_linkdata *ld;
2596 	zval *link, *mods, *mod, *modinfo;
2597 	zend_string *modval;
2598 	zval *attrib, *modtype, *vals;
2599 	zval *fetched;
2600 	char *dn;
2601 	size_t dn_len;
2602 	int i, j, k;
2603 	int num_mods, num_modprops, num_modvals;
2604 	LDAPMod **ldap_mods;
2605 	LDAPControl **lserverctrls = NULL;
2606 	uint32_t oper;
2607 
2608 	/*
2609 	$mods = array(
2610 		array(
2611 			"attrib" => "unicodePwd",
2612 			"modtype" => LDAP_MODIFY_BATCH_REMOVE,
2613 			"values" => array($oldpw)
2614 		),
2615 		array(
2616 			"attrib" => "unicodePwd",
2617 			"modtype" => LDAP_MODIFY_BATCH_ADD,
2618 			"values" => array($newpw)
2619 		),
2620 		array(
2621 			"attrib" => "userPrincipalName",
2622 			"modtype" => LDAP_MODIFY_BATCH_REPLACE,
2623 			"values" => array("janitor@corp.contoso.com")
2624 		),
2625 		array(
2626 			"attrib" => "userCert",
2627 			"modtype" => LDAP_MODIFY_BATCH_REMOVE_ALL
2628 		)
2629 	);
2630 	*/
2631 
2632 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsa/|a", &link, &dn, &dn_len, &mods, &serverctrls) != SUCCESS) {
2633 		return;
2634 	}
2635 
2636 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
2637 		RETURN_FALSE;
2638 	}
2639 
2640 	/* perform validation */
2641 	{
2642 		zend_string *modkey;
2643 		zend_long modtype;
2644 
2645 		/* to store the wrongly-typed keys */
2646 		zend_ulong tmpUlong;
2647 
2648 		/* make sure the DN contains no NUL bytes */
2649 		if (_ldap_strlen_max(dn, dn_len) != dn_len) {
2650 			php_error_docref(NULL, E_WARNING, "DN must not contain NUL bytes");
2651 			RETURN_FALSE;
2652 		}
2653 
2654 		/* make sure the top level is a normal array */
2655 		zend_hash_internal_pointer_reset(Z_ARRVAL_P(mods));
2656 		if (zend_hash_get_current_key_type(Z_ARRVAL_P(mods)) != HASH_KEY_IS_LONG) {
2657 			php_error_docref(NULL, E_WARNING, "Modifications array must not be string-indexed");
2658 			RETURN_FALSE;
2659 		}
2660 
2661 		num_mods = zend_hash_num_elements(Z_ARRVAL_P(mods));
2662 
2663 		for (i = 0; i < num_mods; i++) {
2664 			/* is the numbering consecutive? */
2665 			if ((fetched = zend_hash_index_find(Z_ARRVAL_P(mods), i)) == NULL) {
2666 				php_error_docref(NULL, E_WARNING, "Modifications array must have consecutive indices 0, 1, ...");
2667 				RETURN_FALSE;
2668 			}
2669 			mod = fetched;
2670 
2671 			/* is it an array? */
2672 			if (Z_TYPE_P(mod) != IS_ARRAY) {
2673 				php_error_docref(NULL, E_WARNING, "Each entry of modifications array must be an array itself");
2674 				RETURN_FALSE;
2675 			}
2676 
2677 			SEPARATE_ARRAY(mod);
2678 			/* for the modification hashtable... */
2679 			zend_hash_internal_pointer_reset(Z_ARRVAL_P(mod));
2680 			num_modprops = zend_hash_num_elements(Z_ARRVAL_P(mod));
2681 
2682 			for (j = 0; j < num_modprops; j++) {
2683 				/* are the keys strings? */
2684 				if (zend_hash_get_current_key(Z_ARRVAL_P(mod), &modkey, &tmpUlong) != HASH_KEY_IS_STRING) {
2685 					php_error_docref(NULL, E_WARNING, "Each entry of modifications array must be string-indexed");
2686 					RETURN_FALSE;
2687 				}
2688 
2689 				/* is this a valid entry? */
2690 				if (
2691 					!_ldap_str_equal_to_const(ZSTR_VAL(modkey), ZSTR_LEN(modkey), LDAP_MODIFY_BATCH_ATTRIB) &&
2692 					!_ldap_str_equal_to_const(ZSTR_VAL(modkey), ZSTR_LEN(modkey), LDAP_MODIFY_BATCH_MODTYPE) &&
2693 					!_ldap_str_equal_to_const(ZSTR_VAL(modkey), ZSTR_LEN(modkey), LDAP_MODIFY_BATCH_VALUES)
2694 				) {
2695 					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 "'");
2696 					RETURN_FALSE;
2697 				}
2698 
2699 				fetched = zend_hash_get_current_data(Z_ARRVAL_P(mod));
2700 				modinfo = fetched;
2701 
2702 				/* does the value type match the key? */
2703 				if (_ldap_str_equal_to_const(ZSTR_VAL(modkey), ZSTR_LEN(modkey), LDAP_MODIFY_BATCH_ATTRIB)) {
2704 					if (Z_TYPE_P(modinfo) != IS_STRING) {
2705 						php_error_docref(NULL, E_WARNING, "A '" LDAP_MODIFY_BATCH_ATTRIB "' value must be a string");
2706 						RETURN_FALSE;
2707 					}
2708 
2709 					if (Z_STRLEN_P(modinfo) != _ldap_strlen_max(Z_STRVAL_P(modinfo), Z_STRLEN_P(modinfo))) {
2710 						php_error_docref(NULL, E_WARNING, "A '" LDAP_MODIFY_BATCH_ATTRIB "' value must not contain NUL bytes");
2711 						RETURN_FALSE;
2712 					}
2713 				}
2714 				else if (_ldap_str_equal_to_const(ZSTR_VAL(modkey), ZSTR_LEN(modkey), LDAP_MODIFY_BATCH_MODTYPE)) {
2715 					if (Z_TYPE_P(modinfo) != IS_LONG) {
2716 						php_error_docref(NULL, E_WARNING, "A '" LDAP_MODIFY_BATCH_MODTYPE "' value must be a long");
2717 						RETURN_FALSE;
2718 					}
2719 
2720 					/* is the value in range? */
2721 					modtype = Z_LVAL_P(modinfo);
2722 					if (
2723 						modtype != LDAP_MODIFY_BATCH_ADD &&
2724 						modtype != LDAP_MODIFY_BATCH_REMOVE &&
2725 						modtype != LDAP_MODIFY_BATCH_REPLACE &&
2726 						modtype != LDAP_MODIFY_BATCH_REMOVE_ALL
2727 					) {
2728 						php_error_docref(NULL, E_WARNING, "The '" LDAP_MODIFY_BATCH_MODTYPE "' value must match one of the LDAP_MODIFY_BATCH_* constants");
2729 						RETURN_FALSE;
2730 					}
2731 
2732 					/* if it's REMOVE_ALL, there must not be a values array; otherwise, there must */
2733 					if (modtype == LDAP_MODIFY_BATCH_REMOVE_ALL) {
2734 						if (zend_hash_str_exists(Z_ARRVAL_P(mod), LDAP_MODIFY_BATCH_VALUES, strlen(LDAP_MODIFY_BATCH_VALUES))) {
2735 							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");
2736 							RETURN_FALSE;
2737 						}
2738 					}
2739 					else {
2740 						if (!zend_hash_str_exists(Z_ARRVAL_P(mod), LDAP_MODIFY_BATCH_VALUES, strlen(LDAP_MODIFY_BATCH_VALUES))) {
2741 							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");
2742 							RETURN_FALSE;
2743 						}
2744 					}
2745 				}
2746 				else if (_ldap_str_equal_to_const(ZSTR_VAL(modkey), ZSTR_LEN(modkey), LDAP_MODIFY_BATCH_VALUES)) {
2747 					if (Z_TYPE_P(modinfo) != IS_ARRAY) {
2748 						php_error_docref(NULL, E_WARNING, "A '" LDAP_MODIFY_BATCH_VALUES "' value must be an array");
2749 						RETURN_FALSE;
2750 					}
2751 
2752 					SEPARATE_ARRAY(modinfo);
2753 					/* is the array not empty? */
2754 					zend_hash_internal_pointer_reset(Z_ARRVAL_P(modinfo));
2755 					num_modvals = zend_hash_num_elements(Z_ARRVAL_P(modinfo));
2756 					if (num_modvals == 0) {
2757 						php_error_docref(NULL, E_WARNING, "A '" LDAP_MODIFY_BATCH_VALUES "' array must have at least one element");
2758 						RETURN_FALSE;
2759 					}
2760 
2761 					/* are its keys integers? */
2762 					if (zend_hash_get_current_key_type(Z_ARRVAL_P(modinfo)) != HASH_KEY_IS_LONG) {
2763 						php_error_docref(NULL, E_WARNING, "A '" LDAP_MODIFY_BATCH_VALUES "' array must not be string-indexed");
2764 						RETURN_FALSE;
2765 					}
2766 
2767 					/* are the keys consecutive? */
2768 					for (k = 0; k < num_modvals; k++) {
2769 						if ((fetched = zend_hash_index_find(Z_ARRVAL_P(modinfo), k)) == NULL) {
2770 							php_error_docref(NULL, E_WARNING, "A '" LDAP_MODIFY_BATCH_VALUES "' array must have consecutive indices 0, 1, ...");
2771 							RETURN_FALSE;
2772 						}
2773 					}
2774 				}
2775 
2776 				zend_hash_move_forward(Z_ARRVAL_P(mod));
2777 			}
2778 		}
2779 	}
2780 	/* validation was successful */
2781 
2782 	/* allocate array of modifications */
2783 	ldap_mods = safe_emalloc((num_mods+1), sizeof(LDAPMod *), 0);
2784 
2785 	/* for each modification */
2786 	for (i = 0; i < num_mods; i++) {
2787 		/* allocate the modification struct */
2788 		ldap_mods[i] = safe_emalloc(1, sizeof(LDAPMod), 0);
2789 
2790 		/* fetch the relevant data */
2791 		fetched = zend_hash_index_find(Z_ARRVAL_P(mods), i);
2792 		mod = fetched;
2793 
2794 		_ldap_hash_fetch(mod, LDAP_MODIFY_BATCH_ATTRIB, &attrib);
2795 		_ldap_hash_fetch(mod, LDAP_MODIFY_BATCH_MODTYPE, &modtype);
2796 		_ldap_hash_fetch(mod, LDAP_MODIFY_BATCH_VALUES, &vals);
2797 
2798 		/* map the modification type */
2799 		switch (Z_LVAL_P(modtype)) {
2800 			case LDAP_MODIFY_BATCH_ADD:
2801 				oper = LDAP_MOD_ADD;
2802 				break;
2803 			case LDAP_MODIFY_BATCH_REMOVE:
2804 			case LDAP_MODIFY_BATCH_REMOVE_ALL:
2805 				oper = LDAP_MOD_DELETE;
2806 				break;
2807 			case LDAP_MODIFY_BATCH_REPLACE:
2808 				oper = LDAP_MOD_REPLACE;
2809 				break;
2810 			default:
2811 				zend_throw_error(NULL, "Unknown and uncaught modification type.");
2812 				RETVAL_FALSE;
2813 				efree(ldap_mods[i]);
2814 				num_mods = i;
2815 				goto cleanup;
2816 		}
2817 
2818 		/* fill in the basic info */
2819 		ldap_mods[i]->mod_op = oper | LDAP_MOD_BVALUES;
2820 		ldap_mods[i]->mod_type = estrndup(Z_STRVAL_P(attrib), Z_STRLEN_P(attrib));
2821 
2822 		if (Z_LVAL_P(modtype) == LDAP_MODIFY_BATCH_REMOVE_ALL) {
2823 			/* no values */
2824 			ldap_mods[i]->mod_bvalues = NULL;
2825 		}
2826 		else {
2827 			/* allocate space for the values as part of this modification */
2828 			num_modvals = zend_hash_num_elements(Z_ARRVAL_P(vals));
2829 			ldap_mods[i]->mod_bvalues = safe_emalloc((num_modvals+1), sizeof(struct berval *), 0);
2830 
2831 			/* for each value */
2832 			for (j = 0; j < num_modvals; j++) {
2833 				/* fetch it */
2834 				fetched = zend_hash_index_find(Z_ARRVAL_P(vals), j);
2835 				modval = zval_get_string(fetched);
2836 				if (EG(exception)) {
2837 					RETVAL_FALSE;
2838 					ldap_mods[i]->mod_bvalues[j] = NULL;
2839 					num_mods = i + 1;
2840 					goto cleanup;
2841 				}
2842 
2843 				/* allocate the data struct */
2844 				ldap_mods[i]->mod_bvalues[j] = safe_emalloc(1, sizeof(struct berval), 0);
2845 
2846 				/* fill it */
2847 				ldap_mods[i]->mod_bvalues[j]->bv_len = ZSTR_LEN(modval);
2848 				ldap_mods[i]->mod_bvalues[j]->bv_val = estrndup(ZSTR_VAL(modval), ZSTR_LEN(modval));
2849 				zend_string_release(modval);
2850 			}
2851 
2852 			/* NULL-terminate values */
2853 			ldap_mods[i]->mod_bvalues[num_modvals] = NULL;
2854 		}
2855 	}
2856 
2857 	/* NULL-terminate modifications */
2858 	ldap_mods[num_mods] = NULL;
2859 
2860 	if (serverctrls) {
2861 		lserverctrls = _php_ldap_controls_from_array(ld->link, serverctrls);
2862 		if (lserverctrls == NULL) {
2863 			RETVAL_FALSE;
2864 			goto cleanup;
2865 		}
2866 	}
2867 
2868 	/* perform (finally) */
2869 	if ((i = ldap_modify_ext_s(ld->link, dn, ldap_mods, lserverctrls, NULL)) != LDAP_SUCCESS) {
2870 		php_error_docref(NULL, E_WARNING, "Batch Modify: %s", ldap_err2string(i));
2871 		RETVAL_FALSE;
2872 	} else RETVAL_TRUE;
2873 
2874 	/* clean up */
2875 	cleanup: {
2876 		for (i = 0; i < num_mods; i++) {
2877 			/* attribute */
2878 			efree(ldap_mods[i]->mod_type);
2879 
2880 			if (ldap_mods[i]->mod_bvalues != NULL) {
2881 				/* each BER value */
2882 				for (j = 0; ldap_mods[i]->mod_bvalues[j] != NULL; j++) {
2883 					/* free the data bytes */
2884 					efree(ldap_mods[i]->mod_bvalues[j]->bv_val);
2885 
2886 					/* free the bvalue struct */
2887 					efree(ldap_mods[i]->mod_bvalues[j]);
2888 				}
2889 
2890 				/* the BER value array */
2891 				efree(ldap_mods[i]->mod_bvalues);
2892 			}
2893 
2894 			/* the modification */
2895 			efree(ldap_mods[i]);
2896 		}
2897 
2898 		/* the modifications array */
2899 		efree(ldap_mods);
2900 
2901 		if (lserverctrls) {
2902 			_php_ldap_controls_free(&lserverctrls);
2903 		}
2904 	}
2905 }
2906 /* }}} */
2907 
2908 /* {{{ proto int ldap_errno(resource link)
2909    Get the current ldap error number */
PHP_FUNCTION(ldap_errno)2910 PHP_FUNCTION(ldap_errno)
2911 {
2912 	zval *link;
2913 	ldap_linkdata *ld;
2914 
2915 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &link) != SUCCESS) {
2916 		return;
2917 	}
2918 
2919 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
2920 		RETURN_FALSE;
2921 	}
2922 
2923 	RETURN_LONG(_get_lderrno(ld->link));
2924 }
2925 /* }}} */
2926 
2927 /* {{{ proto string ldap_err2str(int errno)
2928    Convert error number to error string */
PHP_FUNCTION(ldap_err2str)2929 PHP_FUNCTION(ldap_err2str)
2930 {
2931 	zend_long perrno;
2932 
2933 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &perrno) != SUCCESS) {
2934 		return;
2935 	}
2936 
2937 	RETURN_STRING(ldap_err2string(perrno));
2938 }
2939 /* }}} */
2940 
2941 /* {{{ proto string ldap_error(resource link)
2942    Get the current ldap error string */
PHP_FUNCTION(ldap_error)2943 PHP_FUNCTION(ldap_error)
2944 {
2945 	zval *link;
2946 	ldap_linkdata *ld;
2947 	int ld_errno;
2948 
2949 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &link) != SUCCESS) {
2950 		return;
2951 	}
2952 
2953 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
2954 		RETURN_FALSE;
2955 	}
2956 
2957 	ld_errno = _get_lderrno(ld->link);
2958 
2959 	RETURN_STRING(ldap_err2string(ld_errno));
2960 }
2961 /* }}} */
2962 
2963 /* {{{ proto bool ldap_compare(resource link, string dn, string attr, string value)
2964    Determine if an entry has a specific value for one of its attributes */
PHP_FUNCTION(ldap_compare)2965 PHP_FUNCTION(ldap_compare)
2966 {
2967 	zval *serverctrls = NULL;
2968 	zval *link;
2969 	char *dn, *attr, *value;
2970 	size_t dn_len, attr_len, value_len;
2971 	ldap_linkdata *ld;
2972 	LDAPControl **lserverctrls = NULL;
2973 	int errno;
2974 	struct berval lvalue;
2975 
2976 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsss|a", &link, &dn, &dn_len, &attr, &attr_len, &value, &value_len, &serverctrls) != SUCCESS) {
2977 		return;
2978 	}
2979 
2980 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
2981 		RETURN_FALSE;
2982 	}
2983 
2984 	if (serverctrls) {
2985 		lserverctrls = _php_ldap_controls_from_array(ld->link, serverctrls);
2986 		if (lserverctrls == NULL) {
2987 			RETVAL_FALSE;
2988 			goto cleanup;
2989 		}
2990 	}
2991 
2992 	lvalue.bv_val = value;
2993 	lvalue.bv_len = value_len;
2994 
2995 	errno = ldap_compare_ext_s(ld->link, dn, attr, &lvalue, lserverctrls, NULL);
2996 
2997 	switch (errno) {
2998 		case LDAP_COMPARE_TRUE:
2999 			RETVAL_TRUE;
3000 			break;
3001 
3002 		case LDAP_COMPARE_FALSE:
3003 			RETVAL_FALSE;
3004 			break;
3005 
3006 		default:
3007 			php_error_docref(NULL, E_WARNING, "Compare: %s", ldap_err2string(errno));
3008 			RETVAL_LONG(-1);
3009 	}
3010 
3011 cleanup:
3012 	if (lserverctrls) {
3013 		_php_ldap_controls_free(&lserverctrls);
3014 	}
3015 
3016 	return;
3017 }
3018 /* }}} */
3019 
3020 /* {{{ proto bool ldap_sort(resource link, resource result, string sortfilter)
3021    Sort LDAP result entries */
PHP_FUNCTION(ldap_sort)3022 PHP_FUNCTION(ldap_sort)
3023 {
3024 	zval *link, *result;
3025 	ldap_linkdata *ld;
3026 	char *sortfilter;
3027 	size_t sflen;
3028 	zend_resource *le;
3029 
3030 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rrs", &link, &result, &sortfilter, &sflen) != SUCCESS) {
3031 		RETURN_FALSE;
3032 	}
3033 
3034 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
3035 		RETURN_FALSE;
3036 	}
3037 
3038 	le = Z_RES_P(result);
3039 	if (le->type != le_result) {
3040 		php_error_docref(NULL, E_WARNING, "Supplied resource is not a valid ldap result resource");
3041 		RETURN_FALSE;
3042 	}
3043 
3044 	if (ldap_sort_entries(ld->link, (LDAPMessage **) &le->ptr, sflen ? sortfilter : NULL, strcmp) != LDAP_SUCCESS) {
3045 		php_error_docref(NULL, E_WARNING, "%s", ldap_err2string(errno));
3046 		RETURN_FALSE;
3047 	}
3048 
3049 	RETURN_TRUE;
3050 }
3051 /* }}} */
3052 
3053 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP
3054 /* {{{ proto bool ldap_get_option(resource link, int option, mixed retval)
3055    Get the current value of various session-wide parameters */
PHP_FUNCTION(ldap_get_option)3056 PHP_FUNCTION(ldap_get_option)
3057 {
3058 	zval *link, *retval;
3059 	ldap_linkdata *ld;
3060 	zend_long option;
3061 
3062 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rlz/", &link, &option, &retval) != SUCCESS) {
3063 		return;
3064 	}
3065 
3066 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
3067 		RETURN_FALSE;
3068 	}
3069 
3070 	switch (option) {
3071 	/* options with int value */
3072 	case LDAP_OPT_DEREF:
3073 	case LDAP_OPT_SIZELIMIT:
3074 	case LDAP_OPT_TIMELIMIT:
3075 	case LDAP_OPT_PROTOCOL_VERSION:
3076 	case LDAP_OPT_ERROR_NUMBER:
3077 	case LDAP_OPT_REFERRALS:
3078 #ifdef LDAP_OPT_RESTART
3079 	case LDAP_OPT_RESTART:
3080 #endif
3081 #ifdef LDAP_OPT_X_SASL_NOCANON
3082 	case LDAP_OPT_X_SASL_NOCANON:
3083 #endif
3084 #ifdef LDAP_OPT_X_TLS_REQUIRE_CERT
3085 	case LDAP_OPT_X_TLS_REQUIRE_CERT:
3086 #endif
3087 #ifdef LDAP_OPT_X_TLS_CRLCHECK
3088 	case LDAP_OPT_X_TLS_CRLCHECK:
3089 #endif
3090 #ifdef LDAP_OPT_X_TLS_PROTOCOL_MIN
3091 	case LDAP_OPT_X_TLS_PROTOCOL_MIN:
3092 #endif
3093 #ifdef LDAP_OPT_X_KEEPALIVE_IDLE
3094 	case LDAP_OPT_X_KEEPALIVE_IDLE:
3095 	case LDAP_OPT_X_KEEPALIVE_PROBES:
3096 	case LDAP_OPT_X_KEEPALIVE_INTERVAL:
3097 #endif
3098 		{
3099 			int val;
3100 
3101 			if (ldap_get_option(ld->link, option, &val)) {
3102 				RETURN_FALSE;
3103 			}
3104 			zval_ptr_dtor(retval);
3105 			ZVAL_LONG(retval, val);
3106 		} break;
3107 #ifdef LDAP_OPT_NETWORK_TIMEOUT
3108 	case LDAP_OPT_NETWORK_TIMEOUT:
3109 		{
3110 			struct timeval *timeout = NULL;
3111 
3112 			if (ldap_get_option(ld->link, LDAP_OPT_NETWORK_TIMEOUT, (void *) &timeout)) {
3113 				if (timeout) {
3114 					ldap_memfree(timeout);
3115 				}
3116 				RETURN_FALSE;
3117 			}
3118 			if (!timeout) {
3119 				RETURN_FALSE;
3120 			}
3121 			zval_ptr_dtor(retval);
3122 			ZVAL_LONG(retval, timeout->tv_sec);
3123 			ldap_memfree(timeout);
3124 		} break;
3125 #elif defined(LDAP_X_OPT_CONNECT_TIMEOUT)
3126 	case LDAP_X_OPT_CONNECT_TIMEOUT:
3127 		{
3128 			int timeout;
3129 
3130 			if (ldap_get_option(ld->link, LDAP_X_OPT_CONNECT_TIMEOUT, &timeout)) {
3131 				RETURN_FALSE;
3132 			}
3133 			zval_ptr_dtor(retval);
3134 			ZVAL_LONG(retval, (timeout / 1000));
3135 		} break;
3136 #endif
3137 #ifdef LDAP_OPT_TIMEOUT
3138 	case LDAP_OPT_TIMEOUT:
3139 		{
3140 			struct timeval *timeout = NULL;
3141 
3142 			if (ldap_get_option(ld->link, LDAP_OPT_TIMEOUT, (void *) &timeout)) {
3143 				if (timeout) {
3144 					ldap_memfree(timeout);
3145 				}
3146 				RETURN_FALSE;
3147 			}
3148 			if (!timeout) {
3149 				RETURN_FALSE;
3150 			}
3151 			zval_ptr_dtor(retval);
3152 			ZVAL_LONG(retval, timeout->tv_sec);
3153 			ldap_memfree(timeout);
3154 		} break;
3155 #endif
3156 	/* options with string value */
3157 	case LDAP_OPT_ERROR_STRING:
3158 #ifdef LDAP_OPT_HOST_NAME
3159 	case LDAP_OPT_HOST_NAME:
3160 #endif
3161 #ifdef HAVE_LDAP_SASL
3162 	case LDAP_OPT_X_SASL_MECH:
3163 	case LDAP_OPT_X_SASL_REALM:
3164 	case LDAP_OPT_X_SASL_AUTHCID:
3165 	case LDAP_OPT_X_SASL_AUTHZID:
3166 #endif
3167 #ifdef LDAP_OPT_X_SASL_USERNAME
3168 	case LDAP_OPT_X_SASL_USERNAME:
3169 #endif
3170 #if (LDAP_API_VERSION > 2000)
3171 	case LDAP_OPT_X_TLS_CACERTDIR:
3172 	case LDAP_OPT_X_TLS_CACERTFILE:
3173 	case LDAP_OPT_X_TLS_CERTFILE:
3174 	case LDAP_OPT_X_TLS_CIPHER_SUITE:
3175 	case LDAP_OPT_X_TLS_KEYFILE:
3176 	case LDAP_OPT_X_TLS_RANDOM_FILE:
3177 #endif
3178 #ifdef LDAP_OPT_X_TLS_PACKAGE
3179 	case LDAP_OPT_X_TLS_PACKAGE:
3180 #endif
3181 #ifdef LDAP_OPT_X_TLS_CRLFILE
3182 	case LDAP_OPT_X_TLS_CRLFILE:
3183 #endif
3184 #ifdef LDAP_OPT_X_TLS_DHFILE
3185 	case LDAP_OPT_X_TLS_DHFILE:
3186 #endif
3187 #ifdef LDAP_OPT_MATCHED_DN
3188 	case LDAP_OPT_MATCHED_DN:
3189 #endif
3190 		{
3191 			char *val = NULL;
3192 
3193 			if (ldap_get_option(ld->link, option, &val) || val == NULL || *val == '\0') {
3194 				if (val) {
3195 					ldap_memfree(val);
3196 				}
3197 				RETURN_FALSE;
3198 			}
3199 			zval_ptr_dtor(retval);
3200 			ZVAL_STRING(retval, val);
3201 			ldap_memfree(val);
3202 		} break;
3203 	case LDAP_OPT_SERVER_CONTROLS:
3204 	case LDAP_OPT_CLIENT_CONTROLS:
3205 		{
3206 			LDAPControl **ctrls = NULL;
3207 
3208 			if (ldap_get_option(ld->link, option, &ctrls) || ctrls == NULL) {
3209 				if (ctrls) {
3210 					ldap_memfree(ctrls);
3211 				}
3212 				RETURN_FALSE;
3213 			}
3214 			zval_ptr_dtor(retval);
3215 			_php_ldap_controls_to_array(ld->link, ctrls, retval, 1);
3216 		} break;
3217 /* options not implemented
3218 	case LDAP_OPT_API_INFO:
3219 	case LDAP_OPT_API_FEATURE_INFO:
3220 */
3221 	default:
3222 		RETURN_FALSE;
3223 	}
3224 	RETURN_TRUE;
3225 }
3226 /* }}} */
3227 
3228 /* {{{ proto bool ldap_set_option(resource link, int option, mixed newval)
3229    Set the value of various session-wide parameters */
PHP_FUNCTION(ldap_set_option)3230 PHP_FUNCTION(ldap_set_option)
3231 {
3232 	zval *link, *newval;
3233 	ldap_linkdata *ld;
3234 	LDAP *ldap;
3235 	zend_long option;
3236 
3237 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "zlz", &link, &option, &newval) != SUCCESS) {
3238 		return;
3239 	}
3240 
3241 	if (Z_TYPE_P(link) == IS_NULL) {
3242 		ldap = NULL;
3243 	} else {
3244 		if ((ld = (ldap_linkdata *)zend_fetch_resource_ex(link, "ldap link", le_link)) == NULL) {
3245 			RETURN_FALSE;
3246 		}
3247 		ldap = ld->link;
3248 	}
3249 
3250 	switch (option) {
3251 	/* options with int value */
3252 	case LDAP_OPT_DEREF:
3253 	case LDAP_OPT_SIZELIMIT:
3254 	case LDAP_OPT_TIMELIMIT:
3255 	case LDAP_OPT_PROTOCOL_VERSION:
3256 	case LDAP_OPT_ERROR_NUMBER:
3257 #ifdef LDAP_OPT_DEBUG_LEVEL
3258 	case LDAP_OPT_DEBUG_LEVEL:
3259 #endif
3260 #ifdef LDAP_OPT_X_TLS_REQUIRE_CERT
3261 	case LDAP_OPT_X_TLS_REQUIRE_CERT:
3262 #endif
3263 #ifdef LDAP_OPT_X_TLS_CRLCHECK
3264 	case LDAP_OPT_X_TLS_CRLCHECK:
3265 #endif
3266 #ifdef LDAP_OPT_X_TLS_PROTOCOL_MIN
3267 	case LDAP_OPT_X_TLS_PROTOCOL_MIN:
3268 #endif
3269 #ifdef LDAP_OPT_X_KEEPALIVE_IDLE
3270 	case LDAP_OPT_X_KEEPALIVE_IDLE:
3271 	case LDAP_OPT_X_KEEPALIVE_PROBES:
3272 	case LDAP_OPT_X_KEEPALIVE_INTERVAL:
3273 #endif
3274 		{
3275 			int val;
3276 
3277 			convert_to_long_ex(newval);
3278 			if (ZEND_LONG_EXCEEDS_INT(Z_LVAL_P(newval))) {
3279 				php_error_docref(NULL, E_WARNING, "Option value is too big");
3280 				RETURN_FALSE;
3281 			}
3282 			val = (int)Z_LVAL_P(newval);
3283 			if (ldap_set_option(ldap, option, &val)) {
3284 				RETURN_FALSE;
3285 			}
3286 		} break;
3287 #ifdef LDAP_OPT_NETWORK_TIMEOUT
3288 	case LDAP_OPT_NETWORK_TIMEOUT:
3289 		{
3290 			struct timeval timeout;
3291 
3292 			convert_to_long_ex(newval);
3293 			timeout.tv_sec = Z_LVAL_P(newval);
3294 			timeout.tv_usec = 0;
3295 			if (ldap_set_option(ldap, LDAP_OPT_NETWORK_TIMEOUT, (void *) &timeout)) {
3296 				RETURN_FALSE;
3297 			}
3298 		} break;
3299 #elif defined(LDAP_X_OPT_CONNECT_TIMEOUT)
3300 	case LDAP_X_OPT_CONNECT_TIMEOUT:
3301 		{
3302 			int timeout;
3303 
3304 			convert_to_long_ex(newval);
3305 			timeout = 1000 * Z_LVAL_P(newval); /* Convert to milliseconds */
3306 			if (ldap_set_option(ldap, LDAP_X_OPT_CONNECT_TIMEOUT, &timeout)) {
3307 				RETURN_FALSE;
3308 			}
3309 		} break;
3310 #endif
3311 #ifdef LDAP_OPT_TIMEOUT
3312 	case LDAP_OPT_TIMEOUT:
3313 		{
3314 			struct timeval timeout;
3315 
3316 			convert_to_long_ex(newval);
3317 			timeout.tv_sec = Z_LVAL_P(newval);
3318 			timeout.tv_usec = 0;
3319 			if (ldap_set_option(ldap, LDAP_OPT_TIMEOUT, (void *) &timeout)) {
3320 				RETURN_FALSE;
3321 			}
3322 		} break;
3323 #endif
3324 		/* options with string value */
3325 	case LDAP_OPT_ERROR_STRING:
3326 #ifdef LDAP_OPT_HOST_NAME
3327 	case LDAP_OPT_HOST_NAME:
3328 #endif
3329 #ifdef HAVE_LDAP_SASL
3330 	case LDAP_OPT_X_SASL_MECH:
3331 	case LDAP_OPT_X_SASL_REALM:
3332 	case LDAP_OPT_X_SASL_AUTHCID:
3333 	case LDAP_OPT_X_SASL_AUTHZID:
3334 #endif
3335 #if (LDAP_API_VERSION > 2000)
3336 	case LDAP_OPT_X_TLS_CACERTDIR:
3337 	case LDAP_OPT_X_TLS_CACERTFILE:
3338 	case LDAP_OPT_X_TLS_CERTFILE:
3339 	case LDAP_OPT_X_TLS_CIPHER_SUITE:
3340 	case LDAP_OPT_X_TLS_KEYFILE:
3341 	case LDAP_OPT_X_TLS_RANDOM_FILE:
3342 #endif
3343 #ifdef LDAP_OPT_X_TLS_CRLFILE
3344 	case LDAP_OPT_X_TLS_CRLFILE:
3345 #endif
3346 #ifdef LDAP_OPT_X_TLS_DHFILE
3347 	case LDAP_OPT_X_TLS_DHFILE:
3348 #endif
3349 #ifdef LDAP_OPT_MATCHED_DN
3350 	case LDAP_OPT_MATCHED_DN:
3351 #endif
3352 		{
3353 			zend_string *val;
3354 			val = zval_get_string(newval);
3355 			if (EG(exception)) {
3356 				RETURN_FALSE;
3357 			}
3358 			if (ldap_set_option(ldap, option, ZSTR_VAL(val))) {
3359 				zend_string_release(val);
3360 				RETURN_FALSE;
3361 			}
3362 			zend_string_release(val);
3363 		} break;
3364 		/* options with boolean value */
3365 	case LDAP_OPT_REFERRALS:
3366 #ifdef LDAP_OPT_RESTART
3367 	case LDAP_OPT_RESTART:
3368 #endif
3369 #ifdef LDAP_OPT_X_SASL_NOCANON
3370 	case LDAP_OPT_X_SASL_NOCANON:
3371 #endif
3372 		{
3373 			void *val;
3374 			val = zend_is_true(newval) ? LDAP_OPT_ON : LDAP_OPT_OFF;
3375 			if (ldap_set_option(ldap, option, val)) {
3376 				RETURN_FALSE;
3377 			}
3378 		} break;
3379 		/* options with control list value */
3380 	case LDAP_OPT_SERVER_CONTROLS:
3381 	case LDAP_OPT_CLIENT_CONTROLS:
3382 		{
3383 			LDAPControl **ctrls;
3384 			int rc;
3385 
3386 			if (Z_TYPE_P(newval) != IS_ARRAY) {
3387 				php_error_docref(NULL, E_WARNING, "Expected array value for this option");
3388 				RETURN_FALSE;
3389 			}
3390 
3391 			ctrls = _php_ldap_controls_from_array(ldap, newval);
3392 
3393 			if (ctrls == NULL) {
3394 				RETURN_FALSE;
3395 			} else {
3396 				rc = ldap_set_option(ldap, option, ctrls);
3397 				_php_ldap_controls_free(&ctrls);
3398 				if (rc != LDAP_SUCCESS) {
3399 					RETURN_FALSE;
3400 				}
3401 			}
3402 		} break;
3403 	default:
3404 		RETURN_FALSE;
3405 	}
3406 	RETURN_TRUE;
3407 }
3408 /* }}} */
3409 
3410 #ifdef HAVE_LDAP_PARSE_RESULT
3411 /* {{{ proto bool ldap_parse_result(resource link, resource result, int &errcode [, string &matcheddn [, string &errmsg [, array &referrals [, array &controls]]]])
3412    Extract information from result */
PHP_FUNCTION(ldap_parse_result)3413 PHP_FUNCTION(ldap_parse_result)
3414 {
3415 	zval *link, *result, *errcode, *matcheddn, *errmsg, *referrals, *serverctrls;
3416 	ldap_linkdata *ld;
3417 	LDAPMessage *ldap_result;
3418 	LDAPControl **lserverctrls = NULL;
3419 	char **lreferrals, **refp;
3420 	char *lmatcheddn, *lerrmsg;
3421 	int rc, lerrcode, myargcount = ZEND_NUM_ARGS();
3422 
3423 	if (zend_parse_parameters(myargcount, "rrz/|z/z/z/z/", &link, &result, &errcode, &matcheddn, &errmsg, &referrals, &serverctrls) != SUCCESS) {
3424 		return;
3425 	}
3426 
3427 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
3428 		RETURN_FALSE;
3429 	}
3430 
3431 	if ((ldap_result = (LDAPMessage *)zend_fetch_resource(Z_RES_P(result), "ldap result", le_result)) == NULL) {
3432 		RETURN_FALSE;
3433 	}
3434 
3435 	rc = ldap_parse_result(ld->link, ldap_result, &lerrcode,
3436 				myargcount > 3 ? &lmatcheddn : NULL,
3437 				myargcount > 4 ? &lerrmsg : NULL,
3438 				myargcount > 5 ? &lreferrals : NULL,
3439 				myargcount > 6 ? &lserverctrls : NULL,
3440 				0);
3441 	if (rc != LDAP_SUCCESS) {
3442 		php_error_docref(NULL, E_WARNING, "Unable to parse result: %s", ldap_err2string(rc));
3443 		RETURN_FALSE;
3444 	}
3445 
3446 	zval_ptr_dtor(errcode);
3447 	ZVAL_LONG(errcode, lerrcode);
3448 
3449 	/* Reverse -> fall through */
3450 	switch (myargcount) {
3451 		case 7:
3452 			zval_ptr_dtor(serverctrls);
3453 			_php_ldap_controls_to_array(ld->link, lserverctrls, serverctrls, 0);
3454 		case 6:
3455 			zval_ptr_dtor(referrals);
3456 			array_init(referrals);
3457 			if (lreferrals != NULL) {
3458 				refp = lreferrals;
3459 				while (*refp) {
3460 					add_next_index_string(referrals, *refp);
3461 					refp++;
3462 				}
3463 				ldap_memvfree((void**)lreferrals);
3464 			}
3465 		case 5:
3466 			zval_ptr_dtor(errmsg);
3467 			if (lerrmsg == NULL) {
3468 				ZVAL_EMPTY_STRING(errmsg);
3469 			} else {
3470 				ZVAL_STRING(errmsg, lerrmsg);
3471 				ldap_memfree(lerrmsg);
3472 			}
3473 		case 4:
3474 			zval_ptr_dtor(matcheddn);
3475 			if (lmatcheddn == NULL) {
3476 				ZVAL_EMPTY_STRING(matcheddn);
3477 			} else {
3478 				ZVAL_STRING(matcheddn, lmatcheddn);
3479 				ldap_memfree(lmatcheddn);
3480 			}
3481 	}
3482 	RETURN_TRUE;
3483 }
3484 /* }}} */
3485 #endif
3486 
3487 /* {{{ Extended operation response parsing, Pierangelo Masarati */
3488 #ifdef HAVE_LDAP_PARSE_EXTENDED_RESULT
3489 /* {{{ proto bool ldap_parse_exop(resource link, resource result [, string retdata [, string retoid]])
3490    Extract information from extended operation result */
PHP_FUNCTION(ldap_parse_exop)3491 PHP_FUNCTION(ldap_parse_exop)
3492 {
3493 	zval *link, *result, *retdata, *retoid;
3494 	ldap_linkdata *ld;
3495 	LDAPMessage *ldap_result;
3496 	char *lretoid;
3497 	struct berval *lretdata;
3498 	int rc, myargcount = ZEND_NUM_ARGS();
3499 
3500 	if (zend_parse_parameters(myargcount, "rr|z/z/", &link, &result, &retdata, &retoid) != SUCCESS) {
3501 		WRONG_PARAM_COUNT;
3502 	}
3503 
3504 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
3505 		RETURN_FALSE;
3506 	}
3507 
3508 	if ((ldap_result = (LDAPMessage *)zend_fetch_resource(Z_RES_P(result), "ldap result", le_result)) == NULL) {
3509 		RETURN_FALSE;
3510 	}
3511 
3512 	rc = ldap_parse_extended_result(ld->link, ldap_result,
3513 				myargcount > 3 ? &lretoid: NULL,
3514 				myargcount > 2 ? &lretdata: NULL,
3515 				0);
3516 	if (rc != LDAP_SUCCESS) {
3517 		php_error_docref(NULL, E_WARNING, "Unable to parse extended operation result: %s", ldap_err2string(rc));
3518 		RETURN_FALSE;
3519 	}
3520 
3521 	/* Reverse -> fall through */
3522 	switch (myargcount) {
3523 		case 4:
3524 			zval_ptr_dtor(retoid);
3525 			if (lretoid == NULL) {
3526 				ZVAL_EMPTY_STRING(retoid);
3527 			} else {
3528 				ZVAL_STRING(retoid, lretoid);
3529 				ldap_memfree(lretoid);
3530 			}
3531 		case 3:
3532 			/* use arg #3 as the data returned by the server */
3533 			zval_ptr_dtor(retdata);
3534 			if (lretdata == NULL) {
3535 				ZVAL_EMPTY_STRING(retdata);
3536 			} else {
3537 				ZVAL_STRINGL(retdata, lretdata->bv_val, lretdata->bv_len);
3538 				ldap_memfree(lretdata->bv_val);
3539 				ldap_memfree(lretdata);
3540 			}
3541 	}
3542 	RETURN_TRUE;
3543 }
3544 /* }}} */
3545 #endif
3546 /* }}} */
3547 
3548 /* {{{ proto resource ldap_first_reference(resource link, resource result)
3549    Return first reference */
PHP_FUNCTION(ldap_first_reference)3550 PHP_FUNCTION(ldap_first_reference)
3551 {
3552 	zval *link, *result;
3553 	ldap_linkdata *ld;
3554 	ldap_resultentry *resultentry;
3555 	LDAPMessage *ldap_result, *entry;
3556 
3557 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rr", &link, &result) != SUCCESS) {
3558 		return;
3559 	}
3560 
3561 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
3562 		RETURN_FALSE;
3563 	}
3564 
3565 	if ((ldap_result = (LDAPMessage *)zend_fetch_resource(Z_RES_P(result), "ldap result", le_result)) == NULL) {
3566 		RETURN_FALSE;
3567 	}
3568 
3569 	if ((entry = ldap_first_reference(ld->link, ldap_result)) == NULL) {
3570 		RETVAL_FALSE;
3571 	} else {
3572 		resultentry = emalloc(sizeof(ldap_resultentry));
3573 		RETVAL_RES(zend_register_resource(resultentry, le_result_entry));
3574 		ZVAL_COPY(&resultentry->res, result);
3575 		resultentry->data = entry;
3576 		resultentry->ber = NULL;
3577 	}
3578 }
3579 /* }}} */
3580 
3581 /* {{{ proto resource ldap_next_reference(resource link, resource reference_entry)
3582    Get next reference */
PHP_FUNCTION(ldap_next_reference)3583 PHP_FUNCTION(ldap_next_reference)
3584 {
3585 	zval *link, *result_entry;
3586 	ldap_linkdata *ld;
3587 	ldap_resultentry *resultentry, *resultentry_next;
3588 	LDAPMessage *entry_next;
3589 
3590 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rr", &link, &result_entry) != SUCCESS) {
3591 		return;
3592 	}
3593 
3594 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
3595 		RETURN_FALSE;
3596 	}
3597 
3598 	if ((resultentry = (ldap_resultentry *)zend_fetch_resource(Z_RES_P(result_entry), "ldap result entry", le_result_entry)) == NULL) {
3599 		RETURN_FALSE;
3600 	}
3601 
3602 	if ((entry_next = ldap_next_reference(ld->link, resultentry->data)) == NULL) {
3603 		RETVAL_FALSE;
3604 	} else {
3605 		resultentry_next = emalloc(sizeof(ldap_resultentry));
3606 		RETVAL_RES(zend_register_resource(resultentry_next, le_result_entry));
3607 		ZVAL_COPY(&resultentry_next->res, &resultentry->res);
3608 		resultentry_next->data = entry_next;
3609 		resultentry_next->ber = NULL;
3610 	}
3611 }
3612 /* }}} */
3613 
3614 #ifdef HAVE_LDAP_PARSE_REFERENCE
3615 /* {{{ proto bool ldap_parse_reference(resource link, resource reference_entry, array referrals)
3616    Extract information from reference entry */
PHP_FUNCTION(ldap_parse_reference)3617 PHP_FUNCTION(ldap_parse_reference)
3618 {
3619 	zval *link, *result_entry, *referrals;
3620 	ldap_linkdata *ld;
3621 	ldap_resultentry *resultentry;
3622 	char **lreferrals, **refp;
3623 
3624 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rrz/", &link, &result_entry, &referrals) != SUCCESS) {
3625 		return;
3626 	}
3627 
3628 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
3629 		RETURN_FALSE;
3630 	}
3631 
3632 	if ((resultentry = (ldap_resultentry *)zend_fetch_resource(Z_RES_P(result_entry), "ldap result entry", le_result_entry)) == NULL) {
3633 		RETURN_FALSE;
3634 	}
3635 
3636 	if (ldap_parse_reference(ld->link, resultentry->data, &lreferrals, NULL /* &serverctrls */, 0) != LDAP_SUCCESS) {
3637 		RETURN_FALSE;
3638 	}
3639 
3640 	zval_ptr_dtor(referrals);
3641 	array_init(referrals);
3642 	if (lreferrals != NULL) {
3643 		refp = lreferrals;
3644 		while (*refp) {
3645 			add_next_index_string(referrals, *refp);
3646 			refp++;
3647 		}
3648 		ldap_memvfree((void**)lreferrals);
3649 	}
3650 	RETURN_TRUE;
3651 }
3652 /* }}} */
3653 #endif
3654 
3655 /* {{{ php_ldap_do_rename
3656  */
php_ldap_do_rename(INTERNAL_FUNCTION_PARAMETERS,int ext)3657 static void php_ldap_do_rename(INTERNAL_FUNCTION_PARAMETERS, int ext)
3658 {
3659 	zval *serverctrls = NULL;
3660 	zval *link;
3661 	ldap_linkdata *ld;
3662 	LDAPControl **lserverctrls = NULL;
3663 	LDAPMessage *ldap_res;
3664 	int rc, msgid;
3665 	char *dn, *newrdn, *newparent;
3666 	size_t dn_len, newrdn_len, newparent_len;
3667 	zend_bool deleteoldrdn;
3668 
3669 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsssb|a", &link, &dn, &dn_len, &newrdn, &newrdn_len, &newparent, &newparent_len, &deleteoldrdn, &serverctrls) != SUCCESS) {
3670 		return;
3671 	}
3672 
3673 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
3674 		RETURN_FALSE;
3675 	}
3676 
3677 	if (newparent_len == 0) {
3678 		newparent = NULL;
3679 	}
3680 
3681 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP
3682 	if (serverctrls) {
3683 		lserverctrls = _php_ldap_controls_from_array(ld->link, serverctrls);
3684 		if (lserverctrls == NULL) {
3685 			RETVAL_FALSE;
3686 			goto cleanup;
3687 		}
3688 	}
3689 
3690 	if (ext) {
3691 		rc = ldap_rename(ld->link, dn, newrdn, newparent, deleteoldrdn, lserverctrls, NULL, &msgid);
3692 	} else {
3693 		rc = ldap_rename_s(ld->link, dn, newrdn, newparent, deleteoldrdn, lserverctrls, NULL);
3694 	}
3695 #else
3696 	if (newparent_len != 0) {
3697 		php_error_docref(NULL, E_WARNING, "You are using old LDAP API, newparent must be the empty string, can only modify RDN");
3698 		RETURN_FALSE;
3699 	}
3700 	if (serverctrls) {
3701 		php_error_docref(NULL, E_WARNING, "You are using old LDAP API, controls are not supported");
3702 		RETURN_FALSE;
3703 	}
3704 	if (ext) {
3705 		php_error_docref(NULL, E_WARNING, "You are using old LDAP API, ldap_rename_ext is not supported");
3706 		RETURN_FALSE;
3707 	}
3708 /* could support old APIs but need check for ldap_modrdn2()/ldap_modrdn() */
3709 	rc = ldap_modrdn2_s(ld->link, dn, newrdn, deleteoldrdn);
3710 #endif
3711 
3712 	if (rc != LDAP_SUCCESS) {
3713 		RETVAL_FALSE;
3714 	} else if (ext) {
3715 		rc = ldap_result(ld->link, msgid, 1 /* LDAP_MSG_ALL */, NULL, &ldap_res);
3716 		if (rc == -1) {
3717 			php_error_docref(NULL, E_WARNING, "Rename operation failed");
3718 			RETVAL_FALSE;
3719 			goto cleanup;
3720 		}
3721 
3722 		/* return a PHP control object */
3723 		RETVAL_RES(zend_register_resource(ldap_res, le_result));
3724 	} else {
3725 		RETVAL_TRUE;
3726 	}
3727 
3728 cleanup:
3729 	if (lserverctrls) {
3730 		_php_ldap_controls_free(&lserverctrls);
3731 	}
3732 
3733 	return;
3734 }
3735 /* }}} */
3736 
3737 /* {{{ proto bool ldap_rename(resource link, string dn, string newrdn, string newparent, bool deleteoldrdn [, array servercontrols])
3738    Modify the name of an entry */
PHP_FUNCTION(ldap_rename)3739 PHP_FUNCTION(ldap_rename)
3740 {
3741 	php_ldap_do_rename(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
3742 }
3743 /* }}} */
3744 
3745 /* {{{ proto resource ldap_rename_ext(resource link, string dn, string newrdn, string newparent, bool deleteoldrdn [, array servercontrols])
3746    Modify the name of an entry */
PHP_FUNCTION(ldap_rename_ext)3747 PHP_FUNCTION(ldap_rename_ext)
3748 {
3749 	php_ldap_do_rename(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
3750 }
3751 /* }}} */
3752 
3753 #ifdef HAVE_LDAP_START_TLS_S
3754 /* {{{ proto bool ldap_start_tls(resource link)
3755    Start TLS */
PHP_FUNCTION(ldap_start_tls)3756 PHP_FUNCTION(ldap_start_tls)
3757 {
3758 	zval *link;
3759 	ldap_linkdata *ld;
3760 	int rc, protocol = LDAP_VERSION3;
3761 
3762 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &link) != SUCCESS) {
3763 		return;
3764 	}
3765 
3766 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
3767 		RETURN_FALSE;
3768 	}
3769 
3770 	if (((rc = ldap_set_option(ld->link, LDAP_OPT_PROTOCOL_VERSION, &protocol)) != LDAP_SUCCESS) ||
3771 		((rc = ldap_start_tls_s(ld->link, NULL, NULL)) != LDAP_SUCCESS)
3772 	) {
3773 		php_error_docref(NULL, E_WARNING,"Unable to start TLS: %s", ldap_err2string(rc));
3774 		RETURN_FALSE;
3775 	} else {
3776 		RETURN_TRUE;
3777 	}
3778 }
3779 /* }}} */
3780 #endif
3781 #endif /* (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP */
3782 
3783 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)
3784 /* {{{ _ldap_rebind_proc()
3785 */
_ldap_rebind_proc(LDAP * ldap,const char * url,ber_tag_t req,ber_int_t msgid,void * params)3786 int _ldap_rebind_proc(LDAP *ldap, const char *url, ber_tag_t req, ber_int_t msgid, void *params)
3787 {
3788 	ldap_linkdata *ld;
3789 	int retval;
3790 	zval cb_args[2];
3791 	zval cb_retval;
3792 	zval *cb_link = (zval *) params;
3793 
3794 	ld = (ldap_linkdata *) zend_fetch_resource_ex(cb_link, "ldap link", le_link);
3795 
3796 	/* link exists and callback set? */
3797 	if (ld == NULL || Z_ISUNDEF(ld->rebindproc)) {
3798 		php_error_docref(NULL, E_WARNING, "Link not found or no callback set");
3799 		return LDAP_OTHER;
3800 	}
3801 
3802 	/* callback */
3803 	ZVAL_COPY_VALUE(&cb_args[0], cb_link);
3804 	ZVAL_STRING(&cb_args[1], url);
3805 	if (call_user_function_ex(EG(function_table), NULL, &ld->rebindproc, &cb_retval, 2, cb_args, 0, NULL) == SUCCESS && !Z_ISUNDEF(cb_retval)) {
3806 		retval = zval_get_long(&cb_retval);
3807 		zval_ptr_dtor(&cb_retval);
3808 	} else {
3809 		php_error_docref(NULL, E_WARNING, "rebind_proc PHP callback failed");
3810 		retval = LDAP_OTHER;
3811 	}
3812 	zval_ptr_dtor(&cb_args[1]);
3813 	return retval;
3814 }
3815 /* }}} */
3816 
3817 /* {{{ proto bool ldap_set_rebind_proc(resource link, string callback)
3818    Set a callback function to do re-binds on referral chasing. */
PHP_FUNCTION(ldap_set_rebind_proc)3819 PHP_FUNCTION(ldap_set_rebind_proc)
3820 {
3821 	zval *link, *callback;
3822 	ldap_linkdata *ld;
3823 
3824 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz", &link, &callback) != SUCCESS) {
3825 		RETURN_FALSE;
3826 	}
3827 
3828 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
3829 		RETURN_FALSE;
3830 	}
3831 
3832 	if (Z_TYPE_P(callback) == IS_STRING && Z_STRLEN_P(callback) == 0) {
3833 		/* unregister rebind procedure */
3834 		if (!Z_ISUNDEF(ld->rebindproc)) {
3835 			zval_ptr_dtor(&ld->rebindproc);
3836 			ZVAL_UNDEF(&ld->rebindproc);
3837 			ldap_set_rebind_proc(ld->link, NULL, NULL);
3838 		}
3839 		RETURN_TRUE;
3840 	}
3841 
3842 	/* callable? */
3843 	if (!zend_is_callable(callback, 0, NULL)) {
3844 		zend_string *callback_name = zend_get_callable_name(callback);
3845 		php_error_docref(NULL, E_WARNING, "Two arguments expected for '%s' to be a valid callback", ZSTR_VAL(callback_name));
3846 		zend_string_release_ex(callback_name, 0);
3847 		RETURN_FALSE;
3848 	}
3849 
3850 	/* register rebind procedure */
3851 	if (Z_ISUNDEF(ld->rebindproc)) {
3852 		ldap_set_rebind_proc(ld->link, _ldap_rebind_proc, (void *) link);
3853 	} else {
3854 		zval_ptr_dtor(&ld->rebindproc);
3855 	}
3856 
3857 	ZVAL_COPY(&ld->rebindproc, callback);
3858 	RETURN_TRUE;
3859 }
3860 /* }}} */
3861 #endif
3862 
php_ldap_do_escape(const zend_bool * map,const char * value,size_t valuelen,zend_long flags)3863 static zend_string* php_ldap_do_escape(const zend_bool *map, const char *value, size_t valuelen, zend_long flags)
3864 {
3865 	char hex[] = "0123456789abcdef";
3866 	size_t i, p = 0;
3867 	size_t len = 0;
3868 	zend_string *ret;
3869 
3870 	for (i = 0; i < valuelen; i++) {
3871 		len += (map[(unsigned char) value[i]]) ? 3 : 1;
3872 	}
3873 	/* Per RFC 4514, a leading and trailing space must be escaped */
3874 	if ((flags & PHP_LDAP_ESCAPE_DN) && (value[0] == ' ')) {
3875 		len += 2;
3876 	}
3877 	if ((flags & PHP_LDAP_ESCAPE_DN) && ((valuelen > 1) && (value[valuelen - 1] == ' '))) {
3878 		len += 2;
3879 	}
3880 
3881 	ret =  zend_string_alloc(len, 0);
3882 
3883 	for (i = 0; i < valuelen; i++) {
3884 		unsigned char v = (unsigned char) value[i];
3885 
3886 		if (map[v] || ((flags & PHP_LDAP_ESCAPE_DN) && ((i == 0) || (i + 1 == valuelen)) && (v == ' '))) {
3887 			ZSTR_VAL(ret)[p++] = '\\';
3888 			ZSTR_VAL(ret)[p++] = hex[v >> 4];
3889 			ZSTR_VAL(ret)[p++] = hex[v & 0x0f];
3890 		} else {
3891 			ZSTR_VAL(ret)[p++] = v;
3892 		}
3893 	}
3894 
3895 	ZSTR_VAL(ret)[p] = '\0';
3896 	ZSTR_LEN(ret) = p;
3897 	return ret;
3898 }
3899 
php_ldap_escape_map_set_chars(zend_bool * map,const char * chars,const size_t charslen,char escape)3900 static void php_ldap_escape_map_set_chars(zend_bool *map, const char *chars, const size_t charslen, char escape)
3901 {
3902 	size_t i = 0;
3903 	while (i < charslen) {
3904 		map[(unsigned char) chars[i++]] = escape;
3905 	}
3906 }
3907 
PHP_FUNCTION(ldap_escape)3908 PHP_FUNCTION(ldap_escape)
3909 {
3910 	char *value, *ignores;
3911 	size_t valuelen = 0, ignoreslen = 0;
3912 	int i;
3913 	zend_long flags = 0;
3914 	zend_bool map[256] = {0}, havecharlist = 0;
3915 
3916 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|sl", &value, &valuelen, &ignores, &ignoreslen, &flags) != SUCCESS) {
3917 		return;
3918 	}
3919 
3920 	if (!valuelen) {
3921 		RETURN_EMPTY_STRING();
3922 	}
3923 
3924 	if (flags & PHP_LDAP_ESCAPE_FILTER) {
3925 		havecharlist = 1;
3926 		php_ldap_escape_map_set_chars(map, "\\*()\0", sizeof("\\*()\0") - 1, 1);
3927 	}
3928 
3929 	if (flags & PHP_LDAP_ESCAPE_DN) {
3930 		havecharlist = 1;
3931 		php_ldap_escape_map_set_chars(map, "\\,=+<>;\"#\r", sizeof("\\,=+<>;\"#\r") - 1, 1);
3932 	}
3933 
3934 	if (!havecharlist) {
3935 		for (i = 0; i < 256; i++) {
3936 			map[i] = 1;
3937 		}
3938 	}
3939 
3940 	if (ignoreslen) {
3941 		php_ldap_escape_map_set_chars(map, ignores, ignoreslen, 0);
3942 	}
3943 
3944 	RETURN_NEW_STR(php_ldap_do_escape(map, value, valuelen, flags));
3945 }
3946 
3947 #ifdef STR_TRANSLATION
3948 /* {{{ php_ldap_do_translate
3949  */
php_ldap_do_translate(INTERNAL_FUNCTION_PARAMETERS,int way)3950 static void php_ldap_do_translate(INTERNAL_FUNCTION_PARAMETERS, int way)
3951 {
3952 	char *value;
3953 	size_t value_len;
3954 	int result;
3955 
3956 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &value, &value_len) != SUCCESS) {
3957 		return;
3958 	}
3959 
3960 	if (value_len == 0) {
3961 		RETURN_FALSE;
3962 	}
3963 
3964 	if (way == 1) {
3965 		result = ldap_8859_to_t61(&value, &value_len, 0);
3966 	} else {
3967 		result = ldap_t61_to_8859(&value, &value_len, 0);
3968 	}
3969 
3970 	if (result == LDAP_SUCCESS) {
3971 		RETVAL_STRINGL(value, value_len);
3972 		free(value);
3973 	} else {
3974 		php_error_docref(NULL, E_WARNING, "Conversion from iso-8859-1 to t61 failed: %s", ldap_err2string(result));
3975 		RETVAL_FALSE;
3976 	}
3977 }
3978 /* }}} */
3979 
3980 /* {{{ proto string ldap_t61_to_8859(string value)
3981    Translate t61 characters to 8859 characters */
PHP_FUNCTION(ldap_t61_to_8859)3982 PHP_FUNCTION(ldap_t61_to_8859)
3983 {
3984 	php_ldap_do_translate(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
3985 }
3986 /* }}} */
3987 
3988 /* {{{ proto string ldap_8859_to_t61(string value)
3989    Translate 8859 characters to t61 characters */
PHP_FUNCTION(ldap_8859_to_t61)3990 PHP_FUNCTION(ldap_8859_to_t61)
3991 {
3992 	php_ldap_do_translate(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
3993 }
3994 /* }}} */
3995 #endif
3996 
3997 #ifdef LDAP_CONTROL_PAGEDRESULTS
3998 /* {{{ proto mixed ldap_control_paged_result(resource link, int pagesize [, bool iscritical [, string cookie]])
3999    Inject paged results control*/
PHP_FUNCTION(ldap_control_paged_result)4000 PHP_FUNCTION(ldap_control_paged_result)
4001 {
4002 	zend_long pagesize;
4003 	zend_bool iscritical;
4004 	zval *link;
4005 	char *cookie = NULL;
4006 	size_t cookie_len = 0;
4007 	struct berval lcookie = { 0L, NULL };
4008 	ldap_linkdata *ld;
4009 	LDAP *ldap;
4010 	BerElement *ber = NULL;
4011 	LDAPControl	ctrl, *ctrlsp[2];
4012 	int rc, myargcount = ZEND_NUM_ARGS();
4013 
4014 	if (zend_parse_parameters(myargcount, "rl|bs", &link, &pagesize, &iscritical, &cookie, &cookie_len) != SUCCESS) {
4015 		return;
4016 	}
4017 
4018 	if (Z_TYPE_P(link) == IS_NULL) {
4019 		ldap = NULL;
4020 	} else {
4021 		if ((ld = (ldap_linkdata *)zend_fetch_resource_ex(link, "ldap link", le_link)) == NULL) {
4022 			RETURN_FALSE;
4023 		}
4024 		ldap = ld->link;
4025 	}
4026 
4027 	ber = ber_alloc_t(LBER_USE_DER);
4028 	if (ber == NULL) {
4029 		php_error_docref(NULL, E_WARNING, "Unable to alloc BER encoding resources for paged results control");
4030 		RETURN_FALSE;
4031 	}
4032 
4033 	ctrl.ldctl_iscritical = 0;
4034 
4035 	switch (myargcount) {
4036 		case 4:
4037 			lcookie.bv_val = cookie;
4038 			lcookie.bv_len = cookie_len;
4039 			/* fallthru */
4040 		case 3:
4041 			ctrl.ldctl_iscritical = (int)iscritical;
4042 			/* fallthru */
4043 	}
4044 
4045 	if (ber_printf(ber, "{iO}", (int)pagesize, &lcookie) == LBER_ERROR) {
4046 		php_error_docref(NULL, E_WARNING, "Unable to BER printf paged results control");
4047 		RETVAL_FALSE;
4048 		goto lcpr_error_out;
4049 	}
4050 	rc = ber_flatten2(ber, &ctrl.ldctl_value, 0);
4051 	if (rc == LBER_ERROR) {
4052 		php_error_docref(NULL, E_WARNING, "Unable to BER encode paged results control");
4053 		RETVAL_FALSE;
4054 		goto lcpr_error_out;
4055 	}
4056 
4057 	ctrl.ldctl_oid = LDAP_CONTROL_PAGEDRESULTS;
4058 
4059 	if (ldap) {
4060 		/* directly set the option */
4061 		ctrlsp[0] = &ctrl;
4062 		ctrlsp[1] = NULL;
4063 
4064 		rc = ldap_set_option(ldap, LDAP_OPT_SERVER_CONTROLS, ctrlsp);
4065 		if (rc != LDAP_SUCCESS) {
4066 			php_error_docref(NULL, E_WARNING, "Unable to set paged results control: %s (%d)", ldap_err2string(rc), rc);
4067 			RETVAL_FALSE;
4068 			goto lcpr_error_out;
4069 		}
4070 		RETVAL_TRUE;
4071 	} else {
4072 		/* return a PHP control object */
4073 		array_init(return_value);
4074 
4075 		add_assoc_string(return_value, "oid", ctrl.ldctl_oid);
4076 		if (ctrl.ldctl_value.bv_len) {
4077 			add_assoc_stringl(return_value, "value", ctrl.ldctl_value.bv_val, ctrl.ldctl_value.bv_len);
4078 		}
4079 		if (ctrl.ldctl_iscritical) {
4080 			add_assoc_bool(return_value, "iscritical", ctrl.ldctl_iscritical);
4081 		}
4082 	}
4083 
4084 lcpr_error_out:
4085 	if (ber != NULL) {
4086 		ber_free(ber, 1);
4087 	}
4088 	return;
4089 }
4090 /* }}} */
4091 
4092 /* {{{ proto bool ldap_control_paged_result_response(resource link, resource result [, string &cookie [, int &estimated]])
4093    Extract paged results control response */
PHP_FUNCTION(ldap_control_paged_result_response)4094 PHP_FUNCTION(ldap_control_paged_result_response)
4095 {
4096 	zval *link, *result, *cookie, *estimated;
4097 	struct berval lcookie;
4098 	int lestimated;
4099 	ldap_linkdata *ld;
4100 	LDAPMessage *ldap_result;
4101 	LDAPControl **lserverctrls, *lctrl;
4102 	BerElement *ber;
4103 	ber_tag_t tag;
4104 	int rc, lerrcode, myargcount = ZEND_NUM_ARGS();
4105 
4106 	if (zend_parse_parameters(myargcount, "rr|z/z/", &link, &result, &cookie, &estimated) != SUCCESS) {
4107 		return;
4108 	}
4109 
4110 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
4111 		RETURN_FALSE;
4112 	}
4113 
4114 	if ((ldap_result = (LDAPMessage *)zend_fetch_resource(Z_RES_P(result), "ldap result", le_result)) == NULL) {
4115 		RETURN_FALSE;
4116 	}
4117 
4118 	rc = ldap_parse_result(ld->link,
4119 				ldap_result,
4120 				&lerrcode,
4121 				NULL,		/* matcheddn */
4122 				NULL,		/* errmsg */
4123 				NULL,		/* referrals */
4124 				&lserverctrls,
4125 				0);
4126 
4127 	if (rc != LDAP_SUCCESS) {
4128 		php_error_docref(NULL, E_WARNING, "Unable to parse result: %s (%d)", ldap_err2string(rc), rc);
4129 		RETURN_FALSE;
4130 	}
4131 
4132 	if (lerrcode != LDAP_SUCCESS) {
4133 		php_error_docref(NULL, E_WARNING, "Result is: %s (%d)", ldap_err2string(lerrcode), lerrcode);
4134 		RETURN_FALSE;
4135 	}
4136 
4137 	if (lserverctrls == NULL) {
4138 		php_error_docref(NULL, E_WARNING, "No server controls in result");
4139 		RETURN_FALSE;
4140 	}
4141 
4142 	lctrl = ldap_control_find(LDAP_CONTROL_PAGEDRESULTS, lserverctrls, NULL);
4143 	if (lctrl == NULL) {
4144 		ldap_controls_free(lserverctrls);
4145 		php_error_docref(NULL, E_WARNING, "No paged results control response in result");
4146 		RETURN_FALSE;
4147 	}
4148 
4149 	ber = ber_init(&lctrl->ldctl_value);
4150 	if (ber == NULL) {
4151 		ldap_controls_free(lserverctrls);
4152 		php_error_docref(NULL, E_WARNING, "Unable to alloc BER decoding resources for paged results control response");
4153 		RETURN_FALSE;
4154 	}
4155 
4156 	tag = ber_scanf(ber, "{io}", &lestimated, &lcookie);
4157 	(void)ber_free(ber, 1);
4158 
4159 	if (tag == LBER_ERROR) {
4160 		ldap_controls_free(lserverctrls);
4161 		php_error_docref(NULL, E_WARNING, "Unable to decode paged results control response");
4162 		RETURN_FALSE;
4163 	}
4164 
4165 	if (lestimated < 0) {
4166 		ldap_controls_free(lserverctrls);
4167 		php_error_docref(NULL, E_WARNING, "Invalid paged results control response value");
4168 		RETURN_FALSE;
4169 	}
4170 
4171 	ldap_controls_free(lserverctrls);
4172 	if (myargcount == 4) {
4173 		zval_ptr_dtor(estimated);
4174 		ZVAL_LONG(estimated, lestimated);
4175 	}
4176 
4177 	zval_ptr_dtor(cookie);
4178  	if (lcookie.bv_len == 0) {
4179 		ZVAL_EMPTY_STRING(cookie);
4180  	} else {
4181 		ZVAL_STRINGL(cookie, lcookie.bv_val, lcookie.bv_len);
4182  	}
4183  	ldap_memfree(lcookie.bv_val);
4184 
4185 	RETURN_TRUE;
4186 }
4187 /* }}} */
4188 #endif
4189 
4190 /* {{{ Extended operations, Pierangelo Masarati */
4191 #ifdef HAVE_LDAP_EXTENDED_OPERATION_S
4192 /* {{{ proto resource ldap_exop(resource link, string reqoid [, string reqdata [, array servercontrols [, string &retdata [, string &retoid]]]])
4193    Extended operation */
PHP_FUNCTION(ldap_exop)4194 PHP_FUNCTION(ldap_exop)
4195 {
4196 	zval *serverctrls = NULL;
4197 	zval *link, *retdata = NULL, *retoid = NULL;
4198 	char *lretoid = NULL;
4199 	zend_string *reqoid, *reqdata = NULL;
4200 	struct berval lreqdata, *lretdata = NULL;
4201 	ldap_linkdata *ld;
4202 	LDAPMessage *ldap_res;
4203 	LDAPControl **lserverctrls = NULL;
4204 	int rc, msgid;
4205 
4206 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rS|S!a!z/z/", &link, &reqoid, &reqdata, &serverctrls, &retdata, &retoid) != SUCCESS) {
4207 		return;
4208 	}
4209 
4210 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
4211 		RETURN_FALSE;
4212 	}
4213 
4214 	if (reqdata) {
4215 		lreqdata.bv_val = ZSTR_VAL(reqdata);
4216 		lreqdata.bv_len = ZSTR_LEN(reqdata);
4217 	} else {
4218 		lreqdata.bv_len = 0;
4219 	}
4220 
4221 	if (serverctrls) {
4222 		lserverctrls = _php_ldap_controls_from_array(ld->link, serverctrls);
4223 		if (lserverctrls == NULL) {
4224 			RETVAL_FALSE;
4225 			goto cleanup;
4226 		}
4227 	}
4228 
4229 	if (retdata) {
4230 		/* synchronous call */
4231 		rc = ldap_extended_operation_s(ld->link, ZSTR_VAL(reqoid),
4232 			lreqdata.bv_len > 0 ? &lreqdata: NULL,
4233 			lserverctrls,
4234 			NULL,
4235 			retoid ? &lretoid : NULL,
4236 			&lretdata );
4237 		if (rc != LDAP_SUCCESS ) {
4238 			php_error_docref(NULL, E_WARNING, "Extended operation %s failed: %s (%d)", ZSTR_VAL(reqoid), ldap_err2string(rc), rc);
4239 			RETVAL_FALSE;
4240 			goto cleanup;
4241 		}
4242 
4243 		if (retoid) {
4244 			zval_ptr_dtor(retoid);
4245 			if (lretoid) {
4246 				ZVAL_STRING(retoid, lretoid);
4247 				ldap_memfree(lretoid);
4248 			} else {
4249 				ZVAL_EMPTY_STRING(retoid);
4250 			}
4251 		}
4252 
4253 		zval_ptr_dtor(retdata);
4254 		if (lretdata) {
4255 			ZVAL_STRINGL(retdata, lretdata->bv_val, lretdata->bv_len);
4256 			ldap_memfree(lretdata->bv_val);
4257 			ldap_memfree(lretdata);
4258 		} else {
4259 			ZVAL_EMPTY_STRING(retdata);
4260 		}
4261 
4262 		RETVAL_TRUE;
4263 		goto cleanup;
4264 	}
4265 
4266 	/* asynchronous call */
4267 	rc = ldap_extended_operation(ld->link, ZSTR_VAL(reqoid),
4268 		lreqdata.bv_len > 0 ? &lreqdata: NULL,
4269 		lserverctrls,
4270 		NULL,
4271 		&msgid);
4272 	if (rc != LDAP_SUCCESS ) {
4273 		php_error_docref(NULL, E_WARNING, "Extended operation %s failed: %s (%d)", ZSTR_VAL(reqoid), ldap_err2string(rc), rc);
4274 		RETVAL_FALSE;
4275 		goto cleanup;
4276 	}
4277 
4278 	rc = ldap_result(ld->link, msgid, 1 /* LDAP_MSG_ALL */, NULL, &ldap_res);
4279 	if (rc == -1) {
4280 		php_error_docref(NULL, E_WARNING, "Extended operation %s failed", ZSTR_VAL(reqoid));
4281 		RETVAL_FALSE;
4282 		goto cleanup;
4283 	}
4284 
4285 	/* return a PHP control object */
4286 	RETVAL_RES(zend_register_resource(ldap_res, le_result));
4287 
4288 	cleanup:
4289 	if (lserverctrls) {
4290 		_php_ldap_controls_free(&lserverctrls);
4291 	}
4292 }
4293 /* }}} */
4294 #endif
4295 
4296 #ifdef HAVE_LDAP_PASSWD
4297 /* {{{ proto bool|string ldap_exop_passwd(resource link [, string user [, string oldpw [, string newpw [, array ctrls]]]])
4298    Passwd modify extended operation */
PHP_FUNCTION(ldap_exop_passwd)4299 PHP_FUNCTION(ldap_exop_passwd)
4300 {
4301 	zval *link, *serverctrls;
4302 	struct berval luser = { 0L, NULL };
4303 	struct berval loldpw = { 0L, NULL };
4304 	struct berval lnewpw = { 0L, NULL };
4305 	struct berval lgenpasswd = { 0L, NULL };
4306 	LDAPControl *ctrl, **lserverctrls = NULL, *requestctrls[2] = { NULL, NULL };
4307 	LDAPMessage* ldap_res = NULL;
4308 	ldap_linkdata *ld;
4309 	int rc, myargcount = ZEND_NUM_ARGS(), msgid, err;
4310 	char* errmsg = NULL;
4311 
4312 	if (zend_parse_parameters(myargcount, "r|sssz/", &link, &luser.bv_val, &luser.bv_len, &loldpw.bv_val, &loldpw.bv_len, &lnewpw.bv_val, &lnewpw.bv_len, &serverctrls) == FAILURE) {
4313 		return;
4314 	}
4315 
4316 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
4317 		RETVAL_FALSE;
4318 		goto cleanup;
4319 	}
4320 
4321 	switch (myargcount) {
4322 		case 5:
4323 			/* ldap_create_passwordpolicy_control() allocates ctrl */
4324 			if (ldap_create_passwordpolicy_control(ld->link, &ctrl) == LDAP_SUCCESS) {
4325 				requestctrls[0] = ctrl;
4326 			}
4327 	}
4328 
4329 	/* asynchronous call to get result and controls */
4330 	rc = ldap_passwd(ld->link, &luser,
4331 		loldpw.bv_len > 0 ? &loldpw : NULL,
4332 		lnewpw.bv_len > 0 ? &lnewpw : NULL,
4333 		requestctrls,
4334 		NULL, &msgid);
4335 
4336 	if (requestctrls[0] != NULL) {
4337 		ldap_control_free(requestctrls[0]);
4338 	}
4339 
4340 	if (rc != LDAP_SUCCESS ) {
4341 		php_error_docref(NULL, E_WARNING, "Passwd modify extended operation failed: %s (%d)", ldap_err2string(rc), rc);
4342 		RETVAL_FALSE;
4343 		goto cleanup;
4344 	}
4345 
4346 	rc = ldap_result(ld->link, msgid, 1 /* LDAP_MSG_ALL */, NULL, &ldap_res);
4347 	if ((rc < 0) || !ldap_res) {
4348 		rc = _get_lderrno(ld->link);
4349 		php_error_docref(NULL, E_WARNING, "Passwd modify extended operation failed: %s (%d)", ldap_err2string(rc), rc);
4350 		RETVAL_FALSE;
4351 		goto cleanup;
4352 	}
4353 
4354 	rc = ldap_parse_passwd(ld->link, ldap_res, &lgenpasswd);
4355 	if( rc != LDAP_SUCCESS ) {
4356 		php_error_docref(NULL, E_WARNING, "Passwd modify extended operation failed: %s (%d)", ldap_err2string(rc), rc);
4357 		RETVAL_FALSE;
4358 		goto cleanup;
4359 	}
4360 
4361 	rc = ldap_parse_result(ld->link, ldap_res, &err, NULL, &errmsg, NULL, (myargcount > 4 ? &lserverctrls : NULL), 0);
4362 	if( rc != LDAP_SUCCESS ) {
4363 		php_error_docref(NULL, E_WARNING, "Passwd modify extended operation failed: %s (%d)", ldap_err2string(rc), rc);
4364 		RETVAL_FALSE;
4365 		goto cleanup;
4366 	}
4367 
4368 	if (myargcount > 4) {
4369 		zval_ptr_dtor(serverctrls);
4370 		_php_ldap_controls_to_array(ld->link, lserverctrls, serverctrls, 0);
4371 	}
4372 
4373 	/* return */
4374 	if (lnewpw.bv_len == 0) {
4375 		if (lgenpasswd.bv_len == 0) {
4376 			RETVAL_EMPTY_STRING();
4377 		} else {
4378 			RETVAL_STRINGL(lgenpasswd.bv_val, lgenpasswd.bv_len);
4379 		}
4380 	} else if (err == LDAP_SUCCESS) {
4381 		RETVAL_TRUE;
4382 	} else {
4383 		php_error_docref(NULL, E_WARNING, "Passwd modify extended operation failed: %s (%d)", (errmsg ? errmsg : ldap_err2string(err)), err);
4384 		RETVAL_FALSE;
4385 	}
4386 
4387 cleanup:
4388 	if (lgenpasswd.bv_val != NULL) {
4389 		ldap_memfree(lgenpasswd.bv_val);
4390 	}
4391 	if (ldap_res != NULL) {
4392 		ldap_msgfree(ldap_res);
4393 	}
4394 	if (errmsg != NULL) {
4395 		ldap_memfree(errmsg);
4396 	}
4397 }
4398 /* }}} */
4399 #endif
4400 
4401 #ifdef HAVE_LDAP_WHOAMI_S
4402 /* {{{ proto bool|string ldap_exop_whoami(resource link)
4403    Whoami extended operation */
PHP_FUNCTION(ldap_exop_whoami)4404 PHP_FUNCTION(ldap_exop_whoami)
4405 {
4406 	zval *link;
4407 	struct berval *lauthzid;
4408 	ldap_linkdata *ld;
4409 	int rc;
4410 
4411 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &link) == FAILURE) {
4412 		WRONG_PARAM_COUNT;
4413 	}
4414 
4415 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
4416 		RETURN_FALSE;
4417 	}
4418 
4419 	/* synchronous call */
4420 	rc = ldap_whoami_s(ld->link, &lauthzid, NULL, NULL);
4421 	if (rc != LDAP_SUCCESS ) {
4422 		php_error_docref(NULL, E_WARNING, "Whoami extended operation failed: %s (%d)", ldap_err2string(rc), rc);
4423 		RETURN_FALSE;
4424 	}
4425 
4426 	if (lauthzid == NULL) {
4427 		RETVAL_EMPTY_STRING();
4428 	} else {
4429 		RETVAL_STRINGL(lauthzid->bv_val, lauthzid->bv_len);
4430 		ldap_memfree(lauthzid->bv_val);
4431 		ldap_memfree(lauthzid);
4432 	}
4433 }
4434 /* }}} */
4435 #endif
4436 
4437 #ifdef HAVE_LDAP_REFRESH_S
4438 /* {{{ proto bool|int ldap_exop_refresh(resource link , string dn , int ttl)
4439    DDS refresh extended operation */
PHP_FUNCTION(ldap_exop_refresh)4440 PHP_FUNCTION(ldap_exop_refresh)
4441 {
4442 	zval *link, *ttl;
4443 	struct berval ldn;
4444 	ber_int_t lttl;
4445 	ber_int_t newttl;
4446 	ldap_linkdata *ld;
4447 	int rc;
4448 
4449 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsz", &link, &ldn.bv_val, &ldn.bv_len, &ttl) != SUCCESS) {
4450 		WRONG_PARAM_COUNT;
4451 	}
4452 
4453 	if ((ld = (ldap_linkdata *)zend_fetch_resource(Z_RES_P(link), "ldap link", le_link)) == NULL) {
4454 		RETURN_FALSE;
4455 	}
4456 
4457 	lttl = (ber_int_t)zval_get_long(ttl);
4458 
4459 	rc = ldap_refresh_s(ld->link, &ldn, lttl, &newttl, NULL, NULL);
4460 	if (rc != LDAP_SUCCESS ) {
4461 		php_error_docref(NULL, E_WARNING, "Refresh extended operation failed: %s (%d)", ldap_err2string(rc), rc);
4462 		RETURN_FALSE;
4463 	}
4464 
4465 	RETURN_LONG(newttl);
4466 }
4467 /* }}} */
4468 #endif
4469 
4470 /* }}} */
4471 
4472 /* {{{ arginfo */
4473 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_connect, 0, 0, 0)
4474 	ZEND_ARG_INFO(0, hostname)
4475 	ZEND_ARG_INFO(0, port)
4476 #ifdef HAVE_ORALDAP
4477 	ZEND_ARG_INFO(0, wallet)
4478 	ZEND_ARG_INFO(0, wallet_passwd)
4479 	ZEND_ARG_INFO(0, authmode)
4480 #endif
4481 ZEND_END_ARG_INFO()
4482 
4483 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_resource, 0, 0, 1)
4484 	ZEND_ARG_INFO(0, link_identifier)
4485 ZEND_END_ARG_INFO()
4486 
4487 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_bind, 0, 0, 1)
4488 	ZEND_ARG_INFO(0, link_identifier)
4489 	ZEND_ARG_INFO(0, bind_rdn)
4490 	ZEND_ARG_INFO(0, bind_password)
4491 ZEND_END_ARG_INFO()
4492 
4493 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_bind_ext, 0, 0, 1)
4494 	ZEND_ARG_INFO(0, link_identifier)
4495 	ZEND_ARG_INFO(0, bind_rdn)
4496 	ZEND_ARG_INFO(0, bind_password)
4497 	ZEND_ARG_INFO(0, servercontrols)
4498 ZEND_END_ARG_INFO()
4499 
4500 #ifdef HAVE_LDAP_SASL
4501 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_sasl_bind, 0, 0, 1)
4502 	ZEND_ARG_INFO(0, link)
4503 	ZEND_ARG_INFO(0, binddn)
4504 	ZEND_ARG_INFO(0, password)
4505 	ZEND_ARG_INFO(0, sasl_mech)
4506 	ZEND_ARG_INFO(0, sasl_realm)
4507 	ZEND_ARG_INFO(0, sasl_authz_id)
4508 	ZEND_ARG_INFO(0, props)
4509 ZEND_END_ARG_INFO()
4510 #endif
4511 
4512 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_read, 0, 0, 3)
4513 	ZEND_ARG_INFO(0, link_identifier)
4514 	ZEND_ARG_INFO(0, base_dn)
4515 	ZEND_ARG_INFO(0, filter)
4516 	ZEND_ARG_INFO(0, attributes)
4517 	ZEND_ARG_INFO(0, attrsonly)
4518 	ZEND_ARG_INFO(0, sizelimit)
4519 	ZEND_ARG_INFO(0, timelimit)
4520 	ZEND_ARG_INFO(0, deref)
4521 	ZEND_ARG_INFO(0, servercontrols)
4522 ZEND_END_ARG_INFO()
4523 
4524 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_list, 0, 0, 3)
4525 	ZEND_ARG_INFO(0, link_identifier)
4526 	ZEND_ARG_INFO(0, base_dn)
4527 	ZEND_ARG_INFO(0, filter)
4528 	ZEND_ARG_INFO(0, attributes)
4529 	ZEND_ARG_INFO(0, attrsonly)
4530 	ZEND_ARG_INFO(0, sizelimit)
4531 	ZEND_ARG_INFO(0, timelimit)
4532 	ZEND_ARG_INFO(0, deref)
4533 	ZEND_ARG_INFO(0, servercontrols)
4534 ZEND_END_ARG_INFO()
4535 
4536 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_search, 0, 0, 3)
4537 	ZEND_ARG_INFO(0, link_identifier)
4538 	ZEND_ARG_INFO(0, base_dn)
4539 	ZEND_ARG_INFO(0, filter)
4540 	ZEND_ARG_INFO(0, attributes)
4541 	ZEND_ARG_INFO(0, attrsonly)
4542 	ZEND_ARG_INFO(0, sizelimit)
4543 	ZEND_ARG_INFO(0, timelimit)
4544 	ZEND_ARG_INFO(0, deref)
4545 	ZEND_ARG_INFO(0, servercontrols)
4546 ZEND_END_ARG_INFO()
4547 
4548 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_count_entries, 0, 0, 2)
4549 	ZEND_ARG_INFO(0, link_identifier)
4550 	ZEND_ARG_INFO(0, result_identifier)
4551 ZEND_END_ARG_INFO()
4552 
4553 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_first_entry, 0, 0, 2)
4554 	ZEND_ARG_INFO(0, link_identifier)
4555 	ZEND_ARG_INFO(0, result_identifier)
4556 ZEND_END_ARG_INFO()
4557 
4558 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_next_entry, 0, 0, 2)
4559 	ZEND_ARG_INFO(0, link_identifier)
4560 	ZEND_ARG_INFO(0, result_identifier)
4561 ZEND_END_ARG_INFO()
4562 
4563 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_get_entries, 0, 0, 2)
4564 	ZEND_ARG_INFO(0, link_identifier)
4565 	ZEND_ARG_INFO(0, result_identifier)
4566 ZEND_END_ARG_INFO()
4567 
4568 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_first_attribute, 0, 0, 2)
4569 	ZEND_ARG_INFO(0, link_identifier)
4570 	ZEND_ARG_INFO(0, result_entry_identifier)
4571 ZEND_END_ARG_INFO()
4572 
4573 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_next_attribute, 0, 0, 2)
4574 	ZEND_ARG_INFO(0, link_identifier)
4575 	ZEND_ARG_INFO(0, result_entry_identifier)
4576 ZEND_END_ARG_INFO()
4577 
4578 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_get_attributes, 0, 0, 2)
4579 	ZEND_ARG_INFO(0, link_identifier)
4580 	ZEND_ARG_INFO(0, result_entry_identifier)
4581 ZEND_END_ARG_INFO()
4582 
4583 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_get_values, 0, 0, 3)
4584 	ZEND_ARG_INFO(0, link_identifier)
4585 	ZEND_ARG_INFO(0, result_entry_identifier)
4586 	ZEND_ARG_INFO(0, attribute)
4587 ZEND_END_ARG_INFO()
4588 
4589 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_get_values_len, 0, 0, 3)
4590 	ZEND_ARG_INFO(0, link_identifier)
4591 	ZEND_ARG_INFO(0, result_entry_identifier)
4592 	ZEND_ARG_INFO(0, attribute)
4593 ZEND_END_ARG_INFO()
4594 
4595 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_get_dn, 0, 0, 2)
4596 	ZEND_ARG_INFO(0, link_identifier)
4597 	ZEND_ARG_INFO(0, result_entry_identifier)
4598 ZEND_END_ARG_INFO()
4599 
4600 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_explode_dn, 0, 0, 2)
4601 	ZEND_ARG_INFO(0, dn)
4602 	ZEND_ARG_INFO(0, with_attrib)
4603 ZEND_END_ARG_INFO()
4604 
4605 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_dn2ufn, 0, 0, 1)
4606 	ZEND_ARG_INFO(0, dn)
4607 ZEND_END_ARG_INFO()
4608 
4609 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_add, 0, 0, 3)
4610 	ZEND_ARG_INFO(0, link_identifier)
4611 	ZEND_ARG_INFO(0, dn)
4612 	ZEND_ARG_INFO(0, entry)
4613 	ZEND_ARG_INFO(0, servercontrols)
4614 ZEND_END_ARG_INFO()
4615 
4616 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_add_ext, 0, 0, 3)
4617 	ZEND_ARG_INFO(0, link_identifier)
4618 	ZEND_ARG_INFO(0, dn)
4619 	ZEND_ARG_INFO(0, entry)
4620 	ZEND_ARG_INFO(0, servercontrols)
4621 ZEND_END_ARG_INFO()
4622 
4623 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_delete, 0, 0, 2)
4624 	ZEND_ARG_INFO(0, link_identifier)
4625 	ZEND_ARG_INFO(0, dn)
4626 	ZEND_ARG_INFO(0, servercontrols)
4627 ZEND_END_ARG_INFO()
4628 
4629 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_delete_ext, 0, 0, 2)
4630 	ZEND_ARG_INFO(0, link_identifier)
4631 	ZEND_ARG_INFO(0, dn)
4632 	ZEND_ARG_INFO(0, servercontrols)
4633 ZEND_END_ARG_INFO()
4634 
4635 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_modify, 0, 0, 3)
4636 	ZEND_ARG_INFO(0, link_identifier)
4637 	ZEND_ARG_INFO(0, dn)
4638 	ZEND_ARG_INFO(0, entry)
4639 	ZEND_ARG_INFO(0, servercontrols)
4640 ZEND_END_ARG_INFO()
4641 
4642 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_modify_batch, 0, 0, 3)
4643 	ZEND_ARG_INFO(0, link_identifier)
4644 	ZEND_ARG_INFO(0, dn)
4645 	ZEND_ARG_ARRAY_INFO(0, modifications_info, 0)
4646 	ZEND_ARG_INFO(0, servercontrols)
4647 ZEND_END_ARG_INFO()
4648 
4649 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_mod_add, 0, 0, 3)
4650 	ZEND_ARG_INFO(0, link_identifier)
4651 	ZEND_ARG_INFO(0, dn)
4652 	ZEND_ARG_INFO(0, entry)
4653 	ZEND_ARG_INFO(0, servercontrols)
4654 ZEND_END_ARG_INFO()
4655 
4656 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_mod_add_ext, 0, 0, 3)
4657 	ZEND_ARG_INFO(0, link_identifier)
4658 	ZEND_ARG_INFO(0, dn)
4659 	ZEND_ARG_INFO(0, entry)
4660 	ZEND_ARG_INFO(0, servercontrols)
4661 ZEND_END_ARG_INFO()
4662 
4663 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_mod_replace, 0, 0, 3)
4664 	ZEND_ARG_INFO(0, link_identifier)
4665 	ZEND_ARG_INFO(0, dn)
4666 	ZEND_ARG_INFO(0, entry)
4667 	ZEND_ARG_INFO(0, servercontrols)
4668 ZEND_END_ARG_INFO()
4669 
4670 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_mod_replace_ext, 0, 0, 3)
4671 	ZEND_ARG_INFO(0, link_identifier)
4672 	ZEND_ARG_INFO(0, dn)
4673 	ZEND_ARG_INFO(0, entry)
4674 	ZEND_ARG_INFO(0, servercontrols)
4675 ZEND_END_ARG_INFO()
4676 
4677 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_mod_del, 0, 0, 3)
4678 	ZEND_ARG_INFO(0, link_identifier)
4679 	ZEND_ARG_INFO(0, dn)
4680 	ZEND_ARG_INFO(0, entry)
4681 	ZEND_ARG_INFO(0, servercontrols)
4682 ZEND_END_ARG_INFO()
4683 
4684 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_mod_del_ext, 0, 0, 3)
4685 	ZEND_ARG_INFO(0, link_identifier)
4686 	ZEND_ARG_INFO(0, dn)
4687 	ZEND_ARG_INFO(0, entry)
4688 	ZEND_ARG_INFO(0, servercontrols)
4689 ZEND_END_ARG_INFO()
4690 
4691 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_err2str, 0, 0, 1)
4692 	ZEND_ARG_INFO(0, errno)
4693 ZEND_END_ARG_INFO()
4694 
4695 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_compare, 0, 0, 4)
4696 	ZEND_ARG_INFO(0, link_identifier)
4697 	ZEND_ARG_INFO(0, dn)
4698 	ZEND_ARG_INFO(0, attribute)
4699 	ZEND_ARG_INFO(0, value)
4700 	ZEND_ARG_INFO(0, servercontrols)
4701 ZEND_END_ARG_INFO()
4702 
4703 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_sort, 0, 0, 3)
4704 	ZEND_ARG_INFO(0, link)
4705 	ZEND_ARG_INFO(0, result)
4706 	ZEND_ARG_INFO(0, sortfilter)
4707 ZEND_END_ARG_INFO()
4708 
4709 #ifdef LDAP_CONTROL_PAGEDRESULTS
4710 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_control_paged_result, 0, 0, 2)
4711 	ZEND_ARG_INFO(0, link)
4712 	ZEND_ARG_INFO(0, pagesize)
4713 	ZEND_ARG_INFO(0, iscritical)
4714 	ZEND_ARG_INFO(0, cookie)
4715 ZEND_END_ARG_INFO();
4716 
4717 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_control_paged_result_response, 0, 0, 2)
4718 	ZEND_ARG_INFO(0, link)
4719 	ZEND_ARG_INFO(0, result)
4720 	ZEND_ARG_INFO(1, cookie)
4721 	ZEND_ARG_INFO(1, estimated)
4722 ZEND_END_ARG_INFO();
4723 #endif
4724 
4725 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP
4726 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_rename, 0, 0, 5)
4727 	ZEND_ARG_INFO(0, link_identifier)
4728 	ZEND_ARG_INFO(0, dn)
4729 	ZEND_ARG_INFO(0, newrdn)
4730 	ZEND_ARG_INFO(0, newparent)
4731 	ZEND_ARG_INFO(0, deleteoldrdn)
4732 	ZEND_ARG_INFO(0, servercontrols)
4733 ZEND_END_ARG_INFO()
4734 
4735 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_rename_ext, 0, 0, 5)
4736 	ZEND_ARG_INFO(0, link_identifier)
4737 	ZEND_ARG_INFO(0, dn)
4738 	ZEND_ARG_INFO(0, newrdn)
4739 	ZEND_ARG_INFO(0, newparent)
4740 	ZEND_ARG_INFO(0, deleteoldrdn)
4741 	ZEND_ARG_INFO(0, servercontrols)
4742 ZEND_END_ARG_INFO()
4743 
4744 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_get_option, 0, 0, 3)
4745 	ZEND_ARG_INFO(0, link_identifier)
4746 	ZEND_ARG_INFO(0, option)
4747 	ZEND_ARG_INFO(1, retval)
4748 ZEND_END_ARG_INFO()
4749 
4750 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_set_option, 0, 0, 3)
4751 	ZEND_ARG_INFO(0, link_identifier)
4752 	ZEND_ARG_INFO(0, option)
4753 	ZEND_ARG_INFO(0, newval)
4754 ZEND_END_ARG_INFO()
4755 
4756 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_first_reference, 0, 0, 2)
4757 	ZEND_ARG_INFO(0, link)
4758 	ZEND_ARG_INFO(0, result)
4759 ZEND_END_ARG_INFO()
4760 
4761 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_next_reference, 0, 0, 2)
4762 	ZEND_ARG_INFO(0, link)
4763 	ZEND_ARG_INFO(0, entry)
4764 ZEND_END_ARG_INFO()
4765 
4766 #ifdef HAVE_LDAP_PARSE_REFERENCE
4767 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_parse_reference, 0, 0, 3)
4768 	ZEND_ARG_INFO(0, link)
4769 	ZEND_ARG_INFO(0, entry)
4770 	ZEND_ARG_INFO(1, referrals)
4771 ZEND_END_ARG_INFO()
4772 #endif
4773 
4774 
4775 #ifdef HAVE_LDAP_PARSE_RESULT
4776 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_parse_result, 0, 0, 3)
4777 	ZEND_ARG_INFO(0, link)
4778 	ZEND_ARG_INFO(0, result)
4779 	ZEND_ARG_INFO(1, errcode)
4780 	ZEND_ARG_INFO(1, matcheddn)
4781 	ZEND_ARG_INFO(1, errmsg)
4782 	ZEND_ARG_INFO(1, referrals)
4783 	ZEND_ARG_INFO(1, serverctrls)
4784 ZEND_END_ARG_INFO()
4785 #endif
4786 #endif
4787 
4788 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)
4789 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_set_rebind_proc, 0, 0, 2)
4790 	ZEND_ARG_INFO(0, link)
4791 	ZEND_ARG_INFO(0, callback)
4792 ZEND_END_ARG_INFO()
4793 #endif
4794 
4795 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_escape, 0, 0, 1)
4796 	ZEND_ARG_INFO(0, value)
4797 	ZEND_ARG_INFO(0, ignore)
4798 	ZEND_ARG_INFO(0, flags)
4799 ZEND_END_ARG_INFO()
4800 
4801 #ifdef STR_TRANSLATION
4802 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_t61_to_8859, 0, 0, 1)
4803 	ZEND_ARG_INFO(0, value)
4804 ZEND_END_ARG_INFO()
4805 
4806 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_8859_to_t61, 0, 0, 1)
4807 	ZEND_ARG_INFO(0, value)
4808 ZEND_END_ARG_INFO()
4809 #endif
4810 
4811 #ifdef HAVE_LDAP_EXTENDED_OPERATION_S
4812 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_exop, 0, 0, 2)
4813 	ZEND_ARG_INFO(0, link)
4814 	ZEND_ARG_INFO(0, reqoid)
4815 	ZEND_ARG_INFO(0, reqdata)
4816 	ZEND_ARG_INFO(0, servercontrols)
4817 	ZEND_ARG_INFO(1, retdata)
4818 	ZEND_ARG_INFO(1, retoid)
4819 ZEND_END_ARG_INFO()
4820 #endif
4821 
4822 #ifdef HAVE_LDAP_PASSWD
4823 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_exop_passwd, 0, 0, 1)
4824 	ZEND_ARG_INFO(0, link)
4825 	ZEND_ARG_INFO(0, user)
4826 	ZEND_ARG_INFO(0, oldpw)
4827 	ZEND_ARG_INFO(0, newpw)
4828 	ZEND_ARG_INFO(1, serverctrls)
4829 ZEND_END_ARG_INFO()
4830 #endif
4831 
4832 #ifdef HAVE_LDAP_WHOAMI_S
4833 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_exop_whoami, 0, 0, 1)
4834 	ZEND_ARG_INFO(0, link)
4835 ZEND_END_ARG_INFO()
4836 #endif
4837 
4838 #ifdef HAVE_LDAP_REFRESH_S
4839 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_exop_refresh, 0, 0, 3)
4840 	ZEND_ARG_INFO(0, link)
4841 	ZEND_ARG_INFO(0, dn)
4842 	ZEND_ARG_INFO(0, ttl)
4843 ZEND_END_ARG_INFO()
4844 #endif
4845 
4846 #ifdef HAVE_LDAP_PARSE_EXTENDED_RESULT
4847 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_parse_exop, 0, 0, 4)
4848 	ZEND_ARG_INFO(0, link)
4849 	ZEND_ARG_INFO(0, result)
4850 	ZEND_ARG_INFO(1, retdata)
4851 	ZEND_ARG_INFO(1, retoid)
4852 ZEND_END_ARG_INFO()
4853 #endif
4854 /* }}} */
4855 
4856 /*
4857 	This is just a small subset of the functionality provided by the LDAP library. All the
4858 	operations are synchronous. Referrals are not handled automatically.
4859 */
4860 /* {{{ ldap_functions[]
4861  */
4862 static const zend_function_entry ldap_functions[] = {
4863 	PHP_FE(ldap_connect,								arginfo_ldap_connect)
4864 	PHP_FALIAS(ldap_close,		ldap_unbind,			arginfo_ldap_resource)
4865 	PHP_FE(ldap_bind,									arginfo_ldap_bind)
4866 	PHP_FE(ldap_bind_ext,								arginfo_ldap_bind_ext)
4867 #ifdef HAVE_LDAP_SASL
4868 	PHP_FE(ldap_sasl_bind,								arginfo_ldap_sasl_bind)
4869 #endif
4870 	PHP_FE(ldap_unbind,									arginfo_ldap_resource)
4871 	PHP_FE(ldap_read,									arginfo_ldap_read)
4872 	PHP_FE(ldap_list,									arginfo_ldap_list)
4873 	PHP_FE(ldap_search,									arginfo_ldap_search)
4874 	PHP_FE(ldap_free_result,							arginfo_ldap_resource)
4875 	PHP_FE(ldap_count_entries,							arginfo_ldap_count_entries)
4876 	PHP_FE(ldap_first_entry,							arginfo_ldap_first_entry)
4877 	PHP_FE(ldap_next_entry,								arginfo_ldap_next_entry)
4878 	PHP_FE(ldap_get_entries,							arginfo_ldap_get_entries)
4879 	PHP_FE(ldap_first_attribute,						arginfo_ldap_first_attribute)
4880 	PHP_FE(ldap_next_attribute,							arginfo_ldap_next_attribute)
4881 	PHP_FE(ldap_get_attributes,							arginfo_ldap_get_attributes)
4882 	PHP_FALIAS(ldap_get_values,	ldap_get_values_len,	arginfo_ldap_get_values)
4883 	PHP_FE(ldap_get_values_len,							arginfo_ldap_get_values_len)
4884 	PHP_FE(ldap_get_dn,									arginfo_ldap_get_dn)
4885 	PHP_FE(ldap_explode_dn,								arginfo_ldap_explode_dn)
4886 	PHP_FE(ldap_dn2ufn,									arginfo_ldap_dn2ufn)
4887 	PHP_FE(ldap_add,									arginfo_ldap_add)
4888 	PHP_FE(ldap_add_ext,								arginfo_ldap_add_ext)
4889 	PHP_FE(ldap_delete,									arginfo_ldap_delete)
4890 	PHP_FE(ldap_delete_ext,								arginfo_ldap_delete_ext)
4891 	PHP_FE(ldap_modify_batch,							arginfo_ldap_modify_batch)
4892 	PHP_FALIAS(ldap_modify,		ldap_mod_replace,		arginfo_ldap_modify)
4893 
4894 /* additional functions for attribute based modifications, Gerrit Thomson */
4895 	PHP_FE(ldap_mod_add,								arginfo_ldap_mod_add)
4896 	PHP_FE(ldap_mod_add_ext,							arginfo_ldap_mod_add_ext)
4897 	PHP_FE(ldap_mod_replace,							arginfo_ldap_mod_replace)
4898 	PHP_FE(ldap_mod_replace_ext,						arginfo_ldap_mod_replace_ext)
4899 	PHP_FE(ldap_mod_del,								arginfo_ldap_mod_del)
4900 	PHP_FE(ldap_mod_del_ext,							arginfo_ldap_mod_del_ext)
4901 /* end gjt mod */
4902 
4903 	PHP_FE(ldap_errno,									arginfo_ldap_resource)
4904 	PHP_FE(ldap_err2str,								arginfo_ldap_err2str)
4905 	PHP_FE(ldap_error,									arginfo_ldap_resource)
4906 	PHP_FE(ldap_compare,								arginfo_ldap_compare)
4907 	PHP_DEP_FE(ldap_sort,									arginfo_ldap_sort)
4908 
4909 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP
4910 	PHP_FE(ldap_rename,									arginfo_ldap_rename)
4911 	PHP_FE(ldap_rename_ext,								arginfo_ldap_rename_ext)
4912 	PHP_FE(ldap_get_option,								arginfo_ldap_get_option)
4913 	PHP_FE(ldap_set_option,								arginfo_ldap_set_option)
4914 	PHP_FE(ldap_first_reference,						arginfo_ldap_first_reference)
4915 	PHP_FE(ldap_next_reference,							arginfo_ldap_next_reference)
4916 #ifdef HAVE_LDAP_PARSE_REFERENCE
4917 	PHP_FE(ldap_parse_reference,						arginfo_ldap_parse_reference)
4918 #endif
4919 #ifdef HAVE_LDAP_PARSE_RESULT
4920 	PHP_FE(ldap_parse_result,							arginfo_ldap_parse_result)
4921 #endif
4922 #ifdef HAVE_LDAP_START_TLS_S
4923 	PHP_FE(ldap_start_tls,								arginfo_ldap_resource)
4924 #endif
4925 #ifdef HAVE_LDAP_EXTENDED_OPERATION_S
4926 	PHP_FE(ldap_exop,									arginfo_ldap_exop)
4927 #endif
4928 #ifdef HAVE_LDAP_PASSWD
4929 	PHP_FE(ldap_exop_passwd,							arginfo_ldap_exop_passwd)
4930 #endif
4931 #ifdef HAVE_LDAP_WHOAMI_S
4932 	PHP_FE(ldap_exop_whoami,							arginfo_ldap_exop_whoami)
4933 #endif
4934 #ifdef HAVE_LDAP_REFRESH_S
4935 	PHP_FE(ldap_exop_refresh,							arginfo_ldap_exop_refresh)
4936 #endif
4937 #ifdef HAVE_LDAP_PARSE_EXTENDED_RESULT
4938 	PHP_FE(ldap_parse_exop,								arginfo_ldap_parse_exop)
4939 #endif
4940 #endif
4941 
4942 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)
4943 	PHP_FE(ldap_set_rebind_proc,						arginfo_ldap_set_rebind_proc)
4944 #endif
4945 
4946 	PHP_FE(ldap_escape,									arginfo_ldap_escape)
4947 
4948 #ifdef STR_TRANSLATION
4949 	PHP_FE(ldap_t61_to_8859,							arginfo_ldap_t61_to_8859)
4950 	PHP_FE(ldap_8859_to_t61,							arginfo_ldap_8859_to_t61)
4951 #endif
4952 
4953 #ifdef LDAP_CONTROL_PAGEDRESULTS
4954 	PHP_FE(ldap_control_paged_result,							arginfo_ldap_control_paged_result)
4955 	PHP_FE(ldap_control_paged_result_response,		arginfo_ldap_control_paged_result_response)
4956 #endif
4957 	PHP_FE_END
4958 };
4959 /* }}} */
4960 
4961 zend_module_entry ldap_module_entry = { /* {{{ */
4962 	STANDARD_MODULE_HEADER,
4963 	"ldap",
4964 	ldap_functions,
4965 	PHP_MINIT(ldap),
4966 	PHP_MSHUTDOWN(ldap),
4967 	NULL,
4968 	NULL,
4969 	PHP_MINFO(ldap),
4970 	PHP_LDAP_VERSION,
4971 	PHP_MODULE_GLOBALS(ldap),
4972 	PHP_GINIT(ldap),
4973 	NULL,
4974 	NULL,
4975 	STANDARD_MODULE_PROPERTIES_EX
4976 };
4977 /* }}} */
4978 
4979 /*
4980  * Local variables:
4981  * tab-width: 4
4982  * c-basic-offset: 4
4983  * End:
4984  * vim600: sw=4 ts=4 fdm=marker
4985  * vim<600: sw=4 ts=4
4986  */
4987