Source code of Windows XP (NT5)
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.

471 lines
13 KiB

  1. //Copyright (c) Microsoft Corporation. All rights reserved.
  2. /*
  3. security.cpp
  4. */
  5. #include <windows.h> /* required for all Windows applications */
  6. #include <stdlib.h>
  7. #include <stdio.h>
  8. #include <stddef.h>
  9. #define SECURITY_WIN32
  10. #include <sspi.h>
  11. #include <rpc.h>
  12. #include <rpcdce.h>
  13. #include "debug.h"
  14. #include "wintel.h"
  15. #include "telnet.h"
  16. #include "commands.h"
  17. static CredHandle hCredential = { 0, 0 };
  18. static CtxtHandle hContext = { 0, 0 };
  19. static PSecPkgInfo pspi;
  20. #define DEFAULT_BUFFER_SIZE 4096
  21. BOOL StuffEscapeIACs( PUCHAR* ppBufDest, UCHAR bufSrc[], DWORD* pdwSize );
  22. void NTLMCleanup()
  23. {
  24. FreeCredentialsHandle(&hCredential);
  25. if(pspi)
  26. {
  27. FreeContextBuffer( pspi );
  28. pspi=NULL;
  29. }
  30. }
  31. BOOL StartNTLMAuth(WI *pwi)
  32. {
  33. unsigned char *sbuf = NULL;
  34. PUCHAR destBuf = NULL;
  35. DWORD dwSize = 0;
  36. BOOL bRetVal = FALSE;
  37. int inx;
  38. TimeStamp tsExpiry;
  39. SECURITY_STATUS secStatus;
  40. SecBufferDesc OutBuffDesc;
  41. SecBuffer OutSecBuff;
  42. ULONG fContextAttr;
  43. HANDLE hProc = NULL;
  44. HANDLE hAccessToken = NULL;
  45. TOKEN_INFORMATION_CLASS tic;
  46. DWORD dwSizeReqd;
  47. VOID* tokenData = NULL;
  48. SID_NAME_USE sidType;
  49. DWORD dwStrSize1 = MAX_PATH + 1;
  50. DWORD dwStrSize2 = MAX_PATH + 1;
  51. SEC_WINNT_AUTH_IDENTITY AuthIdentity;
  52. WCHAR szWideUser[ MAX_PATH + 1 ] ;
  53. WCHAR szWideDomain[ MAX_PATH + 1 ] ;
  54. OutSecBuff.pvBuffer = NULL;
  55. /*
  56. added code to get user name and domain so we can pass it
  57. AcquireCredentialsHandle(); this is to prevent optimization happening in NT
  58. for the case where client and server are on same machine, in which case the
  59. same user in different sessions gets the same Authentication Id thereby
  60. affecting our process clean up in telnet server
  61. */
  62. hProc = OpenProcess( PROCESS_ALL_ACCESS, FALSE,
  63. GetCurrentProcessId() );
  64. if( hProc == NULL )
  65. {
  66. goto End;
  67. }
  68. if( !OpenProcessToken( hProc, TOKEN_QUERY, &hAccessToken ))
  69. {
  70. CloseHandle( hProc );
  71. goto End;
  72. }
  73. //get user info
  74. tic = TokenUser;
  75. //find out how much memory is reqd.
  76. GetTokenInformation( hAccessToken, tic, NULL, 0, &dwSizeReqd );
  77. //allocate that memory
  78. tokenData = (TOKEN_USER*) malloc( dwSizeReqd );
  79. // and check if the allocation succeeded
  80. if (!tokenData) {
  81. CloseHandle( hProc );
  82. CloseHandle( hAccessToken );
  83. goto End;
  84. }
  85. //actually get the user info
  86. if( !GetTokenInformation( hAccessToken, tic, tokenData, dwSizeReqd,
  87. &dwSizeReqd ) )
  88. {
  89. CloseHandle( hProc );
  90. CloseHandle( hAccessToken );
  91. goto End;
  92. }
  93. CloseHandle( hProc );
  94. CloseHandle( hAccessToken );
  95. //convert user SID into a name and domain
  96. if( !LookupAccountSid( NULL, ((TOKEN_USER*) tokenData)->User.Sid,
  97. szWideUser, &dwStrSize1, szWideDomain, &dwStrSize2, &sidType ) )
  98. {
  99. goto End;
  100. }
  101. SfuZeroMemory( &AuthIdentity, sizeof(AuthIdentity) );
  102. if( szWideDomain != NULL )
  103. {
  104. AuthIdentity.Domain = szWideDomain;
  105. AuthIdentity.DomainLength = wcslen(szWideDomain) ;
  106. }
  107. if( szWideUser != NULL )
  108. {
  109. AuthIdentity.User = szWideUser;
  110. AuthIdentity.UserLength = wcslen(szWideUser) ;
  111. }
  112. /// leave password empty via SfuZeroMemory above
  113. /// if ( Password != NULL )
  114. /// {
  115. /// AuthIdentity.Password = Password;
  116. /// AuthIdentity.PasswordLength = lstrlen(Password);
  117. /// }
  118. AuthIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
  119. if ( SEC_E_OK != (secStatus = AcquireCredentialsHandle(
  120. NULL, // SEC_CHAR * pszPrincipal, // name of principal
  121. ( LPTSTR ) L"NTLM", //SEC_CHAR * pszPackage, // name of package
  122. SECPKG_CRED_OUTBOUND, //ULONG fCredentialUse, // flags indicating use
  123. NULL, // PLUID pvLogonID, // pointer to logon identifier
  124. (PVOID) &AuthIdentity, //PVOID pAuthData, // package-specific data
  125. NULL, //PVOID pGetKeyFn, // pointer to GetKey function
  126. NULL, //PVOID pvGetKeyArgument, // value to pass to GetKey
  127. &hCredential, // credential handle
  128. &tsExpiry)) // life time of the returned credentials);
  129. )
  130. {
  131. goto End;
  132. }
  133. secStatus = QuerySecurityPackageInfo(( LPTSTR ) L"NTLM", &pspi);
  134. if ( secStatus != SEC_E_OK || !pspi)
  135. {
  136. goto End;
  137. }
  138. //
  139. // Prepare our output buffer. We use a temporary buffer because
  140. // the real output buffer will most likely need to be uuencoded
  141. //
  142. OutBuffDesc.ulVersion = 0;
  143. OutBuffDesc.cBuffers = 1;
  144. OutBuffDesc.pBuffers = &OutSecBuff;
  145. OutSecBuff.cbBuffer = pspi->cbMaxToken;
  146. OutSecBuff.BufferType = SECBUFFER_TOKEN;
  147. OutSecBuff.pvBuffer = malloc(pspi->cbMaxToken);
  148. if( !OutSecBuff.pvBuffer ) {
  149. goto End;
  150. }
  151. // We will start using sbuf after the call to the below API
  152. // So allocate it here and bail out if allocation fails
  153. sbuf = (unsigned char*)malloc(DEFAULT_BUFFER_SIZE);
  154. if (!sbuf)
  155. {
  156. goto End;
  157. }
  158. secStatus = InitializeSecurityContext(
  159. &hCredential, // handle to the credentials
  160. NULL, // handle of partially formed context
  161. NULL, //SEC_CHAR * pszTargetName, // name of the target of the context
  162. ISC_REQ_REPLAY_DETECT, // required context attributes
  163. 0, //ULONG Reserved1, // reserved; must be zero
  164. SECURITY_NATIVE_DREP, //ULONG TargetDataRep, // data representation on the target
  165. NULL, //PSecBufferDesc pInput, // pointer to the input buffers
  166. 0, //ULONG Reserved2, // reserved; must be zero
  167. &hContext, // receives the new context handle
  168. &OutBuffDesc, // pointer to the output buffers
  169. &fContextAttr, // receives the context attributes
  170. &tsExpiry); // receives the life span of the security context);
  171. switch ( secStatus )
  172. {
  173. case SEC_I_CONTINUE_NEEDED:
  174. sbuf[0] = IAC;
  175. sbuf[1] = SB;
  176. sbuf[2] = TO_AUTH;
  177. sbuf[3] = AU_IS;
  178. sbuf[4] = AUTH_TYPE_NTLM;
  179. sbuf[5] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY;
  180. sbuf[6] = NTLM_AUTH;
  181. inx = 7;
  182. dwSize = sizeof(OutSecBuff) - sizeof(LPSTR);
  183. if( !StuffEscapeIACs( &destBuf, ( UCHAR *)&OutSecBuff, &dwSize ) )
  184. {
  185. //copy maximum 'n' bytes where 'n' is minimum of the available sbuf and size of data to copy.
  186. if(DEFAULT_BUFFER_SIZE > dwSize+inx+2) //for IAC SE
  187. {
  188. memcpy( sbuf+inx, (LPSTR)&OutSecBuff, sizeof(OutSecBuff) - sizeof(LPSTR));
  189. inx += sizeof(OutSecBuff) - sizeof(LPSTR);
  190. }
  191. }
  192. else
  193. {
  194. //copy maximum 'n' bytes where 'n' is minimum of the available sbuf and size of data to copy.
  195. if(DEFAULT_BUFFER_SIZE > dwSize+inx+2) //for IAC SE
  196. {
  197. memcpy( sbuf+inx, destBuf, dwSize);
  198. inx += dwSize;
  199. }
  200. }
  201. if(destBuf)
  202. {
  203. free( destBuf );
  204. destBuf = NULL;
  205. }
  206. dwSize = OutSecBuff.cbBuffer;
  207. if( !StuffEscapeIACs( &destBuf, OutSecBuff.pvBuffer, &dwSize ) )
  208. {
  209. if(DEFAULT_BUFFER_SIZE > OutSecBuff.cbBuffer+inx+2) //for IAC SE
  210. {
  211. memcpy( sbuf+inx, OutSecBuff.pvBuffer, OutSecBuff.cbBuffer); //no overflow. Check already present.
  212. inx += OutSecBuff.cbBuffer;
  213. }
  214. }
  215. else
  216. {
  217. if(DEFAULT_BUFFER_SIZE > dwSize+inx+2) //for IAC SE
  218. {
  219. memcpy( sbuf+inx, destBuf, dwSize );//no overflow. Check already present.
  220. inx += dwSize;
  221. }
  222. }
  223. if(destBuf)
  224. {
  225. free( destBuf );
  226. destBuf = NULL;
  227. }
  228. sbuf[inx++] = IAC;
  229. sbuf[inx++] = SE;
  230. FWriteToNet( pwi, ( char * )sbuf, inx );
  231. break;
  232. case SEC_I_COMPLETE_AND_CONTINUE:
  233. case SEC_I_COMPLETE_NEEDED:
  234. default:
  235. goto End;
  236. }
  237. pwi->eState = Authenticating;
  238. bRetVal = TRUE;
  239. End:
  240. if(tokenData)
  241. free( tokenData );
  242. if(OutSecBuff.pvBuffer)
  243. free(OutSecBuff.pvBuffer);
  244. if(sbuf)
  245. free(sbuf);
  246. return bRetVal;
  247. }
  248. BOOL DoNTLMAuth(WI *pwi, PUCHAR pBuffer, DWORD dwSize)
  249. {
  250. SECURITY_STATUS secStatus;
  251. SecBufferDesc InBuffDesc;
  252. SecBuffer InSecBuff;
  253. SecBuffer *pInSecBuff = NULL;
  254. SecBufferDesc OutBuffDesc;
  255. SecBuffer OutSecBuff;
  256. BOOL bStatus=FALSE;
  257. ULONG fContextAttr;
  258. TimeStamp tsExpiry;
  259. unsigned char *sbuf = NULL;
  260. PUCHAR destBuf = NULL;
  261. int inx;
  262. OutSecBuff.pvBuffer = NULL;
  263. pInSecBuff = (SecBuffer *)malloc(sizeof(SecBuffer));
  264. if( NULL == pInSecBuff )
  265. {
  266. goto Done;
  267. }
  268. // Copy the 1st two fields of SecBuffer from pBuffer to pInSecBuffer. Use memcpy because
  269. // pBuffer is not guaranteed to be an aligned pointer.
  270. // Use offsetof to copy whatever is there before pvBuffer.
  271. memcpy((PVOID)pInSecBuff, (PVOID)pBuffer, offsetof(SecBuffer, pvBuffer));//Attack ? Size not known.
  272. // now set pvBuffer to point into the pBuffer area.
  273. pInSecBuff->pvBuffer = (PVOID)(pBuffer+offsetof(SecBuffer,pvBuffer));
  274. if( dwSize<(sizeof(SecBuffer)) ||
  275. dwSize<(offsetof(SecBuffer,pvBuffer)+ pInSecBuff->cbBuffer) ||
  276. !pspi
  277. )
  278. {
  279. goto Done;
  280. }
  281. //
  282. // Prepare our Input buffer - Note the server is expecting the client's
  283. // negotiation packet on the first call
  284. //
  285. InBuffDesc.ulVersion = 0;
  286. InBuffDesc.cBuffers = 1;
  287. InBuffDesc.pBuffers = &InSecBuff;
  288. InSecBuff.cbBuffer = pInSecBuff->cbBuffer;
  289. InSecBuff.BufferType = pInSecBuff->BufferType;
  290. InSecBuff.pvBuffer = pInSecBuff->pvBuffer;
  291. //
  292. // Prepare our output buffer. We use a temporary buffer because
  293. // the real output buffer will most likely need to be uuencoded
  294. //
  295. OutBuffDesc.ulVersion = 0;
  296. OutBuffDesc.cBuffers = 1;
  297. OutBuffDesc.pBuffers = &OutSecBuff;
  298. OutSecBuff.cbBuffer = pspi->cbMaxToken;
  299. OutSecBuff.BufferType = SECBUFFER_TOKEN;
  300. OutSecBuff.pvBuffer = malloc(pspi->cbMaxToken);
  301. if( !OutSecBuff.pvBuffer ) {
  302. goto Done;
  303. }
  304. sbuf = (unsigned char*)malloc(DEFAULT_BUFFER_SIZE);
  305. if (!sbuf)
  306. {
  307. goto Done;
  308. }
  309. secStatus = InitializeSecurityContext(
  310. &hCredential, // handle to the credentials
  311. &hContext, // handle of partially formed context
  312. ( LPTSTR ) L"NTLM",//SEC_CHAR * pszTargetName, // name of the target of the context
  313. ISC_REQ_DELEGATE |
  314. ISC_REQ_REPLAY_DETECT, // required context attributes
  315. 0, //ULONG Reserved1, // reserved; must be zero
  316. SECURITY_NATIVE_DREP, //ULONG TargetDataRep, // data representation on the target
  317. &InBuffDesc, // pointer to the input buffers
  318. 0, //ULONG Reserved2, // reserved; must be zero
  319. &hContext, // receives the new context handle
  320. &OutBuffDesc, // pointer to the output buffers
  321. &fContextAttr, // receives the context attributes
  322. &tsExpiry); // receives the life span of the security context);
  323. switch ( secStatus ) {
  324. case SEC_E_OK:
  325. case SEC_I_CONTINUE_NEEDED:
  326. sbuf[0] = IAC;
  327. sbuf[1] = SB;
  328. sbuf[2] = TO_AUTH;
  329. sbuf[3] = AU_IS;
  330. sbuf[4] = AUTH_TYPE_NTLM;
  331. sbuf[5] = AUTH_CLIENT_TO_SERVER | AUTH_HOW_ONE_WAY;
  332. sbuf[6] = NTLM_RESPONSE;
  333. inx = 7;
  334. dwSize = sizeof(OutSecBuff) - sizeof(LPSTR);
  335. if( !StuffEscapeIACs( &destBuf, (UCHAR *)&OutSecBuff, &dwSize ) )
  336. {
  337. if(DEFAULT_BUFFER_SIZE > dwSize+inx+2) //for IAC SE
  338. {
  339. memcpy( sbuf+inx, (LPSTR)&OutSecBuff, sizeof(OutSecBuff) - sizeof(LPSTR) );//no overflow. Check already present.
  340. inx += sizeof(OutSecBuff) - sizeof(LPSTR);
  341. }
  342. }
  343. else
  344. {
  345. if(DEFAULT_BUFFER_SIZE > dwSize+inx+2) //for IAC SE
  346. {
  347. memcpy( sbuf+inx, destBuf, dwSize );//no overflow. Check already present.
  348. inx += dwSize;
  349. }
  350. }
  351. if(destBuf)
  352. {
  353. free( destBuf );
  354. destBuf = NULL;
  355. }
  356. dwSize = OutSecBuff.cbBuffer;
  357. if( !StuffEscapeIACs( &destBuf, OutSecBuff.pvBuffer, &dwSize ) )
  358. {
  359. if(DEFAULT_BUFFER_SIZE > OutSecBuff.cbBuffer+inx+2) //for IAC SE
  360. {
  361. memcpy( sbuf+inx, OutSecBuff.pvBuffer, OutSecBuff.cbBuffer);
  362. inx += OutSecBuff.cbBuffer;
  363. }
  364. }
  365. else
  366. {
  367. if(DEFAULT_BUFFER_SIZE > dwSize+inx+2) //for IAC SE
  368. {
  369. memcpy( sbuf+inx, destBuf, dwSize );
  370. inx += dwSize;
  371. }
  372. }
  373. if(destBuf)
  374. {
  375. free( destBuf );
  376. destBuf = NULL;
  377. }
  378. sbuf[inx++] = IAC;
  379. sbuf[inx++] = SE;
  380. FWriteToNet(pwi, ( char * )sbuf, inx);
  381. break;
  382. case SEC_I_COMPLETE_NEEDED:
  383. case SEC_I_COMPLETE_AND_CONTINUE:
  384. default:
  385. goto Done;
  386. }
  387. bStatus=TRUE;
  388. Done:
  389. if (sbuf)
  390. {
  391. free(sbuf);
  392. }
  393. if (pInSecBuff)
  394. {
  395. free(pInSecBuff);
  396. }
  397. if (OutSecBuff.pvBuffer)
  398. {
  399. free(OutSecBuff.pvBuffer);
  400. }
  401. pwi->eState=AuthChallengeRecvd;
  402. return(bStatus);
  403. }