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.91 2005/04/06 14:55:59 mast Exp $ + // $Id: client.pike,v 1.92 2005/04/06 16:49:16 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:105:    inherit .protocol;       private {    string bound_dn; // When actually bound, set to the bind DN.    string ldap_basedn; // baseDN    int ldap_scope; // SCOPE_*    int ldap_deref; // 0: ...    int ldap_sizelimit;    int ldap_timelimit;    mapping lauth = ([]); -  object last_rv; // last returned value +  result last_rv; // last returned value    }      //! @ignore   static function(string:string) get_attr_decoder (string attr,    DO_IF_DEBUG (void|int nowarn))   {    if (mapping(string:mixed) attr_descr = get_attr_type_descr (attr)) {    if (function(string:string) decoder =    syntax_decode_fns[attr_descr->syntax_oid])    return decoder;
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:162:    //!    //! @seealso    //! @[LDAP.client.search], @[LDAP.client.result.fetch]    //!    class result // ------------------    {       private int resultcode = LDAP_SUCCESS;    private string resultstring;    private int actnum = 0; -  private array(mapping(string:array(string))) entry = ({}); +  private array(mapping(string:string|array(string))) entry = ({});    private int flags;    array(string) referrals;       static array decode_entries (array(string) rawres)    { -  array(mapping(string:array(string))) res = ({}); +  array(mapping(string:string|array(string))) 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]; \    if (array(object) derattribs = ASN1_GET_ATTR_ARRAY (derent)) { \    string dn = (SET_DN); \ -  +  mapping(string:string|array) 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)) { \ +  if (attr_descr["SINGLE-VALUE"]) { \ +  if (sizeof (attrs[attr])) { \ +  DO_IF_DEBUG ( \ +  if (sizeof (attrs[attr]) > 1) \ +  ERROR ("Got multple values %O for single valued " \ +  "attribute %O.\n", attrs[attr], attr); \ +  ); \ +  attrs[attr] = attrs[attr][0]; \ +  } \ +  else \ +  attrs[attr] = 0; \ +  } \ +  } \ +  DO_IF_DEBUG ( \ +  else if (dn != "") \ +  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]; \ +  if (array(object) derattribs = ASN1_GET_ATTR_ARRAY (derent)) { \ +  string dn = (SET_DN); \    mapping(string:array) attrs = (["dn": ({dn})]); \ -  foreach (derattribs, object derattr) \ +  foreach (derattribs, object derattr) { \ +  string attr; \    {SET_ATTR;} \ -  +  } \    res += ({attrs}); \    } \    } \ -  +  } \    } while (0)       if (ldap_version < 3) {    // Use the values raw.    if (flags & SEARCH_LOWER_ATTRS)    DECODE_ENTRIES (ASN1_GET_DN (derent), { -  attrs[lower_case (ASN1_GET_ATTR_NAME (derattr))] = +  attrs[attr = lower_case (ASN1_GET_ATTR_NAME (derattr))] =    ASN1_GET_ATTR_VALUES (derattr);    });    else    DECODE_ENTRIES (ASN1_GET_DN (derent), { -  attrs[ASN1_GET_ATTR_NAME (derattr)] = +  attrs[attr = ASN1_GET_ATTR_NAME (derattr)] =    ASN1_GET_ATTR_VALUES (derattr);    });    }       else {    // LDAPv3: Decode values as appropriate according to the    // schema. Note that attributes with the ";binary" option    // won't be matched by get_attr_type_descr and are therefore    // left untouched.    if (flags & SEARCH_LOWER_ATTRS)    DECODE_ENTRIES (utf8_to_string (ASN1_GET_DN (derent)), { -  string attr = lower_case (ASN1_GET_ATTR_NAME (derattr)); +  attr = lower_case (ASN1_GET_ATTR_NAME (derattr));    if (function(string:string) decoder =    // Microsoft AD has several attributes in its root DSE    // that they have not bothered to include in their    // schema. So if this is the root being fetched then    // send the nowarn flag to get_attr_encoder to avoid    // complaints about that.    get_attr_decoder (attr, DO_IF_DEBUG (dn == "")))    attrs[attr] = map (ASN1_GET_ATTR_VALUES (derattr), decoder);    else    attrs[attr] = ASN1_GET_ATTR_VALUES (derattr);    });    else    DECODE_ENTRIES (utf8_to_string (ASN1_GET_DN (derent)), { -  string attr = ASN1_GET_ATTR_NAME (derattr); +  attr = ASN1_GET_ATTR_NAME (derattr);    if (function(string:string) decoder =    get_attr_decoder (attr, DO_IF_DEBUG (dn == "")))    attrs[attr] = map (ASN1_GET_ATTR_VALUES (derattr), decoder);    else    attrs[attr] = ASN1_GET_ATTR_VALUES (derattr);    });    }      #undef DECODE_ENTRIES   
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:358:    //! returned mapping will affect future @[fetch] calls for the    //! same entry.    //!    //! @note    //! In Pike 7.6 and earlier, the special @expr{"dn"@} entry was    //! incorrectly returned in UTF-8 encoded form for LDAPv3    //! connections.    //!    //! @seealso    //! @[fetch_all] -  int|mapping(string:array(string)) fetch(int|void idx) { +  int|mapping(string: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;    }       //! -  //! Returns distinguished name (DN) of the current entry -  //! in the result list. Notice that this is the same -  //! as @expr{fetch()->dn[0]@}. +  //! Returns distinguished name (DN) of the current entry in the +  //! result list. Note that this is the same as getting the +  //! @expr{"dn"@} field from the return value from @[fetch].    //!    //! @note    //! In Pike 7.6 and earlier, this field was incorrectly returned    //! in UTF-8 encoded form for LDAPv3 connections. -  string get_dn() { return fetch()["dn"][0]; } +  string get_dn() +  { +  string|array(string) dn = fetch()->dn; +  return stringp (dn) ? dn : dn[0]; // To cope with SEARCH_MULTIVAL_ARRAYS_ONLY. +  }       //!    //! Initialized the result cursor to the first entry    //! in the result list.    //!    //! @seealso    //! @[LDAP.client.result.next]    void first() { actnum = 0; }       //!
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:400:    //! in the result list. Returns 0 at the end.    //!    //! @seealso    //! @[LDAP.client.result.next]    int next() {    if (actnum < sizeof (entry))    actnum++;    return count_entries();    }    -  array(mapping(string:array(string))) fetch_all() +  array(mapping(string:string|array(string))) fetch_all()    //! Convenience function to fetch all entries at once. The cursor    //! isn't affected.    //!    //! @returns    //! Returns an array where each element is the entry from the    //! result. Don't be destructive on the returned value.    //!    //! @seealso    //! @[fetch]    {
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:497: 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.91 $"/" ")[1] ]); +  info = ([ "code_revision" : ("$Revision: 1.92 $"/" ")[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:1019:   array(string) get_root_dse_attr (string attr)   //! Returns the value of an attribute in the root DSE (DSA-Specific   //! Entry) of the bound server. The result is cached. A working   //! connection is assumed.   //!   //! @returns   //! The return value is an array of the attribute values, which have   //! been UTF-8 decoded where appropriate.   //!   //! Don't be destructive on the returned array. + //! + //! @note + //! This function intentionally does not try to simplify the return + //! values for single-valued attributes (c.f. + //! @[Protocols.LDAP.SEARCH_MULTIVAL_ARRAYS_ONLY]). That since (at + //! least) Microsoft AD has a bunch of attributes in the root DSE + //! that they don't bother to provide schema entries for. The return + //! value format wouldn't be reliable if they suddenly change that.   {    attr = lower_case (attr);       if (!root_dse || zero_type (root_dse[attr])) {    PROFILE("get_root_dse_attr", {       multiset(string) attrs = root_dse ? (<>) :    // Get a bunch of attributes in one go.    (<    // Request all standard operational attributes (RFC 2252,
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:1397:    //! Returns object @[LDAP.client.result] on success, @expr{0@}    //! otherwise.    //!    //! @note    //! The API change: the returning code was changed in Pike 7.3+    //! to follow his logic better.    //!    //! @seealso    //! @[result], @[result.fetch], @[read], @[get_supported_controls],    //! @[Protocols.LDAP.quote_filter_value] -  object|int search (string|void filter, array(string)|void attrs, +  result|int search (string|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 = ({});       filter=filter||lauth->filter; // default from LDAP URI   
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:1557:    seterr (last_rv->error_number());    //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    - mapping(string:array(string)) read (string object_name, + mapping(string:string|array(string)) read ( +  string object_name,    void|string filter,    void|array(string) attrs,    void|int attrsonly,    void|mapping(string:array(int|string)) controls,    void|int flags)   //! Reads a specified object in the LDAP server. @[object_name] is the   //! distinguished name for the object. The rest of the arguments are   //! the same as to @[search].   //!   //! The default filter and attributes that might have been set in the
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:1638:    } // while    });       PROFILE ("result", last_rv = result (rawarr, 0, flags));    seterr (last_rv->error_number());       if (ldap_errno != LDAP_SUCCESS) return 0;    return last_rv->fetch();   }    - array(string) read_attr (string object_name, + string|array(string) read_attr (string object_name,    string attr,    void|string filter,    void|mapping(string:array(int|string)) controls)   //! Reads a specified attribute of a specified object in the LDAP   //! server. @[object_name] is the distinguished name of the object and   //! @[attr] is the attribute. The rest of the arguments are the same   //! as to @[search].   //!   //! The default filter that might have been set in the LDAP URL   //! doesn't affect this call. If @[filter] isn't set then   //! @expr{"(objectClass=*)"@} is used.   //!   //! @returns - //! Returns an array containing the values of the attribute on - //! string form. Returns zero if there was an error. + //! For single-valued attributes, the value is returned as a string. + //! For multivalued attributes, the value is returned as an array of + //! strings. Returns zero if there was an error.   //!   //! @seealso   //! @[read], @[get_root_dse_attr]   { -  if (mapping(string:array(string)) res = -  read (object_name, filter, ({attr}), 0, controls)) { +  if (mapping(string:string|array(string)) res = +  read (object_name, filter, ({attr}), 0, controls, +  SEARCH_MULTIVAL_ARRAYS_ONLY)) {    m_delete (res, "dn");    // Get the value regardless of the case of the attribute name that    // the server used in the response.    return get_iterator (res)->value();    }    return 0;   }      //! Return the LDAP protocol version in use.   int get_protocol_version() {return ldap_version;}