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.

701 lines
18 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 2000
  6. //
  7. // File: common.cxx
  8. //
  9. // Contents: Shared SSPI code
  10. //
  11. //
  12. // History: 11-March-2000 Created Todds
  13. //
  14. //------------------------------------------------------------------------
  15. //+-------------------------------------------------------------------------
  16. //
  17. // Function: SspAllocate
  18. //
  19. // Synopsis: Copies a string from the client and if necessary converts
  20. // from ansi to unicode
  21. //
  22. // Effects: allocates output with either KerbAllocate (unicode)
  23. // or RtlAnsiStringToUnicodeString
  24. //
  25. // Arguments: StringPointer - address of string in client process
  26. // StringLength - Lenght (in characters) of string
  27. // AnsiString - if TRUE, string is ansi
  28. // LocalString - receives allocated string
  29. //
  30. // Requires:
  31. //
  32. // Returns:
  33. //
  34. // Notes:
  35. //
  36. //
  37. //--------------------------------------------------------------------------
  38. PVOID
  39. SspAllocate(
  40. IN ULONG BufferSize
  41. )
  42. {
  43. PVOID pBuffer = NULL;
  44. if (*pSspState == SspLsaMode)
  45. {
  46. pBuffer = LsaFunctions->AllocateLsaHeap(BufferSize);
  47. if (pBuffer != NULL)
  48. {
  49. RtlZeroMemory(Buffer, BufferSize);
  50. }
  51. }
  52. else
  53. {
  54. ASSERT((*pSspState) == SspUserMode);
  55. pBuffer = LocalAlloc(LPTR, BufferSize);
  56. }
  57. return pBuffer;
  58. }
  59. //+-------------------------------------------------------------------------
  60. //
  61. // Function: SspFree
  62. //
  63. // Synopsis: Copies a string from the client and if necessary converts
  64. // from ansi to unicode
  65. //
  66. // Effects: allocates output with either KerbAllocate (unicode)
  67. // or RtlAnsiStringToUnicodeString
  68. //
  69. // Arguments: StringPointer - address of string in client process
  70. // StringLength - Lenght (in characters) of string
  71. // AnsiString - if TRUE, string is ansi
  72. // LocalString - receives allocated string
  73. //
  74. // Requires:
  75. //
  76. // Returns:
  77. //
  78. // Notes:
  79. //
  80. //
  81. //--------------------------------------------------------------------------
  82. VOID
  83. SspFree(
  84. IN PVOID pBuffer
  85. )
  86. {
  87. if (ARGUMENT_PRESENT(Buffer))
  88. {
  89. if ((*pSspState) == SspLsaMode)
  90. {
  91. LsaFunctions->FreeLsaHeap(Buffer);
  92. }
  93. else
  94. {
  95. ASSERT((*pSspState) == SspUserMode);
  96. LocalFree(Buffer);
  97. }
  98. }
  99. }
  100. //+-------------------------------------------------------------------------
  101. //
  102. // Function: SspCopyClientString
  103. //
  104. // Synopsis: Copies a string from the client and if necessary converts
  105. // from ansi to unicode
  106. //
  107. // Effects: allocates output with SspAllocate, free w/ SspFree
  108. //
  109. // Arguments: StringPointer - address of string in client process
  110. // StringLength - Lenght (in characters) of string
  111. // UnicodeString - if TRUE, string is ansi
  112. // MaxLength - Maximum length of string (useful for pwds)
  113. // LocalString - receives allocated string
  114. //
  115. // Requires:
  116. //
  117. // Returns:
  118. //
  119. // Notes:
  120. //
  121. //
  122. //--------------------------------------------------------------------------
  123. NTSTATUS
  124. SspCopyClientString(
  125. IN PVOID StringPointer,
  126. IN ULONG StringLength,
  127. IN BOOLEAN UnicodeString,
  128. OUT PUNICODE_STRING LocalString,
  129. IN ULONG MaxLength = 0xFFFF
  130. )
  131. {
  132. NTSTATUS Status = STATUS_SUCCESS;
  133. STRING TempString = {0};
  134. ULONG SourceSize = 0;
  135. ULONG CharacterSize = (DoUnicode ? sizeof(WCHAR) : sizeof(CHAR));
  136. // init outputs
  137. LocalString->Length = LocalString->MaximumLength = 0;
  138. LocalString->Buffer = NULL;
  139. if (NULL != StringPointer)
  140. {
  141. // For 0 length strings, allocate 2 bytes
  142. if (StringLength == 0)
  143. {
  144. LocalString->Buffer = (LPWSTR) SspAllocate(sizeof(WCHAR));
  145. if (NULL == LocalString->Buffer)
  146. {
  147. DebugLog((DEB_ERROR,"SspCopyClientString allocation failure!\n");
  148. Status = STATUS_NO_MEMORY;
  149. goto Cleanup;
  150. }
  151. LocalString->MaximumLength = sizeof(WCHAR);
  152. *LocalString->Buffer = L"\0";
  153. }
  154. else
  155. {
  156. //
  157. // Ensure no overflow against UNICODE_STRING, or desired string
  158. //
  159. SourceSize = (StringLength + 1) * CharacterSize;
  160. if ((StringLength > MaxLength) || (SourceSize > 0xFFFF))
  161. {
  162. Status = STATUS_INVALID_PARAMETER;
  163. DebugLog((DEB_WARN, "SspCopyClientString, String is too big for UNICODE_STRING\n"));
  164. goto Cleanup;
  165. }
  166. TempString.Buffer = (LPSTR) SspAllocate(SourceSize);
  167. if (NULL == TempString.Buffer)
  168. {
  169. DebugLog((DEB_ERROR,"SspCopyClientString allocation failure!\n");
  170. Status = STATUS_NO_MEMORY;
  171. goto Cleanup;
  172. }
  173. TempString.Length = (USHORT) (SourceSize - CharacterSize);
  174. TempString.MaximumLength = (USHORT) SourceSize;
  175. Status = LsaFunctions->CopyFromClientBuffer(
  176. NULL,
  177. SourceSize - CharacterSize,
  178. TempString.Buffer,
  179. StringPointer
  180. );
  181. if (!NT_SUCCESS(Status))
  182. {
  183. DebugLog((
  184. DEB_ERROR,
  185. "SspCopyClientString:LsaFn->CopyFromClientBuffer Failed - 0x%x\n",
  186. Status));
  187. goto Cleanup;
  188. }
  189. // We've put info into a STRING structure. Now do
  190. // translation to UNICODE_STRING.
  191. if (UnicodeString)
  192. {
  193. LocalString->Buffer = (LPWSTR) TemporaryString.Buffer;
  194. LocalString->Length = TempString.Length;
  195. LocalString->MaximumLength = TempString.MaximumLength;
  196. }
  197. else
  198. {
  199. NTSTATUS Status1;
  200. Status1 = RtlOemStringToUnicodeString(
  201. LocalString,
  202. &TemporaryString,
  203. TRUE
  204. ); // allocate destination
  205. if (!NT_SUCCESS(Status1))
  206. {
  207. Status = STATUS_NO_MEMORY;
  208. DebugLog((
  209. DEB_ERROR,
  210. "SspCopyClientString, Error from RtlOemStringToUnicodeString is 0x%lx\n",
  211. Status
  212. ));
  213. goto Cleanup;
  214. }
  215. }
  216. }
  217. }
  218. Cleanup:
  219. if (TempString.Buffer != NULL)
  220. {
  221. //
  222. // Free this if we failed and were doing unicode or if we weren't
  223. // doing unicode
  224. //
  225. if ((UnicodeString && !NT_SUCCESS(Status)) || !UnicodeString)
  226. {
  227. NtLmFree(TemporaryString.Buffer);
  228. }
  229. }
  230. return Status;
  231. }
  232. //+-------------------------------------------------------------------------
  233. //
  234. // Function: SspAllocate
  235. //
  236. // Synopsis: Copies a string from the client and if necessary converts
  237. // from ansi to unicode
  238. //
  239. // Effects: allocates output with either KerbAllocate (unicode)
  240. // or RtlAnsiStringToUnicodeString
  241. //
  242. // Arguments: StringPointer - address of string in client process
  243. // StringLength - Lenght (in characters) of string
  244. // AnsiString - if TRUE, string is ansi
  245. // LocalString - receives allocated string
  246. //
  247. // Requires:
  248. //
  249. // Returns:
  250. //
  251. // Notes:
  252. //
  253. //
  254. //--------------------------------------------------------------------------
  255. NTSTATUS
  256. SspCopyAuthorizationData(IN PVOID AuthorizationData,
  257. IN OUT PBOOLEAN NullSession)
  258. {
  259. PSEC_WINNT_AUTH_IDENTITY_EXW pAuthIdentityEx = NULL;
  260. BOOLEAN UnicodeString = TRUE;
  261. // Init out parameters
  262. *NullSession = FALSE;
  263. if (NULL == AuthorizationData)
  264. {
  265. return STATUS_SUCCESS;
  266. }
  267. pAuthIdentity = (PSEC_WINNT_AUTH_IDENTITY_EXW)
  268. SspAllocate(sizeof(SEC_WINNT_AUTH_IDENTITY_EXW));
  269. if (NULL != pAuthIdentity)
  270. {
  271. Status = LsaFunctions->CopyFromClientBuffer(
  272. NULL,
  273. sizeof(SEC_WINNT_AUTH_IDENTITY),
  274. pAuthIdentityEx,
  275. AuthorizationData
  276. );
  277. if (!NT_SUCCESS(Status))
  278. {
  279. DebugLog((DEB_ERROR,"Fail: LsaFunctions->CopyFromClientBuffer is 0x%lx\n", Status));
  280. goto Cleanup;
  281. }
  282. } else {
  283. Status = STATUS_NO_MEMORY;
  284. DebugLog((DEB_ERROR, "Fail: Alloc in SspCopyAuthData\n");
  285. goto Cleanup;
  286. }
  287. //
  288. // Do we have an EX version?
  289. //
  290. if (pAuthIdentityEx->Version == SEC_WINNT_AUTH_IDENTITY_VERSION)
  291. {
  292. Status = LsaFunctions->CopyFromClientBuffer(
  293. NULL,
  294. sizeof(SEC_WINNT_AUTH_IDENTITY_EXW),
  295. pAuthIdentityEx,
  296. AuthorizationData
  297. );
  298. if (!NT_SUCCESS(Status))
  299. {
  300. DebugLog((DEB_ERROR,"Fail: Error from LsaFunctions->CopyFromClientBuffer 0x%lx\n", Status));
  301. goto Cleanup;
  302. }
  303. pAuthIdentity = (PSEC_WINNT_AUTH_IDENTITY) &pAuthIdentityEx->User;
  304. CredSize = pAuthIdentityEx->Length;
  305. Offset = FIELD_OFFSET(SEC_WINNT_AUTH_IDENTITY_EXW, User);
  306. }
  307. else
  308. {
  309. pAuthIdentity = (PSEC_WINNT_AUTH_IDENTITY_W) pAuthIdentityEx;
  310. CredSize = sizeof(SEC_WINNT_AUTH_IDENTITY_W);
  311. }
  312. if ((pAuthIdentity->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI) != 0)
  313. {
  314. DoUnicode = FALSE;
  315. //
  316. // Turn off the marshalled flag because we don't support marshalling
  317. // with ansi.
  318. //
  319. pAuthIdentity->Flags &= ~SEC_WINNT_AUTH_IDENTITY_MARSHALLED;
  320. }
  321. else if ((pAuthIdentity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE) == 0)
  322. {
  323. Status = SEC_E_INVALID_TOKEN;
  324. SspPrint((SSP_CRITICAL,"SpAcquireCredentialsHandle, Error from pAuthIdentity->Flags is 0x%lx\n", pAuthIdentity->Flags));
  325. goto Cleanup;
  326. }
  327. //
  328. // For NTLM, we've got to verify that this is indeed a NULL session
  329. //
  330. if ((pAuthIdentity->UserLength == 0) &&
  331. (pAuthIdentity->DomainLength == 0) &&
  332. (pAuthIdentity->PasswordLength == 0) &&
  333. (pAuthIdentity->User != NULL) &&
  334. (pAuthIdentity->Domain != NULL) &&
  335. (pAuthIdentity->Password != NULL))
  336. {
  337. *NullSession = TRUE;
  338. }
  339. //
  340. // Copy over marshalled data
  341. //
  342. if((pAuthIdentity->Flags & SEC_WINNT_AUTH_IDENTITY_MARSHALLED) != 0 )
  343. {
  344. ULONG TmpCredentialSize;
  345. ULONG_PTR EndOfCreds;
  346. ULONG_PTR TmpUser;
  347. ULONG_PTR TmpDomain;
  348. ULONG_PTR TmpPassword;
  349. if( pAuthIdentity->UserLength > UNLEN ||
  350. pAuthIdentity->PasswordLength > PWLEN ||
  351. pAuthIdentity->DomainLength > DNS_MAX_NAME_LENGTH ) {
  352. SspPrint((SSP_CRITICAL,"Supplied credentials illegal length.\n"));
  353. Status = STATUS_INVALID_PARAMETER;
  354. goto Cleanup;
  355. }
  356. //
  357. // The callers can set the length of field to n chars, but they
  358. // will really occupy n+1 chars (null-terminator).
  359. //
  360. TmpCredentialSize = CredSize +
  361. ( pAuthIdentity->UserLength +
  362. pAuthIdentity->DomainLength +
  363. pAuthIdentity->PasswordLength +
  364. (((pAuthIdentity->User != NULL) ? 1 : 0) +
  365. ((pAuthIdentity->Domain != NULL) ? 1 : 0) +
  366. ((pAuthIdentity->Password != NULL) ? 1 : 0)) ) * sizeof(WCHAR);
  367. EndOfCreds = (ULONG_PTR) AuthorizationData + TmpCredentialSize;
  368. //
  369. // Verify that all the offsets are valid and no overflow will happen
  370. //
  371. TmpUser = (ULONG_PTR) pAuthIdentity->User;
  372. if ((TmpUser != NULL) &&
  373. ( (TmpUser < (ULONG_PTR) AuthorizationData) ||
  374. (TmpUser > EndOfCreds) ||
  375. ((TmpUser + (pAuthIdentity->UserLength) * sizeof(WCHAR)) > EndOfCreds ) ||
  376. ((TmpUser + (pAuthIdentity->UserLength * sizeof(WCHAR))) < TmpUser)))
  377. {
  378. SspPrint((SSP_CRITICAL,"Username in supplied credentials has invalid pointer or length.\n"));
  379. Status = STATUS_INVALID_PARAMETER;
  380. goto Cleanup;
  381. }
  382. TmpDomain = (ULONG_PTR) pAuthIdentity->Domain;
  383. if ((TmpDomain != NULL) &&
  384. ( (TmpDomain < (ULONG_PTR) AuthorizationData) ||
  385. (TmpDomain > EndOfCreds) ||
  386. ((TmpDomain + (pAuthIdentity->DomainLength) * sizeof(WCHAR)) > EndOfCreds ) ||
  387. ((TmpDomain + (pAuthIdentity->DomainLength * sizeof(WCHAR))) < TmpDomain)))
  388. {
  389. SspPrint((SSP_CRITICAL,"Domainname in supplied credentials has invalid pointer or length.\n"));
  390. Status = STATUS_INVALID_PARAMETER;
  391. goto Cleanup;
  392. }
  393. TmpPassword = (ULONG_PTR) pAuthIdentity->Password;
  394. if ((TmpPassword != NULL) &&
  395. ( (TmpPassword < (ULONG_PTR) AuthorizationData) ||
  396. (TmpPassword > EndOfCreds) ||
  397. ((TmpPassword + (pAuthIdentity->PasswordLength) * sizeof(WCHAR)) > EndOfCreds ) ||
  398. ((TmpPassword + (pAuthIdentity->PasswordLength * sizeof(WCHAR))) < TmpPassword)))
  399. {
  400. SspPrint((SSP_CRITICAL,"Password in supplied credentials has invalid pointer or length.\n"));
  401. Status = STATUS_INVALID_PARAMETER;
  402. goto Cleanup;
  403. }
  404. //
  405. // Allocate a chunk of memory for the credentials
  406. //
  407. TmpCredentials = (PSEC_WINNT_AUTH_IDENTITY_W) NtLmAllocate(TmpCredentialSize - Offset);
  408. if (TmpCredentials == NULL)
  409. {
  410. Status = STATUS_INSUFFICIENT_RESOURCES;
  411. goto Cleanup;
  412. }
  413. //
  414. // Copy the credentials from the client
  415. //
  416. Status = LsaFunctions->CopyFromClientBuffer(
  417. NULL,
  418. TmpCredentialSize - Offset,
  419. TmpCredentials,
  420. (PUCHAR) AuthorizationData + Offset
  421. );
  422. if (!NT_SUCCESS(Status))
  423. {
  424. SspPrint((SSP_CRITICAL,"Failed to copy whole auth identity\n"));
  425. goto Cleanup;
  426. }
  427. //
  428. // Now convert all the offsets to pointers.
  429. //
  430. if (TmpCredentials->User != NULL)
  431. {
  432. USHORT cbUser;
  433. TmpCredentials->User = (LPWSTR) RtlOffsetToPointer(
  434. TmpCredentials->User,
  435. (PUCHAR) TmpCredentials - (PUCHAR) AuthorizationData - Offset
  436. );
  437. ASSERT( (TmpCredentials->UserLength*sizeof(WCHAR)) <= 0xFFFF );
  438. cbUser = (USHORT)(TmpCredentials->UserLength * sizeof(WCHAR));
  439. UserName.Buffer = (PWSTR)NtLmAllocate( cbUser );
  440. if (UserName.Buffer == NULL ) {
  441. Status = STATUS_INSUFFICIENT_RESOURCES;
  442. goto Cleanup;
  443. }
  444. CopyMemory( UserName.Buffer, TmpCredentials->User, cbUser );
  445. UserName.Length = cbUser;
  446. UserName.MaximumLength = cbUser;
  447. }
  448. if (TmpCredentials->Domain != NULL)
  449. {
  450. USHORT cbDomain;
  451. TmpCredentials->Domain = (LPWSTR) RtlOffsetToPointer(
  452. TmpCredentials->Domain,
  453. (PUCHAR) TmpCredentials - (PUCHAR) AuthorizationData - Offset
  454. );
  455. ASSERT( (TmpCredentials->DomainLength*sizeof(WCHAR)) <= 0xFFFF );
  456. cbDomain = (USHORT)(TmpCredentials->DomainLength * sizeof(WCHAR));
  457. DomainName.Buffer = (PWSTR)NtLmAllocate( cbDomain );
  458. if (DomainName.Buffer == NULL ) {
  459. Status = STATUS_INSUFFICIENT_RESOURCES;
  460. goto Cleanup;
  461. }
  462. CopyMemory( DomainName.Buffer, TmpCredentials->Domain, cbDomain );
  463. DomainName.Length = cbDomain;
  464. DomainName.MaximumLength = cbDomain;
  465. }
  466. if (TmpCredentials->Password != NULL)
  467. {
  468. USHORT cbPassword;
  469. TmpCredentials->Password = (LPWSTR) RtlOffsetToPointer(
  470. TmpCredentials->Password,
  471. (PUCHAR) TmpCredentials - (PUCHAR) AuthorizationData - Offset
  472. );
  473. ASSERT( (TmpCredentials->PasswordLength*sizeof(WCHAR)) <= 0xFFFF );
  474. cbPassword = (USHORT)(TmpCredentials->PasswordLength * sizeof(WCHAR));
  475. Password.Buffer = (PWSTR)NtLmAllocate( cbPassword );
  476. if (Password.Buffer == NULL ) {
  477. ZeroMemory( TmpCredentials->Password, cbPassword );
  478. Status = STATUS_INSUFFICIENT_RESOURCES;
  479. goto Cleanup;
  480. }
  481. CopyMemory( Password.Buffer, TmpCredentials->Password, cbPassword );
  482. Password.Length = cbPassword;
  483. Password.MaximumLength = cbPassword;
  484. ZeroMemory( TmpCredentials->Password, cbPassword );
  485. }
  486. }
  487. //
  488. // Data was *not* marshalled, copy strings individually
  489. //
  490. else
  491. {
  492. if (pAuthIdentity->Password != NULL)
  493. {
  494. Status = SspCopyClientString(
  495. pAuthIdentity->Password,
  496. pAuthIdentity->PasswordLength,
  497. UnicodeString,
  498. &Password
  499. );
  500. if (!NT_SUCCESS(Status))
  501. {
  502. DebugLog((DEB_ERROR,"SpAcquireCredentialsHandle, Error from CopyClientString is 0x%lx\n", Status));
  503. goto Cleanup;
  504. }
  505. }
  506. if (pAuthIdentity->User != NULL)
  507. {
  508. Status = SspCopyClientString(
  509. pAuthIdentity->User,
  510. pAuthIdentity->UserLength,
  511. UnicodeString,
  512. &UserName
  513. );
  514. if (!NT_SUCCESS(Status))
  515. {
  516. DebugLog((DEB_ERROR, "SpAcquireCredentialsHandle, Error from CopyClientString is 0x%lx\n", Status));
  517. goto Cleanup;
  518. }
  519. }
  520. if (pAuthIdentity->Domain != NULL)
  521. {
  522. Status = SspCopyClientString(
  523. pAuthIdentity->Domain,
  524. pAuthIdentity->DomainLength,
  525. UnicodeString,
  526. &DomainName
  527. );
  528. if (!NT_SUCCESS(Status))
  529. {
  530. DebugLog((DEB_ERROR, "SpAcquireCredentialsHandle, Error from CopyClientString is 0x%lx\n", Status));
  531. goto Cleanup;
  532. }
  533. //
  534. // Make sure that the domain name length is not greater
  535. // than the allowed dns domain name
  536. //
  537. if (DomainName.Length > DNS_MAX_NAME_LENGTH * sizeof(WCHAR))
  538. {
  539. DebugLog((DEB_ERROR, "SpAcquireCredentialsHandle: Invalid supplied domain name %wZ\n",
  540. &DomainName ));
  541. Status = SEC_E_UNKNOWN_CREDENTIALS;
  542. goto Cleanup;
  543. }
  544. }
  545. }
  546. }
  547. }