#pike __REAL_VERSION__ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if constant(.ldap_privates.ldap_der_decode) |
|
#include "ldap_globals.h" |
|
#include "ldap_errors.h" |
|
#if constant(SSL.sslfile) |
import SSL.constants; |
#endif |
|
#ifdef LDAP_PROTOCOL_PROFILE |
int _prof_gtim; |
#endif |
|
|
|
|
#define ASN1_DECODE_RESULTAPP(X) (.ldap_privates.ldap_der_decode(X)->elements[1]->get_tag()) |
#define ASN1_DECODE_RESULTCODE(X) (int)(.ldap_privates.ldap_der_decode(X)->elements[1]->elements[0]->value->cast_to_int()) |
#define ASN1_DECODE_RESULTSTRING(X) (.ldap_privates.ldap_der_decode(X)->elements[1]->elements[2]->value) |
#define ASN1_DECODE_RESULTREFS(X) (.ldap_privates.ldap_der_decode(X)->elements[1]->elements[3]->elements) |
#define ASN1_DECODE_ENTRIES(X) _New_decode(X) |
#define ASN1_DECODE_DN(X) (string)((X)->elements[0]->value) |
#define ASN1_DECODE_RAWDEBUG(X) (.ldap_privates.ldap_der_decode(X)->debug_string()) |
#define ASN1_GET_ATTR_ARRAY(X) (array)((X)->elements[1]->elements) |
#define ASN1_GET_ATTR_NAME(X) ((X)->elements[0]->value) |
|
|
|
|
|
inherit .protocol; |
|
private int binded = 0; |
private string ldap_basedn = ""; |
private int ldap_scope = 0; |
private int ldap_deref = 0; |
private int ldap_sizelimit = 0; |
private int ldap_timelimit = 0; |
private mapping lauth = ([]); |
private object last_rv = 0; |
|
|
|
|
|
|
|
class result |
{ |
|
private int resultcode = LDAP_SUCCESS; |
private string resultstring; |
private int entrycnt = 0; |
private int actnum = 0; |
private array(mapping(string:array(string))) entry = ({}); |
array(string) referrals; |
|
private string utf2s(string in) { |
|
|
string out = ""; |
catch( out = utf8_to_string(in) ); |
return out; |
|
} |
|
private array _get_attr_values(int ver, object x) { |
|
array res = ({}); |
|
if(!sizeof(x->elements)) |
return(res); |
foreach(x->elements[1]->elements, object val1) |
res += ({ val1->value }); |
if(ver == 3) { |
|
res = Array.map(res, utf2s); |
} |
return(res); |
} |
|
private array _New_decode(array ar) { |
|
array res = ({}); |
array entry1; |
mapping attrs; |
object oder; |
|
foreach(ar, string raw1) { |
oder = (.ldap_privates.ldap_der_decode(raw1)->elements[1]); |
attrs = (["dn":({ASN1_DECODE_DN(oder)})]); |
if(catch(entry1 = ASN1_GET_ATTR_ARRAY(oder))) continue; |
foreach(entry1, object attr1) { |
attrs += ([ASN1_GET_ATTR_NAME(attr1):_get_attr_values(ldap_version, attr1)]); |
} |
res += ({attrs}); |
} |
|
return (res); |
} |
|
|
|
|
object|int create(array rawres, int|void stuff) { |
|
|
|
int lastel = sizeof(rawres) - 1; |
|
if (lastel < 0) { |
global::seterr (LDAP_LOCAL_ERROR); |
THROW(({"LDAP: Internal error.\n",backtrace()})); |
return(-global::ldap_errno); |
} |
DWRITE(sprintf("result.create: rawres=%O\n",rawres[lastel])); |
|
|
resultcode = ASN1_DECODE_RESULTCODE(rawres[lastel]); |
DWRITE(sprintf("result.create: code=%d\n",resultcode)); |
resultstring = ASN1_DECODE_RESULTSTRING(rawres[lastel]); |
DWRITE(sprintf("result.create: str=%s\n",resultstring)); |
#ifdef V3_REFERRALS |
|
if(resultcode == 10) { |
referrals = ({}); |
foreach(ASN1_DECODE_RESULTREFS(rawres[lastel]), object ref1) |
referrals += ({ ref1->value }); |
DWRITE(sprintf("result.create: refs=%O\n",referrals)); |
} |
#endif |
DWRITE(sprintf("result.create: elements=%d\n",lastel+1)); |
if (lastel) { |
entry = ASN1_DECODE_ENTRIES(rawres[..lastel-1]); |
entrycnt = sizeof(entry); |
} |
|
#if 0 |
|
switch(stuff) { |
case 1: DWRITE("result.create: stuff=1\n"); |
break; |
default: DWRITE(sprintf("result.create: stuff=%d\n", stuff)); |
|
} |
#endif |
|
return(this_object()); |
|
} |
|
|
|
|
|
|
int error_number() { return(resultcode); } |
|
|
|
|
|
|
string error_string() { |
return((stringp(resultstring) && sizeof(resultstring)) ? |
resultstring : ldap_errlist[resultcode]); |
} |
|
|
|
|
|
|
int num_entries() { return(entrycnt); } |
|
|
|
|
|
|
|
int count_entries() { return(entrycnt - actnum); } |
|
|
|
|
|
|
|
int|mapping(string:array(string)) fetch(int|void idx) { |
|
if (!idx) |
idx = actnum + 1; |
if ((idx <= num_entries()) && (idx > 0)) { |
actnum = idx - 1; |
return(entry[actnum]); |
} |
return(0); |
} |
|
|
|
|
|
string get_dn() { return(fetch()["dn"][0]); } |
|
|
|
|
|
|
|
void first() { actnum = 0; } |
|
|
|
|
|
|
|
|
int next() { |
if (actnum < (num_entries()-1)) { |
actnum++; |
return(count_entries()); |
} |
return(0); |
} |
|
} |
|
|
|
private int chk_ver() { |
|
if ((ldap_version != 2) && (ldap_version != 3)) { |
seterr (LDAP_PROTOCOL_ERROR); |
THROW(({"LDAP: Unknown/unsupported protocol version.\n",backtrace()})); |
return(-ldap_errno); |
} |
return(0); |
} |
|
private int chk_binded() { |
|
|
if ((ldap_version == 2) && !binded) { |
seterr (LDAP_PROTOCOL_ERROR); |
THROW(({"LDAP: Must binded first.\n",backtrace()})); |
return(-ldap_errno); |
} |
if ((ldap_version == 3) && !binded) |
bind(); |
return(0); |
} |
|
private int chk_dn(string dn) { |
|
if ((!dn) || (!sizeof(dn))) { |
seterr (LDAP_INVALID_DN_SYNTAX); |
THROW(({"LDAP: Invalid DN syntax.\n",backtrace()})); |
return(-ldap_errno); |
} |
return(0); |
} |
|
|
mapping info; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void create(string|void url, object|void context) |
{ |
|
info = ([ "code_revision" : ("$Revision: 1.46 $"/" ")[1] ]); |
|
if(!url || !sizeof(url)) |
url = LDAP_DEFAULT_URL; |
|
lauth = parse_url(url); |
|
if(!stringp(lauth->scheme) || |
((lauth->scheme != "ldap") |
#if constant(SSL.sslfile) |
&& (lauth->scheme != "ldaps") |
#endif |
)) { |
THROW(({"Unknown scheme in server URL.\n",backtrace()})); |
} |
|
if(!lauth->host) |
lauth += ([ "host" : LDAP_DEFAULT_HOST ]); |
if(!lauth->port) |
lauth += ([ "port" : lauth->scheme == "ldap" ? LDAP_DEFAULT_PORT : LDAPS_DEFAULT_PORT ]); |
|
#if constant(SSL.sslfile) |
if(lauth->scheme == "ldaps" && !context) { |
context = SSL.context(); |
|
context->preferred_suites = ({ |
SSL_rsa_with_idea_cbc_sha, |
SSL_rsa_with_rc4_128_sha, |
SSL_rsa_with_rc4_128_md5, |
SSL_rsa_with_3des_ede_cbc_sha, |
}); |
} |
#endif |
|
if(!(::connect(lauth->host, lauth->port))) { |
|
seterr (LDAP_SERVER_DOWN); |
DWRITE("client.create: ERROR: can't open socket.\n"); |
|
|
|
|
|
THROW(({"Failed to connect to LDAP server.\n",backtrace()})); |
} |
|
#if constant(SSL.sslfile) |
if(lauth->scheme == "ldaps") { |
context->random = Crypto.randomness.reasonably_random()->read; |
::create(SSL.sslfile(::_fd, context, 1,1)); |
info->tls_version = ldapfd->version; |
} else |
::create(::_fd); |
#else |
if(lauth->scheme == "ldaps") { |
THROW(({"LDAP: LDAPS is not available without SSL support.\n",backtrace()})); |
} |
else |
::create(::_fd); |
#endif |
|
DWRITE("client.create: connected!\n"); |
|
DWRITE(sprintf("client.create: remote = %s\n", query_address())); |
DWRITE_HI("client.OPEN: " + lauth->host + ":" + (string)(lauth->port) + " - OK\n"); |
|
binded = 0; |
|
if(lauth->scope) |
set_scope(lauth->scope); |
if(lauth->basedn) |
set_basedn(lauth->basedn); |
|
} |
|
private mixed send_bind_op(string name, string password) { |
|
|
object msgval, vers, namedn, auth, app; |
|
vers = Standards.ASN1.Types.asn1_integer(ldap_version); |
namedn = Standards.ASN1.Types.asn1_octet_string(name); |
auth = ASN1_CONTEXT_OCTET_STRING(0, password); |
|
|
msgval = ASN1_APPLICATION_SEQUENCE(0, ({vers, namedn, auth})); |
|
return (do_op(msgval)); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int bind (string|void dn, string|void password, int|void version) { |
|
int id; |
mixed raw; |
|
if (!version) |
version = LDAP_DEFAULT_VERSION; |
if (chk_ver()) |
return(0); |
if (!stringp(dn)) |
dn = mappingp(lauth->ext) ? lauth->ext->bindname||"" : ""; |
if (!stringp(password)) |
password = ""; |
ldap_version = version; |
if(ldap_version == 3) { |
dn = string_to_utf8(dn); |
password = string_to_utf8(password); |
} |
if(intp(raw = send_bind_op(dn, password))) { |
THROW(({error_string()+"\n",backtrace()})); |
return(-ldap_errno); |
} |
|
binded = 0; |
last_rv = result(({raw}),1); |
if (!last_rv->error_number()) |
binded = 1; |
DWRITE_HI(sprintf("client.BIND: %s\n", last_rv->error_string())); |
seterr (last_rv->error_number()); |
return binded; |
|
} |
|
private int send_unbind_op() { |
|
|
writemsg(ASN1_APPLICATION_OCTET_STRING(2, "")); |
|
|
|
return (1); |
} |
|
void destroy() { |
|
|
destruct(this_object()); |
} |
|
|
|
int unbind () { |
|
if (send_unbind_op() < 1) { |
THROW(({error_string()+"\n",backtrace()})); |
return(-ldap_errno); |
} |
binded = 0; |
DWRITE_HI("client.UNBIND: OK\n"); |
|
} |
|
private int|string send_op_withdn(int op, string dn) { |
|
|
return (do_op(ASN1_APPLICATION_OCTET_STRING(op, dn))); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
int delete (string dn) { |
|
int id; |
mixed raw; |
|
if (chk_ver()) |
return(0); |
if (chk_binded()) |
return(0); |
if (chk_dn(dn)) |
return(0); |
if(ldap_version == 3) { |
dn = string_to_utf8(dn); |
} |
if(intp(raw = send_op_withdn(10, dn))) { |
THROW(({error_string()+"\n",backtrace()})); |
return(0); |
} |
|
last_rv = result(({raw})); |
DWRITE_HI(sprintf("client.DELETE: %s\n", last_rv->error_string())); |
seterr (last_rv->error_number()); |
return (!last_rv->error_number()); |
|
} |
|
private int|string send_compare_op(string dn, array(string) aval) { |
|
|
object msgval; |
|
msgval = ASN1_APPLICATION_SEQUENCE(14, |
({ Standards.ASN1.Types.asn1_octet_string(dn), |
Standards.ASN1.Types.asn1_sequence( |
({ Standards.ASN1.Types.asn1_octet_string(aval[0]), |
Standards.ASN1.Types.asn1_octet_string(aval[1]) |
})) |
}) |
); |
|
return (do_op(msgval)); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int compare (string dn, array(string) aval) { |
|
int id; |
mixed raw; |
|
|
|
if (chk_ver()) |
return(0); |
if (chk_binded()) |
return(0); |
if (chk_dn(dn)) |
return(0); |
if(ldap_version == 3) { |
dn = string_to_utf8(dn); |
aval = Array.map(aval, string_to_utf8); |
} |
if(intp(raw = send_compare_op(dn, aval))) { |
THROW(({error_string()+"\n",backtrace()})); |
return(0); |
} |
|
last_rv = result(({raw})); |
DWRITE_HI(sprintf("client.COMPARE: %s\n", last_rv->error_string())); |
seterr (last_rv->error_number()); |
return (!last_rv->error_number()); |
|
} |
|
private int|string send_add_op(string dn, mapping(string:array(string)) attrs) { |
|
|
object msgval; |
string atype; |
array(object) oatt = ({}); |
|
foreach(indices(attrs), atype) { |
string aval; |
array(object) ohlp = ({}); |
|
foreach(values(attrs[atype]), aval) |
ohlp += ({Standards.ASN1.Types.asn1_octet_string(aval)}); |
oatt += ({Standards.ASN1.Types.asn1_sequence( |
({Standards.ASN1.Types.asn1_octet_string(atype), |
Standards.ASN1.Types.asn1_set(ohlp) |
})) |
}); |
} |
|
msgval = ASN1_APPLICATION_SEQUENCE(8, |
({Standards.ASN1.Types.asn1_octet_string(dn), |
Standards.ASN1.Types.asn1_sequence(oatt) |
})); |
|
return (do_op(msgval)); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int add (string dn, mapping(string:array(string)) attrs) { |
|
int id; |
mixed raw; |
|
if (chk_ver()) |
return(0); |
if (chk_binded()) |
return(0); |
if (chk_dn(dn)) |
return(0); |
if(ldap_version == 3) { |
dn = string_to_utf8(dn); |
array(string) keys = indices(attrs); |
array(array(string)) vals = values(attrs); |
attrs = mkmapping(Array.map(keys, string_to_utf8), |
Array.map(vals, Array.map, string_to_utf8)); |
} |
if(intp(raw = send_add_op(dn, attrs))) { |
THROW(({error_string()+"\n",backtrace()})); |
return(0); |
} |
|
last_rv = result(({raw})); |
DWRITE_HI(sprintf("client.ADD: %s\n", last_rv->error_string())); |
seterr (last_rv->error_number()); |
return (!last_rv->error_number()); |
|
} |
|
private static array(string) filter_get_sub1expr(string fstr) { |
|
|
array(string) rvarr = ({}); |
int leftflg = 0, nskip = 0; |
|
for(int ix=0; ix<sizeof(fstr); ix++) |
if((fstr[ix] == '(') && (!ix || (fstr[ix-1] != '\\'))) { |
leftflg = ix+1; |
while(++ix < sizeof(fstr)) { |
if((fstr[ix] == '(') && (fstr[ix-1] != '\\')) { |
nskip++; |
continue; |
} |
if((fstr[ix] == ')') && (fstr[ix-1] != '\\')) |
if(nskip) { |
nskip--; |
continue; |
} else { |
rvarr += ({fstr[leftflg..(ix-1)]}); |
leftflg = 0; |
break; |
} |
} |
} |
if(leftflg) { |
; |
} |
|
return(rvarr); |
} |
|
object make_simple_filter(string filter) { |
|
|
object rv; |
int op, ix; |
|
DWRITE(sprintf("client.make_simple_filter: filter: [%s]\n", filter)); |
if((op = predef::search(filter, ">=")) > 0) { |
DWRITE("client.make_simple_filter: [>=]\n"); |
return(ASN1_CONTEXT_SEQUENCE(5, |
({Standards.ASN1.Types.asn1_octet_string(filter[..(op-1)]), |
Standards.ASN1.Types.asn1_octet_string(filter[(op+2)..]) |
}))); |
} |
if((op = predef::search(filter, "<=")) > 0) { |
DWRITE("client.make_simple_filter: [<=]\n"); |
return(ASN1_CONTEXT_SEQUENCE(6, |
({Standards.ASN1.Types.asn1_octet_string(filter[..(op-1)]), |
Standards.ASN1.Types.asn1_octet_string(filter[(op+2)..]) |
}))); |
} |
if((op = predef::search(filter, "=")) > 0) { |
if((filter[-2] == '=') && (filter[-1] == '*')) |
return(make_simple_filter(filter[..op-1])); |
ix = predef::search(filter[(op+1)..], "*"); |
if ((ix != -1) && (filter[op+ix] != '\\')) { |
object ohlp; |
array oarr = ({}), ahlp = ({}); |
array filtval = filter[(op+1)..] / "*"; |
|
|
for(int cnt = 0; cnt < sizeof(filtval); cnt++) { |
if(cnt) { |
if(sizeof(filtval[cnt-1]) && filtval[cnt-1][-1] == '\\') |
ahlp[-1] = reverse(reverse(ahlp[-1])[1..]) + filtval[cnt]; |
else |
ahlp += ({ filtval[cnt] }); |
} else |
ahlp = ({ filtval[cnt] }); |
} |
|
|
ix = sizeof(ahlp); |
for (int cnt = 0; cnt < ix; cnt++) |
if(!cnt) { |
if(sizeof(ahlp[0])) |
oarr = ({ASN1_CONTEXT_OCTET_STRING(0, ahlp[0])}); |
} else |
if(cnt == ix-1) { |
if(sizeof(ahlp[ix-1])) |
oarr += ({ASN1_CONTEXT_OCTET_STRING(2, ahlp[ix-1])}); |
} else { |
if(sizeof(ahlp[cnt])) |
oarr += ({ASN1_CONTEXT_OCTET_STRING(1, ahlp[cnt])}); |
} |
|
|
DWRITE(sprintf("client.make_simple_filter: substring: [%s]:\n%O\n", filter, ahlp)); |
return(ASN1_CONTEXT_SEQUENCE(4, |
({Standards.ASN1.Types.asn1_octet_string(filter[..(op-1)]), |
Standards.ASN1.Types.asn1_sequence(oarr) |
}))); |
} else { |
DWRITE("client.make_simple_filter: [=]\n"); |
return(ASN1_CONTEXT_SEQUENCE(3, |
({Standards.ASN1.Types.asn1_octet_string(filter[..(op-1)]), |
Standards.ASN1.Types.asn1_octet_string(filter[(op+1)..]) |
}))); |
} |
} |
|
DWRITE("client.make_simple_filter: [present]\n"); |
return(ASN1_CONTEXT_OCTET_STRING(7, filter)); |
} |
|
|
object|int make_filter(string filter) { |
|
|
object ohlp; |
array(object) oarr = ({}); |
int op ; |
|
DWRITE("client.make_filter: filter=["+filter+"]\n"); |
|
if (!sizeof(filter)) return make_simple_filter(filter); |
|
|
filter = String.trim_all_whites(filter); |
|
|
#if 1 |
if(filter[0] == '(') { |
int ix; |
string f2 = reverse(filter[1..]); |
if((ix = predef::search(f2, ")")) > -1) { |
filter = reverse(f2[ix+1..]); |
return(make_filter(filter)); |
} |
return(-1); |
} |
#endif |
|
op = -1; |
|
DWRITE(sprintf("client.make_filter: ftype=%c\n",filter[0])); |
switch (filter[0]) { |
case '&': |
case '|': |
foreach(filter_get_sub1expr(filter[1..]), string sub1expr) |
if (objectp(ohlp = make_filter(sub1expr))) |
oarr += ({ohlp}); |
else |
return(0); |
DWRITE(sprintf("client.make_filter: expr_cnt=%d\n",sizeof(oarr))); |
|
op = 0; |
if (filter[0] == '|') |
op = 1; |
return(ASN1_CONTEXT_SET(op, oarr)); |
case '!': |
if (objectp(ohlp = make_filter(filter_get_sub1expr(filter[1..])[0]))) |
return(ASN1_CONTEXT_SEQUENCE(2, ({ ohlp}) )); |
else |
return(0); |
break; |
default : |
return(make_simple_filter(filter)); |
} |
} |
|
private int|string send_search_op(string basedn, int scope, int deref, |
int sizelimit, int timelimit, int attrsonly, |
string filter, void|array(string) attrs){ |
|
|
|
object msgval, ofilt; |
array(object) ohlp; |
|
if(!objectp(ofilt = make_filter(filter))) { |
return(-seterr(LDAP_FILTER_ERROR)); |
} |
ohlp = ({ofilt}); |
if (arrayp(attrs)) { |
array(object) o2 = ({}); |
foreach(attrs, string s2) |
o2 += ({Standards.ASN1.Types.asn1_octet_string(s2)}); |
ohlp += ({Standards.ASN1.Types.asn1_sequence(o2)}); |
} else |
ohlp += ({Standards.ASN1.Types.asn1_sequence(({}))}); |
|
msgval = ASN1_APPLICATION_SEQUENCE(3, |
({ Standards.ASN1.Types.asn1_octet_string(basedn), |
ASN1_ENUMERATED(scope), |
ASN1_ENUMERATED(deref), |
Standards.ASN1.Types.asn1_integer(sizelimit), |
Standards.ASN1.Types.asn1_integer(timelimit), |
ASN1_BOOLEAN(attrsonly ? -1 : 0), |
@ohlp |
})) ; |
|
return (do_op(msgval)); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
object|int search (string|void filter, array(string)|void attrs, |
int|void attrsonly) { |
|
int id,nv; |
mixed raw; |
array(string) rawarr = ({}); |
|
filter=filter||lauth->filter; |
|
DWRITE_HI("client.SEARCH: " + (string)filter + "\n"); |
if (chk_ver()) |
return(0); |
if (chk_binded()) |
return(0); |
if(ldap_version == 3) { |
filter = string_to_utf8(filter); |
} |
#ifdef LDAP_PROTOCOL_PROFILE |
_prof_gtim = gauge{ |
#endif |
if(intp(raw = send_search_op(ldap_basedn, ldap_scope, ldap_deref, |
ldap_sizelimit, ldap_timelimit, attrsonly, filter, |
attrs||lauth->attributes))) { |
THROW(({error_string()+"\n",backtrace()})); |
return(0); |
} |
#ifdef LDAP_PROTOCOL_PROFILE |
}; |
DWRITE_PROF("send_search_op: %O\n", _prof_gtim); |
#endif |
|
rawarr = ({raw}); |
#ifdef LDAP_PROTOCOL_PROFILE |
_prof_gtim = gauge{ |
#endif |
while (ASN1_DECODE_RESULTAPP(raw) != 5) { |
#ifdef LDAP_PROTOCOL_PROFILEx |
DWRITE_PROF("readmsg: %O\n", gauge { raw = readmsg(id); }); |
#else |
raw = readmsg(id); |
#endif |
if (intp(raw)) { |
THROW(({error_string()+"\n",backtrace()})); |
return(0); |
} |
rawarr += ({raw}); |
} |
#ifdef LDAP_PROTOCOL_PROFILE |
}; |
DWRITE_PROF("rawarr++: %O\n", _prof_gtim); |
#endif |
|
#ifdef LDAP_PROTOCOL_PROFILE |
_prof_gtim = gauge{ last_rv = result(rawarr); }; |
DWRITE_PROF("result: %O\n", _prof_gtim); |
#else |
last_rv = result(rawarr); |
#endif |
if(objectp(last_rv)) |
seterr (last_rv->error_number()); |
|
|
|
DWRITE_HI(sprintf("client.SEARCH: %s (entries: %d)\n", |
last_rv->error_string(), last_rv->num_entries())); |
return(last_rv); |
|
} |
|
|
|
|
string set_basedn (string base_dn) { |
|
string old_dn = ldap_basedn; |
|
if(ldap_version == 3) { |
base_dn = string_to_utf8(base_dn); |
} |
ldap_basedn = base_dn; |
DWRITE_HI("client.SET_BASEDN = " + base_dn + "\n"); |
return(old_dn); |
} |
|
|
|
|
|
|
|
|
int set_scope (int|string scope) { |
|
int old_scope = ldap_scope; |
|
|
if(stringp(scope)) |
switch (lower_case(scope)) { |
case "sub": scope = 2; break; |
case "one": scope = 1; break; |
case "base": scope = 0; break; |
default: return (-1); |
} |
else |
if(scope != 0 && scope != 1 && scope != 2) |
return (-1); |
|
ldap_scope = scope; |
DWRITE_HI("client.SET_SCOPE = " + (string)scope + "\n"); |
return(old_scope); |
} |
|
|
|
|
|
int set_option (int opttype, int value) { |
|
DWRITE_HI("client.SET_OPTION: " + (string)opttype + " = " + (string)value + "\n"); |
switch (opttype) { |
case 1: |
|
ldap_deref = value; |
|
|
break; |
case 2: |
|
ldap_sizelimit = value; |
|
|
break; |
case 3: |
|
ldap_timelimit = value; |
|
|
break; |
case 4: |
default: return(-1); |
} |
|
|
return(0); |
} |
|
|
|
int get_option (int opttype) { |
|
|
DWRITE_HI("client.GET_OPTION: " + (string)opttype + "\n"); |
switch (opttype) { |
case 1: |
return(ldap_deref); |
case 2: |
return(ldap_sizelimit); |
case 3: |
return(ldap_timelimit); |
case 4: |
} |
|
return(-1); |
} |
|
private int|string send_modify_op(string dn, |
mapping(string:array(mixed)) attropval) { |
|
|
object o, msgval; |
string atype; |
array(object) oatt = ({}), attrarr; |
|
|
foreach(indices(attropval), atype) { |
if(!intp((attropval[atype])[0])) |
return(seterr (LDAP_PROTOCOL_ERROR)); |
attrarr = ({}); |
for(int ix=1; ix<sizeof(attropval[atype]); ix++) |
attrarr += ({Standards.ASN1.Types.asn1_octet_string( |
(attropval[atype])[ix])}); |
|
o = Standards.ASN1.Types.asn1_sequence( |
({Standards.ASN1.Types.asn1_octet_string(atype), |
Standards.ASN1.Types.asn1_set(attrarr) |
})); |
|
|
|
oatt += ({Standards.ASN1.Types.asn1_sequence( |
({ASN1_ENUMERATED((attropval[atype])[0]), |
o |
}))}); |
} |
|
msgval = ASN1_APPLICATION_SEQUENCE(6, |
({ Standards.ASN1.Types.asn1_octet_string(dn), |
Standards.ASN1.Types.asn1_sequence(oatt) |
})); |
|
return (do_op(msgval)); |
} |
|
private int|string send_modifydn_op(string dn, string newrdn, |
int deleteoldrdn, string newsuperior) { |
|
object msgval; |
array seq=({ Standards.ASN1.Types.asn1_octet_string(dn), |
Standards.ASN1.Types.asn1_octet_string(newrdn), |
Standards.ASN1.Types.asn1_boolean(deleteoldrdn) |
}); |
if(newsuperior) |
seq+=({Standards.ASN1.Types.asn1_octet_string(newsuperior)}); |
|
msgval = ASN1_APPLICATION_SEQUENCE(12, seq); |
|
return (do_op(msgval)); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int modifydn (string dn, string newrdn, int deleteoldrdn, |
string|void newsuperior) { |
|
mixed raw; |
|
if (chk_ver()) |
return(0); |
if (chk_binded()) |
return(0); |
if (chk_dn(dn)) |
return(0); |
if(ldap_version == 3) { |
dn = string_to_utf8(dn); |
newrdn = string_to_utf8(newrdn); |
if(newsuperior) newsuperior = string_to_utf8(newsuperior); |
} |
if(intp(raw = send_modifydn_op(dn, newrdn, deleteoldrdn, newsuperior))) { |
THROW(({error_string()+"\n",backtrace()})); |
return(0); |
} |
|
last_rv = result(({raw})); |
DWRITE_HI(sprintf("client.MODIFYDN: %s\n", last_rv->error_string())); |
seterr (last_rv->error_number()); |
return (!last_rv->error_number()); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int modify (string dn, mapping(string:array(mixed)) attropval) { |
|
int id; |
mixed raw; |
|
if (chk_ver()) |
return(0); |
if (chk_binded()) |
return(0); |
if (chk_dn(dn)) |
return(0); |
if(ldap_version == 3) { |
dn = string_to_utf8(dn); |
array(string) keys = indices(attropval); |
array(array(mixed)) vals = values(attropval); |
attropval = mkmapping(Array.map(keys, string_to_utf8), |
Array.map(vals, Array.map, lambda(mixed x) { |
return |
(stringp(x)? |
string_to_utf8(x) : |
x); |
})); |
} |
if(intp(raw = send_modify_op(dn, attropval))) { |
THROW(({error_string()+"\n",backtrace()})); |
return(0); |
} |
|
last_rv = result(({raw})); |
DWRITE_HI(sprintf("client.MODIFY: %s\n", last_rv->error_string())); |
seterr (last_rv->error_number()); |
return (!last_rv->error_number()); |
|
} |
|
|
|
|
|
array|int get_referrals() { |
if(last_rv->referrals) |
return last_rv->referrals; |
return 0; |
} |
|
|
|
mapping|int parse_url (string ldapuri) { |
|
|
|
string url=ldapuri, s, scheme; |
array ar; |
mapping res; |
|
s = (url / ":")[0]; |
url = url[sizeof(s)..]; |
|
res = ([ "scheme" : s ]); |
|
#ifdef LDAP_URL_STRICT |
if (url[..2] != "://") |
return(-1); |
#endif |
|
s = (url[3..] / "/")[0]; |
url = url[sizeof(s)+4..]; |
|
res += ([ "host" : (s / ":")[0] ]); |
|
if(sizeof(s / ":") > 1) |
res += ([ "port" : (int)((s / ":")[1]) ]); |
|
ar = url / "?"; |
|
switch (sizeof(ar)) { |
case 5: if (sizeof(ar[4])) { |
mapping extensions = ([]); |
foreach(ar[4] / ",", string ext) { |
int ix = predef::search(ext, "="); |
if(ix) |
extensions += ([ ext[..(ix-1)] : replace(ext[ix+1..],QUOTED_COMMA, ",") ]); |
} |
if (sizeof(extensions)) |
res += ([ "ext" : extensions ]); |
} |
|
case 4: res += ([ "filter" : ar[3] ]); |
case 3: switch (ar[2]) { |
case "sub": res += ([ "scope" : 2 ]); break; |
case "one": res += ([ "scope" : 1 ]); break; |
default: res += ([ "scope" : 0]); |
} |
case 2: res += sizeof(ar[1]) ? ([ "attributes" : ar[1] / "," ]) : ([]); |
case 1: res += ([ "basedn" : ar[0] ]); |
} |
|
return (res); |
|
} |
|
#endif |
|
|