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.25 2001/08/15 18:10:53 hop Exp $ + // $Id: client.pike,v 1.26 2001/09/17 02:45:42 hop 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:67:   // Interesting, applicable   // RFC 2307 (LDAP as network information services; draft?)         #if constant(.ldap_privates.ldap_der_decode)      #include "ldap_globals.h"      #include "ldap_errors.h"    + import SSL.constants; +    #ifdef LDAP_PROTOCOL_PROFILE   int _prof_gtim;   #endif      // ------------------------      // ASN.1 decode macros   #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)    -  +  //! module Protocols +  //! submodule LDAP +  //! +  //! class client +  //! +  //! 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    private string ldap_basedn = ""; // baseDN    private int ldap_scope = 0; // 0: base, 1: onelevel, 2: subtree    private int ldap_deref = 0; // 0: ...    private int ldap_sizelimit = 0;    private int ldap_timelimit = 0;    private mapping lauth = ([]);          -  +  //! Contains the result of a LDAP search. +  //! +  //! @seealso +  //! @[LDAP.client.search], @[LDAP.client.result.fetch] +  //!    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;    -  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); } -  +     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) {    // deUTF8
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:152:    entry1 = ASN1_GET_ATTR_ARRAY(oder);    foreach(entry1, object attr1) {    attrs += ([ASN1_GET_ATTR_NAME(attr1):_get_attr_values(ldap_version, attr1)]);    }    res += ({attrs});    }       return (res);    } // _New_decode    +  //! +  //! 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, int|void stuff) {    // rawres: array of result in raw format, but WITHOUT LDAP PDU !!!    // stuff: 1=bind result; ...       int lastel = sizeof(rawres) - 1;       if (lastel < 0) {    ::seterr (LDAP_LOCAL_ERROR);    THROW(({"LDAP: Internal error.\n",backtrace()}));    return(-::ldap_errno);
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:197: Inside #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());    -  } // create +  }    -  int|mapping(string:array(string)) fetch(int|void ix) { +  //! +  //! Returns error number of search result. +  //! +  //! @seealso +  //! @[LDAP.client.result.error_string] +  int error_number() { return(resultcode); }    -  if (!ix) -  ix = actnum + 1; -  if ((ix <= num_entries()) && (ix > 0)) { -  actnum = ix - 1; +  //! +  //! Returns error description of search result. +  //! +  //! @seealso +  //! @[LDAP.client.result.error_number] +  string error_string() { +  return((stringp(resultstring) && sizeof(resultstring)) ? +  resultstring : ldap_errlist[resultcode]); +  } +  +  //! +  //! Returns the number of entries. +  //! +  //! @seealso +  //! @[LDAP.client.result.count_entries] +  int num_entries() { return(entrycnt); } +  +  //! +  //! Returns the number of entries from current cursor +  //! possition till end of the list. +  //! +  //! @seealso +  //! @[LDAP.client.result.first], @[LDAP.client.result.next] +  int count_entries() { return(entrycnt - actnum); } +  +  //! @decl mapping(string:array(string)) fetch() +  //! @decl mapping(string:array(string)) fetch(int) +  //! +  //! Returns a mapping with an entry for each attribute. +  //! Each entry is an array of values of the attribute. +  //! +  //! @param idx +  //! Optional argument can be used for direct access +  //! to the entry other then currently pointed by cursor. +  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);    }    -  +  //! +  //! Returns distinguished name (DN) of the current entry +  //! in the result list. Notice that this is the same +  //! as fetch()->dn[0].    string get_dn() { return(fetch()["dn"][0]); }    -  +  //! +  //! Initialized the result cursor to the first entry +  //! in the result list. +  //! +  //! @seealso +  //! @[LDAP.client.result.next]    void first() { actnum = 0; }    -  +  //! +  //! Moves the result cursor to the next entry +  //! in the result list. Returns number of remained entries +  //! in the result list. Returns 0 at the end. +  //! +  //! @seealso +  //! @[LDAP.client.result.next]    int next() {    if (actnum < (num_entries()-1)) {    actnum++;    return(count_entries());    }    return(0);    }       } // end of class 'result' ---------------   
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:259:    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);    }    -  // API function (ldap_open) -  // -  // create(string|void server) -  // -  // server: server URL in form "ldap://hostname/basedn???!bindname= -  void create(string|void server) +  //! Several information about code itself and about active connection too +  mapping info; +  +  //! @decl void create() +  //! @decl void create(string) +  //! @decl void create(string, object) +  //! +  //! Create object. The first optional argument can be used later +  //! for subsequence operations. The second one can specify +  //! TLS context of connection. +  //! +  //! @param url +  //! LDAP server URL in form +  //! @tt{"ldap://hostname/basedn?attrlist?scope?ext"@} +  //! +  //! @param context +  //! TLS context of connection +  //! +  //! @seealso +  //! @[LDAP.client.bind], @[LDAP.client.search] +  void create(string|void url, object|void context)    {    -  if(!server || !sizeof(server)) -  server = LDAP_DEFAULT_URL; +  info = ([ "code_revision" : ("$Revision: 1.26 $"/" ")[1] ]);    -  lauth = parse_url(server); +  if(!url || !sizeof(url)) +  url = LDAP_DEFAULT_URL;    -  if(!stringp(lauth->scheme) || (lauth->scheme != "ldap")) { +  lauth = parse_url(url); +  +  if(!stringp(lauth->scheme) || +  ((lauth->scheme != "ldap") && (lauth->scheme != "ldaps"))) {    THROW(({"Unknown scheme in server URL.\n",backtrace()}));    }       if(!lauth->host) -  lauth += ([ "host" : parse_url(LDAP_DEFAULT_URL)->host ]); +  lauth += ([ "host" : LDAP_DEFAULT_HOST ]);    if(!lauth->port) -  lauth += ([ "port" : parse_url(LDAP_DEFAULT_URL)->port ]); +  lauth += ([ "port" : lauth->scheme == "ldap" ? LDAP_DEFAULT_PORT : LDAPS_DEFAULT_PORT ]);    -  ::create(lauth->host, lauth->port); -  if(!::connected) { +  if(lauth->scheme == "ldaps" && !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, +  SSL_rsa_with_3des_ede_cbc_sha, +  }); +  } +  +  if(!(::connect(lauth->host, lauth->port))) { +  //errno = ldapfd->errno(); +  seterr (LDAP_SERVER_DOWN); +  DWRITE("client.create: ERROR: can't open socket.\n"); +  //ldapfd->destroy(); +  //ldap=0; +  //ok = 0; +  //if(con_fail) +  // con_fail(this_object(), @extra_args);    THROW(({"Failed to connect to LDAP server.\n",backtrace()}));    } -  +  +  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); +  +  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);   
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:312:    vers = Standards.ASN1.Types.asn1_integer(ldap_version);    namedn = Standards.ASN1.Types.asn1_octet_string(name);    auth = ASN1_CONTEXT_OCTET_STRING(0, password);    // SASL credentials ommited       msgval = ASN1_APPLICATION_SEQUENCE(0, ({vers, namedn, auth}));       return (do_op(msgval));    }    -  // API function (ldap_bind) -  // -  // bind(string|void name, string|void password, int|void proto) -  // -  // name: -  // password: -  // proto: protocol version, supported 2 and 3 -  int bind (string|void name, string|void password, int|void proto) { +  //! @decl int bind() +  //! @decl int bind(string, string) +  //! @decl int bind(string, string, version) +  //! +  //! Authenticates connection to the direcory. +  //! +  //! First form uses default value previously entered in create. +  //! +  //! Second form uses value from parameters: +  //! +  //! @param dn +  //! The distinguished name (DN) of an entry aginst which will +  //! be made authentication. +  //! @param password +  //! Password used for authentication. +  //! +  //! Third form allows specify the version of LDAP protocol used +  //! by connection to the LDAP server. +  //! +  //! @param version +  //! Only @tt{2@} or @tt{3@} can be entered. +  //! +  //! @note +  //! Only simple authentication type is implemented. So be warned +  //! clear text passwords are sent to the directory server. +  int bind (string|void dn, string|void password, int|void version) {       int id;    mixed raw;    object rv;    -  if (!proto) -  proto = LDAP_DEFAULT_VERSION; +  if (!version) +  version = LDAP_DEFAULT_VERSION;    if (chk_ver())    return(-ldap_errno); -  if (!stringp(name)) -  name = mappingp(lauth->ext) ? lauth->ext->bindname||"" : ""; +  if (!stringp(dn)) +  dn = mappingp(lauth->ext) ? lauth->ext->bindname||"" : "";    if (!stringp(password))    password = ""; -  ldap_version = proto; +  ldap_version = version;    if(ldap_version == 3) { -  name = string_to_utf8(name); +  dn = string_to_utf8(dn);    password = string_to_utf8(password);    } -  if(intp(raw = send_bind_op(name, password))) { +  if(intp(raw = send_bind_op(dn, password))) {    THROW(({error_string()+"\n",backtrace()}));    return(-ldap_errno);    }       rv = result(({raw}),1);    if (!rv->error_number())    binded = 1;    DWRITE_HI(sprintf("client.BIND: %s\n", rv->error_string()));    return (seterr (rv->error_number()));   
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:367:       return (1);    }       void destroy() {       //send_unbind_op();    destruct(this_object());    }    -  // API function (ldap_unbind) -  // -  // unbind() -  // +  //! +  //! 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;    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)));       }    -  // API function (ldap_delete) -  // -  // delete(string dn) -  // -  // dn: DN of deleted object +  //! +  //! Deletes entry from the LDAP server. +  //! +  //! @param dn +  //! The distinguished name of deleted entry.    int delete (string dn) {       int id;    mixed raw;    object rv;       if (chk_ver())    return(-ldap_errno);    if (chk_binded())    return(-ldap_errno);
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:438:    ({ Standards.ASN1.Types.asn1_octet_string(aval[0]),    Standards.ASN1.Types.asn1_octet_string(aval[1])    }))    })    );       return (do_op(msgval));    }       -  // API function (ldap_compare) -  // -  // compare(string dn, array(string) aval) -  // -  // dn: DN of compared object -  // aval: attribute value +  //! +  //! Compares given attribute value with one in the directory. +  //! +  //! @param dn +  //! The distinguished name of compared entry. +  //! +  //! @param aval +  //! The mapping of compared attributes and theirs values.    int compare (string dn, array(string) aval) {       int id;    mixed raw;    object rv;       // if (!aval || sizeof(aval)<2)    // error    if (chk_ver())    return(-ldap_errno);
pike.git/lib/modules/Protocols.pmod/LDAP.pmod/client.pike:1042:    default: res += ([ "scope" : 0]); // = "base"    }    case 2: res += sizeof(ar[1]) ? ([ "attributes" : ar[1] / "," ]) : ([]);    case 1: res += ([ "basedn" : ar[0] ]);    }       return (res);       } //parse_uri    -  +    #endif