9c453b1ad0
unserialize() and call_user_func_array() were straightforward. They were called from all over the runtime, but I renamed those implementations and codemodded the runtime. The is_* functions were only ever being called by the CVarRef signature, so I deleted all the other ones (same for f_gettype). Only some of the is_* functions were being called from the runtime, so I made inline versions of those without the f_ prefix.
1246 linhas
35 KiB
C++
1246 linhas
35 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 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("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 ? 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("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("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;
|
|
}
|
|
|
|
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("oid")) {
|
|
raise_warning("Control must have an oid key");
|
|
error = 1;
|
|
break;
|
|
}
|
|
String val = ctrlval["oid"].toString();
|
|
stringHolder.append(val);
|
|
ctrl = *ctrlp = (LDAPControl*)malloc(sizeof(**ctrlp));
|
|
ctrl->ldctl_oid = (char*)val.data();
|
|
if (ctrlval.exists("value")) {
|
|
val = ctrlval["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("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("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("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("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("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);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
}
|