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.

358 lines
9.6 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. 0,
  127. FALSE, // no dups - this is a primary logon
  128. &LogonSession
  129. );
  130. if (!NT_SUCCESS(Status))
  131. {
  132. goto Cleanup;
  133. }
  134. //
  135. // Unpack the supplied service ticket
  136. //
  137. KerbErr = KerbUnpackData(
  138. LogonInfo->ServiceTicket,
  139. LogonInfo->ServiceTicketLength,
  140. KERB_TICKET_PDU,
  141. (PVOID *) &Ticket
  142. );
  143. if (!KERB_SUCCESS(KerbErr))
  144. {
  145. DebugLog((DEB_ERROR,"Failed to unpack service ticket in ticket logon\n"));
  146. Status = KerbMapKerbError(KerbErr);
  147. goto Cleanup;
  148. }
  149. //
  150. // Build a ticket structure from the service ticket.
  151. //
  152. KdcReply.ticket = *Ticket;
  153. Status = KerbCreateTicketCacheEntry(
  154. &KdcReply,
  155. NULL, // no kdc reply
  156. NULL, // no target name
  157. NULL, // no target realm
  158. 0, // no flags
  159. NULL, // no ticket cache
  160. NULL, // no credential key
  161. WorkstationTicket
  162. );
  163. if (!NT_SUCCESS(Status))
  164. {
  165. goto Cleanup;
  166. }
  167. //
  168. // Return the new logon session.
  169. //
  170. *NewLogonSession = LogonSession;
  171. LogonSession = NULL;
  172. Cleanup:
  173. if (!NT_SUCCESS(Status))
  174. {
  175. if (LogonSession != NULL)
  176. {
  177. KerbReferenceLogonSessionByPointer(LogonSession, TRUE);
  178. KerbDereferenceLogonSession(LogonSession);
  179. }
  180. }
  181. if (Ticket != NULL)
  182. {
  183. KerbFreeData(KERB_TICKET_PDU, Ticket);
  184. }
  185. return(Status);
  186. }
  187. //+-------------------------------------------------------------------------
  188. //
  189. // Function: KerbExtractForwardedTgt
  190. //
  191. // Synopsis: Extracts a forwarded TGT from its encoded representation
  192. // and sticks it in the logon session ticket cache. This
  193. // also updates the user name & domain name in the
  194. // logon session, if they aren't present.
  195. //
  196. // Effects:
  197. //
  198. // Arguments:
  199. //
  200. // Requires:
  201. //
  202. // Returns:
  203. //
  204. // Notes:
  205. //
  206. //
  207. //--------------------------------------------------------------------------
  208. NTSTATUS
  209. KerbExtractForwardedTgt(
  210. IN PKERB_LOGON_SESSION LogonSession,
  211. IN PKERB_MESSAGE_BUFFER ForwardedTgt,
  212. IN PKERB_ENCRYPTED_TICKET WorkstationTicket
  213. )
  214. {
  215. PKERB_CRED KerbCred = NULL;
  216. PKERB_ENCRYPTED_CRED EncryptedCred = NULL;
  217. KERBERR KerbErr;
  218. NTSTATUS Status = STATUS_SUCCESS;
  219. D_DebugLog((DEB_TRACE, "Extracting a forwarded TGT\n"));
  220. KerbErr = KerbUnpackKerbCred(
  221. ForwardedTgt->Buffer,
  222. ForwardedTgt->BufferSize,
  223. &KerbCred
  224. );
  225. if (!KERB_SUCCESS(KerbErr))
  226. {
  227. DebugLog((DEB_WARN, "Failed to unpack kerb cred for forwaded tgt\n"));
  228. Status = KerbMapKerbError(KerbErr);
  229. goto Cleanup;
  230. }
  231. //
  232. // Now decrypt the encrypted part of the KerbCred.
  233. //
  234. KerbErr = KerbDecryptDataEx(
  235. &KerbCred->encrypted_part,
  236. &WorkstationTicket->key,
  237. KERB_CRED_SALT,
  238. (PULONG) &KerbCred->encrypted_part.cipher_text.length,
  239. KerbCred->encrypted_part.cipher_text.value
  240. );
  241. if (!KERB_SUCCESS(KerbErr))
  242. {
  243. DebugLog((DEB_ERROR,"Failed to decrypt KERB_CRED: 0x%x. %ws, line %d\n",KerbErr, THIS_FILE, __LINE__));
  244. if (KerbErr == KRB_ERR_GENERIC)
  245. {
  246. Status = KerbMapKerbError(KerbErr);
  247. goto Cleanup;
  248. }
  249. else
  250. {
  251. Status = STATUS_LOGON_FAILURE;
  252. //
  253. // MIT clients don't encrypt the encrypted part, so drop through
  254. //
  255. }
  256. }
  257. //
  258. // Now unpack the encrypted part.
  259. //
  260. KerbErr = KerbUnpackEncryptedCred(
  261. KerbCred->encrypted_part.cipher_text.value,
  262. KerbCred->encrypted_part.cipher_text.length,
  263. &EncryptedCred
  264. );
  265. if (!KERB_SUCCESS(KerbErr))
  266. {
  267. //
  268. // Use the old status if it is available.
  269. //
  270. if (NT_SUCCESS(Status))
  271. {
  272. Status = KerbMapKerbError(KerbErr);
  273. }
  274. DebugLog((DEB_WARN, "Failed to unpack encrypted cred\n"));
  275. goto Cleanup;
  276. }
  277. //
  278. // Now build a logon session.
  279. //
  280. Status = KerbCreateLogonSessionFromKerbCred(
  281. NULL,
  282. WorkstationTicket,
  283. KerbCred,
  284. EncryptedCred,
  285. &LogonSession
  286. );
  287. if (!NT_SUCCESS(Status))
  288. {
  289. DebugLog((DEB_ERROR,"Failed to create logon session from kerb cred: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  290. goto Cleanup;
  291. }
  292. Cleanup:
  293. if (EncryptedCred != NULL)
  294. {
  295. KerbFreeEncryptedCred(EncryptedCred);
  296. }
  297. if (KerbCred != NULL)
  298. {
  299. KerbFreeKerbCred(KerbCred);
  300. }
  301. return(Status);
  302. }