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.90 2005/04/02 19:12:19 nilsson Exp $ + // $Id: client.pike,v 1.91 2005/04/06 14:55:59 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:72: Inside #if constant(.ldap_privates)
  #if constant(.ldap_privates)      #include "ldap_globals.h"      #include "ldap_errors.h"      #if constant(SSL.Cipher.CipherAlgorithm)   import SSL.Constants;   #endif    - import Protocols.LDAP; + import ".";      // ------------------------      // 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)
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:98:   #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())       //! 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 { -  int binded = 0; // flag for v2 operations -  string ldap_basedn = ""; // baseDN -  int ldap_scope = 0; // SCOPE_* -  int ldap_deref = 0; // 0: ... -  int ldap_sizelimit = 0; -  int ldap_timelimit = 0; +  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 = 0; // last returned value +  object last_rv; // last returned value    }    - static constant supported_extensions = (<"bindname">); -  +    //! @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;   #ifdef DEBUG    else if (!get_constant_name (attr_descr->syntax_oid))
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:349:    //!    //! @member string "dn"    //! This special entry contains the object name of the entry as    //! a distinguished name.    //! @endmapping    //!    //! Zero is returned if the cursor is outside the valid range of    //! entries.    //!    //! @note -  //! Don't be destructive on the returned mapping. +  //! It's undefined whether or not destructive operations on the +  //! 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) {   
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:443:    seterr (LDAP_PROTOCOL_ERROR);    THROW(({"LDAP: Unknown/unsupported protocol version.\n",backtrace()}));    return -ldap_errno;    }    return 0;    }       private int chk_binded() {    // For version 2: we must be 'binded' first !!!    -  if ((ldap_version == 2) && !binded) { +  switch (ldap_version) { +  case 2: +  if (!bound_dn) {    seterr (LDAP_PROTOCOL_ERROR); -  THROW(({"LDAP: Must binded first.\n",backtrace()})); +  THROW(({"LDAP: Must bind first.\n",backtrace()}));    return -ldap_errno;    } -  if ((ldap_version == 3) && !binded) +  break; +  case 3: +  if (!bound_dn)    bind(); -  +  break; +  }    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;    }
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:480: Inside #if undefined(PARSE_RFCS)
   //!    //! Create object. The first optional argument can be used later    //! for subsequence operations. The second one can specify    //! TLS context of connection. The default context only allows    //! 128-bit encryption methods, so you may need to provide your    //! own context if your LDAP server supports only export encryption.    //!    //! @param url    //! LDAP server URL on the form    //! @expr{"ldap://hostname/basedn?attrlist?scope?ext"@}. See RFC -  //! 2255. +  //! 2255. It can also be a mapping as returned by +  //! @[Protocol.LDAP.parse_ldap_url].    //!    //! @param context    //! TLS context of connection    //!    //! @seealso    //! @[LDAP.client.bind], @[LDAP.client.search] -  void create(string|void url, object|void context) +  void create(string|mapping(string:mixed)|void url, object|void context)    {    -  info = ([ "code_revision" : ("$Revision: 1.90 $"/" ")[1] ]); +  info = ([ "code_revision" : ("$Revision: 1.91 $"/" ")[1] ]);       if(!url || !sizeof(url))    url = LDAP_DEFAULT_URL;    -  lauth = parse_url(url); +  if (mappingp (url)) +  lauth = url; +  else +  lauth = parse_ldap_url(url);       if(!stringp(lauth->scheme) ||    ((lauth->scheme != "ldap")   #if constant(SSL.Cipher.CipherAlgorithm)    && (lauth->scheme != "ldaps")   #endif    )) {    THROW(({"Unknown scheme in server URL.\n",backtrace()}));    }   
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:555: Inside #if undefined(PARSE_RFCS)
   }    else    ::create(low_fd);   #endif       DWRITE("client.create: connected!\n");       DWRITE(sprintf("client.create: remote = %s\n", low_fd->query_address()));    DWRITE_HI("client.OPEN: " + lauth->host + ":" + (string)(lauth->port) + " - OK\n");    -  binded = 0; -  -  if(lauth->scope) -  set_scope(lauth->scope); -  set_basedn(lauth->basedn); -  +  reset_options();    } // create   #endif    -  + void reset_options() + //! Resets all connection options, such as the scope and the base DN, + //! to the defaults determined from the LDAP URL when the connection + //! was created. + { +  set_scope (lauth->scope || SCOPE_BASE); +  set_basedn (lauth->basedn); +  ldap_deref = 0; +  ldap_sizelimit = 0; +  ldap_timelimit = 0; +  last_rv = 0; + } +     private mixed send_bind_op(string name, string password) {    // Simple BIND operation       object msgval, vers, namedn, auth, app;    string pass = password;    password = "censored";       vers = Standards.ASN1.Types.asn1_integer(ldap_version);    namedn = Standards.ASN1.Types.asn1_octet_string(name);    auth = ASN1_CONTEXT_OCTET_STRING(0, pass);
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:688:       int id;    mixed raw;    string pass = password;    password = "censored";       if (!version)    version = LDAP_DEFAULT_VERSION;    if (chk_ver())    return 0; +  +  if (bound_dn && ldap_version <= 2) { +  ERROR ("Can't bind a connection more than once in LDAPv2.\n"); +  return 0; +  } +     if (!stringp(dn))    dn = mappingp(lauth->ext) ? lauth->ext->bindname||"" : "";    if (!stringp(pass))    pass = "";    ldap_version = version;    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 -ldap_errno; +  return 0;    }    -  binded = 0; +  bound_dn = 0;    last_rv = result(({raw}),1);    if (!last_rv->error_number()) -  binded = 1; +  bound_dn = dn;    DWRITE_HI(sprintf("client.BIND: %s\n", last_rv->error_string()));    seterr (last_rv->error_number()); -  return binded; +  return !!bound_dn;       } // bind          private int send_unbind_op() {    // UNBIND operation       writemsg(ASN1_APPLICATION_OCTET_STRING(2, ""));       //ldap::close();
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:741:   #endif       //!    //! Unbinds from the directory and close the connection.    int unbind () {       if (send_unbind_op() < 1) {    THROW(({error_string()+"\n",backtrace()}));    return -ldap_errno;    } -  binded = 0; +  bound_dn = 0;    DWRITE_HI("client.UNBIND: OK\n");       } // unbind       private int|string send_op_withdn(int op, string dn) {    // DELETE, ...       return do_op(ASN1_APPLICATION_OCTET_STRING(op, dn));       }
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:1670:    }    ldap_basedn = base_dn;    DWRITE_HI("client.SET_BASEDN = " + base_dn + "\n");    return old_dn;    }      //! Returns the current base DN for searches using @[search] and   //! schema queries using @[get_attr_type_descr].   string get_basedn() {return utf8_to_string (ldap_basedn);}    + //! Returns the bind DN currently in use for the connection. Zero is + //! returned if the connection isn't bound. The empty string is + //! returned if the connection is in use but no bind DN has been given + //! explicitly to @[bind]. + string get_bound_dn() {return bound_dn;} +     //!    //! Sets value of scope for search operation.    //!    //! @param scope    //! The value can be one of the @expr{SCOPE_*@} constants or a    //! string @expr{"base"@}, @expr{"one"@} or @expr{"sub"@}.    //!    //! @returns    //! Returns the @expr{SCOPE_*@} constant for the old scope.    int set_scope (int|string scope) {
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:1761:    return ldap_timelimit;    case 4: // LDAP_OPT_REFERRALS    }       return -1;    }      mapping(string:mixed) get_parsed_url() {return lauth;}   //! Returns a mapping containing the data parsed from the LDAP URL   //! passed to @[create]. The mapping has the same format as the return - //! value from @[parse_url]. Don't be destructive on the returned - //! value. + //! value from @[Protocols.LDAP.parse_ldap_url]. Don't be destructive + //! on the returned value.       private int|string send_modify_op(string dn,    mapping(string:array(mixed)) attropval) {    // MODIFY       object o, msgval;    string atype;    array(object) oatt = ({}), attrarr;      
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:1958:    //! Gets referrals.    //!    //! @returns    //! Returns array of referrals or @expr{0@}.    array|int get_referrals() {    if(last_rv->referrals)    return last_rv->referrals;    return 0;    }    -  //! Parses an LDAP URL and returns its fields in a mapping. -  //! -  //! @returns -  //! The returned mapping contains these fields: -  //! -  //! @mapping -  //! @member string scheme -  //! The URL scheme, either @expr{"ldap"@} or @expr{"ldaps"@}. -  //! @member string host -  //! @member int port -  //! @member string basedn -  //! Self-explanatory. -  //! @member array(string) attributes -  //! Array containing the attributes. Undefined if none was -  //! specified. -  //! @member int scope -  //! The scope as one of the @expr{SEARCH_*@} constants. -  //! Undefined if none was specified. -  //! @member string filter -  //! The search filter. Undefined if none was specified. -  //! @member mapping(string:string|int(1..1)) ext -  //! The extensions. Undefined if none was specified. The mapping -  //! values are @expr{1@} for extensions without values. Critical -  //! extensions are checked and the leading @expr{"!"@} do not -  //! remain in the mapping indices. -  //! @endmapping -  //! -  //! @seealso -  //! @[get_parsed_url] -  mapping(string:mixed) parse_url (string ldapuri) { -  -  // ldap://machine.at.home.cz:123/c=cz?attr1,attr2,attr3?sub?(uid=*)?!bindname=uid=hop,dc=unibase,dc=cz" -  -  string url=ldapuri; -  array ar; -  mapping(string:mixed) res = ([]); -  -  if (sscanf (url, "%[^:]://%s", res->scheme, url) != 2) -  ERROR ("Failed to parse scheme from ldap url.\n"); -  -  sscanf (url, "%[^/]/%s", string hostport, url); -  sscanf (hostport, "%[^:]:%s", res->host, string port); -  if (port) -  if (sscanf (port, "%d%*c", res->port) != 1) -  ERROR ("Failed to parse port number from %O.\n", port); -  -  ar = url / "?"; -  -  switch (sizeof(ar)) { -  case 5: if (sizeof(ar[4])) { -  mapping extensions = ([]); -  foreach(ar[4] / ",", string ext) { -  sscanf (ext, "%[^=]=%s", string extype, string exvalue); -  extype = _Roxen.http_decode_string (extype); -  if (has_prefix (extype, "!")) { -  extype = extype[1..]; -  if (!supported_extensions[extype[1..]]) -  ERROR ("Critical extension %s is not supported.\n", extype); +  //! Compatibility alias for @[Protocols.LDAP.parse_ldap_url]. +  mapping(string:mixed) parse_url (string ldapuri) +  { +  return parse_ldap_url (ldapuri);    } -  if (extype == "") -  ERROR ("Failed to parse extension type from %O.\n", ext); -  extensions[extype] = -  exvalue ? _Roxen.http_decode_string (exvalue) : 1; -  } -  res->ext = extensions; -  } -  case 4: res->filter = _Roxen.http_decode_string (ar[3]); -  case 3: res->scope = (["base": SCOPE_BASE, -  "one": SCOPE_ONE, -  "sub": SCOPE_SUB])[ar[2]]; -  case 2: if (sizeof(ar[1])) res->attributes = -  map (ar[1] / ",", _Roxen.http_decode_string); -  case 1: res->basedn = _Roxen.http_decode_string (ar[0]); -  break; -  default: res->basedn = ""; -  } +     -  return res; +     -  } //parse_uri -  -  +    // Schema handling.      static mapping(string:array(string)) query_subschema (string dn,    array(string) attrs)   // Queries the server for the specified attributes in the subschema   // applicable for the specified object. The return value is on the   // same form as from simple_read (specifically there's no UTF-8   // decoding of the values).   //   // If dn == "" then the attribute values might be joined from several