123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495 |
- /*##############################################################################
- Copyright (C) 2011 HPCC Systems.
- All rights reserved. This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- ############################################################################## */
- #ifndef __LDAPCONNECTION_HPP
- #define __LDAPCONNECTION_HPP
- #include <stdlib.h>
- #include "thirdparty.h"
- #include "jiface.hpp"
- #include "jliball.hpp"
- #include "seclib.hpp"
- #ifdef _WIN32
- #include <windows.h>
- #include <winldap.h>
- #include <winber.h>
- #include <rpc.h>
- #include <rpcdce.h>
- #include "dsgetdc.h"
- #include <lm.h>
- #else
- #define LDAP_DEPRECATED 1
- #include <stdio.h>
- #include <string.h>
- #include <ldap_cdefs.h>
- #include <ldap.h>
- #endif
- #ifdef _WIN32
- typedef struct l_timeval TIMEVAL;
- #else
- typedef struct timeval TIMEVAL;
- #endif
- #define LDAPTIMEOUT 60 //20 second connection/search timeout
- #define DEFAULT_LDAP_POOL_SIZE 10
- // 1 for ActiveDirectory, 2 for iPlanet, 3 for openLdap
- enum LdapServerType
- {
- LDAPSERVER_UNKNOWN = 0,
- ACTIVE_DIRECTORY = 1,
- IPLANET = 2,
- OPEN_LDAP = 3
- };
- enum ACT_TYPE
- {
- USER_ACT = 0,
- GROUP_ACT = 1
- };
-
- interface IPermissionProcessor;
- interface ILdapConnection : extends IInterface
- {
- virtual LDAP* getLd() = 0;
- };
- interface ILdapConnectionPool : extends IInterface
- {
- virtual ILdapConnection* getConnection() = 0;
- virtual ILdapConnection* getSSLConnection() = 0;
- };
- interface ILdapConfig : extends IInterface
- {
- virtual LdapServerType getServerType() = 0;
- virtual StringBuffer& getLdapHost(StringBuffer& hostbuf) = 0;
- virtual void markDown(const char* ldaphost) = 0;
- virtual int getLdapPort() = 0;
- virtual int getLdapSecurePort() = 0;
- virtual const char* getProtocol() = 0;
- virtual const char* getBasedn() = 0;
- virtual const char* getDomain() = 0;
- virtual const char* getAuthMethod() = 0;
- virtual const char* getUserBasedn() = 0;
- virtual const char* getGroupBasedn() = 0;
- virtual const char* getResourceBasedn(SecResourceType rtype) = 0;
- virtual const char* getTemplateName() = 0;
- virtual const char* getSysUser() = 0;
- virtual const char* getSysUserDn() = 0;
- virtual const char* getSysUserCommonName() = 0;
- virtual const char* getSysUserPassword() = 0;
- virtual const char* getSysUserBasedn() = 0;
- virtual bool sysuserSpecified() = 0;
- virtual int getMaxConnections() = 0;
- virtual void setResourceBasedn(const char* rbasedn, SecResourceType rtype = RT_DEFAULT) = 0;
- };
- class CPermission : public CInterface, implements IInterface
- {
- StringBuffer m_account_name;
- ACT_TYPE m_account_type;
- int m_allows;
- int m_denies;
- public:
- IMPLEMENT_IINTERFACE
-
- CPermission(const char* account_name, ACT_TYPE account_type, int allows, int denies)
- {
- m_account_name.append(account_name);
- m_account_type = account_type;
- m_allows = allows;
- m_denies = denies;
- }
- const char* getAccount_name() {return m_account_name.str();}
- ACT_TYPE getAccount_type() {return m_account_type;}
- int getAllows() {return m_allows;}
- int getDenies() {return m_denies;}
- void setAllows(int allows) { m_allows = allows;}
- void setDenies(int denies) { m_denies = denies;}
- };
- class CPermissionAction : public CInterface, implements IInterface
- {
- public:
- StringBuffer m_action;
- StringBuffer m_basedn;
- SecResourceType m_rtype;
- StringBuffer m_rname;
-
- StringBuffer m_account_name;
- ACT_TYPE m_account_type;
- int m_allows;
- int m_denies;
- IMPLEMENT_IINTERFACE
- };
- interface ILdapClient : extends IInterface
- {
- virtual void init(IPermissionProcessor* pp) = 0;
- virtual LdapServerType getServerType() = 0;
- virtual bool authenticate(ISecUser& user) = 0;
- virtual bool authorize(SecResourceType rtype, ISecUser&, IArrayOf<ISecResource>& resources) = 0;
- virtual bool addResources(SecResourceType rtype, ISecUser& user, IArrayOf<ISecResource>& resources, SecPermissionType ptype, const char* basedn) = 0;
- virtual bool addUser(ISecUser& user) = 0;
- virtual void getGroups(const char *user, StringArray& groups) = 0;
- virtual bool getUserInfo(ISecUser& user, const char* infotype = NULL) = 0;
- virtual ISecUser* lookupUser(unsigned uid) = 0;
- virtual bool lookupAccount(MemoryBuffer& sidbuf, StringBuffer& account_name, ACT_TYPE& act_type) = 0;
- virtual void lookupSid(const char* act_name, MemoryBuffer& act_sid, ACT_TYPE act_type) = 0;
- virtual void setPermissionProcessor(IPermissionProcessor* pp) = 0;
- virtual bool retrieveUsers(IUserArray& users) = 0;
- virtual bool retrieveUsers(const char* searchstr, IUserArray& users) = 0;
- virtual void getAllGroups(StringArray & groups) = 0;
- virtual void setResourceBasedn(const char* rbasedn, SecResourceType rtype = RT_DEFAULT) = 0;
- virtual ILdapConfig* getLdapConfig() = 0;
- virtual bool userInGroup(const char* userdn, const char* groupdn) = 0;
- virtual bool updateUser(ISecUser& user, const char* newPassword) = 0;
- virtual bool updateUser(const char* type, ISecUser& user) = 0;
- virtual bool updateUser(const char* username, const char* newPassword) = 0;
- virtual bool getResources(SecResourceType rtype, const char * basedn, const char* prefix, IArrayOf<ISecResource>& resources) = 0;
- virtual bool getResourcesEx(SecResourceType rtype, const char * basedn, const char* prefix, const char* searchstr, IArrayOf<ISecResource>& resources) = 0;
- virtual bool getPermissionsArray(const char* basedn, SecResourceType rtype, const char* name, IArrayOf<CPermission>& permissions) = 0;
- virtual bool changePermission(CPermissionAction& action) = 0;
- virtual void changeUserGroup(const char* action, const char* username, const char* groupname) = 0;
- virtual bool deleteUser(ISecUser* user) = 0;
- virtual void addGroup(const char* groupname) = 0;
- virtual void deleteGroup(const char* groupname) = 0;
- virtual void getGroupMembers(const char* groupname, StringArray & users) = 0;
- virtual void deleteResource(SecResourceType rtype, const char* name, const char* basedn) = 0;
- virtual void renameResource(SecResourceType rtype, const char* oldname, const char* newname, const char* basedn) = 0;
- virtual void copyResource(SecResourceType rtype, const char* oldname, const char* newname, const char* basedn) = 0;
- virtual void normalizeDn(const char* dn, StringBuffer& ndn) = 0;
- virtual bool isSuperUser(ISecUser* user) = 0;
- virtual int countEntries(const char* basedn, const char* objectClass, int limit) = 0;
- virtual int countUsers(const char* searchstr, int limit) = 0;
- virtual int countResources(const char* basedn, const char* searchstr, int limit) = 0;
- virtual ILdapConfig* queryConfig() = 0;
- virtual const char* getPasswordStorageScheme() = 0;
- };
- ILdapClient* createLdapClient(IPropertyTree* cfg);
- #ifdef _WIN32
- bool verifyServerCert(LDAP* ld, PCCERT_CONTEXT pServerCert);
- #endif
- class LdapUtils
- {
- public:
- static LDAP* LdapInit(const char* protocol, const char* host, int port, int secure_port)
- {
- LDAP* ld = NULL;
- if(stricmp(protocol, "ldaps") == 0)
- {
- #ifdef _WIN32
- ld = ldap_sslinit((char*)host, secure_port, 1);
- if (ld == NULL )
- throw MakeStringException(-1, "ldap_sslinit error" );
- int rc = 0;
- unsigned long version = LDAP_VERSION3;
- long lv = 0;
-
- rc = ldap_set_option(ld,
- LDAP_OPT_PROTOCOL_VERSION,
- (void*)&version);
- if (rc != LDAP_SUCCESS)
- throw MakeStringException(-1, "ldap_set_option error - %s", ldap_err2string(rc));
- rc = ldap_get_option(ld,LDAP_OPT_SSL,(void*)&lv);
- if (rc != LDAP_SUCCESS)
- throw MakeStringException(-1, "ldap_get_option error - %s", ldap_err2string(rc));
- // If SSL is not enabled, enable it.
- if ((void*)lv != LDAP_OPT_ON)
- {
- rc = ldap_set_option(ld, LDAP_OPT_SSL, LDAP_OPT_ON);
- if (rc != LDAP_SUCCESS)
- throw MakeStringException(-1, "ldap_set_option error - %s", ldap_err2string(rc));
- }
-
- ldap_set_option(ld, LDAP_OPT_SERVER_CERTIFICATE, verifyServerCert);
- #else
- // Initialize an LDAP session for TLS/SSL
- #ifndef HAVE_TLS
- //throw MakeStringException(-1, "openldap client library libldap not compiled with TLS support");
- #endif
- StringBuffer uri("ldaps://");
- uri.appendf("%s:%d", host, secure_port);
- DBGLOG("connecting to %s", uri.str());
- int rc = ldap_initialize(&ld, uri.str());
- if(rc != LDAP_SUCCESS)
- {
- DBGLOG("ldap_initialize error %s", ldap_err2string(rc));
- throw MakeStringException(-1, "ldap_initialize error %s", ldap_err2string(rc));
- }
- int reqcert = LDAP_OPT_X_TLS_NEVER;
- ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &reqcert);
- #endif
- }
- else
- {
- // Initialize an LDAP session
- if ((ld = ldap_init( (char*)host, port )) == NULL)
- {
- throw MakeStringException(-1, "ldap_init error");
- }
- }
- return ld;
- }
- static int LdapSimpleBind(LDAP* ld, char* userdn, char* password)
- {
- #ifndef _WIN32
- TIMEVAL timeout = {LDAPTIMEOUT, 0};
- ldap_set_option(ld, LDAP_OPT_TIMEOUT, &timeout);
- ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &timeout);
- #endif
- return ldap_simple_bind_s(ld, userdn, password);
- /*
- //TODO: bugs need to be fixed: (1) in ldap_result, is "1" actually meant for LDAP_MESSAGE_ONE? (2) should call ldap_msgfree on result
- int final_rc = LDAP_SUCCESS;
- int msgid = ldap_simple_bind(ld, userdn, password);
- if(msgid < 0)
- {
- #ifndef _WIN32
- final_rc = ldap_get_lderrno(ld, NULL, NULL);
- #else
- final_rc = LDAP_OTHER;
- #endif
- }
- else
- {
- LDAPMessage* result = NULL;
- TIMEVAL timeOut = {LDAPTIMEOUT,0};
- int rc = ldap_result(ld, msgid, 1, &timeOut, &result);
- if(rc < 0)
- {
- #ifndef _WIN32
- final_rc = ldap_get_lderrno(ld, NULL, NULL);
- #else
- final_rc = LDAP_OTHER;
- #endif
- }
- else if(rc == 0)
- {
- final_rc = LDAP_TIMEOUT;
- }
- else
- {
- final_rc = ldap_result2error(ld, result, 1);
- }
- }
- return final_rc;
- */
- }
- // userdn is required for ldap_simple_bind_s, not really necessary for ldap_bind_s.
- static int LdapBind(LDAP* ld, const char* domain, const char* username, const char* password, const char* userdn, LdapServerType server_type, const char* method="kerboros")
- {
- bool binddone = false;
- int rc = LDAP_SUCCESS;
- // By default, use kerberos authentication
- if((method == NULL) || (strlen(method) == 0) || (stricmp(method, "kerberos") == 0))
- {
- #ifdef _WIN32
- if(server_type == ACTIVE_DIRECTORY)
- {
- if(username != NULL)
- {
- SEC_WINNT_AUTH_IDENTITY secIdent;
- secIdent.User = (unsigned char*)username;
- secIdent.UserLength = strlen(username);
- secIdent.Password = (unsigned char*)password;
- secIdent.PasswordLength = strlen(password);
- // Somehow, setting the domain makes it slower
- secIdent.Domain = (unsigned char*)domain;
- secIdent.DomainLength = strlen(domain);
- secIdent.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
- int rc = ldap_bind_s(ld, (char*)userdn, (char*)&secIdent, LDAP_AUTH_NEGOTIATE);
- if(rc != LDAP_SUCCESS)
- {
- DBGLOG("ldap_bind_s for user %s failed with %d - %s.", username, rc, ldap_err2string(rc));
- return rc;
- }
- }
- else
- {
- int rc = ldap_bind_s(ld, NULL, NULL, LDAP_AUTH_NEGOTIATE);
- if(rc != LDAP_SUCCESS)
- {
- DBGLOG("User Authentication Failed - ldap_bind_s for current user failed with %d - %s.", rc, ldap_err2string(rc));
- return rc;
- }
- }
- binddone = true;
- }
- #endif
- }
- if(!binddone)
- {
- if(userdn == NULL)
- {
- DBGLOG("userdn can't be NULL in order to bind to ldap server.");
- return LDAP_INVALID_CREDENTIALS;
- }
- int rc = LdapSimpleBind(ld, (char*)userdn, (char*)password);
- if (rc != LDAP_SUCCESS )
- {
- // For Active Directory, try binding with NT format username
- if(server_type == ACTIVE_DIRECTORY)
- {
- StringBuffer logonname;
- logonname.append(domain).append("\\").append(username);
- rc = LdapSimpleBind(ld, (char*)logonname.str(), (char*)password);
- if(rc != LDAP_SUCCESS)
- {
- #ifdef LDAP_OPT_DIAGNOSTIC_MESSAGE
- char *msg=NULL;
- ldap_get_option(ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, (void*)&msg);
- DBGLOG("LDAP bind error for user %s with %d - %s. %s", logonname.str(), rc, ldap_err2string(rc), msg&&*msg?msg:"");
- ldap_memfree(msg);
- #else
- DBGLOG("LDAP bind error for user %s with 0x%"I64F"x - %s", username, (unsigned __int64) rc, ldap_err2string(rc));
- #endif
- return rc;
- }
- }
- else
- {
- DBGLOG("LDAP bind error for user %s with 0x%"I64F"x - %s", username, (unsigned __int64) rc, ldap_err2string(rc));
- return rc;
- }
- }
- }
-
- return rc;
- }
- static void bin2str(MemoryBuffer& from, StringBuffer& to)
- {
- const char* frombuf = from.toByteArray();
- char tmp[3];
- for(unsigned i = 0; i < from.length(); i++)
- {
- unsigned char c = frombuf[i];
- sprintf(tmp, "%02X", c);
- tmp[2] = 0;
- to.append("\\").append(tmp);
- }
- }
- static int getServerInfo(const char* ldapserver, int ldapport, StringBuffer& domainDN, LdapServerType& stype, const char* domainname);
- static void normalizeDn(const char* dn, const char* basedn, StringBuffer& dnbuf)
- {
- dnbuf.clear();
- cleanupDn(dn, dnbuf);
- if(!containsBasedn(dnbuf.str()))
- dnbuf.append(",").append(basedn);
- }
- static bool containsBasedn(const char* str)
- {
- if(str == NULL || str[0] == '\0')
- return false;
- else
- return (strstr(str, "dc=") != NULL);
- }
- static void cleanupDn(const char* dn, StringBuffer& dnbuf)
- {
- if(dn == NULL || dn[0] == '\0')
- return;
- const char* ptr = dn;
- while(ptr && *ptr != '\0')
- {
- char c = *ptr;
- if(!isspace(c))
- {
- c = tolower(c);
- dnbuf.append(c);
- }
- ptr++;
- }
- }
-
- static bool getDcName(const char* domain, StringBuffer& dc)
- {
- bool ret = false;
- #ifdef _WIN32
- PDOMAIN_CONTROLLER_INFO psInfo = NULL;
- DWORD dwErr = DsGetDcName(NULL, domain, NULL, NULL, DS_FORCE_REDISCOVERY | DS_DIRECTORY_SERVICE_REQUIRED, &psInfo);
- if( dwErr == NO_ERROR)
- {
- const char* dcname = psInfo->DomainControllerName;
- if(dcname != NULL)
- {
- while(*dcname == '\\')
- dcname++;
- dc.append(dcname);
- ret = true;
- }
- NetApiBufferFree(psInfo);
- }
- else
- {
- DBGLOG("Error getting domain controller, error = %d", dwErr);
- ret = false;
- }
- #endif
- return ret;
- }
- static void getName(const char* dn, StringBuffer& name)
- {
- const char* bptr = dn;
- while(*bptr != '\0' && *bptr != '=')
- bptr++;
-
- if(*bptr == '\0')
- {
- name.append(dn);
- return;
- }
- else
- bptr++;
- const char* colon = strstr(bptr, ",");
- if(colon == NULL)
- name.append(bptr);
- else
- name.append(colon - bptr, bptr);
- }
- };
- #endif
|