// @(#)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) //______________________________________________________________________________ TLDAPServer::TLDAPServer(const char *host, Int_t port, const char *binddn, const char *password, Int_t version) { // 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 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( ); } } //______________________________________________________________________________ TLDAPServer::TLDAPServer(const TLDAPServer& lds) : TObject(lds), fLd(lds.fLd), fBinddn(lds.fBinddn), fPassword(lds.fPassword), fIsConnected(lds.fIsConnected) { // Copy constructor } //______________________________________________________________________________ TLDAPServer& TLDAPServer::operator=(const TLDAPServer& lds) { // Equal operator if(this!=&lds) { TObject::operator=(lds); fLd=lds.fLd; fBinddn=lds.fBinddn; fPassword=lds.fPassword; fIsConnected=lds.fIsConnected; } return *this; } //______________________________________________________________________________ TLDAPServer::~TLDAPServer() { // If the object is connected to the server, it disconnects. Unbind(); } //______________________________________________________________________________ Int_t TLDAPServer::Bind() { // Binds to the server with specified binddn and password. // Return value: LDAP error code, 0 if successfully bound. 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; } //______________________________________________________________________________ void TLDAPServer::Unbind() { // Unbinds from the server with specified binddn and password. if (IsConnected()) { ldap_unbind(fLd); fIsConnected = kFALSE; } } //______________________________________________________________________________ const char *TLDAPServer::GetNamingContexts() { // 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. 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; } //______________________________________________________________________________ const char *TLDAPServer::GetSubschemaSubentry() { // 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. 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; } //______________________________________________________________________________ TLDAPResult *TLDAPServer::GetObjectClasses() { // 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. 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; } //______________________________________________________________________________ TLDAPResult *TLDAPServer::GetAttributeTypes() { // 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. 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; } //______________________________________________________________________________ TLDAPResult *TLDAPServer::Search(const char *base, Int_t scope, const char *filter, TList *attrs, Bool_t attrsonly) { // 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). 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; } //______________________________________________________________________________ Int_t TLDAPServer::AddEntry(TLDAPEntry &entry) { // Adds entry to the LDAP tree. // Be sure that you are bound with write permissions. // Return value: LDAP error code. 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; } //______________________________________________________________________________ Int_t TLDAPServer::ModifyEntry(TLDAPEntry &entry, Int_t mode) { // 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 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; } //______________________________________________________________________________ Int_t TLDAPServer::DeleteEntry(const char *dn) { // 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. 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; } //______________________________________________________________________________ Int_t TLDAPServer::RenameEntry(const char *dn, const char *newrdn, Bool_t removeattr) { // 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 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; } //______________________________________________________________________________ void TLDAPServer::DeleteMods(LDAPMod **mods) { // Deletes the array of LDAPMod structures and frees its memory. // LDAPMod **mods: Pointer to the zero-terminated array of pointers // to LDAPMod structures #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 }