pike.git / lib / modules / Protocols.pmod / LDAP.pmod / client.pike

version» Context lines:

pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:1:   #pike __REAL_VERSION__      // LDAP client protocol implementation for Pike.   // - // $Id: client.pike,v 1.108 2007/10/08 15:59:04 mast Exp $ + // $Id: client.pike,v 1.109 2007/10/08 16:47:09 mast Exp $   //   // Honza Petrous, hop@unibase.cz   //   // ----------------------------------------------------------------------   //   // History:   //   // v0.0 1998-05-25 Starting up!   // v1.0 1998-06-21 Core functions (open, bind, unbind, delete, add,   // compare, search), only V2 operations,
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:83:      // ASN.1 decode macros      #define ASN1_GET_RESULTAPP(X) ((X)->elements[1]->get_tag())   #define ASN1_GET_DN(X) ((X)->elements[0]->value)   #define ASN1_GET_ATTR_ARRAY(X) (sizeof ((X)->elements) > 1 && \    (array) ((X)->elements[1]->elements))   #define ASN1_GET_ATTR_NAME(X) ((X)->elements[0]->value)   #define ASN1_GET_ATTR_VALUES(X) ((X)->elements[1]->elements->value)    - #define ASN1_DECODE_RESULTAPP(X) ASN1_GET_RESULTAPP (.ldap_privates.ldap_der_decode(X)) - #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_RAWDEBUG(X) (.ldap_privates.ldap_der_decode(X)->debug_string()) + #define ASN1_RESULTCODE(X) (int)((X)->elements[1]->elements[0]->value->cast_to_int()) + #define ASN1_RESULTSTRING(X) ((X)->elements[1]->elements[2]->value) + #define ASN1_RESULTREFS(X) ((X)->elements[1]->elements[3]->elements) + #define ASN1_RAWDEBUG(X) ((X)->debug_string())       //! Contains the client implementation of the LDAP protocol.    //! All of the version 2 protocol features are implemented    //! but only the base parts of the version 3.       inherit .protocol;       private {    string bound_dn; // When actually bound, set to the bind DN.    string md5_password; // MD5 hash of the bind password, if any.
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:177:    private string resultstring;    private int actnum = 0;    private array(ResultEntry) entry = ({});    private int flags;    array(string) referrals;       // All entries up to but not including this one have been decoded    // using decode_entry, the rest have not.    private int first_undecoded_entry = 0;    -  array(ResultEntry) decode_entries (array rawres) +  array(ResultEntry) decode_entries (array(object) entries)    {    array(ResultEntry) res = ({});      #define DECODE_ENTRIES(SET_DN, SET_ATTR) do { \    if (flags & SEARCH_MULTIVAL_ARRAYS_ONLY) { \ -  foreach (rawres, string rawent) { \ -  object derent = .ldap_privates.ldap_der_decode (rawent)->elements[1]; \ +  foreach (entries, object entry) { \ +  object derent = entry->elements[1]; \    if (array(object) derattribs = ASN1_GET_ATTR_ARRAY (derent)) { \    string dn; \    {SET_DN;} \    ResultEntry attrs = (["dn": dn]); \    foreach (derattribs, object derattr) { \    string attr; \    {SET_ATTR;} \    sscanf (attr, "%[^;]", string bare_attr); \    if (mapping(string:mixed) attr_descr = \    get_attr_type_descr (bare_attr)) { \
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:220:    werror ("Warning: Couldn't fetch attribute description for %O - " \    "multivalued attribute assumed.\n", attr); \    ); \    } \    res += ({attrs}); \    } \    } \    } \    \    else { \ -  foreach (rawres, string rawent) { \ -  object derent = .ldap_privates.ldap_der_decode (rawent)->elements[1]; \ +  foreach (entries, object entry) { \ +  object derent = entry->elements[1]; \    if (array(object) derattribs = ASN1_GET_ATTR_ARRAY (derent)) { \    string dn; \    {SET_DN;} \    ResultEntry attrs = (["dn": ({dn})]); \    foreach (derattribs, object derattr) { \    string attr; \    {SET_ATTR;} \    } \    res += ({attrs}); \    } \
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:339:    }      #undef DECODE_VALUE       ent->dn = dn;    }       //!    //! You can't create instances of this object yourself.    //! The only way to create it is via a search of a LDAP server. -  object|int create(array rawres, void|int stuff, void|int flags) { -  // rawres: array of result in raw format, but WITHOUT LDAP PDU !!! +  object|int create(array(object) entries, int stuff, int flags) { +  // entries: array of der decoded entries, but WITHOUT LDAP PDU !!!    // stuff: 1=bind result; ...       this_program::flags = flags;       // Note: Might do additional schema queries to the server while    // decoding the result. That means possible interleaving problem    // if search() is extended to not retrieve the complete reply at    // once.    -  int lastel = sizeof(rawres) - 1; -  -  if (lastel < 0) { +  if (!sizeof (entries)) {    seterr (LDAP_LOCAL_ERROR);    THROW(({"LDAP: Internal error.\n",backtrace()}));    return -ldap_errno;    } -  DWRITE(sprintf("result.create: rawres=%O\n",rawres[lastel])); +  DWRITE(sprintf("result.create: %O\n",entries[-1]));    -  // The last element of 'rawres' is result itself -  resultcode = ASN1_DECODE_RESULTCODE(rawres[lastel]); +  // The last element of 'entries' is result itself +  resultcode = ASN1_RESULTCODE (entries[-1]);    DWRITE(sprintf("result.create: code=%d\n",resultcode)); -  resultstring = ASN1_DECODE_RESULTSTRING(rawres[lastel]); +  resultstring = ASN1_RESULTSTRING (entries[-1]);    if (resultstring == "")    resultstring = 0;    else if (ldap_version >= 3)    if (mixed err = catch (resultstring = utf8_to_string (resultstring)))    DWRITE (sprintf ("Failed to decode result string %O: %s",    resultstring, describe_error (err)));    DWRITE(sprintf("result.create: str=%O\n",resultstring));   #ifdef V3_REFERRALS    // referral (v3 mode)    if(resultcode == 10) {    referrals = ({}); -  foreach(ASN1_DECODE_RESULTREFS(rawres[lastel]), object ref1) +  foreach(ASN1_RESULTREFS (entries[-1]), object ref1)    referrals += ({ ref1->value });    DWRITE(sprintf("result.create: refs=%O\n",referrals));    }   #endif -  DWRITE(sprintf("result.create: elements=%d\n",lastel+1)); +  DWRITE(sprintf("result.create: elements=%d\n",sizeof (entries)));   #if 0 -  DWRITE(sprintf("result.create: entries=%O\n",rawres[..lastel-1])); +  DWRITE(sprintf("result.create: entries=%O\n", entries[..<1]));   #endif    -  entry = decode_entries (rawres[..lastel-1]); +  entry = decode_entries (entries[..<1]);      #if 0 -  // Context specific proccessing of 'rawres' +  // Context specific proccessing of 'entries'    switch(stuff) {    case 1: DWRITE("result.create: stuff=1\n");    break;    default: DWRITE(sprintf("result.create: stuff=%d\n", stuff));       }   #endif       return this;   
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:575:    {    for (; first_undecoded_entry < sizeof (entry); first_undecoded_entry++)    decode_entry (entry[first_undecoded_entry]);    return entry;    }       } // end of class 'result' ---------------       // helper functions and macros    + // To make a result from any ldap operation that only returns a plain + // LDAPResult. + #define SIMPLE_RESULT(STR, STUFF, FLAGS) \ +  result (({.ldap_privates.ldap_der_decode (STR)}), (STUFF), (FLAGS)) +    #ifdef ENABLE_PAGED_SEARCH   #define IF_ELSE_PAGED_SEARCH(X,Y) X   #else /* !ENABLE_PAGED_SEARCH */   #define IF_ELSE_PAGED_SEARCH(X,Y) Y   #endif      #ifdef LDAP_PROTOCOL_PROFILE   #define PROFILE(STR, CODE...) DWRITE_PROF(STR + ": %O\n", gauge {CODE;})   #else   #define PROFILE(STR, CODE...) do { CODE; } while(0)
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:654: Inside #if undefined(PARSE_RFCS)
   //! @[Protocol.LDAP.parse_ldap_url].    //!    //! @param context    //! TLS context of connection    //!    //! @seealso    //! @[LDAP.client.bind], @[LDAP.client.search]    void create(string|mapping(string:mixed)|void url, object|void context)    {    -  info = ([ "code_revision" : ("$Revision: 1.108 $"/" ")[1] ]); +  info = ([ "code_revision" : ("$Revision: 1.109 $"/" ")[1] ]);       if(!url || !sizeof(url))    url = LDAP_DEFAULT_URL;       if (mappingp (url))    lauth = url;    else    lauth = parse_ldap_url(url);       if(!stringp(lauth->scheme) ||
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:774: Inside #if constant(SSL.Cipher.CipherAlgorithm)
   THROW(({"LDAP: TLS/SSL already established.\n",backtrace()}));    }       // NOTE: should we be on the lookout for requests in flight?             msgval = ASN1_APPLICATION_SEQUENCE(23, ({Standards.ASN1.Types.OctetString("1.3.6.1.4.1.1466.20037")}));       do_op(msgval); -  int result = ASN1_DECODE_RESULTCODE(readbuf); +  int result = ASN1_RESULTCODE(.ldap_privates.ldap_der_decode (readbuf));    if(result!=0) return 0;    // otherwise, we can try to negotiate.    if(!context)    {    context = SSL.context();    // Allow only strong crypto    context->preferred_suites = ({    SSL_rsa_with_idea_cbc_sha,    SSL_rsa_with_rc4_128_sha,    SSL_rsa_with_rc4_128_md5,
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:885:    if(ldap_version == 3) {    dn = string_to_utf8(dn);    pass = string_to_utf8(pass);    }    if(intp(raw = send_bind_op(dn, pass))) {    THROW(({error_string()+"\n",backtrace()}));    return 0;    }       bound_dn = md5_password = 0; -  last_rv = result(({raw}),1); +  last_rv = SIMPLE_RESULT (raw, 1, 0);    if (!last_rv->error_number()) {    bound_dn = dn;    md5_password = Crypto.MD5()->update (pass)->digest();    }    DWRITE_HI(sprintf("client.BIND: %s\n", last_rv->error_string()));    seterr (last_rv->error_number(), last_rv->error_string());    return !!bound_dn;       } // bind   
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:968:    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})); +  last_rv = SIMPLE_RESULT (raw, 0, 0);    DWRITE_HI(sprintf("client.DELETE: %s\n", last_rv->error_string()));    seterr (last_rv->error_number(), last_rv->error_string());    return !last_rv->error_number();       } // delete       private int|string send_compare_op(string dn, string attr, string value) {    // COMPARE       object msgval;
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:1044:    if(ldap_version == 3) {    dn = string_to_utf8(dn);    if (function(string:string) encoder = get_attr_encoder (attr))    value = encoder (value);    }    if(intp(raw = send_compare_op(dn, attr, value))) {    THROW(({error_string()+"\n",backtrace()}));    return 0;    }    -  last_rv = result(({raw})); +  last_rv = SIMPLE_RESULT (raw, 0, 0);    DWRITE_HI(sprintf("client.COMPARE: %s\n", last_rv->error_string()));    seterr (last_rv->error_number(), last_rv->error_string());    return last_rv->error_number() == LDAP_COMPARE_TRUE;       } // compare       private int|string send_add_op(string dn, mapping(string:array(string)) attrs) {    // ADD       object msgval;
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:1123:    // only ascii chars are allowed in them.    foreach (indices(attrs), string attr)    if (function(string:string) encoder = get_attr_encoder (attr))    attrs[attr] = map (attrs[attr], encoder);    }    if(intp(raw = send_add_op(dn, attrs))) {    THROW(({error_string()+"\n",backtrace()}));    return 0;    }    -  last_rv = result(({raw})); +  last_rv = SIMPLE_RESULT (raw, 0, 0);    DWRITE_HI(sprintf("client.ADD: %s\n", last_rv->error_string()));    seterr (last_rv->error_number(), last_rv->error_string());    return !last_rv->error_number();       } // add      static mapping(string:array(string)) simple_read (string object_name,    object filter,    array attrs)   // Makes a base object search for object_name. The result is returned
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:1405:    //!    //! @seealso    //! @[result], @[result.fetch], @[read], @[get_supported_controls],    //! @[Protocols.LDAP.quote_filter_value], @[Protocols.LDAP.make_filter]    result|int search (string|object|void filter, array(string)|void attrs,    int|void attrsonly,    void|mapping(string:array(int|string)) controls,    void|int flags) {       int id,nv; -  mixed raw; -  array(string) rawarr = ({}); +  object entry; +  array(object) entries = ({});       DWRITE_HI(sprintf ("client.SEARCH: %O\n", filter));    if (chk_ver())    return 0;    if (chk_binded())    return 0;       if (!objectp (filter))    if (mixed err = catch {    if (!filter)
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:1465: Inside #if 0
   // "Tells server not to generate referrals" (NtLdap.h)    common_controls += ({make_control (LDAP_SERVER_DOMAIN_SCOPE_OID)});    }   #endif      #ifdef ENABLE_PAGED_SEARCH    get_supported_controls();   #endif       object cookie = Standards.ASN1.Types.asn1_octet_string(""); -  rawarr = ({}); +     do {    PROFILE("send_search_op", {    array ctrls = common_controls;    IF_ELSE_PAGED_SEARCH (    if (supported_controls[LDAP_PAGED_RESULT_OID_STRING]) {    // LDAP Control Extension for Simple Paged Results Manipulation    // RFC 2696.    ctrls += ({make_control (    LDAP_PAGED_RESULT_OID_STRING,    Standards.ASN1.Types.asn1_sequence(
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:1488:    Standards.ASN1.Types.asn1_integer(0x7fffffff),    cookie, // cookie    }))->get_der(),    sizeof(cookie->value))});    },);    object controls;    if (sizeof(ctrls)) {    controls = .ldap_privates.asn1_sequence(0, ctrls);    }    +  string|int raw;    if(intp(raw = do_op(search_request, controls))) {    THROW(({error_string()+"\n",backtrace()}));    return 0;    } -  +  entry = .ldap_privates.ldap_der_decode (raw);    });    -  PROFILE("rawarr++", { -  rawarr += ({raw}); -  while (ASN1_DECODE_RESULTAPP(raw) != 5) { +  PROFILE("entries++", { +  entries += ({entry}); +  while (ASN1_GET_RESULTAPP(entry) != 5) { +  string|int raw;    PROFILE("readmsg", raw = readmsg(id));    if (intp(raw)) {    THROW(({error_string()+"\n",backtrace()}));    return 0;    } -  rawarr += ({raw}); +  entry = .ldap_privates.ldap_der_decode (raw); +  entries += ({entry});    } // while    });    -  // At this point @[raw] contains a SearchResultDone. +  // At this point @[entry] contains a SearchResultDone.    cookie = 0;    IF_ELSE_PAGED_SEARCH({ -  if ((ASN1_DECODE_RESULTCODE(raw) != 10) && -  (sizeof(.ldap_privates.ldap_der_decode(raw)->elements) > 2)) { -  object controls = .ldap_privates.ldap_der_decode(raw)->elements[2]; +  if ((ASN1_RESULTCODE(entry) != 10) && +  (sizeof(entry->elements) > 2)) { +  object controls = entry->elements[2];    foreach(controls->elements, object control) {    if (!control->constructed ||    !sizeof(control) ||    control->elements[0]->type_name != "OCTET STRING") {    //werror("Protocol error in control %O\n", control);    // FIXME: Fail?    continue;    }    if (control->elements[0]->value !=    LDAP_PAGED_RESULT_OID_STRING) {
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:1550:    control_info->elements[1]->type_name != "OCTET STRING") {    // Unexpected control information.    continue;    }    if (sizeof(control_info->elements[1]->value)) {    cookie = control_info->elements[1];    }    }    if (cookie) {    // Remove the extra end marker. -  rawarr = rawarr[..<1]; +  entries = entries[..<1];    }    }       },);    } while (cookie);    -  PROFILE("result", last_rv = result (rawarr, 0, flags)); +  PROFILE("result", last_rv = result (entries, 0, flags));    if(objectp(last_rv))    seterr (last_rv->error_number(), last_rv->error_string());    //if (rv->error_number() || !rv->num_entries()) // if error or entries=0    // rv = rv->error_number();       DWRITE_HI(sprintf("client.SEARCH: %s (entries: %d)\n",    last_rv->error_string(), last_rv->num_entries()));    return last_rv;       } // search
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:1622:    if (controls) {    array(object) control_list = allocate (sizeof (controls));    int i;    foreach (controls; string type; array(int|string) data)    control_list[i++] =    make_control (type, [string] data[1], [int] data[0]);    if (sizeof (control_list))    ctrls = .ldap_privates.asn1_sequence(0, control_list);    }    -  string|int raw; +  object entry;    PROFILE ("send_get_op", { -  +  string|int raw;    if(intp(raw = do_op(search_request, ctrls))) {    THROW(({error_string()+"\n",backtrace()}));    return 0;    } -  +  entry = .ldap_privates.ldap_der_decode (raw);    });    -  array(string) rawarr; -  PROFILE("rawarr++", { -  rawarr = ({raw}); -  while (ASN1_DECODE_RESULTAPP(raw) != 5) { +  array(object) entries; +  PROFILE("entries++", { +  entries = ({entry}); +  while (ASN1_GET_RESULTAPP(entry) != 5) { +  string|int raw;    // NB: The msgid stuff is defunct in readmsg, so we can    // just as well pass a zero there. :P    PROFILE("readmsg", raw = readmsg(0));    if (intp(raw)) {    THROW(({error_string()+"\n",backtrace()}));    return 0;    } -  rawarr += ({raw}); +  entry = .ldap_privates.ldap_der_decode (raw); +  entries += ({entry});    } // while    });    -  PROFILE ("result", last_rv = result (rawarr, 0, flags)); +  PROFILE ("result", last_rv = result (entries, 0, flags));    seterr (last_rv->error_number(), last_rv->error_string());       if (ldap_errno != LDAP_SUCCESS) return 0;    return last_rv->fetch();   }      string|array(string) read_attr (string object_name,    string attr,    void|string filter,    void|mapping(string:array(int|string)) controls)
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:1916:    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})); +  last_rv = SIMPLE_RESULT (raw, 0, 0);    DWRITE_HI(sprintf("client.MODIFYDN: %s\n", last_rv->error_string()));    seterr (last_rv->error_number(), last_rv->error_string());    return !last_rv->error_number();       } //modifydn       //! The Modify Operation allows a client to request that a modification    //! of an entry be performed on its behalf by a server.    //!    //! @param dn
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:1993:    for (int i = sizeof (op); --i;) // Skips first element.    op[i] = encoder (op[i]);    attropval[attr] = op;    }    }    if(intp(raw = send_modify_op(dn, attropval))) {    THROW(({error_string()+"\n",backtrace()}));    return 0;    }    -  last_rv = result(({raw})); +  last_rv = SIMPLE_RESULT (raw, 0, 0);    DWRITE_HI(sprintf("client.MODIFY: %s\n", last_rv->error_string()));    seterr (last_rv->error_number(), last_rv->error_string());    return !last_rv->error_number();       } // modify       //! Gets referrals.    //!    //! @returns    //! Returns array of referrals or @expr{0@}.