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.

477 lines
12 KiB

  1. /************************************************************************************************
  2. Copyright (c) 2001 Microsoft Corporation
  3. File Name: NTAuth.cpp
  4. Abstract: Implementation of CAuthServer class to do NTLM/Kerberos authentication
  5. Notes:
  6. History: 10/10/2001 Created by Hao Yu (haoyu)
  7. ************************************************************************************************/
  8. #include "stdafx.h"
  9. #include "NTAuth.h"
  10. #include "uuencode.h"
  11. #include <atlbase.h>
  12. //Initialize static members
  13. long CAuthServer::m_glInit=0;
  14. PSecurityFunctionTable CAuthServer::m_gpFuncs=NULL;
  15. HINSTANCE CAuthServer::m_ghLib=NULL;
  16. IP3Config *CAuthServer::m_gpIConfig=NULL;
  17. //Static fuction to load SSPI Provider function table
  18. HRESULT CAuthServer::GlobalInit()
  19. {
  20. HRESULT hr=S_OK;
  21. FARPROC pInit=NULL;
  22. PSecPkgInfo pPkgInfo;
  23. if( 0==InterlockedCompareExchange(&m_glInit, 2, 0))
  24. {
  25. //Initialization needed
  26. TCHAR tszWinDir[MAX_PATH+sizeof(NT_SEC_DLL_NAME)+1];
  27. if(0!=GetWindowsDirectory(tszWinDir, MAX_PATH+1))
  28. {
  29. tszWinDir[MAX_PATH]=0;
  30. _tcscat(tszWinDir, NT_SEC_DLL_NAME );
  31. m_ghLib=LoadLibrary(tszWinDir);
  32. if(NULL == m_ghLib)
  33. {
  34. hr=HRESULT_FROM_WIN32(GetLastError());
  35. }
  36. }
  37. else
  38. {
  39. hr=E_FAIL;
  40. }
  41. if(S_OK==hr)
  42. {
  43. pInit=GetProcAddress(m_ghLib, SECURITY_ENTRYPOINT_ANSI);
  44. if(NULL == pInit)
  45. {
  46. hr=HRESULT_FROM_WIN32(GetLastError());
  47. }
  48. }
  49. if(S_OK==hr)
  50. {
  51. m_gpFuncs = (PSecurityFunctionTable) pInit();
  52. if(NULL == m_gpFuncs)
  53. {
  54. hr=HRESULT_FROM_WIN32(GetLastError());
  55. }
  56. }
  57. if(S_OK==hr)
  58. {
  59. //Make sure the security package is available
  60. if(SEC_SUCCESS(m_gpFuncs->QuerySecurityPackageInfo(NTLM_PACKAGE,
  61. &pPkgInfo)))
  62. {
  63. m_gpFuncs->FreeContextBuffer(pPkgInfo);
  64. }
  65. else
  66. {
  67. hr=E_FAIL;
  68. }
  69. }
  70. if(S_OK==hr)
  71. {
  72. //To circumvent the ADsGetObject leak
  73. hr = CoCreateInstance( __uuidof( P3Config ), NULL, CLSCTX_ALL, __uuidof( IP3Config ),reinterpret_cast<LPVOID *>( &m_gpIConfig ));
  74. }
  75. if(S_OK==hr)
  76. {
  77. //Set the flag to be 1
  78. InterlockedExchange(&m_glInit, 1);
  79. }
  80. else
  81. {
  82. //Cleanup
  83. m_gpFuncs=NULL;
  84. if(NULL != m_ghLib)
  85. {
  86. FreeLibrary(m_ghLib);
  87. m_ghLib=NULL;
  88. }
  89. //Set the falg to be 0
  90. InterlockedExchange(&m_glInit, 0);
  91. }
  92. }
  93. else
  94. {
  95. while(1!=m_glInit)
  96. {
  97. Sleep(50); //Wait for the initialization to be done
  98. }
  99. }
  100. return hr;
  101. }
  102. void CAuthServer::GlobalUninit()
  103. {
  104. long lRet=InterlockedCompareExchange(&m_glInit, -1, 1);
  105. switch (lRet)
  106. {
  107. case 2:while(1!=m_glInit)
  108. {
  109. Sleep(50);
  110. }
  111. case 1:m_gpFuncs=NULL;
  112. if(NULL != m_ghLib)
  113. {
  114. FreeLibrary(m_ghLib);
  115. m_ghLib=NULL;
  116. }
  117. if(m_gpIConfig!=NULL)
  118. {
  119. m_gpIConfig->Release();
  120. m_gpIConfig=NULL;
  121. }
  122. break;
  123. case 0://Nothing needed to be done
  124. default: break;
  125. };
  126. }
  127. CAuthServer::CAuthServer()
  128. {
  129. m_bInit=FALSE;
  130. m_bHaveSecContext=FALSE;
  131. m_bFirstCall=TRUE;
  132. }
  133. CAuthServer::~CAuthServer()
  134. {
  135. Cleanup();
  136. }
  137. void CAuthServer::Cleanup()
  138. {
  139. if(NULL != m_gpFuncs)
  140. {
  141. if(m_bInit)
  142. {
  143. m_bInit=FALSE;
  144. m_bFirstCall=TRUE;
  145. m_gpFuncs->FreeCredentialHandle(&m_hCredHandle);
  146. if(m_bHaveSecContext)
  147. {
  148. m_bHaveSecContext=FALSE;
  149. m_gpFuncs->DeleteSecurityContext(&m_hSecContext);
  150. }
  151. }
  152. }
  153. else
  154. {
  155. //This should never happen!
  156. g_EventLogger.LogEvent(LOGTYPE_ERR_CRITICAL,
  157. EVENT_POP3_UNEXPECTED_ERROR);
  158. }
  159. }
  160. HRESULT CAuthServer::InitCredential()
  161. {
  162. HRESULT hr=S_OK;
  163. SECURITY_STATUS status;
  164. TimeStamp tsExpire;
  165. if(!m_bInit)
  166. {
  167. if(m_glInit!=1)
  168. {
  169. hr=GlobalInit();
  170. }
  171. if(S_OK == hr )
  172. {
  173. if(!m_bInit)
  174. {
  175. status = m_gpFuncs->AcquireCredentialsHandle(
  176. NULL,
  177. NTLM_PACKAGE,
  178. SECPKG_CRED_INBOUND,
  179. NULL,
  180. NULL,
  181. NULL,
  182. NULL,
  183. &m_hCredHandle,
  184. &tsExpire);
  185. if(SEC_E_OK != status)
  186. {
  187. hr=E_FAIL;
  188. }
  189. else
  190. {
  191. m_bInit=TRUE;
  192. }
  193. }
  194. }
  195. }
  196. return hr;
  197. }
  198. HRESULT CAuthServer::HandShake(LPBYTE pInBuf,
  199. DWORD cbInBufSize,
  200. LPBYTE pOutBuf,
  201. PDWORD pcbOutBufSize)
  202. {
  203. HRESULT hr=S_OK;
  204. SECURITY_STATUS status;
  205. TimeStamp tsExpire;
  206. ULONG ulContextAttributes;
  207. BUFFER uuBuf;
  208. DWORD cbDecoded=0;
  209. BYTE pBuf[AUTH_BUF_SIZE];
  210. SecBufferDesc OutBuffDesc;
  211. SecBuffer OutSecBuff;
  212. SecBufferDesc InBuffDesc;
  213. SecBuffer InSecBuff;
  214. if( (NULL == pInBuf) ||
  215. (NULL == pOutBuf) ||
  216. (NULL == pcbOutBufSize) )
  217. {
  218. return E_INVALIDARG;
  219. }
  220. if(!m_bInit)
  221. {
  222. hr = InitCredential();
  223. }
  224. uuBuf.pBuf=pBuf;
  225. uuBuf.cLen=AUTH_BUF_SIZE;
  226. if( !uudecode((char *)pInBuf, &uuBuf, &cbDecoded))
  227. {
  228. hr=E_FAIL;
  229. }
  230. if( S_OK == hr )
  231. {
  232. OutBuffDesc.ulVersion = 0;
  233. OutBuffDesc.cBuffers = 1;
  234. OutBuffDesc.pBuffers = &OutSecBuff;
  235. OutSecBuff.cbBuffer = *pcbOutBufSize;
  236. OutSecBuff.BufferType = SECBUFFER_TOKEN;
  237. OutSecBuff.pvBuffer = pOutBuf;
  238. InBuffDesc.ulVersion = 0;
  239. InBuffDesc.cBuffers = 1;
  240. InBuffDesc.pBuffers = &InSecBuff;
  241. InSecBuff.cbBuffer = cbDecoded;//cbInBufSize;
  242. InSecBuff.BufferType = SECBUFFER_TOKEN;
  243. InSecBuff.pvBuffer = pBuf;//pInBuf;
  244. status = m_gpFuncs->AcceptSecurityContext (
  245. &m_hCredHandle,
  246. m_bFirstCall? NULL:&m_hSecContext,
  247. &InBuffDesc,
  248. 0,
  249. SECURITY_NETWORK_DREP,
  250. &m_hSecContext,
  251. &OutBuffDesc,
  252. &ulContextAttributes,
  253. &tsExpire );
  254. if( !SEC_SUCCESS(status) )
  255. {
  256. hr=E_FAIL;
  257. }
  258. else
  259. {
  260. m_bHaveSecContext=TRUE;
  261. m_bFirstCall=FALSE;
  262. }
  263. switch(status)
  264. {
  265. case SEC_E_OK:hr=S_OK;
  266. break;
  267. case SEC_I_CONTINUE_NEEDED:hr=S_FALSE;
  268. break;
  269. case SEC_I_COMPLETE_AND_CONTINUE:hr=S_FALSE;
  270. //Continue to do the following
  271. case SEC_I_COMPLETE_NEEDED:if(m_gpFuncs->CompleteAuthToken)
  272. {
  273. status=m_gpFuncs->CompleteAuthToken(
  274. &m_hSecContext,
  275. &OutBuffDesc);
  276. if( !(SEC_SUCCESS(status)) )
  277. {
  278. hr=E_FAIL;
  279. }
  280. }
  281. else
  282. {
  283. hr=E_FAIL;
  284. }
  285. break;
  286. default: hr=E_FAIL;
  287. }
  288. }
  289. if(SUCCEEDED(hr))
  290. {
  291. uuBuf.cLen=AUTH_BUF_SIZE;
  292. if(OutSecBuff.cbBuffer > (AUTH_BUF_SIZE-5)*2/3)
  293. {
  294. //This is the case where the buffer is not big
  295. // enough
  296. hr=E_OUTOFMEMORY;
  297. }
  298. else
  299. {
  300. if(uuencode(pOutBuf, OutSecBuff.cbBuffer, &uuBuf))
  301. {
  302. pOutBuf[AUTH_BUF_SIZE-1]=0;
  303. if( 0>_snprintf((char *)pOutBuf,
  304. AUTH_BUF_SIZE-1,
  305. "+ %s\r\n",
  306. (char *)(uuBuf.pBuf)) )
  307. {
  308. hr=E_FAIL;
  309. }
  310. else
  311. {
  312. *pcbOutBufSize=strlen((char *)pOutBuf);
  313. }
  314. }
  315. else
  316. {
  317. hr=E_FAIL;
  318. }
  319. }
  320. }
  321. if(FAILED(hr))
  322. {
  323. if(m_bHaveSecContext)
  324. {
  325. m_gpFuncs->DeleteSecurityContext(&m_hSecContext);
  326. m_bHaveSecContext=FALSE;
  327. m_bFirstCall=TRUE;
  328. }
  329. }
  330. return hr;
  331. }
  332. HRESULT CAuthServer::GetUserName(WCHAR *wszUserName)
  333. {
  334. SecPkgContext_Names SecUserName;
  335. SECURITY_STATUS status;
  336. WCHAR *pUserName=NULL;
  337. WCHAR *pAt=NULL;
  338. VARIANT var;
  339. VariantInit(&var);
  340. HRESULT hr=S_OK;
  341. if(NULL==wszUserName)
  342. {
  343. return E_POINTER;
  344. }
  345. if(!m_bHaveSecContext)
  346. {
  347. return E_FAIL;
  348. }
  349. status=QueryContextAttributes( &m_hSecContext,
  350. SECPKG_ATTR_NAMES,
  351. &SecUserName);
  352. if(SEC_E_OK != status)
  353. {
  354. return E_FAIL;
  355. }
  356. else
  357. {
  358. if(AUTH_AD==g_dwAuthMethod)
  359. {
  360. var.vt=VT_BSTR;
  361. var.bstrVal=SysAllocString(SecUserName.sUserName);
  362. if(NULL == var.bstrVal)
  363. {
  364. var.vt=VT_EMPTY;
  365. hr=E_OUTOFMEMORY;
  366. }
  367. else
  368. {
  369. hr=g_pAuthMethod->Get(SZ_EMAILADDR, &var);
  370. if(SUCCEEDED(hr))
  371. {
  372. if(wcslen(var.bstrVal) < POP3_MAX_ADDRESS_LENGTH)
  373. {
  374. wcscpy(wszUserName, var.bstrVal);
  375. }
  376. else
  377. {
  378. hr=E_FAIL;
  379. }
  380. }
  381. }
  382. }
  383. else //SAM case
  384. {
  385. pAt=wcschr(SecUserName.sUserName, L'\\');
  386. if(NULL == pAt)
  387. {
  388. pUserName=SecUserName.sUserName;
  389. }
  390. else
  391. {
  392. pUserName=pAt+1;
  393. }
  394. CComPtr<IP3Config> spIConfig;
  395. CComPtr<IP3Domains> spIDomains;
  396. hr = CoCreateInstance( __uuidof( P3Config ), NULL, CLSCTX_ALL, __uuidof( IP3Config ),reinterpret_cast<LPVOID *>( &spIConfig ));
  397. if( S_OK == hr )
  398. {
  399. if( S_OK== hr)
  400. {
  401. hr = spIConfig->get_Domains( &spIDomains );
  402. }
  403. }
  404. if( S_OK == hr )
  405. {
  406. BSTR bstrDomainName=NULL;
  407. CComBSTR bstrUserName(pUserName);
  408. hr = spIDomains->SearchForMailbox(bstrUserName, &bstrDomainName);
  409. if ( S_OK == hr )
  410. {
  411. if(0> _snwprintf(wszUserName, POP3_MAX_ADDRESS_LENGTH-1, L"%s@%s", pUserName, bstrDomainName) )
  412. {
  413. hr=E_FAIL;
  414. }
  415. wszUserName[POP3_MAX_ADDRESS_LENGTH-1]=L'\0';
  416. SysFreeString(bstrDomainName);
  417. }
  418. }
  419. }
  420. m_gpFuncs->FreeContextBuffer(SecUserName.sUserName);
  421. VariantClear(&var);
  422. return hr;
  423. }
  424. }