Back to index

php5  5.3.10
ldap.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Authors: Amitay Isaacs  <amitay@w-o-i.com>                           |
00016    |          Eric Warnke    <ericw@albany.edu>                           |
00017    |          Rasmus Lerdorf <rasmus@php.net>                             |
00018    |          Gerrit Thomson <334647@swin.edu.au>                         |
00019    |          Jani Taskinen  <sniper@iki.fi>                              |
00020    |          Stig Venaas    <venaas@uninett.no>                          |
00021    |          Doug Goldstein <cardoe@cardoe.com>                          |
00022    | PHP 4.0 updates:  Zeev Suraski <zeev@zend.com>                       |
00023    +----------------------------------------------------------------------+
00024  */
00025  
00026 /* $Id: ldap.c 321634 2012-01-01 13:15:04Z felipe $ */
00027 #define IS_EXT_MODULE
00028 
00029 #ifdef HAVE_CONFIG_H
00030 #include "config.h"
00031 #endif
00032 
00033 /* Additional headers for NetWare */
00034 #if defined(NETWARE) && (NEW_LIBC)
00035 #include <sys/select.h>
00036 #include <sys/timeval.h>
00037 #endif
00038 
00039 #include "php.h"
00040 #include "php_ini.h"
00041 
00042 #include <stddef.h>
00043 
00044 #include "ext/standard/dl.h"
00045 #include "php_ldap.h"
00046 
00047 #ifdef PHP_WIN32
00048 #include <string.h>
00049 #include "config.w32.h"
00050 #if HAVE_NSLDAP
00051 #include <winsock2.h>
00052 #endif
00053 #define strdup _strdup
00054 #undef WINDOWS
00055 #undef strcasecmp
00056 #undef strncasecmp
00057 #define WINSOCK 1
00058 #define __STDC__ 1
00059 #endif
00060 
00061 #include "ext/standard/php_string.h"
00062 #include "ext/standard/info.h"
00063 
00064 #ifdef HAVE_LDAP_SASL_H
00065 #include <sasl.h>
00066 #elif defined(HAVE_LDAP_SASL_SASL_H)
00067 #include <sasl/sasl.h>
00068 #endif
00069 
00070 typedef struct {
00071        LDAP *link;
00072 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)
00073        zval *rebindproc;
00074 #endif
00075 } ldap_linkdata;
00076 
00077 typedef struct {
00078        LDAPMessage *data;
00079        BerElement *ber;
00080        int id;
00081 } ldap_resultentry;
00082 
00083 ZEND_DECLARE_MODULE_GLOBALS(ldap)
00084 static PHP_GINIT_FUNCTION(ldap);
00085 
00086 static int le_link, le_result, le_result_entry;
00087 
00088 #ifdef COMPILE_DL_LDAP
00089 ZEND_GET_MODULE(ldap)
00090 #endif
00091 
00092 static void _close_ldap_link(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
00093 {
00094        ldap_linkdata *ld = (ldap_linkdata *)rsrc->ptr;
00095 
00096        ldap_unbind_s(ld->link);
00097 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)
00098        if (ld->rebindproc != NULL) {
00099               zval_dtor(ld->rebindproc);
00100               FREE_ZVAL(ld->rebindproc);
00101        }
00102 #endif
00103        efree(ld);
00104        LDAPG(num_links)--;
00105 }
00106 /* }}} */
00107 
00108 static void _free_ldap_result(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
00109 {
00110        LDAPMessage *result = (LDAPMessage *)rsrc->ptr;
00111        ldap_msgfree(result);
00112 }
00113 /* }}} */
00114 
00115 static void _free_ldap_result_entry(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
00116 {
00117        ldap_resultentry *entry = (ldap_resultentry *)rsrc->ptr;
00118 
00119        if (entry->ber != NULL) {
00120               ber_free(entry->ber, 0);
00121               entry->ber = NULL;
00122        }
00123        zend_list_delete(entry->id);
00124        efree(entry);
00125 } 
00126 /* }}} */
00127 
00128 /* {{{ PHP_INI_BEGIN
00129  */
00130 PHP_INI_BEGIN()
00131        STD_PHP_INI_ENTRY_EX("ldap.max_links", "-1", PHP_INI_SYSTEM, OnUpdateLong, max_links, zend_ldap_globals, ldap_globals, display_link_numbers)
00132 PHP_INI_END()
00133 /* }}} */
00134 
00135 /* {{{ PHP_GINIT_FUNCTION
00136  */
00137 static PHP_GINIT_FUNCTION(ldap)
00138 {
00139        ldap_globals->num_links = 0;
00140 }
00141 /* }}} */
00142 
00143 /* {{{ PHP_MINIT_FUNCTION
00144  */
00145 PHP_MINIT_FUNCTION(ldap)
00146 {
00147        REGISTER_INI_ENTRIES();
00148 
00149        /* Constants to be used with deref-parameter in php_ldap_do_search() */
00150        REGISTER_LONG_CONSTANT("LDAP_DEREF_NEVER", LDAP_DEREF_NEVER, CONST_PERSISTENT | CONST_CS);
00151        REGISTER_LONG_CONSTANT("LDAP_DEREF_SEARCHING", LDAP_DEREF_SEARCHING, CONST_PERSISTENT | CONST_CS);
00152        REGISTER_LONG_CONSTANT("LDAP_DEREF_FINDING", LDAP_DEREF_FINDING, CONST_PERSISTENT | CONST_CS);
00153        REGISTER_LONG_CONSTANT("LDAP_DEREF_ALWAYS", LDAP_DEREF_ALWAYS, CONST_PERSISTENT | CONST_CS);
00154 
00155 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10
00156        /* LDAP options */
00157        REGISTER_LONG_CONSTANT("LDAP_OPT_DEREF", LDAP_OPT_DEREF, CONST_PERSISTENT | CONST_CS);
00158        REGISTER_LONG_CONSTANT("LDAP_OPT_SIZELIMIT", LDAP_OPT_SIZELIMIT, CONST_PERSISTENT | CONST_CS);
00159        REGISTER_LONG_CONSTANT("LDAP_OPT_TIMELIMIT", LDAP_OPT_TIMELIMIT, CONST_PERSISTENT | CONST_CS);
00160 #ifdef LDAP_OPT_NETWORK_TIMEOUT
00161        REGISTER_LONG_CONSTANT("LDAP_OPT_NETWORK_TIMEOUT", LDAP_OPT_NETWORK_TIMEOUT, CONST_PERSISTENT | CONST_CS);
00162 #elif defined (LDAP_X_OPT_CONNECT_TIMEOUT)
00163        REGISTER_LONG_CONSTANT("LDAP_OPT_NETWORK_TIMEOUT", LDAP_X_OPT_CONNECT_TIMEOUT, CONST_PERSISTENT | CONST_CS);
00164 #endif
00165        REGISTER_LONG_CONSTANT("LDAP_OPT_PROTOCOL_VERSION", LDAP_OPT_PROTOCOL_VERSION, CONST_PERSISTENT | CONST_CS);
00166        REGISTER_LONG_CONSTANT("LDAP_OPT_ERROR_NUMBER", LDAP_OPT_ERROR_NUMBER, CONST_PERSISTENT | CONST_CS);
00167        REGISTER_LONG_CONSTANT("LDAP_OPT_REFERRALS", LDAP_OPT_REFERRALS, CONST_PERSISTENT | CONST_CS);
00168 #ifdef LDAP_OPT_RESTART
00169        REGISTER_LONG_CONSTANT("LDAP_OPT_RESTART", LDAP_OPT_RESTART, CONST_PERSISTENT | CONST_CS);
00170 #endif
00171 #ifdef LDAP_OPT_HOST_NAME
00172        REGISTER_LONG_CONSTANT("LDAP_OPT_HOST_NAME", LDAP_OPT_HOST_NAME, CONST_PERSISTENT | CONST_CS);
00173 #endif
00174        REGISTER_LONG_CONSTANT("LDAP_OPT_ERROR_STRING", LDAP_OPT_ERROR_STRING, CONST_PERSISTENT | CONST_CS);
00175 #ifdef LDAP_OPT_MATCHED_DN
00176        REGISTER_LONG_CONSTANT("LDAP_OPT_MATCHED_DN", LDAP_OPT_MATCHED_DN, CONST_PERSISTENT | CONST_CS);
00177 #endif
00178        REGISTER_LONG_CONSTANT("LDAP_OPT_SERVER_CONTROLS", LDAP_OPT_SERVER_CONTROLS, CONST_PERSISTENT | CONST_CS);
00179        REGISTER_LONG_CONSTANT("LDAP_OPT_CLIENT_CONTROLS", LDAP_OPT_CLIENT_CONTROLS, CONST_PERSISTENT | CONST_CS);
00180 #endif
00181 #ifdef LDAP_OPT_DEBUG_LEVEL
00182        REGISTER_LONG_CONSTANT("LDAP_OPT_DEBUG_LEVEL", LDAP_OPT_DEBUG_LEVEL, CONST_PERSISTENT | CONST_CS);
00183 #endif
00184 
00185 #ifdef HAVE_LDAP_SASL
00186        REGISTER_LONG_CONSTANT("LDAP_OPT_X_SASL_MECH", LDAP_OPT_X_SASL_MECH, CONST_PERSISTENT | CONST_CS);
00187        REGISTER_LONG_CONSTANT("LDAP_OPT_X_SASL_REALM", LDAP_OPT_X_SASL_REALM, CONST_PERSISTENT | CONST_CS);
00188        REGISTER_LONG_CONSTANT("LDAP_OPT_X_SASL_AUTHCID", LDAP_OPT_X_SASL_AUTHCID, CONST_PERSISTENT | CONST_CS);
00189        REGISTER_LONG_CONSTANT("LDAP_OPT_X_SASL_AUTHZID", LDAP_OPT_X_SASL_AUTHZID, CONST_PERSISTENT | CONST_CS);
00190 #endif
00191 
00192 #ifdef ORALDAP
00193        REGISTER_LONG_CONSTANT("GSLC_SSL_NO_AUTH", GSLC_SSL_NO_AUTH, CONST_PERSISTENT | CONST_CS);
00194        REGISTER_LONG_CONSTANT("GSLC_SSL_ONEWAY_AUTH", GSLC_SSL_ONEWAY_AUTH, CONST_PERSISTENT | CONST_CS);
00195        REGISTER_LONG_CONSTANT("GSLC_SSL_TWOWAY_AUTH", GSLC_SSL_TWOWAY_AUTH, CONST_PERSISTENT | CONST_CS);
00196 #endif
00197 
00198        le_link = zend_register_list_destructors_ex(_close_ldap_link, NULL, "ldap link", module_number);
00199        le_result = zend_register_list_destructors_ex(_free_ldap_result, NULL, "ldap result", module_number);
00200        le_result_entry = zend_register_list_destructors_ex(_free_ldap_result_entry, NULL, "ldap result entry", module_number);
00201 
00202        Z_TYPE(ldap_module_entry) = type;
00203 
00204        return SUCCESS;
00205 }
00206 /* }}} */
00207 
00208 /* {{{ PHP_MSHUTDOWN_FUNCTION
00209  */
00210 PHP_MSHUTDOWN_FUNCTION(ldap)
00211 {
00212        UNREGISTER_INI_ENTRIES();
00213        return SUCCESS;
00214 }
00215 /* }}} */
00216 
00217 /* {{{ PHP_MINFO_FUNCTION
00218  */
00219 PHP_MINFO_FUNCTION(ldap)
00220 {
00221        char tmp[32];
00222 #if HAVE_NSLDAP
00223        LDAPVersion ver;
00224        double SDKVersion;
00225 #endif
00226 
00227        php_info_print_table_start();
00228        php_info_print_table_row(2, "LDAP Support", "enabled");
00229        php_info_print_table_row(2, "RCS Version", "$Id: ldap.c 321634 2012-01-01 13:15:04Z felipe $");
00230 
00231        if (LDAPG(max_links) == -1) {
00232               snprintf(tmp, 31, "%ld/unlimited", LDAPG(num_links));
00233        } else {
00234               snprintf(tmp, 31, "%ld/%ld", LDAPG(num_links), LDAPG(max_links));
00235        }
00236        php_info_print_table_row(2, "Total Links", tmp);
00237 
00238 #ifdef LDAP_API_VERSION
00239        snprintf(tmp, 31, "%d", LDAP_API_VERSION);
00240        php_info_print_table_row(2, "API Version", tmp);
00241 #endif
00242 
00243 #ifdef LDAP_VENDOR_NAME
00244        php_info_print_table_row(2, "Vendor Name", LDAP_VENDOR_NAME);
00245 #endif
00246 
00247 #ifdef LDAP_VENDOR_VERSION
00248        snprintf(tmp, 31, "%d", LDAP_VENDOR_VERSION);
00249        php_info_print_table_row(2, "Vendor Version", tmp);
00250 #endif
00251 
00252 #if HAVE_NSLDAP
00253        SDKVersion = ldap_version(&ver);
00254        snprintf(tmp, 31, "%F", SDKVersion/100.0);
00255        php_info_print_table_row(2, "SDK Version", tmp);
00256 
00257        snprintf(tmp, 31, "%F", ver.protocol_version/100.0);
00258        php_info_print_table_row(2, "Highest LDAP Protocol Supported", tmp);
00259 
00260        snprintf(tmp, 31, "%F", ver.SSL_version/100.0);
00261        php_info_print_table_row(2, "SSL Level Supported", tmp);
00262 
00263        if (ver.security_level != LDAP_SECURITY_NONE) {
00264               snprintf(tmp, 31, "%d", ver.security_level);
00265        } else {
00266               strcpy(tmp, "SSL not enabled");
00267        }
00268        php_info_print_table_row(2, "Level of Encryption", tmp);
00269 #endif
00270 
00271 #ifdef HAVE_LDAP_SASL
00272        php_info_print_table_row(2, "SASL Support", "Enabled");
00273 #endif
00274 
00275        php_info_print_table_end();
00276        DISPLAY_INI_ENTRIES();
00277 }
00278 /* }}} */
00279 
00280 /* {{{ proto resource ldap_connect([string host [, int port [, string wallet [, string wallet_passwd [, int authmode]]]]])
00281    Connect to an LDAP server */
00282 PHP_FUNCTION(ldap_connect)
00283 {
00284        char *host = NULL;
00285        int hostlen;
00286        long port = 389; /* Default port */
00287 #ifdef HAVE_ORALDAP
00288        char *wallet = NULL, *walletpasswd = NULL;
00289        int walletlen = 0, walletpasswdlen = 0;
00290        long authmode = GSLC_SSL_NO_AUTH;
00291        int ssl=0;
00292 #endif
00293        ldap_linkdata *ld;
00294        LDAP *ldap;
00295 
00296 #ifdef HAVE_ORALDAP
00297        if (ZEND_NUM_ARGS() == 3 || ZEND_NUM_ARGS() == 4) {
00298               WRONG_PARAM_COUNT;
00299        }
00300 
00301        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|slssl", &host, &hostlen, &port, &wallet, &walletlen, &walletpasswd, &walletpasswdlen, &authmode) != SUCCESS) {
00302               RETURN_FALSE;
00303        }
00304 
00305        if (ZEND_NUM_ARGS() == 5) {
00306               ssl = 1;
00307        }
00308 #else
00309        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sl", &host, &hostlen, &port) != SUCCESS) {
00310               RETURN_FALSE;
00311        }
00312 #endif
00313 
00314        if (LDAPG(max_links) != -1 && LDAPG(num_links) >= LDAPG(max_links)) {
00315               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Too many open links (%ld)", LDAPG(num_links));
00316               RETURN_FALSE;
00317        }
00318 
00319        ld = ecalloc(1, sizeof(ldap_linkdata));
00320 
00321 #ifdef LDAP_API_FEATURE_X_OPENLDAP
00322        if (host != NULL && strchr(host, '/')) {
00323               int rc;
00324               
00325               rc = ldap_initialize(&ldap, host);
00326               if (rc != LDAP_SUCCESS) {
00327                      efree(ld);
00328                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not create session handle: %s", ldap_err2string(rc));
00329                      RETURN_FALSE;
00330               }
00331        } else {
00332               ldap = ldap_init(host, port);
00333        }
00334 #else
00335        ldap = ldap_open(host, port);
00336 #endif
00337        
00338        if (ldap == NULL) {
00339               efree(ld);
00340               RETURN_FALSE;
00341        } else {
00342 #ifdef HAVE_ORALDAP
00343               if (ssl) {
00344                      if (ldap_init_SSL(&ldap->ld_sb, wallet, walletpasswd, authmode)) {
00345                             efree(ld);
00346                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSL init failed");
00347                             RETURN_FALSE;
00348                      }
00349               }                    
00350 #endif
00351               LDAPG(num_links)++;
00352               ld->link = ldap;
00353               ZEND_REGISTER_RESOURCE(return_value, ld, le_link);
00354        }
00355 
00356 }
00357 /* }}} */
00358 
00359 /* {{{ _get_lderrno
00360  */
00361 static int _get_lderrno(LDAP *ldap)
00362 {
00363 #if !HAVE_NSLDAP
00364 #if LDAP_API_VERSION > 2000 || HAVE_ORALDAP_10
00365        int lderr;
00366 
00367        /* New versions of OpenLDAP do it this way */
00368        ldap_get_option(ldap, LDAP_OPT_ERROR_NUMBER, &lderr);
00369        return lderr;
00370 #else
00371        return ldap->ld_errno;
00372 #endif
00373 #else
00374        return ldap_get_lderrno(ldap, NULL, NULL);
00375 #endif
00376 }
00377 /* }}} */
00378 
00379 /* {{{ proto bool ldap_bind(resource link [, string dn [, string password]])
00380    Bind to LDAP directory */
00381 PHP_FUNCTION(ldap_bind)
00382 {
00383        zval *link;
00384        char *ldap_bind_dn = NULL, *ldap_bind_pw = NULL;
00385        int ldap_bind_dnlen, ldap_bind_pwlen;
00386        ldap_linkdata *ld;
00387        int rc;
00388 
00389        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|ss", &link, &ldap_bind_dn, &ldap_bind_dnlen, &ldap_bind_pw, &ldap_bind_pwlen) != SUCCESS) {
00390               RETURN_FALSE;
00391        }
00392 
00393        ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
00394 
00395        if ((rc = ldap_bind_s(ld->link, ldap_bind_dn, ldap_bind_pw, LDAP_AUTH_SIMPLE)) != LDAP_SUCCESS) {
00396               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to bind to server: %s", ldap_err2string(rc));
00397               RETURN_FALSE;
00398        } else {
00399               RETURN_TRUE;
00400        }
00401 }
00402 /* }}} */
00403 
00404 #ifdef HAVE_LDAP_SASL
00405 typedef struct {
00406        char *mech;
00407        char *realm;
00408        char *authcid;
00409        char *passwd;
00410        char *authzid;
00411 } php_ldap_bictx;
00412 
00413 /* {{{ _php_sasl_setdefs
00414  */
00415 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)
00416 {
00417        php_ldap_bictx *ctx;
00418 
00419        ctx = ber_memalloc(sizeof(php_ldap_bictx));      
00420        ctx->mech    = (sasl_mech) ? ber_strdup(sasl_mech) : NULL;
00421        ctx->realm   = (sasl_realm) ? ber_strdup(sasl_realm) : NULL;
00422        ctx->authcid = (sasl_authc_id) ? ber_strdup(sasl_authc_id) : NULL;
00423        ctx->passwd  = (passwd) ? ber_strdup(passwd) : NULL;
00424        ctx->authzid = (sasl_authz_id) ? ber_strdup(sasl_authz_id) : NULL;
00425 
00426        if (ctx->mech == NULL) {
00427               ldap_get_option(ld, LDAP_OPT_X_SASL_MECH, &ctx->mech);
00428        }
00429        if (ctx->realm == NULL) {
00430               ldap_get_option(ld, LDAP_OPT_X_SASL_REALM, &ctx->realm);
00431        }
00432        if (ctx->authcid == NULL) {
00433               ldap_get_option(ld, LDAP_OPT_X_SASL_AUTHCID, &ctx->authcid);
00434        }
00435        if (ctx->authzid == NULL) {
00436               ldap_get_option(ld, LDAP_OPT_X_SASL_AUTHZID, &ctx->authzid);
00437        }
00438 
00439        return ctx;
00440 }
00441 /* }}} */
00442 
00443 /* {{{ _php_sasl_freedefs
00444  */
00445 static void _php_sasl_freedefs(php_ldap_bictx *ctx)
00446 {
00447        if (ctx->mech) ber_memfree(ctx->mech);
00448        if (ctx->realm) ber_memfree(ctx->realm);
00449        if (ctx->authcid) ber_memfree(ctx->authcid);
00450        if (ctx->passwd) ber_memfree(ctx->passwd);
00451        if (ctx->authzid) ber_memfree(ctx->authzid);
00452        ber_memfree(ctx);
00453 }
00454 /* }}} */
00455 
00456 /* {{{ _php_sasl_interact
00457    Internal interact function for SASL */
00458 static int _php_sasl_interact(LDAP *ld, unsigned flags, void *defaults, void *in)
00459 {
00460        sasl_interact_t *interact = in;
00461        const char *p;
00462        php_ldap_bictx *ctx = defaults;
00463 
00464        for (;interact->id != SASL_CB_LIST_END;interact++) {
00465               p = NULL;
00466               switch(interact->id) {
00467                      case SASL_CB_GETREALM:
00468                             p = ctx->realm;
00469                             break;
00470                      case SASL_CB_AUTHNAME:
00471                             p = ctx->authcid;
00472                             break;
00473                      case SASL_CB_USER:
00474                             p = ctx->authzid;
00475                             break;
00476                      case SASL_CB_PASS:
00477                             p = ctx->passwd;
00478                             break;
00479               }
00480               if (p) {
00481                      interact->result = p;
00482                      interact->len = strlen(interact->result);
00483               }
00484        }
00485        return LDAP_SUCCESS;
00486 }
00487 /* }}} */
00488 
00489 /* {{{ 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]]]]]]])
00490    Bind to LDAP directory using SASL */
00491 PHP_FUNCTION(ldap_sasl_bind)
00492 {
00493        zval *link;
00494        ldap_linkdata *ld;
00495        char *binddn = NULL;
00496        char *passwd = NULL;
00497        char *sasl_mech = NULL;
00498        char *sasl_realm = NULL;
00499        char *sasl_authz_id = NULL;
00500        char *sasl_authc_id = NULL;
00501        char *props = NULL;
00502        int rc, dn_len, passwd_len, mech_len, realm_len, authc_id_len, authz_id_len, props_len;
00503        php_ldap_bictx *ctx;
00504 
00505        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|sssssss", &link, &binddn, &dn_len, &passwd, &passwd_len, &sasl_mech, &mech_len, &sasl_realm, &realm_len, &sasl_authc_id, &authc_id_len, &sasl_authz_id, &authz_id_len, &props, &props_len) != SUCCESS) {
00506               RETURN_FALSE;
00507        }
00508 
00509        ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
00510 
00511        ctx = _php_sasl_setdefs(ld->link, sasl_mech, sasl_realm, sasl_authc_id, passwd, sasl_authz_id);
00512 
00513        if (props) {
00514               ldap_set_option(ld->link, LDAP_OPT_X_SASL_SECPROPS, props);
00515        }
00516 
00517        rc = ldap_sasl_interactive_bind_s(ld->link, binddn, ctx->mech, NULL, NULL, LDAP_SASL_QUIET, _php_sasl_interact, ctx);
00518        if (rc != LDAP_SUCCESS) {
00519               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to bind to server: %s", ldap_err2string(rc));
00520               RETVAL_FALSE;
00521        } else {
00522               RETVAL_TRUE;
00523        }
00524        _php_sasl_freedefs(ctx);
00525 }
00526 /* }}} */
00527 #endif /* HAVE_LDAP_SASL */
00528 
00529 /* {{{ proto bool ldap_unbind(resource link)
00530    Unbind from LDAP directory */
00531 PHP_FUNCTION(ldap_unbind)
00532 {
00533        zval *link;
00534        ldap_linkdata *ld;
00535 
00536        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &link) != SUCCESS) {
00537               RETURN_FALSE;
00538        }
00539 
00540        ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
00541 
00542        zend_list_delete(Z_LVAL_P(link));
00543        RETURN_TRUE;
00544 }
00545 /* }}} */
00546 
00547 /* {{{ php_set_opts
00548  */
00549 static void php_set_opts(LDAP *ldap, int sizelimit, int timelimit, int deref, int *old_sizelimit, int *old_timelimit, int *old_deref)
00550 {
00551        /* sizelimit */
00552        if (sizelimit > -1) {
00553 #if (LDAP_API_VERSION >= 2004) || HAVE_NSLDAP || HAVE_ORALDAP_10
00554               ldap_get_option(ldap, LDAP_OPT_SIZELIMIT, old_sizelimit);
00555               ldap_set_option(ldap, LDAP_OPT_SIZELIMIT, &sizelimit);
00556 #else
00557               *old_sizelimit = ldap->ld_sizelimit; 
00558               ldap->ld_sizelimit = sizelimit; 
00559 #endif
00560        }
00561 
00562        /* timelimit */
00563        if (timelimit > -1) {
00564 #if (LDAP_API_VERSION >= 2004) || HAVE_NSLDAP || HAVE_ORALDAP_10
00565               ldap_get_option(ldap, LDAP_OPT_SIZELIMIT, old_timelimit);
00566               ldap_set_option(ldap, LDAP_OPT_TIMELIMIT, &timelimit);
00567 #else
00568               *old_timelimit = ldap->ld_timelimit; 
00569               ldap->ld_timelimit = timelimit; 
00570 #endif
00571        }
00572 
00573        /* deref */
00574        if (deref > -1) {
00575 #if (LDAP_API_VERSION >= 2004) || HAVE_NSLDAP || HAVE_ORALDAP_10
00576               ldap_get_option(ldap, LDAP_OPT_SIZELIMIT, old_deref);
00577               ldap_set_option(ldap, LDAP_OPT_DEREF, &deref);
00578 #else
00579               *old_deref = ldap->ld_deref; 
00580               ldap->ld_deref = deref; 
00581 #endif
00582        }
00583 }
00584 /* }}} */
00585 
00586 /* {{{ php_ldap_do_search
00587  */
00588 static void php_ldap_do_search(INTERNAL_FUNCTION_PARAMETERS, int scope)
00589 {
00590        zval *link, *base_dn, **filter, *attrs, **attr;
00591        long attrsonly, sizelimit, timelimit, deref;
00592        char *ldap_base_dn = NULL, *ldap_filter = NULL, **ldap_attrs = NULL; 
00593        ldap_linkdata *ld = NULL;
00594        LDAPMessage *ldap_res;
00595        int ldap_attrsonly = 0, ldap_sizelimit = -1, ldap_timelimit = -1, ldap_deref = -1;   
00596        int old_ldap_sizelimit = -1, old_ldap_timelimit = -1, old_ldap_deref = -1;    
00597        int num_attribs = 0, ret = 1, i, errno, argcount = ZEND_NUM_ARGS();
00598 
00599        if (zend_parse_parameters(argcount TSRMLS_CC, "zzZ|allll", &link, &base_dn, &filter, &attrs, &attrsonly,
00600               &sizelimit, &timelimit, &deref) == FAILURE) {
00601               return;
00602        }
00603 
00604        /* Reverse -> fall through */
00605        switch (argcount) {
00606               case 8:
00607                      ldap_deref = deref;
00608               case 7:
00609                      ldap_timelimit = timelimit;
00610               case 6:
00611                      ldap_sizelimit = sizelimit;
00612               case 5:
00613                      ldap_attrsonly = attrsonly;
00614               case 4:
00615                      num_attribs = zend_hash_num_elements(Z_ARRVAL_P(attrs));
00616                      ldap_attrs = safe_emalloc((num_attribs+1), sizeof(char *), 0);
00617 
00618                      for (i = 0; i<num_attribs; i++) {
00619                             if (zend_hash_index_find(Z_ARRVAL_P(attrs), i, (void **) &attr) != SUCCESS) {
00620                                    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array initialization wrong");
00621                                    ret = 0;
00622                                    goto cleanup;
00623                             }
00624 
00625                             SEPARATE_ZVAL(attr);
00626                             convert_to_string_ex(attr);
00627                             ldap_attrs[i] = Z_STRVAL_PP(attr);
00628                      }
00629                      ldap_attrs[num_attribs] = NULL;
00630               default:
00631                      break;
00632        }
00633 
00634        /* parallel search? */
00635        if (Z_TYPE_P(link) == IS_ARRAY) {
00636               int i, nlinks, nbases, nfilters, *rcs;
00637               ldap_linkdata **lds;
00638               zval **entry, *resource;
00639               
00640               nlinks = zend_hash_num_elements(Z_ARRVAL_P(link));
00641               if (nlinks == 0) {
00642                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "No links in link array");
00643                      ret = 0;
00644                      goto cleanup;
00645               }
00646 
00647               if (Z_TYPE_P(base_dn) == IS_ARRAY) {
00648                      nbases = zend_hash_num_elements(Z_ARRVAL_P(base_dn));
00649                      if (nbases != nlinks) {
00650                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Base must either be a string, or an array with the same number of elements as the links array");
00651                             ret = 0;
00652                             goto cleanup;
00653                      }
00654                      zend_hash_internal_pointer_reset(Z_ARRVAL_P(base_dn));
00655               } else {
00656                      nbases = 0; /* this means string, not array */
00657                      /* If anything else than string is passed, ldap_base_dn = NULL */
00658                      if (Z_TYPE_P(base_dn) == IS_STRING) {
00659                             ldap_base_dn = Z_STRVAL_P(base_dn);
00660                      } else {
00661                             ldap_base_dn = NULL;
00662                      }
00663               }
00664 
00665               if (Z_TYPE_PP(filter) == IS_ARRAY) {
00666                      nfilters = zend_hash_num_elements(Z_ARRVAL_PP(filter));
00667                      if (nfilters != nlinks) {
00668                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Filter must either be a string, or an array with the same number of elements as the links array");
00669                             ret = 0;
00670                             goto cleanup;
00671                      }
00672                      zend_hash_internal_pointer_reset(Z_ARRVAL_PP(filter));
00673               } else {
00674                      nfilters = 0; /* this means string, not array */
00675                      convert_to_string_ex(filter);
00676                      ldap_filter = Z_STRVAL_PP(filter);
00677               }
00678 
00679               lds = safe_emalloc(nlinks, sizeof(ldap_linkdata), 0);
00680               rcs = safe_emalloc(nlinks, sizeof(*rcs), 0);
00681               
00682               zend_hash_internal_pointer_reset(Z_ARRVAL_P(link));
00683               for (i=0; i<nlinks; i++) {
00684                      zend_hash_get_current_data(Z_ARRVAL_P(link), (void **)&entry);
00685 
00686                      ld = (ldap_linkdata *) zend_fetch_resource(entry TSRMLS_CC, -1, "ldap link", NULL, 1, le_link);
00687                      if (ld == NULL) {
00688                             ret = 0;
00689                             goto cleanup_parallel;
00690                      }
00691                      if (nbases != 0) { /* base_dn an array? */
00692                             zend_hash_get_current_data(Z_ARRVAL_P(base_dn), (void **)&entry);
00693                             zend_hash_move_forward(Z_ARRVAL_P(base_dn));
00694 
00695                             /* If anything else than string is passed, ldap_base_dn = NULL */
00696                             if (Z_TYPE_PP(entry) == IS_STRING) {
00697                                    ldap_base_dn = Z_STRVAL_PP(entry);
00698                             } else {
00699                                    ldap_base_dn = NULL;
00700                             }
00701                      }
00702                      if (nfilters != 0) { /* filter an array? */
00703                             zend_hash_get_current_data(Z_ARRVAL_PP(filter), (void **)&entry);
00704                             zend_hash_move_forward(Z_ARRVAL_PP(filter));
00705                             convert_to_string_ex(entry);
00706                             ldap_filter = Z_STRVAL_PP(entry);
00707                      }
00708 
00709                      php_set_opts(ld->link, ldap_sizelimit, ldap_timelimit, ldap_deref, &old_ldap_sizelimit, &old_ldap_timelimit, &old_ldap_deref);
00710 
00711                      /* Run the actual search */ 
00712                      rcs[i] = ldap_search(ld->link, ldap_base_dn, scope, ldap_filter, ldap_attrs, ldap_attrsonly);
00713                      lds[i] = ld;
00714                      zend_hash_move_forward(Z_ARRVAL_P(link));
00715               }
00716               
00717               array_init(return_value);
00718 
00719               /* Collect results from the searches */
00720               for (i=0; i<nlinks; i++) {
00721                      MAKE_STD_ZVAL(resource);
00722                      if (rcs[i] != -1) {
00723                             rcs[i] = ldap_result(lds[i]->link, LDAP_RES_ANY, 1 /* LDAP_MSG_ALL */, NULL, &ldap_res);
00724                      }
00725                      if (rcs[i] != -1) {
00726                             ZEND_REGISTER_RESOURCE(resource, ldap_res, le_result);
00727                             add_next_index_zval(return_value, resource);
00728                      } else {
00729                             add_next_index_bool(return_value, 0);
00730                      }
00731               }
00732 
00733 cleanup_parallel:
00734               efree(lds);
00735               efree(rcs);
00736        } else {
00737               convert_to_string_ex(filter);
00738               ldap_filter = Z_STRVAL_PP(filter);
00739 
00740               /* If anything else than string is passed, ldap_base_dn = NULL */
00741               if (Z_TYPE_P(base_dn) == IS_STRING) {
00742                      ldap_base_dn = Z_STRVAL_P(base_dn);
00743               }
00744 
00745               ld = (ldap_linkdata *) zend_fetch_resource(&link TSRMLS_CC, -1, "ldap link", NULL, 1, le_link);
00746               if (ld == NULL) {
00747                      ret = 0;
00748                      goto cleanup;
00749               }
00750 
00751               php_set_opts(ld->link, ldap_sizelimit, ldap_timelimit, ldap_deref, &old_ldap_sizelimit, &old_ldap_timelimit, &old_ldap_deref);
00752 
00753               /* Run the actual search */ 
00754               errno = ldap_search_s(ld->link, ldap_base_dn, scope, ldap_filter, ldap_attrs, ldap_attrsonly, &ldap_res);
00755        
00756               if (errno != LDAP_SUCCESS
00757                      && errno != LDAP_SIZELIMIT_EXCEEDED
00758 #ifdef LDAP_ADMINLIMIT_EXCEEDED
00759                      && errno != LDAP_ADMINLIMIT_EXCEEDED
00760 #endif
00761 #ifdef LDAP_REFERRAL
00762                      && errno != LDAP_REFERRAL
00763 #endif
00764               ) {
00765                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Search: %s", ldap_err2string(errno));
00766                      ret = 0;
00767               } else {
00768                      if (errno == LDAP_SIZELIMIT_EXCEEDED) {
00769                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Partial search results returned: Sizelimit exceeded");
00770                      }
00771 #ifdef LDAP_ADMINLIMIT_EXCEEDED
00772                      else if (errno == LDAP_ADMINLIMIT_EXCEEDED) {
00773                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Partial search results returned: Adminlimit exceeded");
00774                      }
00775 #endif
00776                      
00777                      ZEND_REGISTER_RESOURCE(return_value, ldap_res, le_result);
00778               }
00779        }
00780 
00781 cleanup:
00782        if (ld) {
00783               /* Restoring previous options */
00784               php_set_opts(ld->link, old_ldap_sizelimit, old_ldap_timelimit, old_ldap_deref, &ldap_sizelimit, &ldap_timelimit, &ldap_deref);
00785        }
00786        if (ldap_attrs != NULL) {
00787               efree(ldap_attrs);
00788        }
00789        if (!ret) {
00790               RETVAL_BOOL(ret);
00791        }
00792 }
00793 /* }}} */
00794 
00795 /* {{{ proto resource ldap_read(resource|array link, string base_dn, string filter [, array attrs [, int attrsonly [, int sizelimit [, int timelimit [, int deref]]]]])
00796    Read an entry */
00797 PHP_FUNCTION(ldap_read)
00798 {
00799        php_ldap_do_search(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_SCOPE_BASE);
00800 }
00801 /* }}} */
00802 
00803 /* {{{ proto resource ldap_list(resource|array link, string base_dn, string filter [, array attrs [, int attrsonly [, int sizelimit [, int timelimit [, int deref]]]]])
00804    Single-level search */
00805 PHP_FUNCTION(ldap_list)
00806 {
00807        php_ldap_do_search(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_SCOPE_ONELEVEL);
00808 }
00809 /* }}} */
00810 
00811 /* {{{ proto resource ldap_search(resource|array link, string base_dn, string filter [, array attrs [, int attrsonly [, int sizelimit [, int timelimit [, int deref]]]]])
00812    Search LDAP tree under base_dn */
00813 PHP_FUNCTION(ldap_search)
00814 {
00815        php_ldap_do_search(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_SCOPE_SUBTREE);
00816 }
00817 /* }}} */
00818 
00819 /* {{{ proto bool ldap_free_result(resource result)
00820    Free result memory */
00821 PHP_FUNCTION(ldap_free_result)
00822 {
00823        zval *result;
00824        LDAPMessage *ldap_result;
00825 
00826        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &result) != SUCCESS) {
00827               return;
00828        }
00829 
00830        ZEND_FETCH_RESOURCE(ldap_result, LDAPMessage *, &result, -1, "ldap result", le_result);
00831 
00832        zend_list_delete(Z_LVAL_P(result));  /* Delete list entry */
00833        RETVAL_TRUE;
00834 }
00835 /* }}} */
00836 
00837 /* {{{ proto int ldap_count_entries(resource link, resource result)
00838    Count the number of entries in a search result */
00839 PHP_FUNCTION(ldap_count_entries)
00840 {
00841        zval *link, *result;
00842        ldap_linkdata *ld;
00843        LDAPMessage *ldap_result;
00844 
00845        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &link, &result) != SUCCESS) {
00846               return;
00847        }
00848 
00849        ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
00850        ZEND_FETCH_RESOURCE(ldap_result, LDAPMessage *, &result, -1, "ldap result", le_result);
00851 
00852        RETURN_LONG(ldap_count_entries(ld->link, ldap_result));
00853 }
00854 /* }}} */
00855 
00856 /* {{{ proto resource ldap_first_entry(resource link, resource result)
00857    Return first result id */
00858 PHP_FUNCTION(ldap_first_entry)
00859 {
00860        zval *link, *result;
00861        ldap_linkdata *ld;   
00862        ldap_resultentry *resultentry;
00863        LDAPMessage *ldap_result, *entry;
00864 
00865        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &link, &result) != SUCCESS) {
00866               return;
00867        }
00868 
00869        ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
00870        ZEND_FETCH_RESOURCE(ldap_result, LDAPMessage *, &result, -1, "ldap result", le_result);
00871 
00872        if ((entry = ldap_first_entry(ld->link, ldap_result)) == NULL) {
00873               RETVAL_FALSE;
00874        } else {
00875               resultentry = emalloc(sizeof(ldap_resultentry));
00876               ZEND_REGISTER_RESOURCE(return_value, resultentry, le_result_entry);
00877               resultentry->id = Z_LVAL_P(result);
00878               zend_list_addref(resultentry->id);
00879               resultentry->data = entry;
00880               resultentry->ber = NULL;
00881        }
00882 }
00883 /* }}} */
00884 
00885 /* {{{ proto resource ldap_next_entry(resource link, resource result_entry)
00886    Get next result entry */
00887 PHP_FUNCTION(ldap_next_entry)
00888 {
00889        zval *link, *result_entry;
00890        ldap_linkdata *ld;
00891        ldap_resultentry *resultentry, *resultentry_next;
00892        LDAPMessage *entry_next;
00893 
00894        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &link, &result_entry) != SUCCESS) {
00895               return;
00896        }
00897 
00898        ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
00899        ZEND_FETCH_RESOURCE(resultentry, ldap_resultentry *, &result_entry, -1, "ldap result entry", le_result_entry);
00900 
00901        if ((entry_next = ldap_next_entry(ld->link, resultentry->data)) == NULL) {
00902               RETVAL_FALSE;
00903        } else {
00904               resultentry_next = emalloc(sizeof(ldap_resultentry));
00905               ZEND_REGISTER_RESOURCE(return_value, resultentry_next, le_result_entry);
00906               resultentry_next->id = resultentry->id;
00907               zend_list_addref(resultentry->id);
00908               resultentry_next->data = entry_next;
00909               resultentry_next->ber = NULL;
00910        }
00911 }
00912 /* }}} */
00913 
00914 /* {{{ proto array ldap_get_entries(resource link, resource result)
00915    Get all result entries */
00916 PHP_FUNCTION(ldap_get_entries)
00917 {
00918        zval *link, *result;
00919        LDAPMessage *ldap_result, *ldap_result_entry;
00920        zval *tmp1, *tmp2;
00921        ldap_linkdata *ld;
00922        LDAP *ldap;
00923        int num_entries, num_attrib, num_values, i;
00924        BerElement *ber;
00925        char *attribute;
00926        size_t attr_len;
00927        struct berval **ldap_value;
00928        char *dn;
00929 
00930        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &link, &result) != SUCCESS) {
00931               return;
00932        }
00933 
00934        ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
00935        ZEND_FETCH_RESOURCE(ldap_result, LDAPMessage *, &result, -1, "ldap result", le_result);
00936 
00937        ldap = ld->link;
00938        num_entries = ldap_count_entries(ldap, ldap_result);
00939 
00940        array_init(return_value);
00941        add_assoc_long(return_value, "count", num_entries);
00942 
00943        if (num_entries == 0) {
00944               return;
00945        }
00946        
00947        ldap_result_entry = ldap_first_entry(ldap, ldap_result);
00948        if (ldap_result_entry == NULL) {
00949               zval_dtor(return_value);
00950               RETURN_FALSE;
00951        }
00952 
00953        num_entries = 0;
00954        while (ldap_result_entry != NULL) {
00955               MAKE_STD_ZVAL(tmp1);
00956               array_init(tmp1);
00957 
00958               num_attrib = 0;
00959               attribute = ldap_first_attribute(ldap, ldap_result_entry, &ber);
00960 
00961               while (attribute != NULL) {
00962                      ldap_value = ldap_get_values_len(ldap, ldap_result_entry, attribute);
00963                      num_values = ldap_count_values_len(ldap_value);
00964 
00965                      MAKE_STD_ZVAL(tmp2);
00966                      array_init(tmp2);
00967                      add_assoc_long(tmp2, "count", num_values);
00968                      for (i = 0; i < num_values; i++) {
00969                             add_index_stringl(tmp2, i, ldap_value[i]->bv_val, ldap_value[i]->bv_len, 1);
00970                      }      
00971                      ldap_value_free_len(ldap_value);
00972 
00973                      attr_len = strlen(attribute);
00974                      zend_hash_update(Z_ARRVAL_P(tmp1), php_strtolower(attribute, attr_len), attr_len+1, (void *) &tmp2, sizeof(zval *), NULL);
00975                      add_index_string(tmp1, num_attrib, attribute, 1);
00976 
00977                      num_attrib++;
00978 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10 || WINDOWS
00979                      ldap_memfree(attribute);
00980 #endif
00981                      attribute = ldap_next_attribute(ldap, ldap_result_entry, ber);
00982               }
00983 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10 || WINDOWS
00984               if (ber != NULL) {
00985                      ber_free(ber, 0);
00986               }
00987 #endif
00988 
00989               add_assoc_long(tmp1, "count", num_attrib);
00990               dn = ldap_get_dn(ldap, ldap_result_entry);
00991               add_assoc_string(tmp1, "dn", dn, 1);
00992 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10 || WINDOWS
00993               ldap_memfree(dn);
00994 #else
00995               free(dn);
00996 #endif
00997 
00998               zend_hash_index_update(Z_ARRVAL_P(return_value), num_entries, (void *) &tmp1, sizeof(zval *), NULL);
00999               
01000               num_entries++;
01001               ldap_result_entry = ldap_next_entry(ldap, ldap_result_entry);
01002        }
01003 
01004        add_assoc_long(return_value, "count", num_entries);
01005 
01006 }
01007 /* }}} */
01008 
01009 /* {{{ proto string ldap_first_attribute(resource link, resource result_entry)
01010    Return first attribute */
01011 PHP_FUNCTION(ldap_first_attribute)
01012 {
01013        zval *link, *result_entry;
01014        ldap_linkdata *ld;
01015        ldap_resultentry *resultentry;
01016        char *attribute;
01017        long dummy_ber;
01018 
01019        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr|l", &link, &result_entry, &dummy_ber) != SUCCESS) {
01020               return;
01021        }
01022 
01023        ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
01024        ZEND_FETCH_RESOURCE(resultentry, ldap_resultentry *, &result_entry, -1, "ldap result entry", le_result_entry);
01025 
01026        if ((attribute = ldap_first_attribute(ld->link, resultentry->data, &resultentry->ber)) == NULL) {
01027               RETURN_FALSE;
01028        } else {
01029               RETVAL_STRING(attribute, 1);
01030 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10 || WINDOWS
01031               ldap_memfree(attribute);
01032 #endif
01033        }
01034 }
01035 /* }}} */
01036 
01037 /* {{{ proto string ldap_next_attribute(resource link, resource result_entry)
01038    Get the next attribute in result */
01039 PHP_FUNCTION(ldap_next_attribute)
01040 {
01041        zval *link, *result_entry;
01042        ldap_linkdata *ld;
01043        ldap_resultentry *resultentry;
01044        char *attribute;
01045        long dummy_ber;
01046 
01047        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr|l", &link, &result_entry, &dummy_ber) != SUCCESS) {
01048               return;
01049        }
01050 
01051        ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
01052        ZEND_FETCH_RESOURCE(resultentry, ldap_resultentry *, &result_entry, -1, "ldap result entry", le_result_entry);
01053 
01054        if (resultentry->ber == NULL) {
01055               php_error_docref(NULL TSRMLS_CC, E_WARNING, "called before calling ldap_first_attribute() or no attributes found in result entry");
01056               RETURN_FALSE;
01057        }
01058 
01059        if ((attribute = ldap_next_attribute(ld->link, resultentry->data, resultentry->ber)) == NULL) {
01060 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10 || WINDOWS
01061               if (resultentry->ber != NULL) {
01062                      ber_free(resultentry->ber, 0);
01063                      resultentry->ber = NULL;
01064               }
01065 #endif
01066               RETURN_FALSE;
01067        } else {
01068               RETVAL_STRING(attribute, 1);
01069 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10 || WINDOWS
01070               ldap_memfree(attribute);
01071 #endif
01072        }
01073 }
01074 /* }}} */
01075 
01076 /* {{{ proto array ldap_get_attributes(resource link, resource result_entry)
01077    Get attributes from a search result entry */
01078 PHP_FUNCTION(ldap_get_attributes)
01079 {
01080        zval *link, *result_entry;
01081        zval *tmp;
01082        ldap_linkdata *ld;
01083        ldap_resultentry *resultentry;
01084        char *attribute;
01085        struct berval **ldap_value;
01086        int i, num_values, num_attrib;
01087        BerElement *ber;
01088 
01089        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &link, &result_entry) != SUCCESS) {
01090               return;
01091        }
01092 
01093        ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
01094        ZEND_FETCH_RESOURCE(resultentry, ldap_resultentry *, &result_entry, -1, "ldap result entry", le_result_entry);
01095 
01096        array_init(return_value);
01097        num_attrib = 0;
01098        
01099        attribute = ldap_first_attribute(ld->link, resultentry->data, &ber);
01100        while (attribute != NULL) {
01101               ldap_value = ldap_get_values_len(ld->link, resultentry->data, attribute);
01102               num_values = ldap_count_values_len(ldap_value);
01103 
01104               MAKE_STD_ZVAL(tmp);
01105               array_init(tmp);
01106               add_assoc_long(tmp, "count", num_values);
01107               for (i = 0; i < num_values; i++) {
01108                      add_index_stringl(tmp, i, ldap_value[i]->bv_val, ldap_value[i]->bv_len, 1);
01109               }
01110               ldap_value_free_len(ldap_value);
01111 
01112               zend_hash_update(Z_ARRVAL_P(return_value), attribute, strlen(attribute)+1, (void *) &tmp, sizeof(zval *), NULL);
01113               add_index_string(return_value, num_attrib, attribute, 1);
01114 
01115               num_attrib++;
01116 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10 || WINDOWS
01117               ldap_memfree(attribute);
01118 #endif
01119               attribute = ldap_next_attribute(ld->link, resultentry->data, ber);
01120        }
01121 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10 || WINDOWS
01122        if (ber != NULL) {
01123               ber_free(ber, 0);
01124        }
01125 #endif
01126        
01127        add_assoc_long(return_value, "count", num_attrib);
01128 }
01129 /* }}} */
01130 
01131 /* {{{ proto array ldap_get_values_len(resource link, resource result_entry, string attribute)
01132    Get all values with lengths from a result entry */
01133 PHP_FUNCTION(ldap_get_values_len)
01134 {
01135        zval *link, *result_entry;
01136        ldap_linkdata *ld;
01137        ldap_resultentry *resultentry;
01138        char *attr;
01139        struct berval **ldap_value_len;
01140        int i, num_values, attr_len;
01141        
01142        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rrs", &link, &result_entry, &attr, &attr_len) != SUCCESS) {
01143               return;
01144        }
01145        
01146        ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
01147        ZEND_FETCH_RESOURCE(resultentry, ldap_resultentry *, &result_entry, -1, "ldap result entry", le_result_entry);
01148 
01149        if ((ldap_value_len = ldap_get_values_len(ld->link, resultentry->data, attr)) == NULL) {
01150               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot get the value(s) of attribute %s", ldap_err2string(_get_lderrno(ld->link)));
01151               RETURN_FALSE;
01152        }
01153        
01154        num_values = ldap_count_values_len(ldap_value_len);
01155        array_init(return_value);
01156        
01157        for (i=0; i<num_values; i++) {
01158               add_next_index_stringl(return_value, ldap_value_len[i]->bv_val, ldap_value_len[i]->bv_len, 1);
01159        }
01160        
01161        add_assoc_long(return_value, "count", num_values);
01162        ldap_value_free_len(ldap_value_len);
01163 
01164 }
01165 /* }}} */
01166 
01167 /* {{{ proto string ldap_get_dn(resource link, resource result_entry)
01168    Get the DN of a result entry */
01169 PHP_FUNCTION(ldap_get_dn) 
01170 {
01171        zval *link, *result_entry;
01172        ldap_linkdata *ld;
01173        ldap_resultentry *resultentry;
01174        char *text;
01175 
01176        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &link, &result_entry) != SUCCESS) {
01177               return;
01178        }
01179        
01180        ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
01181        ZEND_FETCH_RESOURCE(resultentry, ldap_resultentry *, &result_entry, -1, "ldap result entry", le_result_entry);
01182 
01183        text = ldap_get_dn(ld->link, resultentry->data);
01184        if (text != NULL) {
01185               RETVAL_STRING(text, 1);
01186 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10 || WINDOWS
01187               ldap_memfree(text);
01188 #else
01189               free(text);
01190 #endif
01191        } else {
01192               RETURN_FALSE;
01193        }
01194 }
01195 /* }}} */
01196 
01197 /* {{{ proto array ldap_explode_dn(string dn, int with_attrib)
01198    Splits DN into its component parts */
01199 PHP_FUNCTION(ldap_explode_dn)
01200 {
01201        long with_attrib;
01202        char *dn, **ldap_value;
01203        int i, count, dn_len;
01204 
01205        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &dn, &dn_len, &with_attrib) != SUCCESS) {
01206               return;
01207        }
01208 
01209        if (!(ldap_value = ldap_explode_dn(dn, with_attrib))) {
01210               /* Invalid parameters were passed to ldap_explode_dn */
01211               RETURN_FALSE;
01212        }
01213 
01214        i=0;
01215        while (ldap_value[i] != NULL) i++;
01216        count = i;
01217 
01218        array_init(return_value);
01219 
01220        add_assoc_long(return_value, "count", count);
01221        for (i = 0; i<count; i++) {
01222               add_index_string(return_value, i, ldap_value[i], 1);
01223        }
01224 
01225        ldap_value_free(ldap_value);
01226 }
01227 /* }}} */
01228 
01229 /* {{{ proto string ldap_dn2ufn(string dn)
01230    Convert DN to User Friendly Naming format */
01231 PHP_FUNCTION(ldap_dn2ufn)
01232 {
01233        char *dn, *ufn;
01234        int dn_len;
01235 
01236        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &dn, &dn_len) != SUCCESS) {
01237               return;
01238        }
01239        
01240        ufn = ldap_dn2ufn(dn);
01241        
01242        if (ufn != NULL) {
01243               RETVAL_STRING(ufn, 1);
01244 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10 || WINDOWS
01245               ldap_memfree(ufn);
01246 #endif
01247        } else {
01248               RETURN_FALSE;
01249        }
01250 }
01251 /* }}} */
01252 
01253 
01254 /* added to fix use of ldap_modify_add for doing an ldap_add, gerrit thomson. */
01255 #define PHP_LD_FULL_ADD 0xff
01256 /* {{{ php_ldap_do_modify
01257  */
01258 static void php_ldap_do_modify(INTERNAL_FUNCTION_PARAMETERS, int oper)
01259 {
01260        zval *link, *entry, **value, **ivalue;
01261        ldap_linkdata *ld;
01262        char *dn;
01263        LDAPMod **ldap_mods;
01264        int i, j, num_attribs, num_values, dn_len;
01265        int *num_berval;
01266        char *attribute;
01267        ulong index;
01268        int is_full_add=0; /* flag for full add operation so ldap_mod_add can be put back into oper, gerrit THomson */
01269 
01270        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsa", &link, &dn, &dn_len, &entry) != SUCCESS) {
01271               return;
01272        }      
01273 
01274        ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
01275 
01276        num_attribs = zend_hash_num_elements(Z_ARRVAL_P(entry));
01277        ldap_mods = safe_emalloc((num_attribs+1), sizeof(LDAPMod *), 0);
01278        num_berval = safe_emalloc(num_attribs, sizeof(int), 0);
01279        zend_hash_internal_pointer_reset(Z_ARRVAL_P(entry));
01280 
01281        /* added by gerrit thomson to fix ldap_add using ldap_mod_add */
01282        if (oper == PHP_LD_FULL_ADD) {
01283               oper = LDAP_MOD_ADD;
01284               is_full_add = 1;
01285        }
01286        /* end additional , gerrit thomson */
01287 
01288        for (i = 0; i < num_attribs; i++) {
01289               ldap_mods[i] = emalloc(sizeof(LDAPMod));
01290               ldap_mods[i]->mod_op = oper | LDAP_MOD_BVALUES;
01291               ldap_mods[i]->mod_type = NULL;
01292 
01293               if (zend_hash_get_current_key(Z_ARRVAL_P(entry), &attribute, &index, 0) == HASH_KEY_IS_STRING) {
01294                      ldap_mods[i]->mod_type = estrdup(attribute);
01295               } else {
01296                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown attribute in the data");
01297                      /* Free allocated memory */
01298                      while (i >= 0) {
01299                             if (ldap_mods[i]->mod_type) {
01300                                    efree(ldap_mods[i]->mod_type);
01301                             }
01302                             efree(ldap_mods[i]);
01303                             i--;
01304                      }
01305                      efree(num_berval);
01306                      efree(ldap_mods);    
01307                      RETURN_FALSE;
01308               }
01309 
01310               zend_hash_get_current_data(Z_ARRVAL_P(entry), (void **)&value);
01311 
01312               if (Z_TYPE_PP(value) != IS_ARRAY) {
01313                      num_values = 1;
01314               } else {
01315                      num_values = zend_hash_num_elements(Z_ARRVAL_PP(value));
01316               }
01317               
01318               num_berval[i] = num_values;
01319               ldap_mods[i]->mod_bvalues = safe_emalloc((num_values + 1), sizeof(struct berval *), 0);
01320 
01321 /* allow for arrays with one element, no allowance for arrays with none but probably not required, gerrit thomson. */
01322               if ((num_values == 1) && (Z_TYPE_PP(value) != IS_ARRAY)) {
01323                      convert_to_string_ex(value);
01324                      ldap_mods[i]->mod_bvalues[0] = (struct berval *) emalloc (sizeof(struct berval));
01325                      ldap_mods[i]->mod_bvalues[0]->bv_len = Z_STRLEN_PP(value);
01326                      ldap_mods[i]->mod_bvalues[0]->bv_val = Z_STRVAL_PP(value);
01327               } else {      
01328                      for (j = 0; j < num_values; j++) {
01329                             if (zend_hash_index_find(Z_ARRVAL_PP(value), j, (void **) &ivalue) != SUCCESS) {
01330                                    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Value array must have consecutive indices 0, 1, ...");
01331                                    num_berval[i] = j;
01332                                    num_attribs = i + 1;
01333                                    RETVAL_FALSE;
01334                                    goto errexit;
01335                             }
01336                             convert_to_string_ex(ivalue);
01337                             ldap_mods[i]->mod_bvalues[j] = (struct berval *) emalloc (sizeof(struct berval));
01338                             ldap_mods[i]->mod_bvalues[j]->bv_len = Z_STRLEN_PP(ivalue);
01339                             ldap_mods[i]->mod_bvalues[j]->bv_val = Z_STRVAL_PP(ivalue);
01340                      }
01341               }
01342               ldap_mods[i]->mod_bvalues[num_values] = NULL;
01343               zend_hash_move_forward(Z_ARRVAL_P(entry));
01344        }
01345        ldap_mods[num_attribs] = NULL;
01346 
01347 /* check flag to see if do_mod was called to perform full add , gerrit thomson */
01348        if (is_full_add == 1) {
01349               if ((i = ldap_add_s(ld->link, dn, ldap_mods)) != LDAP_SUCCESS) {
01350                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Add: %s", ldap_err2string(i));
01351                      RETVAL_FALSE;
01352               } else RETVAL_TRUE;
01353        } else {
01354               if ((i = ldap_modify_ext_s(ld->link, dn, ldap_mods, NULL, NULL)) != LDAP_SUCCESS) {
01355                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Modify: %s", ldap_err2string(i));
01356                      RETVAL_FALSE;
01357               } else RETVAL_TRUE;  
01358        }
01359 
01360 errexit:
01361        for (i = 0; i < num_attribs; i++) {
01362               efree(ldap_mods[i]->mod_type);
01363               for (j = 0; j < num_berval[i]; j++) {
01364                      efree(ldap_mods[i]->mod_bvalues[j]);
01365               }
01366               efree(ldap_mods[i]->mod_bvalues);
01367               efree(ldap_mods[i]);
01368        }
01369        efree(num_berval);
01370        efree(ldap_mods);    
01371 
01372        return;
01373 }
01374 /* }}} */
01375 
01376 /* {{{ proto bool ldap_add(resource link, string dn, array entry)
01377    Add entries to LDAP directory */
01378 PHP_FUNCTION(ldap_add)
01379 {
01380        /* 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 */
01381        php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_LD_FULL_ADD);
01382 }
01383 /* }}} */
01384 
01385 /* three functions for attribute base modifications, gerrit Thomson */
01386 
01387 /* {{{ proto bool ldap_mod_replace(resource link, string dn, array entry)
01388    Replace attribute values with new ones */
01389 PHP_FUNCTION(ldap_mod_replace)
01390 {
01391        php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_REPLACE);
01392 }
01393 /* }}} */
01394 
01395 /* {{{ proto bool ldap_mod_add(resource link, string dn, array entry)
01396    Add attribute values to current */
01397 PHP_FUNCTION(ldap_mod_add)
01398 {
01399        php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_ADD);
01400 }
01401 /* }}} */
01402 
01403 /* {{{ proto bool ldap_mod_del(resource link, string dn, array entry)
01404    Delete attribute values */
01405 PHP_FUNCTION(ldap_mod_del)
01406 {
01407        php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_DELETE);
01408 }
01409 /* }}} */
01410 
01411 /* {{{ proto bool ldap_delete(resource link, string dn)
01412    Delete an entry from a directory */
01413 PHP_FUNCTION(ldap_delete)
01414 {
01415        zval *link;
01416        ldap_linkdata *ld;
01417        char *dn;
01418        int rc, dn_len;
01419 
01420        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &link, &dn, &dn_len) != SUCCESS) {
01421               return;
01422        }
01423 
01424        ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
01425 
01426        if ((rc = ldap_delete_s(ld->link, dn)) != LDAP_SUCCESS) {
01427               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Delete: %s", ldap_err2string(rc));
01428               RETURN_FALSE;
01429        }
01430 
01431        RETURN_TRUE;
01432 }
01433 /* }}} */
01434 
01435 /* {{{ proto int ldap_errno(resource link)
01436    Get the current ldap error number */
01437 PHP_FUNCTION(ldap_errno)
01438 {
01439        zval *link;
01440        ldap_linkdata *ld;
01441 
01442        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &link) != SUCCESS) {
01443               return;
01444        }
01445 
01446        ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
01447 
01448        RETURN_LONG(_get_lderrno(ld->link));
01449 }
01450 /* }}} */
01451 
01452 /* {{{ proto string ldap_err2str(int errno)
01453    Convert error number to error string */
01454 PHP_FUNCTION(ldap_err2str)
01455 {
01456        long perrno;
01457 
01458        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &perrno) != SUCCESS) {
01459               return;
01460        }
01461 
01462        RETURN_STRING(ldap_err2string(perrno), 1);
01463 }
01464 /* }}} */
01465 
01466 /* {{{ proto string ldap_error(resource link)
01467    Get the current ldap error string */
01468 PHP_FUNCTION(ldap_error) 
01469 {
01470        zval *link;
01471        ldap_linkdata *ld;
01472        int ld_errno;
01473 
01474        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &link) != SUCCESS) {
01475               return;
01476        }
01477 
01478        ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
01479 
01480        ld_errno = _get_lderrno(ld->link);
01481 
01482        RETURN_STRING(ldap_err2string(ld_errno), 1);
01483 }
01484 /* }}} */
01485 
01486 /* {{{ proto bool ldap_compare(resource link, string dn, string attr, string value)
01487    Determine if an entry has a specific value for one of its attributes */
01488 PHP_FUNCTION(ldap_compare) 
01489 {
01490        zval *link;
01491        char *dn, *attr, *value;
01492        int dn_len, attr_len, value_len;
01493        ldap_linkdata *ld;
01494        int errno;
01495 
01496        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsss", &link, &dn, &dn_len, &attr, &attr_len, &value, &value_len) != SUCCESS) {
01497               return;
01498        }
01499 
01500        ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
01501 
01502        errno = ldap_compare_s(ld->link, dn, attr, value);
01503 
01504        switch (errno) {
01505               case LDAP_COMPARE_TRUE:
01506                      RETURN_TRUE;
01507                      break;
01508 
01509               case LDAP_COMPARE_FALSE:
01510                      RETURN_FALSE;
01511                      break;
01512        }
01513        
01514        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Compare: %s", ldap_err2string(errno));
01515        RETURN_LONG(-1);
01516 }
01517 /* }}} */
01518 
01519 /* {{{ proto bool ldap_sort(resource link, resource result, string sortfilter)
01520    Sort LDAP result entries */
01521 PHP_FUNCTION(ldap_sort)
01522 {
01523        zval *link, *result;
01524        ldap_linkdata *ld;
01525        char *sortfilter;
01526        int sflen;
01527        zend_rsrc_list_entry *le;
01528 
01529        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rrs", &link, &result, &sortfilter, &sflen) != SUCCESS) {
01530               RETURN_FALSE;
01531        }
01532 
01533        ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
01534 
01535        if (zend_hash_index_find(&EG(regular_list), Z_LVAL_P(result), (void **) &le) != SUCCESS || le->type != le_result) {
01536               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Supplied resource is not a valid ldap result resource");
01537               RETURN_FALSE;
01538        }
01539 
01540        if (ldap_sort_entries(ld->link, (LDAPMessage **) &le->ptr, sflen ? sortfilter : NULL, strcmp) != LDAP_SUCCESS) {
01541               php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", ldap_err2string(errno));
01542               RETURN_FALSE;
01543        }
01544 
01545        RETURN_TRUE;
01546 }
01547 /* }}} */
01548 
01549 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10
01550 /* {{{ proto bool ldap_get_option(resource link, int option, mixed retval)
01551    Get the current value of various session-wide parameters */
01552 PHP_FUNCTION(ldap_get_option) 
01553 {
01554        zval *link, *retval;
01555        ldap_linkdata *ld;
01556        long option;
01557        
01558        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlz", &link, &option, &retval) != SUCCESS) {
01559               return;
01560        }
01561 
01562        ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
01563 
01564        switch (option) {
01565        /* options with int value */
01566        case LDAP_OPT_DEREF:
01567        case LDAP_OPT_SIZELIMIT:
01568        case LDAP_OPT_TIMELIMIT:
01569        case LDAP_OPT_PROTOCOL_VERSION:
01570        case LDAP_OPT_ERROR_NUMBER:
01571        case LDAP_OPT_REFERRALS:
01572 #ifdef LDAP_OPT_RESTART
01573        case LDAP_OPT_RESTART:
01574 #endif
01575               {
01576                      int val;
01577 
01578                      if (ldap_get_option(ld->link, option, &val)) {
01579                             RETURN_FALSE;
01580                      }
01581                      zval_dtor(retval);
01582                      ZVAL_LONG(retval, val);
01583               } break;
01584 #ifdef LDAP_OPT_NETWORK_TIMEOUT
01585        case LDAP_OPT_NETWORK_TIMEOUT:
01586               {
01587                      struct timeval *timeout = NULL;
01588 
01589                      if (ldap_get_option(ld->link, LDAP_OPT_NETWORK_TIMEOUT, (void *) &timeout)) {
01590                             if (timeout) {
01591                                    ldap_memfree(timeout);
01592                             }
01593                             RETURN_FALSE;
01594                      }                 
01595                      if (!timeout) {
01596                             RETURN_FALSE;
01597                      }
01598                      zval_dtor(retval);
01599                      ZVAL_LONG(retval, timeout->tv_sec);
01600                      ldap_memfree(timeout);
01601               } break;
01602 #elif defined(LDAP_X_OPT_CONNECT_TIMEOUT)
01603        case LDAP_X_OPT_CONNECT_TIMEOUT:
01604               {
01605                      int timeout;
01606 
01607                      if (ldap_get_option(ld->link, LDAP_X_OPT_CONNECT_TIMEOUT, &timeout)) {
01608                             RETURN_FALSE;
01609                      }                    
01610                      zval_dtor(retval);
01611                      ZVAL_LONG(retval, (timeout / 1000));
01612               } break;
01613 #endif
01614        /* options with string value */
01615        case LDAP_OPT_ERROR_STRING:
01616 #ifdef LDAP_OPT_HOST_NAME
01617        case LDAP_OPT_HOST_NAME:
01618 #endif
01619 #ifdef HAVE_LDAP_SASL
01620        case LDAP_OPT_X_SASL_MECH:   
01621        case LDAP_OPT_X_SASL_REALM:
01622        case LDAP_OPT_X_SASL_AUTHCID:
01623        case LDAP_OPT_X_SASL_AUTHZID:
01624 #endif
01625 #ifdef LDAP_OPT_MATCHED_DN
01626        case LDAP_OPT_MATCHED_DN:
01627 #endif
01628               {
01629                      char *val = NULL;
01630 
01631                      if (ldap_get_option(ld->link, option, &val) || val == NULL || *val == '\0') {
01632                             if (val) {
01633                                    ldap_memfree(val);
01634                             }
01635                             RETURN_FALSE;
01636                      }
01637                      zval_dtor(retval);
01638                      ZVAL_STRING(retval, val, 1);
01639                      ldap_memfree(val);
01640               } break;
01641 /* options not implemented
01642        case LDAP_OPT_SERVER_CONTROLS:
01643        case LDAP_OPT_CLIENT_CONTROLS:
01644        case LDAP_OPT_API_INFO:
01645        case LDAP_OPT_API_FEATURE_INFO:
01646 */
01647        default:
01648               RETURN_FALSE;
01649        }
01650        RETURN_TRUE;
01651 }
01652 /* }}} */
01653 
01654 /* {{{ proto bool ldap_set_option(resource link, int option, mixed newval)
01655    Set the value of various session-wide parameters */
01656 PHP_FUNCTION(ldap_set_option) 
01657 {
01658        zval *link, **newval;
01659        ldap_linkdata *ld;
01660        LDAP *ldap;
01661        long option;
01662        
01663        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zlZ", &link, &option, &newval) != SUCCESS) {
01664               return;
01665        }
01666 
01667        if (Z_TYPE_P(link) == IS_NULL) {
01668               ldap = NULL;
01669        } else {
01670               ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
01671               ldap = ld->link;
01672        }
01673 
01674        switch (option) {
01675        /* options with int value */
01676        case LDAP_OPT_DEREF:
01677        case LDAP_OPT_SIZELIMIT:
01678        case LDAP_OPT_TIMELIMIT:
01679        case LDAP_OPT_PROTOCOL_VERSION:
01680        case LDAP_OPT_ERROR_NUMBER:
01681 #ifdef LDAP_OPT_DEBUG_LEVEL
01682        case LDAP_OPT_DEBUG_LEVEL:
01683 #endif
01684               {
01685                      int val;
01686 
01687                      convert_to_long_ex(newval);
01688                      val = Z_LVAL_PP(newval);
01689                      if (ldap_set_option(ldap, option, &val)) {
01690                             RETURN_FALSE;
01691                      }
01692               } break;
01693 #ifdef LDAP_OPT_NETWORK_TIMEOUT
01694        case LDAP_OPT_NETWORK_TIMEOUT:
01695               {
01696                      struct timeval timeout;
01697 
01698                      convert_to_long_ex(newval);
01699                      timeout.tv_sec = Z_LVAL_PP(newval);
01700                      timeout.tv_usec = 0;
01701                      if (ldap_set_option(ldap, LDAP_OPT_NETWORK_TIMEOUT, (void *) &timeout)) {
01702                             RETURN_FALSE;
01703                      }                    
01704               } break;
01705 #elif defined(LDAP_X_OPT_CONNECT_TIMEOUT)
01706        case LDAP_X_OPT_CONNECT_TIMEOUT:
01707               {
01708                      int timeout;
01709 
01710                      convert_to_long_ex(newval);
01711                      timeout = 1000 * Z_LVAL_PP(newval); /* Convert to milliseconds */
01712                      if (ldap_set_option(ldap, LDAP_X_OPT_CONNECT_TIMEOUT, &timeout)) {
01713                             RETURN_FALSE;
01714                      }                    
01715               } break;
01716 #endif
01717               /* options with string value */
01718        case LDAP_OPT_ERROR_STRING:
01719 #ifdef LDAP_OPT_HOST_NAME
01720        case LDAP_OPT_HOST_NAME:
01721 #endif
01722 #ifdef HAVE_LDAP_SASL
01723        case LDAP_OPT_X_SASL_MECH:   
01724        case LDAP_OPT_X_SASL_REALM:
01725        case LDAP_OPT_X_SASL_AUTHCID:
01726        case LDAP_OPT_X_SASL_AUTHZID:
01727 #endif
01728 #ifdef LDAP_OPT_MATCHED_DN
01729        case LDAP_OPT_MATCHED_DN:
01730 #endif
01731               {
01732                      char *val;
01733                      convert_to_string_ex(newval);
01734                      val = Z_STRVAL_PP(newval);
01735                      if (ldap_set_option(ldap, option, val)) {
01736                             RETURN_FALSE;
01737                      }
01738               } break;
01739               /* options with boolean value */
01740        case LDAP_OPT_REFERRALS:
01741 #ifdef LDAP_OPT_RESTART
01742        case LDAP_OPT_RESTART:
01743 #endif
01744               {
01745                      void *val;
01746                      convert_to_boolean_ex(newval);
01747                      val = Z_LVAL_PP(newval)
01748                             ? LDAP_OPT_ON : LDAP_OPT_OFF;
01749                      if (ldap_set_option(ldap, option, val)) {
01750                             RETURN_FALSE;
01751                      }
01752               } break;
01753               /* options with control list value */
01754        case LDAP_OPT_SERVER_CONTROLS:
01755        case LDAP_OPT_CLIENT_CONTROLS:
01756               {
01757                      LDAPControl *ctrl, **ctrls, **ctrlp;
01758                      zval **ctrlval, **val;
01759                      int ncontrols;
01760                      char error=0;
01761 
01762                      if ((Z_TYPE_PP(newval) != IS_ARRAY) || !(ncontrols = zend_hash_num_elements(Z_ARRVAL_PP(newval)))) {
01763                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected non-empty array value for this option");
01764                             RETURN_FALSE;
01765                      }
01766                      ctrls = safe_emalloc((1 + ncontrols), sizeof(*ctrls), 0);
01767                      *ctrls = NULL;
01768                      ctrlp = ctrls;
01769                      zend_hash_internal_pointer_reset(Z_ARRVAL_PP(newval));
01770                      while (zend_hash_get_current_data(Z_ARRVAL_PP(newval), (void**)&ctrlval) == SUCCESS) {
01771                             if (Z_TYPE_PP(ctrlval) != IS_ARRAY) {
01772                                    php_error_docref(NULL TSRMLS_CC, E_WARNING, "The array value must contain only arrays, where each array is a control");
01773                                    error = 1;
01774                                    break;
01775                             }
01776                             if (zend_hash_find(Z_ARRVAL_PP(ctrlval), "oid", sizeof("oid"), (void **) &val) != SUCCESS) {
01777                                    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Control must have an oid key");
01778                                    error = 1;
01779                                    break;
01780                             }
01781                             ctrl = *ctrlp = emalloc(sizeof(**ctrlp));
01782                             convert_to_string_ex(val);
01783                             ctrl->ldctl_oid = Z_STRVAL_PP(val);
01784                             if (zend_hash_find(Z_ARRVAL_PP(ctrlval), "value", sizeof("value"), (void **) &val) == SUCCESS) {
01785                                    convert_to_string_ex(val);
01786                                    ctrl->ldctl_value.bv_val = Z_STRVAL_PP(val);
01787                                    ctrl->ldctl_value.bv_len = Z_STRLEN_PP(val);
01788                             } else {
01789                                    ctrl->ldctl_value.bv_val = NULL;
01790                                    ctrl->ldctl_value.bv_len = 0;
01791                             }
01792                             if (zend_hash_find(Z_ARRVAL_PP(ctrlval), "iscritical", sizeof("iscritical"), (void **) &val) == SUCCESS) {
01793                                    convert_to_boolean_ex(val);
01794                                    ctrl->ldctl_iscritical = Z_BVAL_PP(val);
01795                             } else {
01796                                    ctrl->ldctl_iscritical = 0;
01797                             }
01798                             
01799                             ++ctrlp;
01800                             *ctrlp = NULL;
01801                             zend_hash_move_forward(Z_ARRVAL_PP(newval));
01802                      }
01803                      if (!error) {
01804                             error = ldap_set_option(ldap, option, ctrls);
01805                      }
01806                      ctrlp = ctrls;
01807                      while (*ctrlp) {
01808                             efree(*ctrlp);
01809                             ctrlp++;
01810                      }
01811                      efree(ctrls);
01812                      if (error) {
01813                             RETURN_FALSE;
01814                      }
01815               } break;
01816        default:
01817               RETURN_FALSE;
01818        }
01819        RETURN_TRUE;
01820 }
01821 /* }}} */
01822 
01823 #ifdef HAVE_LDAP_PARSE_RESULT
01824 /* {{{ proto bool ldap_parse_result(resource link, resource result, int errcode, string matcheddn, string errmsg, array referrals)
01825    Extract information from result */
01826 PHP_FUNCTION(ldap_parse_result) 
01827 {
01828        zval *link, *result, *errcode, *matcheddn, *errmsg, *referrals;
01829        ldap_linkdata *ld;
01830        LDAPMessage *ldap_result;
01831        char **lreferrals, **refp;
01832        char *lmatcheddn, *lerrmsg;
01833        int rc, lerrcode, myargcount = ZEND_NUM_ARGS();
01834 
01835        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rrz|zzz", &link, &result, &errcode, &matcheddn, &errmsg, &referrals) != SUCCESS) {
01836               return; 
01837        }
01838 
01839        ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
01840        ZEND_FETCH_RESOURCE(ldap_result, LDAPMessage *, &result, -1, "ldap result", le_result);
01841 
01842        rc = ldap_parse_result(ld->link, ldap_result, &lerrcode,
01843                             myargcount > 3 ? &lmatcheddn : NULL,
01844                             myargcount > 4 ? &lerrmsg : NULL,
01845                             myargcount > 5 ? &lreferrals : NULL,
01846                             NULL /* &serverctrls */,
01847                             0);
01848        if (rc != LDAP_SUCCESS) {
01849               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to parse result: %s", ldap_err2string(rc));
01850               RETURN_FALSE;
01851        }
01852 
01853        zval_dtor(errcode);
01854        ZVAL_LONG(errcode, lerrcode);
01855 
01856        /* Reverse -> fall through */
01857        switch (myargcount) {
01858               case 6:
01859                      zval_dtor(referrals);
01860                      array_init(referrals);
01861                      if (lreferrals != NULL) {
01862                             refp = lreferrals;
01863                             while (*refp) {
01864                                    add_next_index_string(referrals, *refp, 1);
01865                                    refp++;
01866                             }
01867                             ldap_value_free(lreferrals);
01868                      }
01869               case 5:
01870                      zval_dtor(errmsg);
01871                      if (lerrmsg == NULL) {
01872                             ZVAL_EMPTY_STRING(errmsg);
01873                      } else {
01874                             ZVAL_STRING(errmsg, lerrmsg, 1);
01875                             ldap_memfree(lerrmsg);
01876                      }
01877               case 4: 
01878                      zval_dtor(matcheddn);
01879                      if (lmatcheddn == NULL) {
01880                             ZVAL_EMPTY_STRING(matcheddn);
01881                      } else {
01882                             ZVAL_STRING(matcheddn, lmatcheddn, 1);
01883                             ldap_memfree(lmatcheddn);
01884                      }
01885        }
01886        RETURN_TRUE;
01887 }
01888 /* }}} */
01889 #endif
01890 
01891 /* {{{ proto resource ldap_first_reference(resource link, resource result)
01892    Return first reference */
01893 PHP_FUNCTION(ldap_first_reference)
01894 {
01895        zval *link, *result;
01896        ldap_linkdata *ld;
01897        ldap_resultentry *resultentry;
01898        LDAPMessage *ldap_result, *entry;
01899 
01900        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &link, &result) != SUCCESS) {
01901               return;
01902        }
01903 
01904        ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
01905        ZEND_FETCH_RESOURCE(ldap_result, LDAPMessage *, &result, -1, "ldap result", le_result);
01906 
01907        if ((entry = ldap_first_reference(ld->link, ldap_result)) == NULL) {
01908               RETVAL_FALSE;
01909        } else {
01910               resultentry = emalloc(sizeof(ldap_resultentry));
01911               ZEND_REGISTER_RESOURCE(return_value, resultentry, le_result_entry);
01912               resultentry->id = Z_LVAL_P(result);
01913               zend_list_addref(resultentry->id);
01914               resultentry->data = entry;
01915               resultentry->ber = NULL;
01916        }
01917 }
01918 /* }}} */
01919 
01920 /* {{{ proto resource ldap_next_reference(resource link, resource reference_entry)
01921    Get next reference */
01922 PHP_FUNCTION(ldap_next_reference)
01923 {
01924        zval *link, *result_entry;
01925        ldap_linkdata *ld;
01926        ldap_resultentry *resultentry, *resultentry_next;
01927        LDAPMessage *entry_next;
01928 
01929        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr", &link, &result_entry) != SUCCESS) {
01930               return;
01931        }
01932 
01933        ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
01934        ZEND_FETCH_RESOURCE(resultentry, ldap_resultentry *, &result_entry, -1, "ldap result entry", le_result_entry);
01935 
01936        if ((entry_next = ldap_next_reference(ld->link, resultentry->data)) == NULL) {
01937               RETVAL_FALSE;
01938        } else {
01939               resultentry_next = emalloc(sizeof(ldap_resultentry));
01940               ZEND_REGISTER_RESOURCE(return_value, resultentry_next, le_result_entry);
01941               resultentry_next->id = resultentry->id;
01942               zend_list_addref(resultentry->id);
01943               resultentry_next->data = entry_next;
01944               resultentry_next->ber = NULL;
01945        }
01946 }
01947 /* }}} */
01948 
01949 #ifdef HAVE_LDAP_PARSE_REFERENCE
01950 /* {{{ proto bool ldap_parse_reference(resource link, resource reference_entry, array referrals)
01951    Extract information from reference entry */
01952 PHP_FUNCTION(ldap_parse_reference)
01953 {
01954        zval *link, *result_entry, *referrals;
01955        ldap_linkdata *ld;
01956        ldap_resultentry *resultentry;
01957        char **lreferrals, **refp;
01958 
01959        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rrz", &link, &result_entry, &referrals) != SUCCESS) {
01960               return;
01961        }
01962 
01963        ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
01964        ZEND_FETCH_RESOURCE(resultentry, ldap_resultentry *, &result_entry, -1, "ldap result entry", le_result_entry);
01965 
01966        if (ldap_parse_reference(ld->link, resultentry->data, &lreferrals, NULL /* &serverctrls */, 0) != LDAP_SUCCESS) {
01967               RETURN_FALSE;
01968        }
01969 
01970        zval_dtor(referrals);
01971        array_init(referrals);
01972        if (lreferrals != NULL) {
01973               refp = lreferrals;
01974               while (*refp) {
01975                      add_next_index_string(referrals, *refp, 1);
01976                      refp++;
01977               }
01978               ldap_value_free(lreferrals);
01979        }
01980        RETURN_TRUE;
01981 }
01982 /* }}} */
01983 #endif
01984 
01985 /* {{{ proto bool ldap_rename(resource link, string dn, string newrdn, string newparent, bool deleteoldrdn);
01986    Modify the name of an entry */
01987 PHP_FUNCTION(ldap_rename)
01988 {
01989        zval *link;
01990        ldap_linkdata *ld;
01991        int rc;
01992        char *dn, *newrdn, *newparent;
01993        int dn_len, newrdn_len, newparent_len;
01994        zend_bool deleteoldrdn;
01995        
01996        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsssb", &link, &dn, &dn_len, &newrdn, &newrdn_len, &newparent, &newparent_len, &deleteoldrdn) != SUCCESS) {
01997               return;
01998        }
01999 
02000        ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
02001 
02002        if (newparent_len == 0) {
02003               newparent = NULL;
02004        }
02005 
02006 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10
02007        rc = ldap_rename_s(ld->link, dn, newrdn, newparent, deleteoldrdn, NULL, NULL);
02008 #else
02009        if (newparent_len != 0) {
02010               php_error_docref(NULL TSRMLS_CC, E_WARNING, "You are using old LDAP API, newparent must be the empty string, can only modify RDN");
02011               RETURN_FALSE;
02012        }
02013 /* could support old APIs but need check for ldap_modrdn2()/ldap_modrdn() */
02014        rc = ldap_modrdn2_s(ld->link, dn, newrdn, deleteoldrdn);
02015 #endif
02016 
02017        if (rc == LDAP_SUCCESS) {
02018               RETURN_TRUE;
02019        }
02020        RETURN_FALSE;
02021 }
02022 /* }}} */
02023 
02024 #ifdef HAVE_LDAP_START_TLS_S
02025 /* {{{ proto bool ldap_start_tls(resource link)
02026    Start TLS */
02027 PHP_FUNCTION(ldap_start_tls)
02028 {
02029        zval *link;
02030        ldap_linkdata *ld;
02031        int rc, protocol = LDAP_VERSION3;
02032 
02033        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &link) != SUCCESS) {
02034               return;
02035        }
02036 
02037        ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
02038 
02039        if (((rc = ldap_set_option(ld->link, LDAP_OPT_PROTOCOL_VERSION, &protocol)) != LDAP_SUCCESS) ||
02040               ((rc = ldap_start_tls_s(ld->link, NULL, NULL)) != LDAP_SUCCESS)
02041        ) {
02042               php_error_docref(NULL TSRMLS_CC, E_WARNING,"Unable to start TLS: %s", ldap_err2string(rc));
02043               RETURN_FALSE;
02044        } else {
02045               RETURN_TRUE;
02046        }
02047 }
02048 /* }}} */
02049 #endif
02050 #endif /* (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10 */
02051 
02052 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)
02053 /* {{{ _ldap_rebind_proc()
02054 */
02055 int _ldap_rebind_proc(LDAP *ldap, const char *url, ber_tag_t req, ber_int_t msgid, void *params)
02056 {
02057        ldap_linkdata *ld;
02058        int retval;
02059        zval *cb_url;
02060        zval **cb_args[2];
02061        zval *cb_retval;
02062        zval *cb_link = (zval *) params;
02063        TSRMLS_FETCH();
02064 
02065        ld = (ldap_linkdata *) zend_fetch_resource(&cb_link TSRMLS_CC, -1, "ldap link", NULL, 1, le_link);
02066 
02067        /* link exists and callback set? */
02068        if (ld == NULL || ld->rebindproc == NULL) {
02069               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Link not found or no callback set");
02070               return LDAP_OTHER;
02071        }
02072 
02073        /* callback */
02074        MAKE_STD_ZVAL(cb_url);
02075        ZVAL_STRING(cb_url, estrdup(url), 0);
02076        cb_args[0] = &cb_link;
02077        cb_args[1] = &cb_url;
02078        if (call_user_function_ex(EG(function_table), NULL, ld->rebindproc, &cb_retval, 2, cb_args, 0, NULL TSRMLS_CC) == SUCCESS && cb_retval) {
02079               convert_to_long_ex(&cb_retval);
02080               retval = Z_LVAL_P(cb_retval);
02081               zval_ptr_dtor(&cb_retval);
02082        } else {
02083               php_error_docref(NULL TSRMLS_CC, E_WARNING, "rebind_proc PHP callback failed");
02084               retval = LDAP_OTHER;
02085        }
02086        zval_dtor(cb_url);
02087        FREE_ZVAL(cb_url);
02088        return retval;
02089 }
02090 /* }}} */
02091 
02092 /* {{{ proto bool ldap_set_rebind_proc(resource link, string callback)
02093    Set a callback function to do re-binds on referral chasing. */
02094 PHP_FUNCTION(ldap_set_rebind_proc)
02095 {
02096        zval *link, *callback;
02097        ldap_linkdata *ld;
02098        char *callback_name;
02099 
02100        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz", &link, &callback) != SUCCESS) {
02101               RETURN_FALSE;
02102        }
02103 
02104        ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
02105 
02106        if (Z_TYPE_P(callback) == IS_STRING && Z_STRLEN_P(callback) == 0) {
02107               /* unregister rebind procedure */
02108               if (ld->rebindproc != NULL) {
02109                      zval_dtor(ld->rebindproc);
02110                      ld->rebindproc = NULL;
02111                      ldap_set_rebind_proc(ld->link, NULL, NULL);
02112               }
02113               RETURN_TRUE;
02114        }
02115 
02116        /* callable? */
02117        if (!zend_is_callable(callback, 0, &callback_name TSRMLS_CC)) {
02118               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Two arguments expected for '%s' to be a valid callback", callback_name);
02119               efree(callback_name);
02120               RETURN_FALSE;
02121        }
02122        efree(callback_name);
02123 
02124        /* register rebind procedure */
02125        if (ld->rebindproc == NULL) {
02126               ldap_set_rebind_proc(ld->link, _ldap_rebind_proc, (void *) link);
02127        } else {
02128               zval_dtor(ld->rebindproc);
02129        }
02130 
02131        ALLOC_ZVAL(ld->rebindproc);
02132        *ld->rebindproc = *callback;
02133        zval_copy_ctor(ld->rebindproc);
02134        RETURN_TRUE;
02135 }
02136 /* }}} */
02137 #endif
02138 
02139 #ifdef STR_TRANSLATION
02140 /* {{{ php_ldap_do_translate
02141  */
02142 static void php_ldap_do_translate(INTERNAL_FUNCTION_PARAMETERS, int way) 
02143 {
02144        char *value;
02145        int result, ldap_len;
02146               
02147        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &value, &value_len) != SUCCESS) {
02148               return;
02149        }
02150 
02151        if (value_len == 0) {
02152               RETURN_FALSE;
02153        }
02154 
02155        if (way == 1) {
02156               result = ldap_8859_to_t61(&value, &value_len, 0);
02157        } else {
02158               result = ldap_t61_to_8859(&value, &value_len, 0);
02159        }
02160 
02161        if (result == LDAP_SUCCESS) {
02162               RETVAL_STRINGL(value, value_len, 1);
02163               free(value);
02164        } else {
02165               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Conversion from iso-8859-1 to t61 failed: %s", ldap_err2string(result));
02166               RETVAL_FALSE;
02167        }
02168 }
02169 /* }}} */
02170 
02171 /* {{{ proto string ldap_t61_to_8859(string value)
02172    Translate t61 characters to 8859 characters */
02173 PHP_FUNCTION(ldap_t61_to_8859)
02174 {
02175        php_ldap_do_translate(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
02176 }
02177 /* }}} */
02178 
02179 /* {{{ proto string ldap_8859_to_t61(string value)
02180    Translate 8859 characters to t61 characters */
02181 PHP_FUNCTION(ldap_8859_to_t61)
02182 {
02183        php_ldap_do_translate(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
02184 }
02185 /* }}} */
02186 #endif
02187 
02188 /* {{{ arginfo */
02189 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_connect, 0, 0, 0)
02190        ZEND_ARG_INFO(0, hostname)
02191        ZEND_ARG_INFO(0, port)
02192 #ifdef HAVE_ORALDAP
02193        ZEND_ARG_INFO(0, wallet)
02194        ZEND_ARG_INFO(0, wallet_passwd)
02195        ZEND_ARG_INFO(0, authmode)
02196 #endif
02197 ZEND_END_ARG_INFO()
02198 
02199 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_resource, 0, 0, 1)
02200        ZEND_ARG_INFO(0, link_identifier)
02201 ZEND_END_ARG_INFO()
02202 
02203 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_bind, 0, 0, 1)
02204        ZEND_ARG_INFO(0, link_identifier)
02205        ZEND_ARG_INFO(0, bind_rdn)
02206        ZEND_ARG_INFO(0, bind_password)
02207 ZEND_END_ARG_INFO()
02208 
02209 #ifdef HAVE_LDAP_SASL
02210 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_sasl_bind, 0, 0, 1)
02211        ZEND_ARG_INFO(0, link)
02212        ZEND_ARG_INFO(0, binddn)
02213        ZEND_ARG_INFO(0, password)
02214        ZEND_ARG_INFO(0, sasl_mech)
02215        ZEND_ARG_INFO(0, sasl_realm)
02216        ZEND_ARG_INFO(0, sasl_authz_id)
02217        ZEND_ARG_INFO(0, props)
02218 ZEND_END_ARG_INFO()
02219 #endif
02220 
02221 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_read, 0, 0, 3)
02222        ZEND_ARG_INFO(0, link_identifier)
02223        ZEND_ARG_INFO(0, base_dn)
02224        ZEND_ARG_INFO(0, filter)
02225        ZEND_ARG_INFO(0, attributes)
02226        ZEND_ARG_INFO(0, attrsonly)
02227        ZEND_ARG_INFO(0, sizelimit)
02228        ZEND_ARG_INFO(0, timelimit)
02229        ZEND_ARG_INFO(0, deref)
02230 ZEND_END_ARG_INFO()
02231 
02232 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_list, 0, 0, 3)
02233        ZEND_ARG_INFO(0, link_identifier)
02234        ZEND_ARG_INFO(0, base_dn)
02235        ZEND_ARG_INFO(0, filter)
02236        ZEND_ARG_INFO(0, attributes)
02237        ZEND_ARG_INFO(0, attrsonly)
02238        ZEND_ARG_INFO(0, sizelimit)
02239        ZEND_ARG_INFO(0, timelimit)
02240        ZEND_ARG_INFO(0, deref)
02241 ZEND_END_ARG_INFO()
02242 
02243 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_search, 0, 0, 3)
02244        ZEND_ARG_INFO(0, link_identifier)
02245        ZEND_ARG_INFO(0, base_dn)
02246        ZEND_ARG_INFO(0, filter)
02247        ZEND_ARG_INFO(0, attributes)
02248        ZEND_ARG_INFO(0, attrsonly)
02249        ZEND_ARG_INFO(0, sizelimit)
02250        ZEND_ARG_INFO(0, timelimit)
02251        ZEND_ARG_INFO(0, deref)
02252 ZEND_END_ARG_INFO()
02253 
02254 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_count_entries, 0, 0, 2)
02255        ZEND_ARG_INFO(0, link_identifier)
02256        ZEND_ARG_INFO(0, result_identifier)
02257 ZEND_END_ARG_INFO()
02258 
02259 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_first_entry, 0, 0, 2)
02260        ZEND_ARG_INFO(0, link_identifier)
02261        ZEND_ARG_INFO(0, result_identifier)
02262 ZEND_END_ARG_INFO()
02263 
02264 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_next_entry, 0, 0, 2)
02265        ZEND_ARG_INFO(0, link_identifier)
02266        ZEND_ARG_INFO(0, result_identifier)
02267 ZEND_END_ARG_INFO()
02268 
02269 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_get_entries, 0, 0, 2)
02270        ZEND_ARG_INFO(0, link_identifier)
02271        ZEND_ARG_INFO(0, result_identifier)
02272 ZEND_END_ARG_INFO()
02273 
02274 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_first_attribute, 0, 0, 2)
02275        ZEND_ARG_INFO(0, link_identifier)
02276        ZEND_ARG_INFO(0, result_entry_identifier)
02277 ZEND_END_ARG_INFO()
02278 
02279 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_next_attribute, 0, 0, 2)
02280        ZEND_ARG_INFO(0, link_identifier)
02281        ZEND_ARG_INFO(0, result_entry_identifier)
02282 ZEND_END_ARG_INFO()
02283 
02284 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_get_attributes, 0, 0, 2)
02285        ZEND_ARG_INFO(0, link_identifier)
02286        ZEND_ARG_INFO(0, result_entry_identifier)
02287 ZEND_END_ARG_INFO()
02288 
02289 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_get_values, 0, 0, 3)
02290        ZEND_ARG_INFO(0, link_identifier)
02291        ZEND_ARG_INFO(0, result_entry_identifier)
02292        ZEND_ARG_INFO(0, attribute)
02293 ZEND_END_ARG_INFO()
02294 
02295 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_get_values_len, 0, 0, 3)
02296        ZEND_ARG_INFO(0, link_identifier)
02297        ZEND_ARG_INFO(0, result_entry_identifier)
02298        ZEND_ARG_INFO(0, attribute)
02299 ZEND_END_ARG_INFO()
02300 
02301 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_get_dn, 0, 0, 2)
02302        ZEND_ARG_INFO(0, link_identifier)
02303        ZEND_ARG_INFO(0, result_entry_identifier)
02304 ZEND_END_ARG_INFO()
02305 
02306 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_explode_dn, 0, 0, 2)
02307        ZEND_ARG_INFO(0, dn)
02308        ZEND_ARG_INFO(0, with_attrib)
02309 ZEND_END_ARG_INFO()
02310 
02311 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_dn2ufn, 0, 0, 1)
02312        ZEND_ARG_INFO(0, dn)
02313 ZEND_END_ARG_INFO()
02314 
02315 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_add, 0, 0, 3)
02316        ZEND_ARG_INFO(0, link_identifier)
02317        ZEND_ARG_INFO(0, dn)
02318        ZEND_ARG_INFO(0, entry)
02319 ZEND_END_ARG_INFO()
02320 
02321 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_delete, 0, 0, 2)
02322        ZEND_ARG_INFO(0, link_identifier)
02323        ZEND_ARG_INFO(0, dn)
02324 ZEND_END_ARG_INFO()
02325 
02326 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_modify, 0, 0, 3)
02327        ZEND_ARG_INFO(0, link_identifier)
02328        ZEND_ARG_INFO(0, dn)
02329        ZEND_ARG_INFO(0, entry)
02330 ZEND_END_ARG_INFO()
02331 
02332 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_mod_add, 0, 0, 3)
02333        ZEND_ARG_INFO(0, link_identifier)
02334        ZEND_ARG_INFO(0, dn)
02335        ZEND_ARG_INFO(0, entry)
02336 ZEND_END_ARG_INFO()
02337 
02338 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_mod_replace, 0, 0, 3)
02339        ZEND_ARG_INFO(0, link_identifier)
02340        ZEND_ARG_INFO(0, dn)
02341        ZEND_ARG_INFO(0, entry)
02342 ZEND_END_ARG_INFO()
02343 
02344 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_mod_del, 0, 0, 3)
02345        ZEND_ARG_INFO(0, link_identifier)
02346        ZEND_ARG_INFO(0, dn)
02347        ZEND_ARG_INFO(0, entry)
02348 ZEND_END_ARG_INFO()
02349 
02350 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_err2str, 0, 0, 1)
02351        ZEND_ARG_INFO(0, errno)
02352 ZEND_END_ARG_INFO()
02353 
02354 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_compare, 0, 0, 4)
02355        ZEND_ARG_INFO(0, link_identifier)
02356        ZEND_ARG_INFO(0, dn)
02357        ZEND_ARG_INFO(0, attribute)
02358        ZEND_ARG_INFO(0, value)
02359 ZEND_END_ARG_INFO()
02360 
02361 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_sort, 0, 0, 3)
02362        ZEND_ARG_INFO(0, link)
02363        ZEND_ARG_INFO(0, result)
02364        ZEND_ARG_INFO(0, sortfilter)
02365 ZEND_END_ARG_INFO()
02366 
02367 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10
02368 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_rename, 0, 0, 5)
02369        ZEND_ARG_INFO(0, link_identifier)
02370        ZEND_ARG_INFO(0, dn)
02371        ZEND_ARG_INFO(0, newrdn)
02372        ZEND_ARG_INFO(0, newparent)
02373        ZEND_ARG_INFO(0, deleteoldrdn)
02374 ZEND_END_ARG_INFO()
02375 
02376 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_get_option, 0, 0, 3)
02377        ZEND_ARG_INFO(0, link_identifier)
02378        ZEND_ARG_INFO(0, option)
02379        ZEND_ARG_INFO(1, retval)
02380 ZEND_END_ARG_INFO()
02381 
02382 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_set_option, 0, 0, 3)
02383        ZEND_ARG_INFO(0, link_identifier)
02384        ZEND_ARG_INFO(0, option)
02385        ZEND_ARG_INFO(0, newval)
02386 ZEND_END_ARG_INFO()
02387 
02388 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_first_reference, 0, 0, 2)
02389        ZEND_ARG_INFO(0, link)
02390        ZEND_ARG_INFO(0, result)
02391 ZEND_END_ARG_INFO()
02392 
02393 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_next_reference, 0, 0, 2)
02394        ZEND_ARG_INFO(0, link)
02395        ZEND_ARG_INFO(0, entry)
02396 ZEND_END_ARG_INFO()
02397 
02398 #ifdef HAVE_LDAP_PARSE_REFERENCE
02399 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_parse_reference, 0, 0, 3)
02400        ZEND_ARG_INFO(0, link)
02401        ZEND_ARG_INFO(0, entry)
02402        ZEND_ARG_INFO(1, referrals)
02403 ZEND_END_ARG_INFO()
02404 #endif
02405 
02406 
02407 #ifdef HAVE_LDAP_PARSE_RESULT
02408 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_parse_result, 0, 0, 3)
02409        ZEND_ARG_INFO(0, link)
02410        ZEND_ARG_INFO(0, result)
02411        ZEND_ARG_INFO(1, errcode)
02412        ZEND_ARG_INFO(1, matcheddn)
02413        ZEND_ARG_INFO(1, errmsg)
02414        ZEND_ARG_INFO(1, referrals)
02415 ZEND_END_ARG_INFO()
02416 #endif
02417 #endif
02418 
02419 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)
02420 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_set_rebind_proc, 0, 0, 2)
02421        ZEND_ARG_INFO(0, link)
02422        ZEND_ARG_INFO(0, callback)
02423 ZEND_END_ARG_INFO()
02424 #endif
02425 
02426 #ifdef STR_TRANSLATION
02427 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_t61_to_8859, 0, 0, 1)
02428        ZEND_ARG_INFO(0, value)
02429 ZEND_END_ARG_INFO()
02430 
02431 ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_8859_to_t61, 0, 0, 1)
02432        ZEND_ARG_INFO(0, value)
02433 ZEND_END_ARG_INFO()
02434 #endif
02435 /* }}} */
02436        
02437 /*
02438        This is just a small subset of the functionality provided by the LDAP library. All the 
02439        operations are synchronous. Referrals are not handled automatically.
02440 */
02441 /* {{{ ldap_functions[]
02442  */
02443 const zend_function_entry ldap_functions[] = {
02444        PHP_FE(ldap_connect,                                                  arginfo_ldap_connect)
02445        PHP_FALIAS(ldap_close,             ldap_unbind,                arginfo_ldap_resource)
02446        PHP_FE(ldap_bind,                                                            arginfo_ldap_bind)
02447 #ifdef HAVE_LDAP_SASL
02448        PHP_FE(ldap_sasl_bind,                                                       arginfo_ldap_sasl_bind)
02449 #endif
02450        PHP_FE(ldap_unbind,                                                          arginfo_ldap_resource)
02451        PHP_FE(ldap_read,                                                            arginfo_ldap_read)
02452        PHP_FE(ldap_list,                                                            arginfo_ldap_list)
02453        PHP_FE(ldap_search,                                                          arginfo_ldap_search)
02454        PHP_FE(ldap_free_result,                                              arginfo_ldap_resource)
02455        PHP_FE(ldap_count_entries,                                            arginfo_ldap_count_entries)
02456        PHP_FE(ldap_first_entry,                                              arginfo_ldap_first_entry)
02457        PHP_FE(ldap_next_entry,                                                      arginfo_ldap_next_entry)
02458        PHP_FE(ldap_get_entries,                                              arginfo_ldap_get_entries)
02459        PHP_FE(ldap_first_attribute,                                          arginfo_ldap_first_attribute)
02460        PHP_FE(ldap_next_attribute,                                           arginfo_ldap_next_attribute)
02461        PHP_FE(ldap_get_attributes,                                           arginfo_ldap_get_attributes)
02462        PHP_FALIAS(ldap_get_values, ldap_get_values_len, arginfo_ldap_get_values)
02463        PHP_FE(ldap_get_values_len,                                           arginfo_ldap_get_values_len)
02464        PHP_FE(ldap_get_dn,                                                          arginfo_ldap_get_dn)
02465        PHP_FE(ldap_explode_dn,                                                      arginfo_ldap_explode_dn)
02466        PHP_FE(ldap_dn2ufn,                                                          arginfo_ldap_dn2ufn)
02467        PHP_FE(ldap_add,                                                             arginfo_ldap_add)
02468        PHP_FE(ldap_delete,                                                          arginfo_ldap_delete)
02469        PHP_FALIAS(ldap_modify,            ldap_mod_replace,           arginfo_ldap_modify)
02470 
02471 /* additional functions for attribute based modifications, Gerrit Thomson */
02472        PHP_FE(ldap_mod_add,                                                  arginfo_ldap_mod_add)
02473        PHP_FE(ldap_mod_replace,                                              arginfo_ldap_mod_replace)
02474        PHP_FE(ldap_mod_del,                                                  arginfo_ldap_mod_del)
02475 /* end gjt mod */
02476 
02477        PHP_FE(ldap_errno,                                                           arginfo_ldap_resource)
02478        PHP_FE(ldap_err2str,                                                  arginfo_ldap_err2str)
02479        PHP_FE(ldap_error,                                                           arginfo_ldap_resource)
02480        PHP_FE(ldap_compare,                                                  arginfo_ldap_compare)
02481        PHP_FE(ldap_sort,                                                            arginfo_ldap_sort)
02482 
02483 #if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10
02484        PHP_FE(ldap_rename,                                                          arginfo_ldap_rename)
02485        PHP_FE(ldap_get_option,                                                      arginfo_ldap_get_option)
02486        PHP_FE(ldap_set_option,                                                      arginfo_ldap_set_option)
02487        PHP_FE(ldap_first_reference,                                          arginfo_ldap_first_reference)
02488        PHP_FE(ldap_next_reference,                                           arginfo_ldap_next_reference)
02489 #ifdef HAVE_LDAP_PARSE_REFERENCE
02490        PHP_FE(ldap_parse_reference,                                          arginfo_ldap_parse_reference)
02491 #endif
02492 #ifdef HAVE_LDAP_PARSE_RESULT
02493        PHP_FE(ldap_parse_result,                                             arginfo_ldap_parse_result)
02494 #endif
02495 #ifdef HAVE_LDAP_START_TLS_S
02496        PHP_FE(ldap_start_tls,                                                       arginfo_ldap_resource)
02497 #endif
02498 #endif
02499 
02500 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)
02501        PHP_FE(ldap_set_rebind_proc,                                          arginfo_ldap_set_rebind_proc)
02502 #endif
02503 
02504 #ifdef STR_TRANSLATION
02505        PHP_FE(ldap_t61_to_8859,                                              arginfo_ldap_t61_to_8859)
02506        PHP_FE(ldap_8859_to_t61,                                              arginfo_ldap_8859_to_t61)
02507 #endif
02508 
02509        PHP_FE_END
02510 };
02511 /* }}} */
02512 
02513 zend_module_entry ldap_module_entry = { /* {{{ */
02514        STANDARD_MODULE_HEADER,
02515        "ldap", 
02516        ldap_functions, 
02517        PHP_MINIT(ldap), 
02518        PHP_MSHUTDOWN(ldap), 
02519        NULL, 
02520        NULL,
02521        PHP_MINFO(ldap), 
02522        NO_VERSION_YET,
02523        PHP_MODULE_GLOBALS(ldap),
02524        PHP_GINIT(ldap),
02525        NULL,
02526        NULL,
02527        STANDARD_MODULE_PROPERTIES_EX
02528 };
02529 /* }}} */
02530 
02531 /*
02532  * Local variables:
02533  * tab-width: 4
02534  * c-basic-offset: 4
02535  * End:
02536  * vim600: sw=4 ts=4 fdm=marker
02537  * vim<600: sw=4 ts=4
02538  */