Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

449 lines
11 KiB

  1. #include "stdafx.h"
  2. #include <stdio.h>
  3. #include <WinCrypt.h>
  4. #include <mailbox.h>
  5. #include <Pop3RegKeys.h>
  6. #include "Pop3Auth.h"
  7. #include "AuthMD5Hash.h"
  8. #include <MD5.h>
  9. #include "authutil.h"
  10. CAuthMD5Hash::CAuthMD5Hash()
  11. {
  12. m_wszMailRoot[0]=0;
  13. m_bstrServerName=NULL;
  14. InitializeCriticalSection(&m_csConfig);
  15. }
  16. CAuthMD5Hash::~CAuthMD5Hash()
  17. {
  18. if(m_bstrServerName!=NULL)
  19. {
  20. SysFreeString(m_bstrServerName);
  21. m_bstrServerName=NULL;
  22. }
  23. DeleteCriticalSection(&m_csConfig);
  24. }
  25. STDMETHODIMP CAuthMD5Hash::Authenticate(/*[in]*/BSTR bstrUserName,/*[in]*/VARIANT vPassword)
  26. {
  27. //Either the password is clear text or it is the MD5 hash
  28. //the user will be authenticated.
  29. HRESULT hr=S_OK;
  30. char szPassword[MAX_PATH];
  31. WCHAR wszResult[MD5_HASH_SIZE+1];
  32. char szHashBuffer[HASH_BUFFER_SIZE];
  33. BSTR bstrPwd;
  34. if(vPassword.vt != VT_BSTR )
  35. {
  36. return E_INVALIDARG;
  37. }
  38. if(vPassword.bstrVal==NULL )
  39. {
  40. bstrPwd=L"";
  41. }
  42. else
  43. {
  44. bstrPwd=vPassword.bstrVal;
  45. }
  46. hr=GetPassword(bstrUserName, szPassword);
  47. if(S_OK==hr)
  48. {
  49. //Not a hash
  50. // Compare the with the stored password
  51. UnicodeToAnsi(szHashBuffer, HASH_BUFFER_SIZE,bstrPwd, -1);
  52. if(0!=strcmp(szHashBuffer, szPassword))
  53. {
  54. if(wcslen(bstrPwd)>MD5_HASH_SIZE) //Can be a hash
  55. {
  56. if(HASH_BUFFER_SIZE <= wcslen(vPassword.bstrVal) + strlen(szPassword) - MD5_HASH_SIZE )
  57. {
  58. //Error!
  59. hr=E_INVALIDARG;
  60. }
  61. else
  62. {
  63. if( 0>_snprintf(szHashBuffer,
  64. HASH_BUFFER_SIZE,
  65. "%S%s",
  66. vPassword.bstrVal+MD5_HASH_SIZE, //The time stamp
  67. szPassword) )
  68. {
  69. //The hashed password is too long to be correct
  70. return E_FAIL;
  71. }
  72. if(MD5Hash((const unsigned char*)szHashBuffer, wszResult))
  73. {
  74. if(0!=wcsncmp(wszResult, vPassword.bstrVal, MD5_HASH_SIZE))
  75. {
  76. hr=E_FAIL;
  77. }
  78. }
  79. else
  80. {
  81. hr=E_FAIL;
  82. }
  83. }
  84. }
  85. else
  86. {
  87. hr=E_FAIL;
  88. }
  89. }
  90. }
  91. //Clean the password in memory
  92. SecureZeroMemory(szPassword,sizeof(szPassword));
  93. SecureZeroMemory(szHashBuffer, sizeof(szHashBuffer));
  94. SecureZeroMemory(wszResult, sizeof(wszResult));
  95. return hr;
  96. }
  97. STDMETHODIMP CAuthMD5Hash::get_Name(/*[out]*/BSTR *pVal)
  98. {
  99. WCHAR wszBuffer[MAX_PATH+1];
  100. if(NULL==pVal)
  101. {
  102. return E_POINTER;
  103. }
  104. if(LoadString(_Module.GetResourceInstance(), IDS_AUTH_MD5_HASH, wszBuffer, MAX_PATH))
  105. {
  106. *pVal=SysAllocString(wszBuffer);
  107. if(NULL==*pVal)
  108. {
  109. return E_OUTOFMEMORY;
  110. }
  111. else
  112. {
  113. return S_OK;
  114. }
  115. }
  116. else
  117. {
  118. return E_FAIL;
  119. }
  120. }
  121. STDMETHODIMP CAuthMD5Hash::get_ID(/*[out]*/BSTR *pVal)
  122. {
  123. if(NULL==pVal)
  124. {
  125. return E_POINTER;
  126. }
  127. *pVal=SysAllocString(SZ_AUTH_ID_MD5_HASH);
  128. if(NULL==*pVal)
  129. {
  130. return E_OUTOFMEMORY;
  131. }
  132. else
  133. {
  134. return S_OK;
  135. }
  136. }
  137. STDMETHODIMP CAuthMD5Hash::Get(/*[in]*/BSTR bstrName, /*[out]*/VARIANT *pVal)
  138. {
  139. return E_NOTIMPL;
  140. }
  141. STDMETHODIMP CAuthMD5Hash::Put(/*[in]*/BSTR bstrName, /*[in]*/VARIANT vVal)
  142. {
  143. if( NULL == bstrName )
  144. {
  145. return E_INVALIDARG;
  146. }
  147. if(0==wcscmp(bstrName,SZ_SERVER_NAME ))
  148. {
  149. if( (vVal.vt!=VT_BSTR) ||
  150. (vVal.bstrVal==NULL ) )
  151. {
  152. return E_INVALIDARG;
  153. }
  154. else
  155. {
  156. if(m_bstrServerName!=NULL)
  157. {
  158. SysFreeString(m_bstrServerName);
  159. m_bstrServerName=NULL;
  160. }
  161. m_bstrServerName = SysAllocString(vVal.bstrVal);
  162. if(NULL == m_bstrServerName)
  163. {
  164. return E_OUTOFMEMORY;
  165. }
  166. return S_OK;
  167. }
  168. }
  169. else if(0==wcscmp(bstrName, SZ_PROPNAME_MAIL_ROOT))
  170. {
  171. if( (vVal.vt!=VT_BSTR) ||
  172. (vVal.bstrVal==NULL ) )
  173. {
  174. return E_INVALIDARG;
  175. }
  176. else if(0==m_wszMailRoot[0])
  177. {
  178. EnterCriticalSection(&m_csConfig);
  179. if(0==m_wszMailRoot[0])
  180. {
  181. if(wcslen(vVal.bstrVal)>=sizeof(m_wszMailRoot)/sizeof(WCHAR))
  182. {
  183. return E_INVALIDARG;
  184. }
  185. wcsncpy(m_wszMailRoot, vVal.bstrVal, sizeof(m_wszMailRoot)/sizeof(WCHAR));
  186. }
  187. LeaveCriticalSection(&m_csConfig);
  188. }
  189. }
  190. else
  191. {
  192. return S_FALSE;
  193. }
  194. return S_OK;
  195. }
  196. BOOL CAuthMD5Hash::MD5Hash(const unsigned char *pOriginal, WCHAR wszResult[MD5_HASH_SIZE+1])
  197. {
  198. MD5_CTX md5;
  199. unsigned char hash[16];
  200. WCHAR *p;
  201. int i;
  202. BOOL bRtVal=FALSE;
  203. if(NULL == pOriginal)
  204. {
  205. return bRtVal;
  206. }
  207. /*
  208. * Take the MD5 hash of the string argument.
  209. */
  210. MD5Init(&md5);
  211. MD5Update(&md5, pOriginal, strlen((char*)pOriginal));
  212. MD5Final(&md5);
  213. bRtVal=TRUE;
  214. if(bRtVal)
  215. {
  216. for (i=0, p=wszResult; i<16; i++, p+=2)
  217. wsprintf(p, L"%02x", md5.digest[i]);
  218. *p = L'\0';
  219. }
  220. return bRtVal;
  221. }
  222. HRESULT CAuthMD5Hash::GetPassword(BSTR bstrUserName, char szPassword[MAX_PATH])
  223. {
  224. return GetMD5Password( bstrUserName, szPassword );
  225. }
  226. HRESULT CAuthMD5Hash::SetPassword(/*[in]*/BSTR bstrUserName,/*[in]*/VARIANT vPassword)
  227. {
  228. // The mailbox should already been created
  229. WCHAR wszAuthGuid[MAX_PATH];
  230. WCHAR wszMailRoot[POP3_MAX_MAILROOT_LENGTH];
  231. DWORD dwAuthDataLen=sizeof(wszAuthGuid)/sizeof(WCHAR);
  232. DWORD dwBytes=0;
  233. DWORD dwCryptDataLen;
  234. DWORD dwRt;
  235. BYTE szEncryptedPswd[MAX_PATH];
  236. HRESULT hr = E_FAIL;
  237. CMailBox mailboxX;
  238. HCRYPTPROV hProv=NULL;
  239. HCRYPTHASH hHash=NULL;
  240. HCRYPTKEY hKey=NULL;
  241. if( ( NULL == bstrUserName ) ||
  242. ( vPassword.vt != VT_BSTR ) ||
  243. ( vPassword.bstrVal==NULL) )
  244. {
  245. return E_INVALIDARG;
  246. }
  247. if( L'\0'== *(vPassword.bstrVal))
  248. {
  249. return E_INVALIDARG;
  250. }
  251. if(m_bstrServerName)
  252. {
  253. dwRt=RegQueryMailRoot(wszMailRoot, sizeof(wszMailRoot)/sizeof(WCHAR) , m_bstrServerName );
  254. if( ERROR_SUCCESS == dwRt )
  255. {
  256. // Replace drive: with drive$
  257. if ( L':' == wszMailRoot[1] )
  258. {
  259. wszMailRoot[1] = L'$';
  260. if ( sizeof(m_wszMailRoot)/sizeof(WCHAR) > (wcslen( wszMailRoot ) + wcslen( m_bstrServerName ) + 3) )
  261. {
  262. wcscpy( m_wszMailRoot, L"\\\\" );
  263. wcscat( m_wszMailRoot, m_bstrServerName );
  264. wcscat( m_wszMailRoot, L"\\" );
  265. wcscat( m_wszMailRoot, wszMailRoot );
  266. if( ! mailboxX.SetMailRoot(m_wszMailRoot) )
  267. {
  268. dwRt= GetLastError();
  269. }
  270. }
  271. else
  272. dwRt = ERROR_INSUFFICIENT_BUFFER;
  273. }
  274. else
  275. dwRt = ERROR_INVALID_DATA;
  276. }
  277. if( ERROR_SUCCESS == dwRt)
  278. {
  279. hr = HRESULT_FROM_WIN32( dwRt );
  280. goto EXIT;
  281. }
  282. }
  283. if ( mailboxX.OpenMailBox( bstrUserName ))
  284. {
  285. if ( mailboxX.LockMailBox())
  286. {
  287. //Set the password
  288. if(ERROR_SUCCESS == RegQueryAuthGuid(wszAuthGuid, &dwAuthDataLen, m_bstrServerName) )
  289. {
  290. if(!CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
  291. {
  292. goto EXIT;
  293. }
  294. if(!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash))
  295. {
  296. goto EXIT;
  297. }
  298. if(!CryptHashData(hHash, (LPBYTE)wszAuthGuid, dwAuthDataLen, 0))
  299. {
  300. goto EXIT;
  301. }
  302. if(!CryptDeriveKey(hProv, CALG_RC4, hHash, (128<<16),&hKey))
  303. {
  304. goto EXIT;
  305. }
  306. dwCryptDataLen=( wcslen(vPassword.bstrVal) +1 ) * sizeof(WCHAR);
  307. if(dwCryptDataLen > MAX_PATH )
  308. {
  309. //Exceed buffer size
  310. goto EXIT;
  311. }
  312. wcscpy((LPWSTR)szEncryptedPswd, vPassword.bstrVal);
  313. if(CryptEncrypt(hKey, 0, FALSE, 0, szEncryptedPswd, &dwCryptDataLen, dwCryptDataLen))
  314. {
  315. if ( mailboxX.SetEncyptedPassword( szEncryptedPswd, dwCryptDataLen, &dwBytes ))
  316. {
  317. hr = S_OK;
  318. }
  319. }
  320. }
  321. mailboxX.UnlockMailBox();
  322. }
  323. }
  324. EXIT:
  325. if(hKey)
  326. {
  327. CryptDestroyKey(hKey);
  328. }
  329. if(hHash)
  330. {
  331. CryptDestroyHash(hHash);
  332. }
  333. if(hProv)
  334. {
  335. CryptReleaseContext(hProv, 0);
  336. }
  337. return hr;
  338. }
  339. STDMETHODIMP CAuthMD5Hash::CreateUser(/*[in]*/BSTR bstrUserName,/*[in]*/VARIANT vPassword)
  340. {
  341. return SetPassword(bstrUserName, vPassword);
  342. }
  343. STDMETHODIMP CAuthMD5Hash::DeleteUser(/*[in]*/BSTR bstrUserName)
  344. {
  345. // Nothing to do in this.
  346. return S_FALSE;
  347. }
  348. STDMETHODIMP CAuthMD5Hash::ChangePassword(/*[in]*/BSTR bstrUserName,/*[in]*/VARIANT vNewPassword,/*[in]*/VARIANT vOldPassword)
  349. {
  350. //This function does not verify old password
  351. return SetPassword(bstrUserName, vNewPassword);
  352. }
  353. STDMETHODIMP CAuthMD5Hash::AssociateEmailWithUser(/*[in]*/BSTR bstrEmailAddr)
  354. {
  355. CMailBox mailboxX;
  356. DWORD dwRt=ERROR_SUCCESS;
  357. WCHAR wszMailRoot[POP3_MAX_MAILROOT_LENGTH];
  358. if(m_bstrServerName)
  359. {
  360. dwRt=RegQueryMailRoot(wszMailRoot,sizeof(wszMailRoot)/sizeof(WCHAR) , m_bstrServerName );
  361. if( ERROR_SUCCESS == dwRt )
  362. {
  363. // Replace drive: with drive$
  364. if ( L':' == wszMailRoot[1] )
  365. {
  366. wszMailRoot[1] = L'$';
  367. if ( sizeof(m_wszMailRoot)/sizeof(WCHAR) > (wcslen( wszMailRoot ) + wcslen( m_bstrServerName ) + 3) )
  368. {
  369. wcscpy( m_wszMailRoot, L"\\\\" );
  370. wcscat( m_wszMailRoot, m_bstrServerName );
  371. wcscat( m_wszMailRoot, L"\\" );
  372. wcscat( m_wszMailRoot, wszMailRoot );
  373. if( ! mailboxX.SetMailRoot(m_wszMailRoot) )
  374. {
  375. dwRt= GetLastError();
  376. }
  377. }
  378. else
  379. dwRt = ERROR_INSUFFICIENT_BUFFER;
  380. }
  381. else
  382. dwRt = ERROR_INVALID_DATA;
  383. }
  384. }
  385. if (ERROR_SUCCESS == dwRt)
  386. {
  387. if ( mailboxX.OpenMailBox( bstrEmailAddr ))
  388. {
  389. return S_OK;
  390. }
  391. else
  392. {
  393. dwRt=GetLastError();
  394. }
  395. }
  396. return HRESULT_FROM_WIN32( dwRt);
  397. }
  398. STDMETHODIMP CAuthMD5Hash::UnassociateEmailWithUser(/*[in]*/BSTR bstrEmailAddr)
  399. {
  400. return AssociateEmailWithUser( bstrEmailAddr );
  401. }