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.

359 lines
9.2 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1992 - 1999
  6. //
  7. // File: tktlogon.cxx
  8. //
  9. // Contents: Code for proxy logon for the Kerberos package
  10. //
  11. //
  12. // History: 15-March Created MikeSw
  13. //
  14. //------------------------------------------------------------------------
  15. #include <kerb.hxx>
  16. #include <kerbp.h>
  17. #ifdef RETAIL_LOG_SUPPORT
  18. static TCHAR THIS_FILE[]=TEXT(__FILE__);
  19. #endif
  20. //+-------------------------------------------------------------------------
  21. //
  22. // Function: KerbCreateTicketLogonSession
  23. //
  24. // Synopsis: Does all the work for a ticket logon, removing it from
  25. // LsaApLogonUserEx2
  26. //
  27. // Effects:
  28. //
  29. // Arguments: WorkstationTicket - ticket to workstation. The ticket
  30. // cache entry is pretty much empty except for
  31. // the ticket, and is not linked
  32. // ForwardedTgt - receives pointers into the Protocol
  33. // SubmitBuffer to the forwarded TGT.
  34. //
  35. // Requires:
  36. //
  37. // Returns:
  38. //
  39. // Notes:
  40. //
  41. //
  42. //--------------------------------------------------------------------------
  43. NTSTATUS
  44. KerbCreateTicketLogonSession(
  45. IN PVOID ProtocolSubmitBuffer,
  46. IN PVOID ClientBufferBase,
  47. IN ULONG SubmitBufferSize,
  48. IN SECURITY_LOGON_TYPE LogonType,
  49. OUT PKERB_LOGON_SESSION * NewLogonSession,
  50. OUT PLUID LogonId,
  51. OUT PKERB_TICKET_CACHE_ENTRY * WorkstationTicket,
  52. OUT PKERB_MESSAGE_BUFFER ForwardedTgt
  53. )
  54. {
  55. NTSTATUS Status = STATUS_SUCCESS;
  56. PKERB_TICKET_LOGON LogonInfo = NULL;
  57. PKERB_LOGON_SESSION LogonSession = NULL;
  58. KERB_KDC_REPLY KdcReply = {0};
  59. ULONG_PTR Offset;
  60. UNICODE_STRING EmptyString = {0};
  61. PKERB_TICKET Ticket = NULL;
  62. KERBERR KerbErr;
  63. *WorkstationTicket = NULL;
  64. ForwardedTgt->Buffer = NULL;
  65. ForwardedTgt->BufferSize = 0;
  66. //
  67. // Pull the interesting information out of the submit buffer
  68. //
  69. if (SubmitBufferSize < sizeof(KERB_TICKET_LOGON))
  70. {
  71. DebugLog((DEB_ERROR,"Submit buffer to logon too small: %d. %ws, line %d\n",SubmitBufferSize, THIS_FILE, __LINE__));
  72. Status = STATUS_INVALID_PARAMETER;
  73. goto Cleanup;
  74. }
  75. LogonInfo = (PKERB_TICKET_LOGON) ProtocolSubmitBuffer;
  76. DsysAssert((LogonInfo->MessageType == KerbTicketLogon) || (LogonInfo->MessageType == KerbTicketUnlockLogon));
  77. //
  78. // Relocate any pointers to be relative to 'LogonInfo'
  79. //
  80. Offset = ((PUCHAR) LogonInfo->ServiceTicket) - ((PUCHAR)ClientBufferBase);
  81. if ( (Offset >= SubmitBufferSize) ||
  82. (Offset + LogonInfo->ServiceTicketLength > SubmitBufferSize))
  83. {
  84. Status = STATUS_INVALID_PARAMETER;
  85. goto Cleanup;
  86. }
  87. LogonInfo->ServiceTicket = (PUCHAR) ProtocolSubmitBuffer + Offset;
  88. if (LogonInfo->TicketGrantingTicketLength != 0)
  89. {
  90. if (LogonInfo->TicketGrantingTicket == NULL)
  91. {
  92. Status = STATUS_INVALID_PARAMETER;
  93. goto Cleanup;
  94. }
  95. Offset = ((PUCHAR) LogonInfo->TicketGrantingTicket) - ((PUCHAR)ClientBufferBase);
  96. if ( (Offset >= SubmitBufferSize) ||
  97. (Offset + LogonInfo->TicketGrantingTicketLength > SubmitBufferSize))
  98. {
  99. Status = STATUS_INVALID_PARAMETER;
  100. goto Cleanup;
  101. }
  102. LogonInfo->TicketGrantingTicket = (PUCHAR) ProtocolSubmitBuffer + Offset;
  103. ForwardedTgt->BufferSize = LogonInfo->TicketGrantingTicketLength;
  104. ForwardedTgt->Buffer = LogonInfo->TicketGrantingTicket;
  105. }
  106. //
  107. // Allocate a locally unique ID for this logon session. We will
  108. // create it in the LSA just before returning.
  109. //
  110. Status = NtAllocateLocallyUniqueId( LogonId );
  111. if (!NT_SUCCESS(Status))
  112. {
  113. DebugLog((DEB_ERROR,"Failed to allocate locally unique ID: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  114. goto Cleanup;
  115. }
  116. //
  117. // Build a logon session to hold all this information
  118. //
  119. Status = KerbCreateLogonSession(
  120. LogonId,
  121. &EmptyString,
  122. &EmptyString,
  123. NULL, // no password
  124. NULL, // no old password
  125. 0, // no password options
  126. LogonType,
  127. &LogonSession
  128. );
  129. if (!NT_SUCCESS(Status))
  130. {
  131. goto Cleanup;
  132. }
  133. //
  134. // Unpack the supplied service ticket
  135. //
  136. KerbErr = KerbUnpackData(
  137. LogonInfo->ServiceTicket,
  138. LogonInfo->ServiceTicketLength,
  139. KERB_TICKET_PDU,
  140. (PVOID *) &Ticket
  141. );
  142. if (!KERB_SUCCESS(KerbErr))
  143. {
  144. DebugLog((DEB_ERROR,"Failed to unpack service ticket in ticket logon\n"));
  145. Status = KerbMapKerbError(KerbErr);
  146. goto Cleanup;
  147. }
  148. //
  149. // Build a ticket structure from the service ticket.
  150. //
  151. KdcReply.ticket = *Ticket;
  152. Status = KerbCacheTicket(
  153. NULL, // no ticket cache
  154. &KdcReply,
  155. NULL, // no kdc reply
  156. NULL, // no target name
  157. NULL, // no target realm
  158. 0, // no flags
  159. FALSE, // don't link entry
  160. WorkstationTicket
  161. );
  162. if (!NT_SUCCESS(Status))
  163. {
  164. goto Cleanup;
  165. }
  166. //
  167. // Return the new logon session.
  168. //
  169. *NewLogonSession = LogonSession;
  170. LogonSession = NULL;
  171. Cleanup:
  172. if (!NT_SUCCESS(Status))
  173. {
  174. if (LogonSession != NULL)
  175. {
  176. KerbReferenceLogonSessionByPointer(LogonSession, TRUE);
  177. KerbDereferenceLogonSession(LogonSession);
  178. }
  179. }
  180. if (Ticket != NULL)
  181. {
  182. KerbFreeData(KERB_TICKET_PDU, Ticket);
  183. }
  184. return(Status);
  185. }
  186. //+-------------------------------------------------------------------------
  187. //
  188. // Function: KerbExtractForwardedTgt
  189. //
  190. // Synopsis: Extracts a forwarded TGT from its encoded representation
  191. // and sticks it in the logon session ticket cache. This
  192. // also updates the user name & domain name in the
  193. // logon session, if they aren't present.
  194. //
  195. // Effects:
  196. //
  197. // Arguments:
  198. //
  199. // Requires:
  200. //
  201. // Returns:
  202. //
  203. // Notes:
  204. //
  205. //
  206. //--------------------------------------------------------------------------
  207. NTSTATUS
  208. KerbExtractForwardedTgt(
  209. IN PKERB_LOGON_SESSION LogonSession,
  210. IN PKERB_MESSAGE_BUFFER ForwardedTgt,
  211. IN PKERB_ENCRYPTED_TICKET WorkstationTicket
  212. )
  213. {
  214. PKERB_CRED KerbCred = NULL;
  215. PKERB_ENCRYPTED_CRED EncryptedCred = NULL;
  216. KERBERR KerbErr;
  217. NTSTATUS Status = STATUS_SUCCESS;
  218. D_DebugLog((DEB_TRACE, "Extracting a forwarded TGT\n"));
  219. KerbErr = KerbUnpackKerbCred(
  220. ForwardedTgt->Buffer,
  221. ForwardedTgt->BufferSize,
  222. &KerbCred
  223. );
  224. if (!KERB_SUCCESS(KerbErr))
  225. {
  226. DebugLog((DEB_WARN, "Failed to unpack kerb cred for forwaded tgt\n"));
  227. Status = KerbMapKerbError(KerbErr);
  228. goto Cleanup;
  229. }
  230. //
  231. // Now decrypt the encrypted part of the KerbCred.
  232. //
  233. KerbErr = KerbDecryptDataEx(
  234. &KerbCred->encrypted_part,
  235. &WorkstationTicket->key,
  236. KERB_CRED_SALT,
  237. (PULONG) &KerbCred->encrypted_part.cipher_text.length,
  238. KerbCred->encrypted_part.cipher_text.value
  239. );
  240. if (!KERB_SUCCESS(KerbErr))
  241. {
  242. DebugLog((DEB_ERROR,"Failed to decrypt KERB_CRED: 0x%x. %ws, line %d\n",KerbErr, THIS_FILE, __LINE__));
  243. if (KerbErr == KRB_ERR_GENERIC)
  244. {
  245. Status = KerbMapKerbError(KerbErr);
  246. goto Cleanup;
  247. }
  248. else
  249. {
  250. Status = STATUS_LOGON_FAILURE;
  251. //
  252. // MIT clients don't encrypt the encrypted part, so drop through
  253. //
  254. }
  255. }
  256. //
  257. // Now unpack the encrypted part.
  258. //
  259. KerbErr = KerbUnpackEncryptedCred(
  260. KerbCred->encrypted_part.cipher_text.value,
  261. KerbCred->encrypted_part.cipher_text.length,
  262. &EncryptedCred
  263. );
  264. if (!KERB_SUCCESS(KerbErr))
  265. {
  266. //
  267. // Use the old status if it is available.
  268. //
  269. if (NT_SUCCESS(Status))
  270. {
  271. Status = KerbMapKerbError(KerbErr);
  272. }
  273. DebugLog((DEB_WARN, "Failed to unpack encrypted cred\n"));
  274. goto Cleanup;
  275. }
  276. //
  277. // Now build a logon session.
  278. //
  279. Status = KerbCreateLogonSessionFromKerbCred(
  280. NULL,
  281. WorkstationTicket,
  282. KerbCred,
  283. EncryptedCred,
  284. &LogonSession
  285. );
  286. if (!NT_SUCCESS(Status))
  287. {
  288. DebugLog((DEB_ERROR,"Failed to create logon session from kerb cred: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  289. goto Cleanup;
  290. }
  291. Cleanup:
  292. if (EncryptedCred != NULL)
  293. {
  294. KerbFreeEncryptedCred(EncryptedCred);
  295. }
  296. if (KerbCred != NULL)
  297. {
  298. KerbFreeKerbCred(KerbCred);
  299. }
  300. return(Status);
  301. }