// @(#)root/ldap:$Id$ // Author: Oleksandr Grebenyuk 21/09/2001 /************************************************************************* * For the licensing terms see $ROOTSYS/LICENSE. * * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ #include "TLDAPServer.h" #include "TLDAPResult.h" #include "TLDAPEntry.h" #include "TLDAPAttribute.h" #include "TObjString.h" #include "TList.h" #include "TError.h" ClassImp(TLDAPServer) //////////////////////////////////////////////////////////////////////////////// /// During construction TLDAPServer object tries to connect to the /// specified server and you should check the connection status by /// calling the IsConnected() member function immediately after /// creating that object. /// const char *host: The name of host to connect. Default is "localhost". /// Int_t port: Port number to connect. Default is LDAP_PORT (=389). /// const char *binddn: Bind DN. /// const char *password: Password. Usually you have to specify bind DN and /// password to have the write permissions. Default /// values for bind DN and password are zero, that means /// anonymous connection. Usually it is enough to read /// the data from the server. /// Int_t version Set LDAP protocol version: LDAP_VERSION1, /// LDAP_VERSION2, LDAP_VERSION3 TLDAPServer::TLDAPServer(const char *host, Int_t port, const char *binddn, const char *password, Int_t version) { fLd = 0; fIsConnected = kFALSE; fBinddn = binddn; fPassword = password; fLd = ldap_init(host, port); if (!fLd) { Error("TLDAPServer", "error in ldap_init function"); } else { if (ldap_set_option(fLd, LDAP_OPT_PROTOCOL_VERSION, &version) != LDAP_OPT_SUCCESS ) { Error("Bind", "Could not set protocol version!"); return; } Bind( ); } } //////////////////////////////////////////////////////////////////////////////// /// Copy constructor TLDAPServer::TLDAPServer(const TLDAPServer& lds) : TObject(lds), fLd(lds.fLd), fBinddn(lds.fBinddn), fPassword(lds.fPassword), fIsConnected(lds.fIsConnected) { } //////////////////////////////////////////////////////////////////////////////// /// Equal operator TLDAPServer& TLDAPServer::operator=(const TLDAPServer& lds) { if(this!=&lds) { TObject::operator=(lds); fLd=lds.fLd; fBinddn=lds.fBinddn; fPassword=lds.fPassword; fIsConnected=lds.fIsConnected; } return *this; } //////////////////////////////////////////////////////////////////////////////// /// If the object is connected to the server, it disconnects. TLDAPServer::~TLDAPServer() { Unbind(); } //////////////////////////////////////////////////////////////////////////////// /// Binds to the server with specified binddn and password. /// Return value: LDAP error code, 0 if successfully bound. Int_t TLDAPServer::Bind() { if (!IsConnected()) { Int_t result = ldap_simple_bind_s(fLd, fBinddn.Data(), fPassword.Data()); if (result != LDAP_SUCCESS) { ldap_unbind(fLd); fIsConnected = kFALSE; switch (result) { case LDAP_INVALID_CREDENTIALS: Error("Bind", "invalid password"); break; case LDAP_INAPPROPRIATE_AUTH: Error("Bind", "entry has no password to check"); break; default : Error("Bind", "%s", ldap_err2string(result)); break; } } else { fIsConnected = kTRUE; } return result; } return 0; } //////////////////////////////////////////////////////////////////////////////// /// Unbinds from the server with specified binddn and password. void TLDAPServer::Unbind() { if (IsConnected()) { ldap_unbind(fLd); fIsConnected = kFALSE; } } //////////////////////////////////////////////////////////////////////////////// /// Performs an LDAPSearch with the attribute "namingContexts" to be /// returned with the result. The value of this attribute is /// extracted and returned as const char. const char *TLDAPServer::GetNamingContexts() { TList *attrs = new TList; attrs->SetOwner(); attrs->AddLast(new TObjString("namingContexts")); const char *namingcontexts = 0; TLDAPResult *result = Search("", LDAP_SCOPE_BASE, 0, attrs, 0); if (result) { TLDAPEntry *entry = result->GetNext(); if (entry) { TLDAPAttribute *attribute = entry->GetAttribute(); if (attribute) namingcontexts = attribute->GetValue(); delete entry; } delete result; } delete attrs; return namingcontexts; } //////////////////////////////////////////////////////////////////////////////// /// Performs an LDAPSearch with the attribute "subschemaSubentry" to /// be returned with the result. The value of this attribute is /// extracted and returned as const char. const char *TLDAPServer::GetSubschemaSubentry() { TList *attrs = new TList; attrs->SetOwner(); attrs->AddLast(new TObjString("subschemaSubentry")); const char *subschema = 0; TLDAPResult *result = Search("", LDAP_SCOPE_BASE, 0, attrs, 0); if (result) { TLDAPEntry *entry = result->GetNext(); if (entry) { TLDAPAttribute *attribute = entry->GetAttribute(); if (attribute) subschema = attribute->GetValue(); delete entry; } delete result; } delete attrs; return subschema; } //////////////////////////////////////////////////////////////////////////////// /// Calls GetSubschemaSubentry() and performs and LDAPSearch with /// the attribute "objectClasses" to be returned with the result. /// The returned result object must be deleted by the user. TLDAPResult *TLDAPServer::GetObjectClasses() { const char *subschema = GetSubschemaSubentry(); TList *attrs = new TList; attrs->SetOwner(); attrs->AddLast(new TObjString("objectClasses")); TLDAPResult *result = Search(subschema, LDAP_SCOPE_BASE, 0, attrs, 0); delete attrs; return result; } //////////////////////////////////////////////////////////////////////////////// /// Calls GetSubschemaSubentry() and performs and LDAPSearch with the /// attribute "attributeTypes" to be returned with the result. /// The returned result object must be deleted by the user. TLDAPResult *TLDAPServer::GetAttributeTypes() { const char *subschema = GetSubschemaSubentry(); TList *attrs = new TList; attrs->SetOwner(); attrs->AddLast(new TObjString("attributeTypes")); TLDAPResult *result = Search(subschema, LDAP_SCOPE_BASE, 0, attrs, 0); delete attrs; return result; } //////////////////////////////////////////////////////////////////////////////// /// Performs searching at the LDAP directory. /// Return value: a TLDAPResult object or 0 in case of error. /// Result needs to be deleted by user. /// const char *base: Specifies the base object for the search operation /// Int_t scope: Specifies the portion of the LDAP tree, relative to /// the base object, to search. /// Must be one of LDAP_SCOPE_BASE (==0), /// LDAP_SCOPE_ONELEVEL (==1) or LDAP_SCOPE_SUBTREE (==2). /// char *filter: The criteria during the search to determine which /// entries to return, 0 means that the filter /// "(objectclass=*)" will be applied /// TList *attrs: The TList of attributes to be returned along with /// each entry, 0 means that all available attributes /// should be returned. /// Int_t attrsonly: This parameter is a boolean specifying whether both /// types and values should be returned with each /// attribute (zero) or types only should be returned /// (non-zero). TLDAPResult *TLDAPServer::Search(const char *base, Int_t scope, const char *filter, TList *attrs, Bool_t attrsonly) { Bind(); Int_t errcode; TLDAPResult *result = 0; if (IsConnected()) { LDAPMessage *searchresult; char **attrslist = 0; if (attrs) { Int_t n = attrs->GetSize(); attrslist = new char* [n + 1]; for (Int_t i = 0; i < n; i++) attrslist[i] = (char*) ((TObjString*)attrs->At(i))->GetName(); attrslist[n] = 0; } if (filter == 0) filter = "(objectClass=*)"; errcode = ldap_search_s(fLd, base, scope, filter, attrslist, attrsonly, &searchresult); delete [] attrslist; if (errcode == LDAP_SUCCESS) { result = new TLDAPResult(fLd, searchresult); } else { ldap_msgfree(searchresult); Error("Search", "%s", ldap_err2string(errcode)); } } else { errcode = LDAP_SERVER_DOWN; Error("Search", "%s", "server is not connected"); } return result; } //////////////////////////////////////////////////////////////////////////////// /// Adds entry to the LDAP tree. /// Be sure that you are bound with write permissions. /// Return value: LDAP error code. Int_t TLDAPServer::AddEntry(TLDAPEntry &entry) { Bind(); Int_t errcode; if (IsConnected()) { LDAPMod **ms = entry.GetMods(0); errcode = ldap_add_s(fLd, entry.GetDn(), ms); TLDAPServer::DeleteMods(ms); if (errcode != LDAP_SUCCESS) Error("AddEntry", "%s", ldap_err2string(errcode)); } else { errcode = LDAP_SERVER_DOWN; Error("AddEntry", "server is not connected"); } return errcode; } //////////////////////////////////////////////////////////////////////////////// /// Modifies specified entry. /// Be sure that you are bound with write permissions. /// Return value: LDAP error code, 0 = success. /// TLDAPEntry &entry: Entry to be modified. /// Int_t mode: Modifying mode. /// Should be one of LDAP_MOD_ADD (==0), /// LDAP_MOD_DELETE (==1) or LDAP_MOD_REPLACE (==2) /// Specifies what to do with all the entry's attributes /// and its values - add to the corresponding entry on /// the server, delete from it, or replace the /// corresponding attributes with new values Int_t TLDAPServer::ModifyEntry(TLDAPEntry &entry, Int_t mode) { Bind(); Int_t errcode; if (IsConnected()) { LDAPMod **ms = entry.GetMods(mode); errcode = ldap_modify_s(fLd, entry.GetDn(), ms); TLDAPServer::DeleteMods(ms); if (errcode != LDAP_SUCCESS) Error("ModifyEntry", "%s", ldap_err2string(errcode)); } else { errcode = LDAP_SERVER_DOWN; Error("ModifyEntry", "server is not connected"); } return errcode; } //////////////////////////////////////////////////////////////////////////////// /// Deletes the entry with specified DN, the base entry must exist. /// Be sure that you are bound with write permissions. /// Return value: LDAP error code, 0 = succes. Int_t TLDAPServer::DeleteEntry(const char *dn) { Bind(); Int_t errcode; if (IsConnected()) { errcode = ldap_delete_s(fLd, dn); if (errcode != LDAP_SUCCESS) Error("DeleteEntry", "%s", ldap_err2string(errcode)); } else { errcode = LDAP_SERVER_DOWN; Error("DeleteEntry", "server is not connected"); } return errcode; } //////////////////////////////////////////////////////////////////////////////// /// Renames the entry with specified DN, the entry must be leaf /// Be sure that you are bound with the write permissions /// Return value: LDAP error code, 0 = succes /// char *dn: Distinguished name of entry to be renamed. /// This entry must be a leaf in the LDAP directory tree. /// char *newrdn: The new relative distinguished name to give the entry /// being renamed. /// Bool_t removeattr: This parameter specifies whether or not the /// attribute values in the old relative distinguished /// name should be removed from the entry /// or retained as non-distinguished attributes. Int_t TLDAPServer::RenameEntry(const char *dn, const char *newrdn, Bool_t removeattr) { Int_t errcode; if (IsConnected()) { errcode = ldap_modrdn2_s(fLd, dn, newrdn, removeattr); if (errcode != LDAP_SUCCESS) Error( "RenameEntry", "%s", ldap_err2string(errcode)); } else { errcode = LDAP_SERVER_DOWN; Error("RenameEntry", "server is not connected"); } return errcode; } //////////////////////////////////////////////////////////////////////////////// /// Deletes the array of LDAPMod structures and frees its memory. /// LDAPMod **mods: Pointer to the zero-terminated array of pointers /// to LDAPMod structures void TLDAPServer::DeleteMods(LDAPMod **mods) { #if 1 ldap_mods_free(mods, 1); #else Int_t i = 0; LDAPMod *mod; while ((mod = mods[i++]) != 0) { if (mod->mod_op & LDAP_MOD_BVALUES) { ber_bvecfree(mod->mod_bvalues); } else { Int_t j = 0; char *c; while ((c = mod->mod_values[j++]) != 0) delete c; } delete mod->mod_type; delete mod; } delete mods; #endif }