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.

426 lines
14 KiB

  1. //Copyright (c) Microsoft Corporation. All rights reserved.
  2. /*
  3. security.cpp
  4. */
  5. #ifdef WHISTLER_BUILD
  6. #include "ntverp.h"
  7. #else
  8. #include <solarver.h>
  9. #endif //WHISTER_BUILD
  10. #include <stddef.h>
  11. #include <common.ver>
  12. #include <debug.h>
  13. #include <TlntUtils.h>
  14. #include <iohandlr.h>
  15. #include <issperr.h>
  16. #include <TelnetD.h>
  17. #include <Session.h>
  18. using namespace _Utils;
  19. using CDebugLevel::TRACE_DEBUGGING;
  20. using CDebugLevel::TRACE_HANDLE;
  21. using CDebugLevel::TRACE_SOCKET;
  22. #pragma warning( disable: 4127 )
  23. #pragma warning( disable: 4706 )
  24. extern HANDLE g_hSyncCloseHandle;
  25. bool CIoHandler::StartNTLMAuth()
  26. {
  27. TimeStamp tsExpiry;
  28. SECURITY_STATUS secStatus;
  29. m_hContext.dwLower = m_hContext.dwUpper = 0 ;
  30. m_hCredential.dwLower = m_hCredential.dwUpper = 0 ;
  31. if ( SEC_E_OK != (secStatus = AcquireCredentialsHandle(
  32. NULL, // name of principal
  33. L"NTLM", // name of package
  34. SECPKG_CRED_BOTH, // flags indicating use
  35. NULL, //PLUID pvLogonID, // pointer to logon identifier
  36. NULL, //PVOID pAuthData, // package-specific data
  37. NULL, //PVOID pGetKeyFn, // pointer to GetKey function
  38. NULL, //PVOID pvGetKeyArgument, // value to pass to GetKey
  39. &m_hCredential, // credential handle
  40. &tsExpiry) ) ) // life time of the returned credentials);
  41. {
  42. return false;
  43. }
  44. secStatus = QuerySecurityPackageInfo(L"NTLM", &m_pspi);
  45. if ( secStatus != SEC_E_OK )
  46. {
  47. return false;
  48. }
  49. return true;
  50. }
  51. bool
  52. CIoHandler::DoNTLMAuth( PUCHAR pBuffer, DWORD dwSize, PUCHAR* pBuf )
  53. {
  54. m_SocketControlState = CIoHandler::STATE_NTLMAUTH;
  55. SECURITY_STATUS secStatus;
  56. SecBufferDesc InBuffDesc;
  57. SecBuffer InSecBuff;
  58. SecBufferDesc OutBuffDesc;
  59. SecBuffer OutSecBuff;
  60. ULONG fContextAttr;
  61. TimeStamp tsExpiry;
  62. __try
  63. {
  64. OutSecBuff.pvBuffer = NULL;
  65. // if we are getting nothing then we fail.
  66. if( dwSize == 0 )
  67. {
  68. goto error;
  69. }
  70. // make sure we get only NTLM now - thats the only thing we support
  71. if( *pBuffer != AUTH_TYPE_NTLM )
  72. {
  73. goto error;
  74. }
  75. if( dwSize < ( 3 + sizeof( SecBuffer ) ))
  76. {
  77. goto error;
  78. }
  79. // get past the auth type and the modifier byte and the Auth scheme.
  80. pBuffer += 3;
  81. dwSize -= 3;
  82. //
  83. // Prepare our Input buffer - Note the server is expecting the client's
  84. // negotiation packet on the first call
  85. //
  86. InBuffDesc.ulVersion = SECBUFFER_VERSION;
  87. InBuffDesc.cBuffers = 1;
  88. InBuffDesc.pBuffers = &InSecBuff;
  89. // Copy the 1st two fields of SecBuffer from pBuffer to pInSecBuffer. Use memcpy because
  90. // pBuffer is not guaranteed to be an aligned pointer.
  91. memcpy((PVOID)&InSecBuff, (PVOID)pBuffer, offsetof(SecBuffer, pvBuffer)); // NO Attack here, Baskar.
  92. // if we don't have enough buffer then let this call return
  93. if( dwSize < InSecBuff.cbBuffer )
  94. {
  95. //m_pReadFromSocketBufferCursor += dwSize;
  96. return false;
  97. }
  98. InSecBuff.pvBuffer = (PVOID)(pBuffer + offsetof(SecBuffer, pvBuffer));
  99. //
  100. // Prepare our output buffer. We use a temporary buffer because
  101. // the real output buffer will most likely need to be uuencoded
  102. //
  103. OutBuffDesc.ulVersion = SECBUFFER_VERSION;
  104. OutBuffDesc.cBuffers = 1;
  105. OutBuffDesc.pBuffers = &OutSecBuff;
  106. OutSecBuff.cbBuffer = m_pspi->cbMaxToken;
  107. OutSecBuff.BufferType = SECBUFFER_TOKEN;
  108. OutSecBuff.pvBuffer = new WCHAR[m_pspi->cbMaxToken];
  109. if( !OutSecBuff.pvBuffer )
  110. {
  111. return false;
  112. }
  113. SfuZeroMemory( OutSecBuff.pvBuffer, m_pspi->cbMaxToken );
  114. secStatus = AcceptSecurityContext(
  115. &m_hCredential, // handle to the credentials
  116. ((fDoNTLMAuthFirstTime) ? NULL: &m_hContext), // handle of partially formed context
  117. &InBuffDesc, // pointer to the input buffers
  118. ASC_REQ_REPLAY_DETECT |
  119. ASC_REQ_MUTUAL_AUTH |
  120. ASC_REQ_DELEGATE, // required context attributes
  121. SECURITY_NATIVE_DREP, // data representation on the target
  122. &m_hContext, // receives the new context handle
  123. &OutBuffDesc, // pointer to the output buffers
  124. &fContextAttr, // receives the context attributes
  125. &tsExpiry // receives the life span of the security context
  126. );
  127. }
  128. __except( EXCEPTION_EXECUTE_HANDLER )
  129. {
  130. secStatus = SEC_E_LOGON_DENIED;
  131. }
  132. switch ( secStatus ) {
  133. case SEC_E_OK:
  134. m_bNTLMAuthenticated = true;
  135. // done with the authentication, we need to send an accept to the client.
  136. (*pBuf)[0] = TC_IAC;
  137. (*pBuf)[1] = TC_SB;
  138. (*pBuf)[2] = TO_AUTH;
  139. (*pBuf)[3] = AU_REPLY;
  140. (*pBuf)[4] = AUTH_TYPE_NTLM;
  141. (*pBuf)[5] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY;
  142. (*pBuf)[6] = NTLM_ACCEPT;
  143. (*pBuf)[7] = TC_IAC;
  144. (*pBuf)[8] = TC_SE;
  145. *pBuf += 9;
  146. m_SocketControlState = CIoHandler::STATE_CHECK_LICENSE;
  147. if( m_bNTLMAuthenticated )
  148. {
  149. GetUserName();
  150. //Needed for logging at logging off
  151. m_pSession->m_fLogonUserResult = SUCCESS;
  152. }
  153. break;
  154. case SEC_I_COMPLETE_NEEDED:
  155. case SEC_I_COMPLETE_AND_CONTINUE:
  156. // these two return values should never be returned for NTLM.
  157. // so we treat them as if we need a continue. we send the data to the client
  158. // and wait for something to come back.
  159. case SEC_I_CONTINUE_NEEDED:
  160. fDoNTLMAuthFirstTime = false;
  161. (*pBuf)[0] = TC_IAC;
  162. (*pBuf)[1] = TC_SB;
  163. (*pBuf)[2] = TO_AUTH;
  164. (*pBuf)[3] = AU_REPLY;
  165. (*pBuf)[4] = AUTH_TYPE_NTLM;
  166. (*pBuf)[5] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY;
  167. (*pBuf)[6] = NTLM_CHALLENGE;
  168. *pBuf += 7;
  169. {
  170. DWORD dwResultSize = sizeof( OutSecBuff ) - sizeof( LPSTR );
  171. StuffEscapeIACs( *pBuf, ( PUCHAR ) &OutSecBuff, &dwResultSize );
  172. *pBuf += dwResultSize;
  173. dwResultSize = OutSecBuff.cbBuffer;
  174. StuffEscapeIACs( *pBuf, ( PUCHAR ) OutSecBuff.pvBuffer, &dwResultSize );
  175. *pBuf += dwResultSize;
  176. }
  177. *(*pBuf) = TC_IAC;
  178. *pBuf +=1;
  179. *(*pBuf) = TC_SE;
  180. *pBuf +=1;
  181. break;
  182. default:
  183. #ifdef LOGGING_ENABLED
  184. m_pSession->LogIfOpted( FAIL, LOGON, true );
  185. #endif
  186. // AcceptSecurityContext returned a value which we don't like.
  187. // We Reject the NTLM authentication and then continue with the clear text user name
  188. // and password.
  189. (*pBuf)[0] = TC_IAC;
  190. (*pBuf)[1] = TC_SB;
  191. (*pBuf)[2] = TO_AUTH;
  192. (*pBuf)[3] = AU_REPLY;
  193. (*pBuf)[4] = AUTH_TYPE_NTLM;
  194. (*pBuf)[5] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY;
  195. (*pBuf)[6] = NTLM_REJECT;
  196. (*pBuf)[7] = TC_IAC;
  197. (*pBuf)[8] = TC_SE;
  198. *pBuf += 9;
  199. strncpy( (char *)*pBuf, NTLM_LOGON_FAIL,MAX_READ_SOCKET_BUFFER); // No Attack, internal Baskar ?
  200. *pBuf += strlen(NTLM_LOGON_FAIL);
  201. switch( secStatus )
  202. {
  203. case SEC_E_INVALID_TOKEN:
  204. case SEC_E_INVALID_HANDLE:
  205. case SEC_E_INTERNAL_ERROR:
  206. strncpy( (char *)*pBuf, INVALID_TOKEN_OR_HANDLE,MAX_READ_SOCKET_BUFFER); // No Attack, internal Baskar ?
  207. *pBuf += strlen(INVALID_TOKEN_OR_HANDLE);
  208. break;
  209. case SEC_E_LOGON_DENIED:
  210. strncpy( (char *)*pBuf, LOGON_DENIED,MAX_READ_SOCKET_BUFFER); // No Attack, internal Baskar ?
  211. *pBuf += strlen(LOGON_DENIED);
  212. break;
  213. case SEC_E_NO_AUTHENTICATING_AUTHORITY:
  214. strncpy( (char *)*pBuf, NO_AUTHENTICATING_AUTHORITY,MAX_READ_SOCKET_BUFFER); // No Attack, internal Baskar ?
  215. *pBuf += strlen(NO_AUTHENTICATING_AUTHORITY);
  216. break;
  217. default:
  218. strncpy( (char *)*pBuf, NTLM_REJECT_STR,MAX_READ_SOCKET_BUFFER); // No Attack, internal Baskar ?
  219. *pBuf += strlen(NTLM_REJECT_STR);
  220. break;
  221. }
  222. strncpy( (char *)*pBuf, USE_PASSWD,MAX_READ_SOCKET_BUFFER); // No Attack, internal Baskar ?
  223. *pBuf += strlen(USE_PASSWD);
  224. error:
  225. char* p = (char*)*pBuf;
  226. if( m_pSession->m_dwNTLMSetting == NTLM_ONLY )
  227. {
  228. sprintf(p, "%s%s", NTLM_ONLY_STR, TERMINATE); // No Attack, internal Baskar ?
  229. *pBuf += strlen(p);
  230. m_SocketControlState = CIoHandler::STATE_TERMINATE;
  231. m_pSession->CIoHandler::m_fShutDownAfterIO = true;
  232. }
  233. else
  234. {
  235. m_SocketControlState = CIoHandler::STATE_BANNER_FOR_AUTH;
  236. }
  237. }
  238. if ( OutSecBuff.pvBuffer != NULL )
  239. delete [] OutSecBuff.pvBuffer;
  240. return true;
  241. }
  242. bool
  243. CIoHandler::GetUserName()
  244. {
  245. bool success = false;
  246. int iStatus = 0;
  247. if ( m_pSession->CIoHandler::m_bNTLMAuthenticated )
  248. {
  249. HANDLE hToken = NULL;
  250. HANDLE hTempToken = NULL;
  251. if (SEC_E_OK == ImpersonateSecurityContext(&m_pSession->CIoHandler::m_hContext))
  252. {
  253. if (OpenThreadToken(
  254. GetCurrentThread(),
  255. TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY,
  256. FALSE,
  257. &hTempToken
  258. ))
  259. {
  260. if (DuplicateTokenEx(
  261. hTempToken,
  262. MAXIMUM_ALLOWED, //TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY,
  263. NULL,
  264. SecurityImpersonation,
  265. TokenPrimary,
  266. &hToken
  267. ))
  268. {
  269. DWORD dwSizeReqd;
  270. TOKEN_USER *tokenData;
  271. GetTokenInformation(
  272. hToken,
  273. TokenUser,
  274. NULL,
  275. 0,
  276. &dwSizeReqd
  277. ); // This call must fail with insufficient buffer
  278. tokenData = (TOKEN_USER*) new BYTE[dwSizeReqd];
  279. //allocate that memory
  280. if (NULL != tokenData)
  281. {
  282. //actually get the user info
  283. if (0 != GetTokenInformation(
  284. hToken,
  285. TokenUser,
  286. (LPVOID)tokenData,
  287. dwSizeReqd,
  288. &dwSizeReqd
  289. ))
  290. {
  291. //convert user SID into a name and domain
  292. SID_NAME_USE sidType;
  293. DWORD dwStrSize1 = MAX_PATH + 1;
  294. DWORD dwStrSize2 = MAX_PATH + 1;
  295. WCHAR szUser [ MAX_PATH + 1 ];
  296. WCHAR szDomain [ MAX_PATH + 1 ];
  297. if(LookupAccountSid( NULL, tokenData->User.Sid,
  298. szUser, &dwStrSize1,
  299. szDomain, &dwStrSize2, &sidType ) )
  300. {
  301. dwStrSize2++; //To account for null char at the end
  302. dwStrSize1++;
  303. //LookupAccountSid seems to return data as per 1252. Convert accordingly
  304. _chVERIFY2( iStatus = WideCharToMultiByte( GetConsoleCP(), 0, szUser,
  305. -1, m_pSession->m_pszUserName, dwStrSize1, NULL, NULL ) );
  306. _chVERIFY2( iStatus = WideCharToMultiByte( GetConsoleCP(), 0, szDomain,
  307. -1, m_pSession->m_pszDomain, dwStrSize2, NULL, NULL ) );
  308. wcscpy(m_pSession->m_szDomain,szDomain);
  309. success = true;
  310. }
  311. else
  312. {
  313. _TRACE( TRACE_DEBUGGING, "Error: LookupAccountSid()" );
  314. }
  315. }
  316. else
  317. {
  318. _TRACE( TRACE_DEBUGGING, "Error: GetTokenInformation()" );
  319. }
  320. delete [] tokenData;
  321. }
  322. m_pSession->m_hToken = hToken;
  323. }
  324. else
  325. {
  326. _TRACE( TRACE_DEBUGGING, "Error: DuplicateTokenEx() - 0x%lx",
  327. GetLastError());
  328. _chASSERT( 0 );
  329. }
  330. TELNET_CLOSE_HANDLE(hTempToken);
  331. }
  332. else
  333. {
  334. _TRACE( TRACE_DEBUGGING, "Error: OpenThreadToken() - 0x%lx",
  335. GetLastError());
  336. _chASSERT( 0 );
  337. }
  338. if(SEC_E_OK != RevertSecurityContext( &m_pSession->CIoHandler::m_hContext ))
  339. {
  340. _TRACE( TRACE_DEBUGGING, "Error: RevertSecurityContext() - "
  341. "0x%lx", GetLastError());
  342. _chASSERT( 0 );
  343. }
  344. }
  345. else
  346. {
  347. _TRACE( TRACE_DEBUGGING, "Error: ImpersonateSecurityContext() - "
  348. "0x%lx", GetLastError());
  349. _chASSERT( 0 );
  350. }
  351. }
  352. return success;
  353. }