syncserv.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. /* --- BEGIN COPYRIGHT BLOCK ---
  2. * Copyright (C) 2005 Red Hat, Inc.
  3. * All rights reserved.
  4. * --- END COPYRIGHT BLOCK --- */
  5. // Created: 2-8-2005
  6. // Author(s): Scott Bridges
  7. #include "syncserv.h"
  8. #include "prerror.h"
  9. static char* certdbh;
  10. // ****************************************************************
  11. // passwdcb
  12. // ****************************************************************
  13. char* passwdcb(PK11SlotInfo* info, PRBool retry, void* arg)
  14. {
  15. char* result = NULL;
  16. unsigned long resultLen = 0;
  17. DWORD type;
  18. HKEY regKey;
  19. if (!retry)
  20. {
  21. RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\PasswordSync", &regKey);
  22. RegQueryValueEx(regKey, "Install Path", NULL, &type, NULL, &resultLen);
  23. result = (char*)malloc(resultLen);
  24. RegQueryValueEx(regKey, "Cert Token", NULL, &type, (unsigned char*)result, &resultLen);
  25. RegCloseKey(regKey);
  26. }
  27. return result;
  28. }
  29. // ****************************************************************
  30. // PassSyncService::PassSyncService
  31. // ****************************************************************
  32. PassSyncService::PassSyncService(const TCHAR *serviceName) : CNTService(serviceName)
  33. {
  34. char sysPath[SYNCSERV_BUF_SIZE];
  35. HKEY regKey;
  36. DWORD type;
  37. unsigned long size;
  38. passhookEventHandle = CreateEvent(NULL, FALSE, FALSE, PASSHAND_EVENT_NAME);
  39. mainLdapConnection = NULL;
  40. results = NULL;
  41. currentResult = NULL;
  42. lastLdapError = LDAP_SUCCESS;
  43. certdbh = NULL;
  44. multipleModify = SYNCSERV_ALLOW_MULTI_MOD;
  45. isRunning = false;
  46. RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\PasswordSync", &regKey);
  47. size = SYNCSERV_BUF_SIZE;
  48. RegQueryValueEx(regKey, "Install Path", NULL, &type, (unsigned char*)installPath, &size);
  49. size = SYNCSERV_BUF_SIZE;
  50. RegQueryValueEx(regKey, "Host Name", NULL, &type, (unsigned char*)ldapHostName, &size);
  51. size = SYNCSERV_BUF_SIZE;
  52. RegQueryValueEx(regKey, "Port Number", NULL, &type, (unsigned char*)ldapHostPort, &size);
  53. size = SYNCSERV_BUF_SIZE;
  54. RegQueryValueEx(regKey, "User Name", NULL, &type, (unsigned char*)ldapAuthUsername, &size);
  55. size = SYNCSERV_BUF_SIZE;
  56. RegQueryValueEx(regKey, "Password", NULL, &type, (unsigned char*)ldapAuthPassword, &size);
  57. size = SYNCSERV_BUF_SIZE;
  58. RegQueryValueEx(regKey, "Search Base", NULL, &type, (unsigned char*)ldapSearchBase, &size);
  59. size = SYNCSERV_BUF_SIZE;
  60. RegQueryValueEx(regKey, "User Name Field", NULL, &type, (unsigned char*)ldapUsernameField, &size);
  61. size = SYNCSERV_BUF_SIZE;
  62. RegQueryValueEx(regKey, "Password Field", NULL, &type, (unsigned char*)ldapPasswordField, &size);
  63. RegCloseKey(regKey);
  64. ExpandEnvironmentStrings("%SystemRoot%", sysPath, SYNCSERV_BUF_SIZE);
  65. _snprintf(certPath, SYNCSERV_BUF_SIZE, "%s", installPath);
  66. _snprintf(logPath, SYNCSERV_BUF_SIZE, "%spasssync.log", installPath);
  67. _snprintf(dataFilename, SYNCSERV_BUF_SIZE, "%s\\system32\\passhook.dat", sysPath);
  68. outLog.open(logPath, ios::out | ios::app);
  69. if(outLog.is_open())
  70. {
  71. timeStamp(&outLog);
  72. outLog << "begin log" << endl;
  73. }
  74. PK11_SetPasswordFunc(passwdcb);
  75. }
  76. // ****************************************************************
  77. // PassSyncService::~PassSyncService
  78. // ****************************************************************
  79. PassSyncService::~PassSyncService()
  80. {
  81. if(outLog.is_open())
  82. {
  83. timeStamp(&outLog);
  84. outLog << "end log" << endl;
  85. }
  86. outLog.close();
  87. }
  88. // ****************************************************************
  89. // PassSyncService::SyncPasswords
  90. // ****************************************************************
  91. int PassSyncService::SyncPasswords()
  92. {
  93. int result = 0;
  94. PASS_INFO_LIST_ITERATOR currentPassInfo;
  95. PASS_INFO_LIST_ITERATOR tempPassInfo;
  96. char* dn;
  97. if(Connect(&mainLdapConnection, ldapAuthUsername, ldapAuthPassword) < 0)
  98. {
  99. // log connection failure.
  100. if(outLog.is_open())
  101. {
  102. timeStamp(&outLog);
  103. outLog << "can not connect to ldap server in SyncPasswords" << endl;
  104. }
  105. goto exit;
  106. }
  107. if(loadSet(&passInfoList, dataFilename) == 0)
  108. {
  109. if(outLog.is_open())
  110. {
  111. timeStamp(&outLog);
  112. outLog << passInfoList.size() << " entries loaded from file" << endl;
  113. }
  114. }
  115. else
  116. {
  117. if(outLog.is_open())
  118. {
  119. timeStamp(&outLog);
  120. outLog << "failed to load entries from file" << endl;
  121. }
  122. }
  123. while(passInfoList.size() > 0)
  124. {
  125. currentPassInfo = passInfoList.begin();
  126. while(currentPassInfo != passInfoList.end())
  127. {
  128. if(QueryUsername(currentPassInfo->username) != 0)
  129. {
  130. // log search failure.
  131. if(outLog.is_open())
  132. {
  133. timeStamp(&outLog);
  134. outLog << "search for " << currentPassInfo->username << " failed in SyncPasswords" << endl;
  135. }
  136. }
  137. else
  138. {
  139. while((dn = GetDN()) != NULL)
  140. {
  141. if(CanBind(dn, currentPassInfo->password))
  142. {
  143. if(outLog.is_open())
  144. {
  145. timeStamp(&outLog);
  146. outLog << "password match, no modify preformed: " << currentPassInfo->username << endl;
  147. }
  148. }
  149. else if(ModifyPassword(dn, currentPassInfo->password) != 0)
  150. {
  151. // log modify failure.
  152. if(outLog.is_open())
  153. {
  154. timeStamp(&outLog);
  155. outLog << "modify password for " << currentPassInfo->username << " failed in SyncPasswords" << endl;
  156. }
  157. }
  158. else
  159. {
  160. if(outLog.is_open())
  161. {
  162. timeStamp(&outLog);
  163. outLog << "password for " << currentPassInfo->username << " modified" << endl;
  164. outLog << "\t" << dn << endl;
  165. }
  166. }
  167. } // end while((dn = GetDN()) != NULL)
  168. }
  169. tempPassInfo = currentPassInfo;
  170. currentPassInfo++;
  171. passInfoList.erase(tempPassInfo);
  172. } // end while(currentPassInfo != passInfoList.end())
  173. } // end while(passInfoList.size() > 0)
  174. if(saveSet(&passInfoList, dataFilename) == 0)
  175. {
  176. if(outLog.is_open())
  177. {
  178. timeStamp(&outLog);
  179. outLog << passInfoList.size() << " entries saved to file" << endl;
  180. }
  181. }
  182. else
  183. {
  184. if(outLog.is_open())
  185. {
  186. timeStamp(&outLog);
  187. outLog << "failed to save entries to file" << endl;
  188. }
  189. }
  190. clearSet(&passInfoList);
  191. Disconnect(&mainLdapConnection);
  192. exit:
  193. return result;
  194. }
  195. // ****************************************************************
  196. //
  197. // ****************************************************************
  198. void PassSyncService::OnStop()
  199. {
  200. isRunning = false;
  201. SetEvent(passhookEventHandle);
  202. }
  203. // ****************************************************************
  204. //
  205. // ****************************************************************
  206. void PassSyncService::OnShutdown()
  207. {
  208. isRunning = false;
  209. SetEvent(passhookEventHandle);
  210. }
  211. // ****************************************************************
  212. // PassSyncService::Run
  213. // ****************************************************************
  214. void PassSyncService::Run()
  215. {
  216. isRunning = true;
  217. SyncPasswords();
  218. while(isRunning)
  219. {
  220. WaitForSingleObject(passhookEventHandle, INFINITE);
  221. SyncPasswords();
  222. ResetEvent(passhookEventHandle);
  223. }
  224. CloseHandle(passhookEventHandle);
  225. }
  226. // ****************************************************************
  227. // PassSyncService::Connect
  228. // ****************************************************************
  229. int PassSyncService::Connect(LDAP** connection, char* dn, char* auth)
  230. {
  231. int result = 0;
  232. if(ldapssl_client_init(certPath, &certdbh) != 0)
  233. {
  234. result = PR_GetError();
  235. if(outLog.is_open())
  236. {
  237. timeStamp(&outLog);
  238. outLog << "ldapssl_client_init failed in Connect" << endl;
  239. outLog << "\t" << result << ": " << ldap_err2string(result) << endl;
  240. }
  241. result = GetLastError();
  242. result = -1;
  243. goto exit;
  244. }
  245. *connection = ldapssl_init(ldapHostName, atoi(ldapHostPort), 1);
  246. if(*connection == NULL)
  247. {
  248. if(outLog.is_open())
  249. {
  250. timeStamp(&outLog);
  251. outLog << "ldapssl_init failed in Connect" << endl;
  252. }
  253. result = -1;
  254. goto exit;
  255. }
  256. ResetBackoff();
  257. while(((lastLdapError = ldap_simple_bind_s(*connection, dn, auth)) != LDAP_SUCCESS) && Backoff())
  258. {
  259. // empty
  260. }
  261. if(lastLdapError != LDAP_SUCCESS)
  262. {
  263. // log reason for bind failure.
  264. if(outLog.is_open())
  265. {
  266. timeStamp(&outLog);
  267. outLog << "ldap error in Connect" << endl;
  268. outLog << "\t" << lastLdapError << ": " << ldap_err2string(lastLdapError) << endl;
  269. }
  270. result = -1;
  271. goto exit;
  272. }
  273. exit:
  274. return result;
  275. }
  276. // ****************************************************************
  277. // PassSyncService::Disconnect
  278. // ****************************************************************
  279. int PassSyncService::Disconnect(LDAP** connection)
  280. {
  281. ldap_unbind(*connection);
  282. connection = NULL;
  283. return 0;
  284. }
  285. // ****************************************************************
  286. // PassSyncService::QueryUsername
  287. // ****************************************************************
  288. int PassSyncService::QueryUsername(char* username)
  289. {
  290. int result = 0;
  291. char searchFilter[SYNCSERV_BUF_SIZE];
  292. results = NULL;
  293. _snprintf(searchFilter, SYNCSERV_BUF_SIZE, "(%s=%s)", ldapUsernameField, username);
  294. ResetBackoff();
  295. while(Backoff())
  296. {
  297. lastLdapError = ldap_search_ext_s(mainLdapConnection, ldapSearchBase, LDAP_SCOPE_ONELEVEL, searchFilter, NULL, 0, NULL, NULL, NULL, -1, &results);
  298. if(lastLdapError != LDAP_SUCCESS)
  299. {
  300. // log reason for search failure.
  301. if(outLog.is_open())
  302. {
  303. timeStamp(&outLog);
  304. outLog << "ldap error in QueryUsername" << endl;
  305. outLog << "\t" << lastLdapError << ": " << ldap_err2string(lastLdapError) << endl;
  306. }
  307. result = -1;
  308. EndBackoff();
  309. }
  310. else if(ldap_first_entry(mainLdapConnection, results) == NULL)
  311. {
  312. if(outLog.is_open())
  313. {
  314. timeStamp(&outLog);
  315. outLog << "there are no entries that match: " << username << endl;
  316. }
  317. result = -1;
  318. }
  319. else if(ldap_next_entry(mainLdapConnection, ldap_first_entry(mainLdapConnection, results)) != NULL)
  320. {
  321. if(outLog.is_open())
  322. {
  323. timeStamp(&outLog);
  324. outLog << "there are multiple entries that match: " << username << endl;
  325. }
  326. if(!SYNCSERV_ALLOW_MULTI_MOD)
  327. {
  328. result = -1;
  329. EndBackoff();
  330. }
  331. }
  332. }
  333. return result;
  334. }
  335. // ****************************************************************
  336. // PassSyncService::GetDN
  337. // ****************************************************************
  338. char* PassSyncService::GetDN()
  339. {
  340. char* result = NULL;
  341. if(currentResult == NULL)
  342. {
  343. currentResult = ldap_first_entry(mainLdapConnection, results);
  344. }
  345. else
  346. {
  347. currentResult = ldap_next_entry(mainLdapConnection, currentResult);
  348. }
  349. result = ldap_get_dn(mainLdapConnection, currentResult);
  350. return result;
  351. }
  352. // ****************************************************************
  353. // PassSyncService::CanBind
  354. // ****************************************************************
  355. bool PassSyncService::CanBind(char* dn, char* password)
  356. {
  357. bool result;
  358. LDAP* tempConnection = NULL;
  359. if(Connect(&tempConnection, dn, password) == 0)
  360. {
  361. Disconnect(&tempConnection);
  362. result = true;
  363. }
  364. else
  365. {
  366. result = false;
  367. }
  368. return result;
  369. }
  370. // ****************************************************************
  371. // PassSyncService::ModifyPassword
  372. // ****************************************************************
  373. int PassSyncService::ModifyPassword(char* dn, char* password)
  374. {
  375. int result = 0;
  376. LDAPMod passMod;
  377. LDAPMod* mods[2] = {&passMod, NULL};
  378. char* modValues[2] = {password, NULL};
  379. passMod.mod_type = ldapPasswordField;
  380. passMod.mod_op = LDAP_MOD_REPLACE;
  381. passMod.mod_values = modValues;
  382. lastLdapError = ldap_modify_ext_s(mainLdapConnection, dn, mods, NULL, NULL);
  383. if(lastLdapError != LDAP_SUCCESS)
  384. {
  385. // log reason for modify failure.
  386. if(outLog.is_open())
  387. {
  388. timeStamp(&outLog);
  389. outLog << "ldap error in ModifyPassword" << endl;
  390. outLog << "\t" << lastLdapError << ": " << ldap_err2string(lastLdapError) << endl;
  391. }
  392. result = -1;
  393. }
  394. return result;
  395. }
  396. // ****************************************************************
  397. // PassSyncService::ResetBackoff
  398. // ****************************************************************
  399. void PassSyncService::ResetBackoff()
  400. {
  401. backoffCount = 0;
  402. }
  403. // ****************************************************************
  404. // PassSyncService::EndBackoff
  405. // ****************************************************************
  406. void PassSyncService::EndBackoff()
  407. {
  408. backoffCount = SYNCSERV_MAX_BACKOFF_COUNT;
  409. }
  410. // ****************************************************************
  411. // PassSyncService::Backoff
  412. // ****************************************************************
  413. bool PassSyncService::Backoff()
  414. {
  415. bool result;
  416. if(backoffCount == 0)
  417. {
  418. result = true;
  419. }
  420. else if(backoffCount < SYNCSERV_MAX_BACKOFF_COUNT)
  421. {
  422. Sleep((2 ^ backoffCount) * SYNCSERV_BASE_BACKOFF_LEN);
  423. result = true;
  424. }
  425. else
  426. {
  427. result = false;
  428. }
  429. backoffCount++;
  430. return result;
  431. }