Arquivos
hhvm/hphp/runtime/ext/ext_ldap.cpp
T
Edwin Smith f29ee5314d Remove String::operator const char*().
Too many ways to shoot self in foot with this gem.
2013-04-25 11:34:21 -07:00

1253 linhas
36 KiB
C++

/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 1997-2010 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include <runtime/ext/ext_ldap.h>
#include <runtime/ext/ext_function.h>
#include <runtime/base/builtin_functions.h>
#include <util/thread_local.h>
#include <lber.h>
#define LDAP_DEPRECATED 1
#include <ldap.h>
#define PHP_LD_FULL_ADD 0xff
namespace HPHP {
IMPLEMENT_DEFAULT_EXTENSION(ldap);
///////////////////////////////////////////////////////////////////////////////
class LdapRequestData {
public:
LdapRequestData() : m_num_links(0), m_max_links(-1) {
}
long m_num_links;
long m_max_links;
};
static IMPLEMENT_THREAD_LOCAL(LdapRequestData, s_ldap_data);
#define LDAPG(name) s_ldap_data->m_ ## name
class LdapLink : public SweepableResourceData {
public:
DECLARE_OBJECT_ALLOCATION(LdapLink)
LdapLink() : link(NULL) {}
~LdapLink() { close();}
void close() {
if (link) {
ldap_unbind_s(link);
link = NULL;
LDAPG(num_links)--;
}
rebindproc.reset();
}
static StaticString s_class_name;
// overriding ResourceData
virtual CStrRef o_getClassNameHook() const { return s_class_name; }
LDAP *link;
Variant rebindproc;
};
IMPLEMENT_OBJECT_ALLOCATION(LdapLink)
StaticString LdapLink::s_class_name("ldap link");
class LdapResult : public SweepableResourceData {
public:
DECLARE_OBJECT_ALLOCATION(LdapResult)
LdapResult(LDAPMessage *res) : data(res) {}
~LdapResult() { close();}
void close() {
if (data) {
ldap_msgfree(data);
data = NULL;
}
}
static StaticString s_class_name;
// overriding ResourceData
virtual CStrRef o_getClassNameHook() const { return s_class_name;}
LDAPMessage *data;
};
IMPLEMENT_OBJECT_ALLOCATION(LdapResult)
StaticString LdapResult::s_class_name("ldap result");
class LdapResultEntry : public SweepableResourceData {
public:
DECLARE_OBJECT_ALLOCATION(LdapResultEntry)
LdapResultEntry(LDAPMessage *entry, ObjectData *res)
: data(entry), ber(NULL), result(res) {}
~LdapResultEntry() { close();}
void close() {
if (ber != NULL) {
ber_free(ber, 0);
ber = NULL;
}
data = NULL;
}
static StaticString s_class_name;
// overriding ResourceData
virtual CStrRef o_getClassNameHook() const { return s_class_name; }
LDAPMessage *data;
BerElement *ber;
Object result; // Reference to LdapResult to avoid premature deallocation
};
IMPLEMENT_OBJECT_ALLOCATION_NO_DEFAULT_SWEEP(LdapResultEntry)
void LdapResultEntry::sweep() {
close();
}
StaticString LdapResultEntry::s_class_name("ldap result entry");
///////////////////////////////////////////////////////////////////////////////
static int _get_lderrno(LDAP *ldap) {
int lderr;
ldap_get_option(ldap, LDAP_OPT_ERROR_NUMBER, &lderr);
return lderr;
}
static bool php_ldap_do_modify(CObjRef link, CStrRef dn, CArrRef entry,
int oper) {
bool is_full_add = false; /* flag for full add operation so ldap_mod_add
can be put back into oper, gerrit THomson */
LdapLink *ld = link.getTyped<LdapLink>();
int num_attribs = entry.size();
LDAPMod **ldap_mods =
(LDAPMod **)malloc((num_attribs+1) * sizeof(LDAPMod *));
int *num_berval = (int*)malloc(num_attribs * sizeof(int));
ArrayIter iter(entry);
int num_values;
/* added by gerrit thomson to fix ldap_add using ldap_mod_add */
if (oper == PHP_LD_FULL_ADD) {
oper = LDAP_MOD_ADD;
is_full_add = true;
}
/* end additional , gerrit thomson */
bool ret = false;
Array stringHolder;
for (int i = 0; i < num_attribs; i++) {
ldap_mods[i] = (LDAPMod*)malloc(sizeof(LDAPMod));
ldap_mods[i]->mod_op = oper | LDAP_MOD_BVALUES;
ldap_mods[i]->mod_type = NULL;
Variant key = iter.first();
Variant value = iter.second();
if (key.isString()) {
ldap_mods[i]->mod_type = strdup(key.toString().data());
} else {
raise_warning("Unknown attribute in the data");
/* Free allocated memory */
while (i >= 0) {
if (ldap_mods[i]->mod_type) {
free(ldap_mods[i]->mod_type);
}
free(ldap_mods[i]);
i--;
}
free(num_berval);
free(ldap_mods);
return false;
}
if (!value.isArray()) {
num_values = 1;
} else {
num_values = value.toArray().size();
}
num_berval[i] = num_values;
ldap_mods[i]->mod_bvalues =
(struct berval**)malloc((num_values + 1) * sizeof(struct berval *));
/* allow for arrays with one element, no allowance for arrays with
none but probably not required, gerrit thomson. */
if (num_values == 1 && !value.isArray()) {
String svalue = value.toString();
stringHolder.append(svalue);
ldap_mods[i]->mod_bvalues[0] = (berval *)malloc(sizeof(struct berval));
ldap_mods[i]->mod_bvalues[0]->bv_len = svalue.size();
ldap_mods[i]->mod_bvalues[0]->bv_val = (char*)svalue.data();
} else {
Array arr = value.toArray();
for (int j = 0; j < num_values; j++) {
if (!arr.exists(j)) {
raise_warning("Value array must have consecutive indices 0, 1, ...");
num_berval[i] = j;
num_attribs = i + 1;
goto errexit;
}
String ivalue = arr[j].toString();
ldap_mods[i]->mod_bvalues[j] = (berval *)malloc(sizeof(struct berval));
ldap_mods[i]->mod_bvalues[j]->bv_len = ivalue.size();
ldap_mods[i]->mod_bvalues[j]->bv_val = (char*)ivalue.data();
}
}
ldap_mods[i]->mod_bvalues[num_values] = NULL;
++iter;
}
ldap_mods[num_attribs] = NULL;
/* check flag to see if do_mod was called to perform full add,
gerrit thomson */
int rc;
if (is_full_add) {
if ((rc = ldap_add_s(ld->link, (char*)dn.data(), ldap_mods))
!= LDAP_SUCCESS) {
raise_warning("Add: %s", ldap_err2string(rc));
} else {
ret = true;
}
} else {
if ((rc = ldap_modify_s(ld->link, (char*)dn.data(), ldap_mods))
!= LDAP_SUCCESS) {
raise_warning("Modify: %s", ldap_err2string(rc));
} else {
ret = true;
}
}
errexit:
for (int i = 0; i < num_attribs; i++) {
free(ldap_mods[i]->mod_type);
for (int j = 0; j < num_berval[i]; j++) {
free(ldap_mods[i]->mod_bvalues[j]);
}
free(ldap_mods[i]->mod_bvalues);
free(ldap_mods[i]);
}
free(num_berval);
free(ldap_mods);
return ret;
}
static void php_set_opts(LDAP *ldap, int sizelimit, int timelimit, int deref,
int *old_sizelimit, int *old_timelimit,
int *old_deref) {
/* sizelimit */
if (sizelimit > -1) {
ldap_get_option(ldap, LDAP_OPT_SIZELIMIT, old_sizelimit);
ldap_set_option(ldap, LDAP_OPT_SIZELIMIT, &sizelimit);
}
/* timelimit */
if (timelimit > -1) {
ldap_get_option(ldap, LDAP_OPT_SIZELIMIT, old_timelimit);
ldap_set_option(ldap, LDAP_OPT_TIMELIMIT, &timelimit);
}
/* deref */
if (deref > -1) {
ldap_get_option(ldap, LDAP_OPT_SIZELIMIT, old_deref);
ldap_set_option(ldap, LDAP_OPT_DEREF, &deref);
}
}
static Variant php_ldap_do_search(CVarRef link, CVarRef base_dn,
CVarRef filter, CArrRef attributes,
int attrsonly, int sizelimit, int timelimit,
int deref, int scope) {
int num_attribs = attributes.size();
int old_sizelimit = -1, old_timelimit = -1, old_deref = -1;
int ldap_err = 1, parallel_search = 1;
char **ldap_attrs = (char**)malloc((num_attribs+1) * sizeof(char *));
Array stringHolder;
Array ret = Array::Create();
char *ldap_base_dn = NULL;
char *ldap_filter = NULL;
LdapLink *ld = NULL;
for (int i = 0; i < num_attribs; i++) {
if (!attributes.exists(i)) {
raise_warning("Array initialization wrong");
ldap_err = 0;
goto cleanup;
}
String attr = attributes[i].toString();
stringHolder.append(attr);
ldap_attrs[i] = (char*)attr.data();
}
ldap_attrs[num_attribs] = NULL;
/* parallel search? */
if (link.isArray()) {
int nlinks = link.toArray().size();
if (nlinks == 0) {
raise_warning("No links in link array");
ldap_err = 0;
goto cleanup;
}
int nbases;
if (base_dn.isArray()) {
nbases = base_dn.toArray().size();
if (nbases != nlinks) {
raise_warning("Base must either be a string, or an array with the "
"same number of elements as the links array");
ldap_err = 0;
goto cleanup;
}
} else {
nbases = 0; /* this means string, not array */
/* If anything else than string is passed, ldap_base_dn = NULL */
if (base_dn.isString()) {
ldap_base_dn = (char*)base_dn.toString().data();
} else {
ldap_base_dn = NULL;
}
}
int nfilters;
if (filter.isArray()) {
nfilters = filter.toArray().size();
if (nfilters != nlinks) {
raise_warning("Filter must either be a string, or an array with the "
"same number of elements as the links array");
ldap_err = 0;
goto cleanup;
}
} else {
nfilters = 0; /* this means string, not array */
String sfilter = filter.toString();
stringHolder.append(sfilter);
ldap_filter = (char*)sfilter.data();
}
LdapLink **lds = (LdapLink**)malloc(nlinks * sizeof(LdapLink*));
int *rcs = (int*)malloc(nlinks * sizeof(int));
ArrayIter iter(link);
ArrayIter iterdn(base_dn.toArray());
ArrayIter iterfilter(filter.toArray());
for (int i = 0; i < nlinks; i++) {
ld = iter.second().toObject().getTyped<LdapLink>(true, true);
if (ld == NULL) {
ldap_err = 0;
goto cleanup_parallel;
}
if (nbases != 0) { /* base_dn an array? */
Variant entry = iterdn.second();
++iterdn;
/* If anything else than string is passed, ldap_base_dn = NULL */
if (entry.isString()) {
ldap_base_dn = (char*)entry.toString().data();
} else {
ldap_base_dn = NULL;
}
}
if (nfilters != 0) { /* filter an array? */
Variant entry = iterfilter.second();
++iterfilter;
String sentry = entry.toString();
stringHolder.append(sentry);
ldap_filter = (char*)sentry.data();
}
php_set_opts(ld->link, sizelimit, timelimit, deref, &old_sizelimit,
&old_timelimit, &old_deref);
/* Run the actual search */
rcs[i] = ldap_search(ld->link, ldap_base_dn, scope, ldap_filter,
ldap_attrs, attrsonly);
lds[i] = ld;
++iter;
}
/* Collect results from the searches */
for (int i = 0; i < nlinks; i++) {
LDAPMessage *ldap_res;
if (rcs[i] != -1) {
rcs[i] = ldap_result(lds[i]->link, LDAP_RES_ANY, 1 /* LDAP_MSG_ALL */,
NULL, &ldap_res);
}
if (rcs[i] != -1) {
ret.append(Object(NEWOBJ(LdapResult)(ldap_res)));
} else {
ret.append(false);
}
}
cleanup_parallel:
free(lds);
free(rcs);
} else {
/* parallel search? */
String sfilter = filter.toString();
ldap_filter = (char*)sfilter.data();
/* If anything else than string is passed, ldap_base_dn = NULL */
if (base_dn.isString()) {
ldap_base_dn = (char*)base_dn.toString().data();
}
ld = link.toObject().getTyped<LdapLink>(true, true);
if (ld == NULL) {
ldap_err = 0;
goto cleanup;
}
php_set_opts(ld->link, sizelimit, timelimit, deref, &old_sizelimit,
&old_timelimit, &old_deref);
/* Run the actual search */
LDAPMessage *ldap_res;
int rc = ldap_search_s(ld->link, ldap_base_dn, scope, ldap_filter,
ldap_attrs, attrsonly, &ldap_res);
if (rc != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED
#ifdef LDAP_ADMINLIMIT_EXCEEDED
&& rc != LDAP_ADMINLIMIT_EXCEEDED
#endif
#ifdef LDAP_REFERRAL
&& rc != LDAP_REFERRAL
#endif
) {
raise_warning("Search: %s", ldap_err2string(rc));
ldap_err = 0;
} else {
if (rc == LDAP_SIZELIMIT_EXCEEDED) {
raise_warning("Partial search results returned: Sizelimit exceeded");
}
#ifdef LDAP_ADMINLIMIT_EXCEEDED
else if (rc == LDAP_ADMINLIMIT_EXCEEDED) {
raise_warning("Partial search results returned: Adminlimit exceeded");
}
#endif
parallel_search = 0;
ret.append(Object(NEWOBJ(LdapResult)(ldap_res)));
}
}
cleanup:
if (ld) {
/* Restoring previous options */
php_set_opts(ld->link, old_sizelimit, old_timelimit, old_deref, &sizelimit,
&timelimit, &deref);
}
if (ldap_attrs != NULL) {
free(ldap_attrs);
}
if (!ldap_err) {
return false;
}
if (!parallel_search) {
return ret.dequeue();
} else {
return ret;
}
}
static int _ldap_rebind_proc(LDAP *ldap, const char *url, ber_tag_t req,
ber_int_t msgid, void *params) {
LdapLink *ld = (LdapLink*)params;
/* link exists and callback set? */
if (ld == NULL || ld->rebindproc.isNull()) {
raise_warning("Link not found or no callback set");
return LDAP_OTHER;
}
/* callback */
Variant ret = vm_call_user_func
(ld->rebindproc, CREATE_VECTOR2(Object(ld), String(url, CopyString)));
return ret.toInt64();
}
static const StaticString s_count("count");
static const StaticString s_dn("dn");
static void get_attributes(Array &ret, LDAP *ldap,
LDAPMessage *ldap_result_entry, bool to_lower) {
int num_attrib = 0;
BerElement *ber;
char *attribute = ldap_first_attribute(ldap, ldap_result_entry, &ber);
while (attribute != NULL) {
struct berval **ldap_value =
ldap_get_values_len(ldap, ldap_result_entry, attribute);
int num_values = ldap_count_values_len(ldap_value);
Array tmp;
tmp.set(s_count, num_values);
for (int i = 0; i < num_values; i++) {
tmp.append(String(ldap_value[i]->bv_val, ldap_value[i]->bv_len,
CopyString));
}
ldap_value_free_len(ldap_value);
String sAttribute(attribute, CopyString);
ret.set(to_lower ? String(Util::toLower(attribute)) : sAttribute, tmp);
ret.set(num_attrib, sAttribute);
num_attrib++;
ldap_memfree(attribute);
attribute = ldap_next_attribute(ldap, ldap_result_entry, ber);
}
if (ber != NULL) {
ber_free(ber, 0);
}
ret.set(s_count, num_attrib);
}
///////////////////////////////////////////////////////////////////////////////
Variant f_ldap_connect(CStrRef hostname /* = null_string */,
int port /* = 389 */) {
if (LDAPG(max_links) != -1 && LDAPG(num_links) >= LDAPG(max_links)) {
raise_warning("Too many open links (%ld)", LDAPG(num_links));
return false;
}
LdapLink *ld = NEWOBJ(LdapLink)();
Object ret(ld);
LDAP *ldap = NULL;
if (!hostname.empty() && hostname.find('/') >= 0) {
int rc = ldap_initialize(&ldap, hostname.data());
if (rc != LDAP_SUCCESS) {
raise_warning("Could not create session handle: %s",
ldap_err2string(rc));
return false;
}
} else {
ldap = ldap_init((char*)hostname.data(), port);
}
if (ldap) {
LDAPG(num_links)++;
ld->link = ldap;
return ret;
}
raise_warning("Unable to initialize LDAP: %s",
Util::safe_strerror(errno).c_str());
return false;
}
Variant f_ldap_explode_dn(CStrRef dn, int with_attrib) {
char **ldap_value;
if (!(ldap_value = ldap_explode_dn((char*)dn.data(), with_attrib))) {
/* Invalid parameters were passed to ldap_explode_dn */
return false;
}
int i = 0;
while (ldap_value[i] != NULL) i++;
int count = i;
Array ret;
ret.set(s_count, count);
for (i = 0; i < count; i++) {
ret.append(String(ldap_value[i], CopyString));
}
ldap_value_free(ldap_value);
return ret;
}
Variant f_ldap_dn2ufn(CStrRef db) {
char *ufn = ldap_dn2ufn((char*)db.data());
if (ufn) {
String ret(ufn, CopyString);
ldap_memfree(ufn);
return ret;
}
return false;
}
String f_ldap_err2str(int errnum) {
return String(ldap_err2string(errnum), CopyString);
}
bool f_ldap_add(CObjRef link, CStrRef dn, CArrRef entry) {
return php_ldap_do_modify(link, dn, entry, PHP_LD_FULL_ADD);
}
bool f_ldap_mod_add(CObjRef link, CStrRef dn, CArrRef entry) {
return php_ldap_do_modify(link, dn, entry, LDAP_MOD_ADD);
}
bool f_ldap_mod_del(CObjRef link, CStrRef dn, CArrRef entry) {
return php_ldap_do_modify(link, dn, entry, LDAP_MOD_DELETE);
}
bool f_ldap_mod_replace(CObjRef link, CStrRef dn, CArrRef entry) {
return php_ldap_do_modify(link, dn, entry, LDAP_MOD_REPLACE);
}
bool f_ldap_modify(CObjRef link, CStrRef dn, CArrRef entry) {
return php_ldap_do_modify(link, dn, entry, LDAP_MOD_REPLACE);
}
bool f_ldap_bind(CObjRef link, CStrRef bind_rdn /* = null_string */,
CStrRef bind_password /* = null_string */) {
int rc;
LdapLink *ld = link.getTyped<LdapLink>();
if ((rc = ldap_bind_s(ld->link, (char*)bind_rdn.data(),
(char*)bind_password.data(),
LDAP_AUTH_SIMPLE)) != LDAP_SUCCESS) {
raise_warning("Unable to bind to server: %s", ldap_err2string(rc));
return false;
}
return true;
}
bool f_ldap_set_rebind_proc(CObjRef link, CVarRef callback) {
LdapLink *ld = link.getTyped<LdapLink>();
if (callback.isString() && callback.toString().empty()) {
/* unregister rebind procedure */
if (!ld->rebindproc.isNull()) {
ld->rebindproc.reset();
ldap_set_rebind_proc(ld->link, NULL, NULL);
}
return true;
}
/* callable? */
if (!f_is_callable(callback)) {
raise_warning("Callback argument is not a valid callback");
return false;
}
/* register rebind procedure */
if (ld->rebindproc.isNull()) {
ldap_set_rebind_proc(ld->link, _ldap_rebind_proc, (void *)link.get());
} else {
ld->rebindproc.reset();
}
ld->rebindproc = callback;
return true;
}
bool f_ldap_sort(CObjRef link, CObjRef result, CStrRef sortfilter) {
LdapLink *ld = link.getTyped<LdapLink>();
LdapResult *res = result.getTyped<LdapResult>();
if (ldap_sort_entries(ld->link, &res->data,
!sortfilter.empty() ? (char*)sortfilter.data() : NULL,
strcmp) != LDAP_SUCCESS) {
raise_warning("%s", ldap_err2string(_get_lderrno(ld->link)));
return false;
}
return true;
}
bool f_ldap_start_tls(CObjRef link) {
LdapLink *ld = link.getTyped<LdapLink>();
int rc, protocol = LDAP_VERSION3;
if (((rc = ldap_set_option(ld->link, LDAP_OPT_PROTOCOL_VERSION, &protocol))
!= LDAP_SUCCESS) ||
((rc = ldap_start_tls_s(ld->link, NULL, NULL)) != LDAP_SUCCESS)) {
raise_warning("Unable to start TLS: %s", ldap_err2string(rc));
return false;
}
return true;
}
bool f_ldap_unbind(CObjRef link) {
LdapLink *ld = link.getTyped<LdapLink>();
ld->close();
return true;
}
bool f_ldap_get_option(CObjRef link, int option, VRefParam retval) {
LdapLink *ld = link.getTyped<LdapLink>();
switch (option) {
/* options with int value */
case LDAP_OPT_DEREF:
case LDAP_OPT_SIZELIMIT:
case LDAP_OPT_TIMELIMIT:
case LDAP_OPT_PROTOCOL_VERSION:
case LDAP_OPT_ERROR_NUMBER:
case LDAP_OPT_REFERRALS:
#ifdef LDAP_OPT_RESTART
case LDAP_OPT_RESTART:
#endif
{
int val;
if (ldap_get_option(ld->link, option, &val)) {
return false;
}
retval = (int64_t)val;
} break;
#ifdef LDAP_OPT_NETWORK_TIMEOUT
case LDAP_OPT_NETWORK_TIMEOUT:
{
struct timeval *timeout;
if (ldap_get_option(ld->link, LDAP_OPT_NETWORK_TIMEOUT,
(void *) &timeout)) {
if (timeout) {
ldap_memfree(timeout);
}
return false;
}
retval = (int64_t)timeout->tv_sec;
ldap_memfree(timeout);
} break;
#elif defined(LDAP_X_OPT_CONNECT_TIMEOUT)
case LDAP_X_OPT_CONNECT_TIMEOUT:
{
int timeout;
if (ldap_get_option(ld->link, LDAP_X_OPT_CONNECT_TIMEOUT, &timeout)) {
return false;
}
retval = (int64_t)(timeout / 1000);
} break;
#endif
/* options with string value */
case LDAP_OPT_ERROR_STRING:
#ifdef LDAP_OPT_HOST_NAME
case LDAP_OPT_HOST_NAME:
#endif
#ifdef HAVE_LDAP_SASL
case LDAP_OPT_X_SASL_MECH:
case LDAP_OPT_X_SASL_REALM:
case LDAP_OPT_X_SASL_AUTHCID:
case LDAP_OPT_X_SASL_AUTHZID:
#endif
#ifdef LDAP_OPT_MATCHED_DN
case LDAP_OPT_MATCHED_DN:
#endif
{
char *val = NULL;
if (ldap_get_option(ld->link, option, &val) || val == NULL ||
*val == '\0') {
if (val) {
ldap_memfree(val);
}
return false;
}
retval = String(val, CopyString);
ldap_memfree(val);
} break;
/* options not implemented
case LDAP_OPT_SERVER_CONTROLS:
case LDAP_OPT_CLIENT_CONTROLS:
case LDAP_OPT_API_INFO:
case LDAP_OPT_API_FEATURE_INFO:
*/
default:
return false;
}
return true;
}
static const StaticString s_oid("oid");
static const StaticString s_value("value");
static const StaticString s_iscritical("iscritical");
bool f_ldap_set_option(CVarRef link, int option, CVarRef newval) {
LDAP *ldap = NULL;
if (!link.isNull()) {
LdapLink *ld = link.toObject().getTyped<LdapLink>();
ldap = ld->link;
}
switch (option) {
/* options with int value */
case LDAP_OPT_DEREF:
case LDAP_OPT_SIZELIMIT:
case LDAP_OPT_TIMELIMIT:
case LDAP_OPT_PROTOCOL_VERSION:
case LDAP_OPT_ERROR_NUMBER:
#ifdef LDAP_OPT_DEBUG_LEVEL
case LDAP_OPT_DEBUG_LEVEL:
#endif
{
int val = newval.toInt64();
if (ldap_set_option(ldap, option, &val)) {
return false;
}
} break;
#ifdef LDAP_OPT_NETWORK_TIMEOUT
case LDAP_OPT_NETWORK_TIMEOUT:
{
struct timeval timeout;
timeout.tv_sec = newval.toInt64();
timeout.tv_usec = 0;
if (ldap_set_option(ldap, LDAP_OPT_NETWORK_TIMEOUT, (void *) &timeout)) {
return false;
}
} break;
#elif defined(LDAP_X_OPT_CONNECT_TIMEOUT)
case LDAP_X_OPT_CONNECT_TIMEOUT:
{
int timeout = 1000 * newval.toInt64(); /* Convert to milliseconds */
if (ldap_set_option(ldap, LDAP_X_OPT_CONNECT_TIMEOUT, &timeout)) {
return false;
}
} break;
#endif
/* options with string value */
case LDAP_OPT_ERROR_STRING:
#ifdef LDAP_OPT_HOST_NAME
case LDAP_OPT_HOST_NAME:
#endif
#ifdef HAVE_LDAP_SASL
case LDAP_OPT_X_SASL_MECH:
case LDAP_OPT_X_SASL_REALM:
case LDAP_OPT_X_SASL_AUTHCID:
case LDAP_OPT_X_SASL_AUTHZID:
#endif
#ifdef LDAP_OPT_MATCHED_DN
case LDAP_OPT_MATCHED_DN:
#endif
{
String snewval = newval.toString();
char *val = (char*)snewval.data();
if (ldap_set_option(ldap, option, val)) {
return false;
}
} break;
/* options with boolean value */
case LDAP_OPT_REFERRALS:
#ifdef LDAP_OPT_RESTART
case LDAP_OPT_RESTART:
#endif
{
void *val = newval.toBoolean() ? LDAP_OPT_ON : LDAP_OPT_OFF;
if (ldap_set_option(ldap, option, val)) {
return false;
}
} break;
/* options with control list value */
case LDAP_OPT_SERVER_CONTROLS:
case LDAP_OPT_CLIENT_CONTROLS:
{
LDAPControl *ctrl, **ctrls, **ctrlp;
int ncontrols;
char error=0;
if (!newval.isArray() || !(ncontrols = newval.toArray().size())) {
raise_warning("Expected non-empty array value for this option");
return false;
}
ctrls = (LDAPControl**)malloc((1 + ncontrols) * sizeof(*ctrls));
*ctrls = NULL;
ctrlp = ctrls;
Array stringHolder;
for (ArrayIter iter(newval); iter; ++iter) {
Variant vctrlval = iter.second();
if (!vctrlval.isArray()) {
raise_warning("The array value must contain only arrays, "
"where each array is a control");
error = 1;
break;
}
Array ctrlval = vctrlval.toArray();
if (!ctrlval.exists(s_oid)) {
raise_warning("Control must have an oid key");
error = 1;
break;
}
String val = ctrlval[s_oid].toString();
stringHolder.append(val);
ctrl = *ctrlp = (LDAPControl*)malloc(sizeof(**ctrlp));
ctrl->ldctl_oid = (char*)val.data();
if (ctrlval.exists(s_value)) {
val = ctrlval[s_value].toString();
stringHolder.append(val);
ctrl->ldctl_value.bv_val = (char*)val.data();
ctrl->ldctl_value.bv_len = val.size();
} else {
ctrl->ldctl_value.bv_val = NULL;
ctrl->ldctl_value.bv_len = 0;
}
if (ctrlval.exists(s_iscritical)) {
ctrl->ldctl_iscritical = val.toBoolean() ? 1 : 0;
} else {
ctrl->ldctl_iscritical = 0;
}
++ctrlp;
*ctrlp = NULL;
}
if (!error) {
error = ldap_set_option(ldap, option, ctrls);
}
ctrlp = ctrls;
while (*ctrlp) {
free(*ctrlp);
ctrlp++;
}
free(ctrls);
if (error) {
return false;
}
} break;
default:
return false;
}
return true;
}
bool f_ldap_close(CObjRef link) {
return f_ldap_unbind(link);
}
Variant f_ldap_list(CVarRef link, CVarRef base_dn, CVarRef filter,
CArrRef attributes /* = null_array */,
int attrsonly /* = 0 */, int sizelimit /* = -1 */,
int timelimit /* = -1 */, int deref /* = -1 */) {
return php_ldap_do_search(link, base_dn, filter, attributes, attrsonly,
sizelimit, timelimit, deref, LDAP_SCOPE_ONELEVEL);
}
Variant f_ldap_read(CVarRef link, CVarRef base_dn, CVarRef filter,
CArrRef attributes /* = null_array */,
int attrsonly /* = 0 */, int sizelimit /* = -1 */,
int timelimit /* = -1 */, int deref /* = -1 */) {
return php_ldap_do_search(link, base_dn, filter, attributes, attrsonly,
sizelimit, timelimit, deref, LDAP_SCOPE_BASE);
}
Variant f_ldap_search(CVarRef link, CVarRef base_dn, CVarRef filter,
CArrRef attributes /* = null_array */,
int attrsonly /* = 0 */, int sizelimit /* = -1 */,
int timelimit /* = -1 */, int deref /* = -1 */) {
return php_ldap_do_search(link, base_dn, filter, attributes, attrsonly,
sizelimit, timelimit, deref, LDAP_SCOPE_SUBTREE);
}
bool f_ldap_rename(CObjRef link, CStrRef dn, CStrRef newrdn, CStrRef newparent,
bool deleteoldrdn) {
LdapLink *ld = link.getTyped<LdapLink>();
int rc = ldap_rename_s(ld->link, (char*)dn.data(), (char*)newrdn.data(),
!newparent.empty() ? (char*)newparent.data() : NULL,
deleteoldrdn, NULL, NULL);
return rc == LDAP_SUCCESS;
}
bool f_ldap_delete(CObjRef link, CStrRef dn) {
LdapLink *ld = link.getTyped<LdapLink>();
int rc;
if ((rc = ldap_delete_s(ld->link, (char*)dn.data())) != LDAP_SUCCESS) {
raise_warning("Delete: %s", ldap_err2string(rc));
return false;
}
return true;
}
Variant f_ldap_compare(CObjRef link, CStrRef dn, CStrRef attribute,
CStrRef value) {
LdapLink *ld = link.getTyped<LdapLink>();
int rc = ldap_compare_s(ld->link, (char*)dn.data(), (char*)attribute.data(),
(char*)value.data());
switch (rc) {
case LDAP_COMPARE_TRUE: return true;
case LDAP_COMPARE_FALSE: return false;
}
raise_warning("Compare: %s", ldap_err2string(rc));
return -1LL;
}
int64_t f_ldap_errno(CObjRef link) {
LdapLink *ld = link.getTyped<LdapLink>();
return _get_lderrno(ld->link);
}
String f_ldap_error(CObjRef link) {
LdapLink *ld = link.getTyped<LdapLink>();
int ld_errno = _get_lderrno(ld->link);
return String(ldap_err2string(ld_errno), CopyString);
}
Variant f_ldap_get_dn(CObjRef link, CObjRef result_entry) {
LdapLink *ld = link.getTyped<LdapLink>();
LdapResultEntry *entry = result_entry.getTyped<LdapResultEntry>();
char *text = ldap_get_dn(ld->link, entry->data);
if (text) {
String ret(text, CopyString);
ldap_memfree(text);
return ret;
}
return false;
}
int64_t f_ldap_count_entries(CObjRef link, CObjRef result) {
LdapLink *ld = link.getTyped<LdapLink>();
LdapResult *res = result.getTyped<LdapResult>();
return ldap_count_entries(ld->link, res->data);
}
Variant f_ldap_get_entries(CObjRef link, CObjRef result) {
LdapLink *ld = link.getTyped<LdapLink>();
LdapResult *res = result.getTyped<LdapResult>();
LDAP *ldap = ld->link;
int num_entries = ldap_count_entries(ldap, res->data);
Array ret;
ret.set(s_count, num_entries);
if (num_entries == 0) {
return uninit_null();
}
LDAPMessage *ldap_result_entry = ldap_first_entry(ldap, res->data);
if (ldap_result_entry == NULL) {
return false;
}
num_entries = 0;
while (ldap_result_entry != NULL) {
Array tmp1 = Array::Create();
get_attributes(tmp1, ldap, ldap_result_entry, true);
char *dn = ldap_get_dn(ldap, ldap_result_entry);
tmp1.set(s_dn, String(dn, CopyString));
ldap_memfree(dn);
ret.set(num_entries, tmp1);
num_entries++;
ldap_result_entry = ldap_next_entry(ldap, ldap_result_entry);
}
ret.set(s_count, num_entries);
return ret;
}
Variant f_ldap_first_entry(CObjRef link, CObjRef result) {
LdapLink *ld = link.getTyped<LdapLink>();
LdapResult *res = result.getTyped<LdapResult>();
LDAPMessage *entry;
if ((entry = ldap_first_entry(ld->link, res->data)) == NULL) {
return false;
}
return NEWOBJ(LdapResultEntry)(entry, res);
}
Variant f_ldap_next_entry(CObjRef link, CObjRef result_entry) {
LdapLink *ld = link.getTyped<LdapLink>();
LdapResultEntry *entry = result_entry.getTyped<LdapResultEntry>();
LDAPMessage *msg;
if ((msg = ldap_next_entry(ld->link, entry->data)) == NULL) {
return false;
}
return NEWOBJ(LdapResultEntry)(msg, entry->result.get());
}
Array f_ldap_get_attributes(CObjRef link, CObjRef result_entry) {
LdapLink *ld = link.getTyped<LdapLink>();
LdapResultEntry *entry = result_entry.getTyped<LdapResultEntry>();
Array ret = Array::Create();
get_attributes(ret, ld->link, entry->data, false);
return ret;
}
Variant f_ldap_first_attribute(CObjRef link, CObjRef result_entry) {
LdapLink *ld = link.getTyped<LdapLink>();
LdapResultEntry *entry = result_entry.getTyped<LdapResultEntry>();
char *attribute;
if ((attribute =
ldap_first_attribute(ld->link, entry->data, &entry->ber)) == NULL) {
return false;
}
String ret(attribute, CopyString);
ldap_memfree(attribute);
return ret;
}
Variant f_ldap_next_attribute(CObjRef link, CObjRef result_entry) {
LdapLink *ld = link.getTyped<LdapLink>();
LdapResultEntry *entry = result_entry.getTyped<LdapResultEntry>();
if (entry->ber == NULL) {
raise_warning("called before calling ldap_first_attribute() or "
"no attributes found in result entry");
return false;
}
char *attribute;
if ((attribute =
ldap_next_attribute(ld->link, entry->data, entry->ber)) == NULL) {
if (entry->ber != NULL) {
ber_free(entry->ber, 0);
entry->ber = NULL;
}
return false;
}
String ret(attribute, CopyString);
ldap_memfree(attribute);
return ret;
}
Variant f_ldap_first_reference(CObjRef link, CObjRef result) {
LdapLink *ld = link.getTyped<LdapLink>();
LdapResult *res = result.getTyped<LdapResult>();
LDAPMessage *entry;
if ((entry = ldap_first_reference(ld->link, res->data)) == NULL) {
return false;
}
return NEWOBJ(LdapResultEntry)(entry, res);
}
Variant f_ldap_next_reference(CObjRef link, CObjRef result_entry) {
LdapLink *ld = link.getTyped<LdapLink>();
LdapResultEntry *entry = result_entry.getTyped<LdapResultEntry>();
LDAPMessage *entry_next;
if ((entry_next = ldap_next_reference(ld->link, entry->data)) == NULL) {
return false;
}
return NEWOBJ(LdapResultEntry)(entry_next, entry->result.get());
}
bool f_ldap_parse_reference(CObjRef link, CObjRef result_entry,
VRefParam referrals) {
LdapLink *ld = link.getTyped<LdapLink>();
LdapResultEntry *entry = result_entry.getTyped<LdapResultEntry>();
char **lreferrals, **refp;
if (ldap_parse_reference(ld->link, entry->data, &lreferrals,
NULL /* &serverctrls */, 0) != LDAP_SUCCESS) {
return false;
}
Array arr = Array::Create();
if (lreferrals != NULL) {
refp = lreferrals;
while (*refp) {
arr.append(String(*refp, CopyString));
refp++;
}
ldap_value_free(lreferrals);
}
referrals = arr;
return true;
}
bool f_ldap_parse_result(CObjRef link, CObjRef result, VRefParam errcode,
VRefParam matcheddn /* = null */,
VRefParam errmsg /* = null */,
VRefParam referrals /* = null */) {
LdapLink *ld = link.getTyped<LdapLink>();
LdapResult *res = result.getTyped<LdapResult>();
int lerrcode;
char **lreferrals, **refp;
char *lmatcheddn, *lerrmsg;
int rc = ldap_parse_result(ld->link, res->data, &lerrcode,
&lmatcheddn, &lerrmsg, &lreferrals,
NULL /* &serverctrls */, 0);
if (rc != LDAP_SUCCESS) {
raise_warning("Unable to parse result: %s", ldap_err2string(rc));
return false;
}
errcode = lerrcode;
/* Reverse -> fall through */
Array arr = Array::Create();
if (lreferrals != NULL) {
refp = lreferrals;
while (*refp) {
arr.append(String(*refp, CopyString));
refp++;
}
ldap_value_free(lreferrals);
}
referrals = arr;
if (lerrmsg == NULL) {
errmsg = String("");
} else {
errmsg = String(lerrmsg, CopyString);
ldap_memfree(lerrmsg);
}
if (lmatcheddn == NULL) {
matcheddn = String("");
} else {
matcheddn = String(lmatcheddn, CopyString);
ldap_memfree(lmatcheddn);
}
return true;
}
bool f_ldap_free_result(CObjRef result) {
LdapResult *res = result.getTyped<LdapResult>();
res->close();
return true;
}
Variant f_ldap_get_values_len(CObjRef link, CObjRef result_entry,
CStrRef attribute) {
LdapLink *ld = link.getTyped<LdapLink>();
LdapResultEntry *entry = result_entry.getTyped<LdapResultEntry>();
struct berval **ldap_value_len;
if ((ldap_value_len =
ldap_get_values_len(ld->link, entry->data,
(char*)attribute.data())) == NULL) {
raise_warning("Cannot get the value(s) of attribute %s",
ldap_err2string(_get_lderrno(ld->link)));
return false;
}
int num_values = ldap_count_values_len(ldap_value_len);
Array ret;
for (int i = 0; i < num_values; i++) {
ret.append(String(ldap_value_len[i]->bv_val, ldap_value_len[i]->bv_len,
CopyString));
}
ret.set(s_count, num_values);
ldap_value_free_len(ldap_value_len);
return ret;
}
Variant f_ldap_get_values(CObjRef link, CObjRef result_entry,
CStrRef attribute) {
return f_ldap_get_values_len(link, result_entry, attribute);
}
///////////////////////////////////////////////////////////////////////////////
}