ldapconnection.hpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #ifndef __LDAPCONNECTION_HPP
  14. #define __LDAPCONNECTION_HPP
  15. #include <stdlib.h>
  16. #include "thirdparty.h"
  17. #include "jiface.hpp"
  18. #include "jliball.hpp"
  19. #include "seclib.hpp"
  20. #ifdef _WIN32
  21. #include <windows.h>
  22. #include <winldap.h>
  23. #include <winber.h>
  24. #include <rpc.h>
  25. #include <rpcdce.h>
  26. #include "dsgetdc.h"
  27. #include <lm.h>
  28. #else
  29. #define LDAP_DEPRECATED 1
  30. #include <stdio.h>
  31. #include <string.h>
  32. #include <ldap_cdefs.h>
  33. #include <ldap.h>
  34. #endif
  35. #ifdef _WIN32
  36. typedef struct l_timeval TIMEVAL;
  37. #else
  38. typedef struct timeval TIMEVAL;
  39. #endif
  40. #define LDAPTIMEOUT 60 //20 second connection/search timeout
  41. #define DEFAULT_LDAP_POOL_SIZE 10
  42. // 1 for ActiveDirectory, 2 for iPlanet, 3 for openLdap
  43. enum LdapServerType
  44. {
  45. LDAPSERVER_UNKNOWN = 0,
  46. ACTIVE_DIRECTORY = 1,
  47. IPLANET = 2,
  48. OPEN_LDAP = 3
  49. };
  50. enum ACT_TYPE
  51. {
  52. USER_ACT = 0,
  53. GROUP_ACT = 1
  54. };
  55. interface IPermissionProcessor;
  56. interface ILdapConnection : extends IInterface
  57. {
  58. virtual LDAP* getLd() = 0;
  59. };
  60. interface ILdapConnectionPool : extends IInterface
  61. {
  62. virtual ILdapConnection* getConnection() = 0;
  63. virtual ILdapConnection* getSSLConnection() = 0;
  64. };
  65. interface ILdapConfig : extends IInterface
  66. {
  67. virtual LdapServerType getServerType() = 0;
  68. virtual StringBuffer& getLdapHost(StringBuffer& hostbuf) = 0;
  69. virtual void markDown(const char* ldaphost) = 0;
  70. virtual int getLdapPort() = 0;
  71. virtual int getLdapSecurePort() = 0;
  72. virtual const char* getProtocol() = 0;
  73. virtual const char* getBasedn() = 0;
  74. virtual const char* getDomain() = 0;
  75. virtual const char* getAuthMethod() = 0;
  76. virtual const char* getUserBasedn() = 0;
  77. virtual const char* getGroupBasedn() = 0;
  78. virtual const char* getResourceBasedn(SecResourceType rtype) = 0;
  79. virtual const char* getTemplateName() = 0;
  80. virtual const char* getSysUser() = 0;
  81. virtual const char* getSysUserDn() = 0;
  82. virtual const char* getSysUserCommonName() = 0;
  83. virtual const char* getSysUserPassword() = 0;
  84. virtual const char* getSysUserBasedn() = 0;
  85. virtual bool sysuserSpecified() = 0;
  86. virtual int getMaxConnections() = 0;
  87. virtual void setResourceBasedn(const char* rbasedn, SecResourceType rtype = RT_DEFAULT) = 0;
  88. };
  89. class CPermission : public CInterface, implements IInterface
  90. {
  91. StringBuffer m_account_name;
  92. ACT_TYPE m_account_type;
  93. int m_allows;
  94. int m_denies;
  95. public:
  96. IMPLEMENT_IINTERFACE
  97. CPermission(const char* account_name, ACT_TYPE account_type, int allows, int denies)
  98. {
  99. m_account_name.append(account_name);
  100. m_account_type = account_type;
  101. m_allows = allows;
  102. m_denies = denies;
  103. }
  104. const char* getAccount_name() {return m_account_name.str();}
  105. ACT_TYPE getAccount_type() {return m_account_type;}
  106. int getAllows() {return m_allows;}
  107. int getDenies() {return m_denies;}
  108. void setAllows(int allows) { m_allows = allows;}
  109. void setDenies(int denies) { m_denies = denies;}
  110. };
  111. class CPermissionAction : public CInterface, implements IInterface
  112. {
  113. public:
  114. StringBuffer m_action;
  115. StringBuffer m_basedn;
  116. SecResourceType m_rtype;
  117. StringBuffer m_rname;
  118. StringBuffer m_account_name;
  119. ACT_TYPE m_account_type;
  120. int m_allows;
  121. int m_denies;
  122. IMPLEMENT_IINTERFACE
  123. };
  124. interface ILdapClient : extends IInterface
  125. {
  126. virtual void init(IPermissionProcessor* pp) = 0;
  127. virtual LdapServerType getServerType() = 0;
  128. virtual bool authenticate(ISecUser& user) = 0;
  129. virtual bool authorize(SecResourceType rtype, ISecUser&, IArrayOf<ISecResource>& resources) = 0;
  130. virtual bool addResources(SecResourceType rtype, ISecUser& user, IArrayOf<ISecResource>& resources, SecPermissionType ptype, const char* basedn) = 0;
  131. virtual bool addUser(ISecUser& user) = 0;
  132. virtual void getGroups(const char *user, StringArray& groups) = 0;
  133. virtual bool getUserInfo(ISecUser& user, const char* infotype = NULL) = 0;
  134. virtual ISecUser* lookupUser(unsigned uid) = 0;
  135. virtual bool lookupAccount(MemoryBuffer& sidbuf, StringBuffer& account_name, ACT_TYPE& act_type) = 0;
  136. virtual void lookupSid(const char* act_name, MemoryBuffer& act_sid, ACT_TYPE act_type) = 0;
  137. virtual void setPermissionProcessor(IPermissionProcessor* pp) = 0;
  138. virtual bool retrieveUsers(IUserArray& users) = 0;
  139. virtual bool retrieveUsers(const char* searchstr, IUserArray& users) = 0;
  140. virtual void getAllGroups(StringArray & groups) = 0;
  141. virtual void setResourceBasedn(const char* rbasedn, SecResourceType rtype = RT_DEFAULT) = 0;
  142. virtual ILdapConfig* getLdapConfig() = 0;
  143. virtual bool userInGroup(const char* userdn, const char* groupdn) = 0;
  144. virtual bool updateUserPassword(ISecUser& user, const char* newPassword, const char* currPassword = 0) = 0;
  145. virtual bool updateUser(const char* type, ISecUser& user) = 0;
  146. virtual bool updateUserPassword(const char* username, const char* newPassword) = 0;
  147. virtual bool getResources(SecResourceType rtype, const char * basedn, const char* prefix, IArrayOf<ISecResource>& resources) = 0;
  148. virtual bool getResourcesEx(SecResourceType rtype, const char * basedn, const char* prefix, const char* searchstr, IArrayOf<ISecResource>& resources) = 0;
  149. virtual bool getPermissionsArray(const char* basedn, SecResourceType rtype, const char* name, IArrayOf<CPermission>& permissions) = 0;
  150. virtual bool changePermission(CPermissionAction& action) = 0;
  151. virtual void changeUserGroup(const char* action, const char* username, const char* groupname) = 0;
  152. virtual bool deleteUser(ISecUser* user) = 0;
  153. virtual void addGroup(const char* groupname) = 0;
  154. virtual void deleteGroup(const char* groupname) = 0;
  155. virtual void getGroupMembers(const char* groupname, StringArray & users) = 0;
  156. virtual void deleteResource(SecResourceType rtype, const char* name, const char* basedn) = 0;
  157. virtual void renameResource(SecResourceType rtype, const char* oldname, const char* newname, const char* basedn) = 0;
  158. virtual void copyResource(SecResourceType rtype, const char* oldname, const char* newname, const char* basedn) = 0;
  159. virtual void normalizeDn(const char* dn, StringBuffer& ndn) = 0;
  160. virtual bool isSuperUser(ISecUser* user) = 0;
  161. virtual int countEntries(const char* basedn, const char* objectClass, int limit) = 0;
  162. virtual int countUsers(const char* searchstr, int limit) = 0;
  163. virtual int countResources(const char* basedn, const char* searchstr, int limit) = 0;
  164. virtual ILdapConfig* queryConfig() = 0;
  165. virtual const char* getPasswordStorageScheme() = 0;
  166. virtual bool createUserScope(ISecUser& user) = 0;
  167. virtual aindex_t getManagedFileScopes(IArrayOf<ISecResource>& scopes) = 0;
  168. virtual int queryDefaultPermission(ISecUser& user) = 0;
  169. };
  170. ILdapClient* createLdapClient(IPropertyTree* cfg);
  171. #ifdef _WIN32
  172. bool verifyServerCert(LDAP* ld, PCCERT_CONTEXT pServerCert);
  173. #endif
  174. class LdapUtils
  175. {
  176. public:
  177. static LDAP* LdapInit(const char* protocol, const char* host, int port, int secure_port)
  178. {
  179. LDAP* ld = NULL;
  180. if(stricmp(protocol, "ldaps") == 0)
  181. {
  182. #ifdef _WIN32
  183. ld = ldap_sslinit((char*)host, secure_port, 1);
  184. if (ld == NULL )
  185. throw MakeStringException(-1, "ldap_sslinit error" );
  186. int rc = 0;
  187. unsigned long version = LDAP_VERSION3;
  188. long lv = 0;
  189. rc = ldap_set_option(ld,
  190. LDAP_OPT_PROTOCOL_VERSION,
  191. (void*)&version);
  192. if (rc != LDAP_SUCCESS)
  193. throw MakeStringException(-1, "ldap_set_option error - %s", ldap_err2string(rc));
  194. rc = ldap_get_option(ld,LDAP_OPT_SSL,(void*)&lv);
  195. if (rc != LDAP_SUCCESS)
  196. throw MakeStringException(-1, "ldap_get_option error - %s", ldap_err2string(rc));
  197. // If SSL is not enabled, enable it.
  198. if ((void*)lv != LDAP_OPT_ON)
  199. {
  200. rc = ldap_set_option(ld, LDAP_OPT_SSL, LDAP_OPT_ON);
  201. if (rc != LDAP_SUCCESS)
  202. throw MakeStringException(-1, "ldap_set_option error - %s", ldap_err2string(rc));
  203. }
  204. ldap_set_option(ld, LDAP_OPT_SERVER_CERTIFICATE, verifyServerCert);
  205. #else
  206. // Initialize an LDAP session for TLS/SSL
  207. #ifndef HAVE_TLS
  208. //throw MakeStringException(-1, "openldap client library libldap not compiled with TLS support");
  209. #endif
  210. StringBuffer uri("ldaps://");
  211. uri.appendf("%s:%d", host, secure_port);
  212. DBGLOG("connecting to %s", uri.str());
  213. int rc = ldap_initialize(&ld, uri.str());
  214. if(rc != LDAP_SUCCESS)
  215. {
  216. DBGLOG("ldap_initialize error %s", ldap_err2string(rc));
  217. throw MakeStringException(-1, "ldap_initialize error %s", ldap_err2string(rc));
  218. }
  219. int reqcert = LDAP_OPT_X_TLS_NEVER;
  220. ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &reqcert);
  221. #endif
  222. }
  223. else
  224. {
  225. // Initialize an LDAP session
  226. if ((ld = ldap_init( (char*)host, port )) == NULL)
  227. {
  228. throw MakeStringException(-1, "ldap_init error");
  229. }
  230. }
  231. return ld;
  232. }
  233. static int LdapSimpleBind(LDAP* ld, char* userdn, char* password)
  234. {
  235. #ifndef _WIN32
  236. TIMEVAL timeout = {LDAPTIMEOUT, 0};
  237. ldap_set_option(ld, LDAP_OPT_TIMEOUT, &timeout);
  238. ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &timeout);
  239. #endif
  240. return ldap_simple_bind_s(ld, userdn, password);
  241. /*
  242. //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
  243. int final_rc = LDAP_SUCCESS;
  244. int msgid = ldap_simple_bind(ld, userdn, password);
  245. if(msgid < 0)
  246. {
  247. #ifndef _WIN32
  248. final_rc = ldap_get_lderrno(ld, NULL, NULL);
  249. #else
  250. final_rc = LDAP_OTHER;
  251. #endif
  252. }
  253. else
  254. {
  255. LDAPMessage* result = NULL;
  256. TIMEVAL timeOut = {LDAPTIMEOUT,0};
  257. int rc = ldap_result(ld, msgid, 1, &timeOut, &result);
  258. if(rc < 0)
  259. {
  260. #ifndef _WIN32
  261. final_rc = ldap_get_lderrno(ld, NULL, NULL);
  262. #else
  263. final_rc = LDAP_OTHER;
  264. #endif
  265. }
  266. else if(rc == 0)
  267. {
  268. final_rc = LDAP_TIMEOUT;
  269. }
  270. else
  271. {
  272. final_rc = ldap_result2error(ld, result, 1);
  273. }
  274. }
  275. return final_rc;
  276. */
  277. }
  278. // userdn is required for ldap_simple_bind_s, not really necessary for ldap_bind_s.
  279. static int LdapBind(LDAP* ld, const char* domain, const char* username, const char* password, const char* userdn, LdapServerType server_type, const char* method="kerboros")
  280. {
  281. bool binddone = false;
  282. int rc = LDAP_SUCCESS;
  283. // By default, use kerberos authentication
  284. if((method == NULL) || (strlen(method) == 0) || (stricmp(method, "kerberos") == 0))
  285. {
  286. #ifdef _WIN32
  287. if(server_type == ACTIVE_DIRECTORY)
  288. {
  289. if(username != NULL)
  290. {
  291. SEC_WINNT_AUTH_IDENTITY secIdent;
  292. secIdent.User = (unsigned char*)username;
  293. secIdent.UserLength = strlen(username);
  294. secIdent.Password = (unsigned char*)password;
  295. secIdent.PasswordLength = strlen(password);
  296. // Somehow, setting the domain makes it slower
  297. secIdent.Domain = (unsigned char*)domain;
  298. secIdent.DomainLength = strlen(domain);
  299. secIdent.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
  300. int rc = ldap_bind_s(ld, (char*)userdn, (char*)&secIdent, LDAP_AUTH_NEGOTIATE);
  301. if(rc != LDAP_SUCCESS)
  302. {
  303. DBGLOG("ldap_bind_s for user %s failed with %d - %s.", username, rc, ldap_err2string(rc));
  304. return rc;
  305. }
  306. }
  307. else
  308. {
  309. int rc = ldap_bind_s(ld, NULL, NULL, LDAP_AUTH_NEGOTIATE);
  310. if(rc != LDAP_SUCCESS)
  311. {
  312. DBGLOG("User Authentication Failed - ldap_bind_s for current user failed with %d - %s.", rc, ldap_err2string(rc));
  313. return rc;
  314. }
  315. }
  316. binddone = true;
  317. }
  318. #endif
  319. }
  320. if(!binddone)
  321. {
  322. if(userdn == NULL)
  323. {
  324. DBGLOG("userdn can't be NULL in order to bind to ldap server.");
  325. return LDAP_INVALID_CREDENTIALS;
  326. }
  327. int rc = LdapSimpleBind(ld, (char*)userdn, (char*)password);
  328. if (rc != LDAP_SUCCESS && server_type == OPEN_LDAP && strchr(userdn,','))
  329. { //Fedora389 is happier without the domain component specified
  330. StringBuffer cn(userdn);
  331. cn.replace(',',(char)NULL);
  332. if (cn.length())//disallow call if no cn
  333. rc = LdapSimpleBind(ld, (char*)cn.str(), (char*)password);
  334. }
  335. if (rc != LDAP_SUCCESS )
  336. {
  337. // For Active Directory, try binding with NT format username
  338. if(server_type == ACTIVE_DIRECTORY)
  339. {
  340. StringBuffer logonname;
  341. logonname.append(domain).append("\\").append(username);
  342. rc = LdapSimpleBind(ld, (char*)logonname.str(), (char*)password);
  343. if(rc != LDAP_SUCCESS)
  344. {
  345. #ifdef LDAP_OPT_DIAGNOSTIC_MESSAGE
  346. char *msg=NULL;
  347. ldap_get_option(ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, (void*)&msg);
  348. DBGLOG("LDAP bind error for user %s with %d - %s. %s", logonname.str(), rc, ldap_err2string(rc), msg&&*msg?msg:"");
  349. ldap_memfree(msg);
  350. #else
  351. DBGLOG("LDAP bind error for user %s with 0x%"I64F"x - %s", username, (unsigned __int64) rc, ldap_err2string(rc));
  352. #endif
  353. return rc;
  354. }
  355. }
  356. else
  357. {
  358. DBGLOG("LDAP bind error for user %s with 0x%"I64F"x - %s", username, (unsigned __int64) rc, ldap_err2string(rc));
  359. return rc;
  360. }
  361. }
  362. }
  363. return rc;
  364. }
  365. static void bin2str(MemoryBuffer& from, StringBuffer& to)
  366. {
  367. const char* frombuf = from.toByteArray();
  368. char tmp[3];
  369. for(unsigned i = 0; i < from.length(); i++)
  370. {
  371. unsigned char c = frombuf[i];
  372. sprintf(tmp, "%02X", c);
  373. tmp[2] = 0;
  374. to.append("\\").append(tmp);
  375. }
  376. }
  377. static int getServerInfo(const char* ldapserver, int ldapport, StringBuffer& domainDN, LdapServerType& stype, const char* domainname);
  378. static void normalizeDn(const char* dn, const char* basedn, StringBuffer& dnbuf)
  379. {
  380. dnbuf.clear();
  381. cleanupDn(dn, dnbuf);
  382. if(!containsBasedn(dnbuf.str()))
  383. dnbuf.append(",").append(basedn);
  384. }
  385. static bool containsBasedn(const char* str)
  386. {
  387. if(str == NULL || str[0] == '\0')
  388. return false;
  389. else
  390. return (strstr(str, "dc=") != NULL);
  391. }
  392. static void cleanupDn(const char* dn, StringBuffer& dnbuf)
  393. {
  394. if(dn == NULL || dn[0] == '\0')
  395. return;
  396. const char* ptr = dn;
  397. while(ptr && *ptr != '\0')
  398. {
  399. char c = *ptr;
  400. if(!isspace(c))
  401. {
  402. c = tolower(c);
  403. dnbuf.append(c);
  404. }
  405. ptr++;
  406. }
  407. }
  408. static bool getDcName(const char* domain, StringBuffer& dc)
  409. {
  410. bool ret = false;
  411. #ifdef _WIN32
  412. PDOMAIN_CONTROLLER_INFO psInfo = NULL;
  413. DWORD dwErr = DsGetDcName(NULL, domain, NULL, NULL, DS_FORCE_REDISCOVERY | DS_DIRECTORY_SERVICE_REQUIRED, &psInfo);
  414. if( dwErr == NO_ERROR)
  415. {
  416. const char* dcname = psInfo->DomainControllerName;
  417. if(dcname != NULL)
  418. {
  419. while(*dcname == '\\')
  420. dcname++;
  421. dc.append(dcname);
  422. ret = true;
  423. }
  424. NetApiBufferFree(psInfo);
  425. }
  426. else
  427. {
  428. DBGLOG("Error getting domain controller, error = %d", dwErr);
  429. ret = false;
  430. }
  431. #endif
  432. return ret;
  433. }
  434. static void getName(const char* dn, StringBuffer& name)
  435. {
  436. const char* bptr = dn;
  437. while(*bptr != '\0' && *bptr != '=')
  438. bptr++;
  439. if(*bptr == '\0')
  440. {
  441. name.append(dn);
  442. return;
  443. }
  444. else
  445. bptr++;
  446. const char* colon = strstr(bptr, ",");
  447. if(colon == NULL)
  448. name.append(bptr);
  449. else
  450. name.append(colon - bptr, bptr);
  451. }
  452. };
  453. #endif