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.

332 lines
10 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 2001
  6. //
  7. // File: krbaudit.cxx
  8. //
  9. // Contents: Auditing routines
  10. //
  11. //
  12. // History: 27-April-2001 Created kumarp
  13. //
  14. //------------------------------------------------------------------------
  15. #include <kerb.hxx>
  16. #include <kerbp.h>
  17. #include <krbaudit.h>
  18. //+-------------------------------------------------------------------------
  19. //
  20. // Function: KerbGetLogonGuid
  21. //
  22. // Synopsis: Gets a unique ID based on certain fields in the ticket
  23. //
  24. // Arguments: pPrimaryCredentials -- primary credentials
  25. // pKdcReplyBody -- kdc reply structure
  26. // pLogonGuid -- returned GUID
  27. //
  28. // Returns: NTSTATUS code
  29. //
  30. // Notes: The generated GUID is MD5 hash of 3 fields:
  31. // -- client name
  32. // -- client realm
  33. // -- ticket start time
  34. //
  35. // All of these fields are available at client/kdc/server machine.
  36. // this allows us to generate the same unique ID on these machines
  37. // without having to introduce a new field in the ticket.
  38. // This GUID is used in audit events allowing us to correlate
  39. // events on three different machines.
  40. //
  41. //--------------------------------------------------------------------------
  42. NTSTATUS
  43. KerbGetLogonGuid(
  44. IN PKERB_PRIMARY_CREDENTIAL pPrimaryCredentials,
  45. IN PKERB_ENCRYPTED_KDC_REPLY pKdcReplyBody,
  46. OUT LPGUID pLogonGuid
  47. )
  48. {
  49. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  50. // ISSUE-2001/04/28-kumarp : use KERB_ENCRYPTED_KDC_REPLY_starttime_present
  51. //if ( KdcReplyBody->flags & KERB_ENCRYPTED_KDC_REPLY_starttime_present )
  52. if ( pKdcReplyBody && pPrimaryCredentials )
  53. {
  54. Status = LsaIGetLogonGuid(
  55. &pPrimaryCredentials->UserName,
  56. &pPrimaryCredentials->DomainName,
  57. (PBYTE) &pKdcReplyBody->starttime,
  58. sizeof(KERB_TIME),
  59. pLogonGuid
  60. );
  61. if (!NT_SUCCESS(Status))
  62. {
  63. RtlZeroMemory( pLogonGuid, sizeof(GUID) );
  64. }
  65. }
  66. return Status;
  67. }
  68. //+-------------------------------------------------------------------------
  69. //
  70. // Function: KerbGenerateAuditForLogonUsingExplicitCreds
  71. //
  72. // Synopsis: Generate an audit event to indicate that somebody logged on
  73. // by supplying explicit credentials.
  74. //
  75. // Arguments: pCurrentUserLogonSession -- logon session of the user
  76. // who supplied credentials of
  77. // another user
  78. // pNewUserPrimaryCredentials -- supplied primary credentials
  79. // pNewUserLogonGuid -- logon GUID for the new logon
  80. //
  81. // Returns: NTSTATUS code
  82. //
  83. // Notes: This event covers credentials obtain from credman
  84. //
  85. //--------------------------------------------------------------------------
  86. NTSTATUS
  87. KerbGenerateAuditForLogonUsingExplicitCreds(
  88. IN PKERB_LOGON_SESSION pCurrentUserLogonSession,
  89. IN PKERB_PRIMARY_CREDENTIAL pNewUserPrimaryCredentials,
  90. IN LPGUID pNewUserLogonGuid
  91. )
  92. {
  93. NTSTATUS Status = STATUS_SUCCESS;
  94. GUID CurrentUserLogonGuid;
  95. LPGUID pCurrentUserLogonGuid = NULL;
  96. PKERB_TICKET_CACHE_ENTRY pTicketCacheEntry = NULL;
  97. UNICODE_STRING OurDomainName = { 0 };
  98. KERB_TIME CurrentUserStartTime = { 0 };
  99. //
  100. // calculate LogonGuid for current logged on user
  101. // we need the following 3 parameters for this:
  102. // -- client name
  103. // -- client realm
  104. // -- ticket start time
  105. //
  106. if ( !(pCurrentUserLogonSession->LogonSessionFlags &
  107. (KERB_LOGON_LOCAL_ONLY | KERB_LOGON_DEFERRED)) )
  108. {
  109. Status = KerbGetOurDomainName( &OurDomainName );
  110. ASSERT( NT_SUCCESS(Status) && L"KerbGenerateAuditForLogonUsingExplicitCreds: KerbGetOurDomainName failed" );
  111. if (NT_SUCCESS(Status))
  112. {
  113. //
  114. // find the cached ticket for the local machine from
  115. // the ticket cache of the current logon session.
  116. //
  117. pTicketCacheEntry =
  118. KerbLocateTicketCacheEntry(
  119. &pCurrentUserLogonSession->PrimaryCredentials.ServerTicketCache,
  120. KerbGlobalMitMachineServiceName,
  121. &OurDomainName
  122. );
  123. if ( pTicketCacheEntry )
  124. {
  125. //
  126. // Convert start time to the format we want.
  127. //
  128. KerbConvertLargeIntToGeneralizedTime(
  129. &CurrentUserStartTime,
  130. NULL,
  131. &pTicketCacheEntry->StartTime
  132. );
  133. //
  134. // Generate the logon GUID
  135. //
  136. Status = LsaIGetLogonGuid(
  137. &pCurrentUserLogonSession->PrimaryCredentials.UserName,
  138. &pCurrentUserLogonSession->PrimaryCredentials.DomainName,
  139. (PBYTE) &CurrentUserStartTime,
  140. sizeof(KERB_TIME),
  141. &CurrentUserLogonGuid
  142. );
  143. if (NT_SUCCESS(Status))
  144. {
  145. pCurrentUserLogonGuid = &CurrentUserLogonGuid;
  146. }
  147. }
  148. else
  149. {
  150. D_DebugLog((DEB_TRACE, "KerbGenerateAuditForLogonUsingExplicitCreds: could not locate ticket"));
  151. }
  152. }
  153. KerbFreeString(&OurDomainName);
  154. }
  155. #if DBG
  156. else
  157. {
  158. //
  159. // KERB_LOGON_LOCAL_ONLY indicates a logon using non Kerberos package.
  160. // Logon GUID is supported only by Kerberos therefore its generation
  161. // is skipped.
  162. //
  163. if (pCurrentUserLogonSession->LogonSessionFlags & KERB_LOGON_LOCAL_ONLY)
  164. {
  165. D_DebugLog((DEB_TRACE,"KerbGenerateAuditForLogonUsingExplicitCreds: LogonSession %p has KERB_LOGON_LOCAL_ONLY\n", pCurrentUserLogonSession));
  166. }
  167. //
  168. // KERB_LOGON_DEFERRED indicates that a logon occurred using
  169. // cached credentials because kdc was not available. In this case,
  170. // we will not have a ticket for local machine therefore generation of
  171. // the logon GUID is skipped.
  172. //
  173. if (pCurrentUserLogonSession->LogonSessionFlags & KERB_LOGON_DEFERRED)
  174. {
  175. D_DebugLog((DEB_TRACE,"KerbGenerateAuditForLogonUsingExplicitCreds: LogonSession %p has KERB_LOGON_DEFERRED\n", pCurrentUserLogonSession));
  176. }
  177. }
  178. #endif
  179. //
  180. // now generate the audit
  181. //
  182. Status = I_LsaIAuditLogonUsingExplicitCreds(
  183. EVENTLOG_AUDIT_SUCCESS,
  184. NULL, // no user sid
  185. &pCurrentUserLogonSession->PrimaryCredentials.UserName,
  186. &pCurrentUserLogonSession->PrimaryCredentials.DomainName,
  187. &pCurrentUserLogonSession->LogonId,
  188. pCurrentUserLogonGuid,
  189. &pNewUserPrimaryCredentials->UserName,
  190. &pNewUserPrimaryCredentials->DomainName,
  191. pNewUserLogonGuid
  192. );
  193. return Status;
  194. }
  195. //+-------------------------------------------------------------------------
  196. //
  197. // Function: KerbAuditLogon
  198. //
  199. // Synopsis: Generate a successful logon audit event
  200. //
  201. // Arguments: LogonStatus -- overall logon status
  202. // LogonSubStatus -- sub-category within a failed logon status
  203. // pEncryptedTicket -- ticket used
  204. // pUserSid -- user's SID
  205. // pWorkstationName -- logon workstation
  206. // pLogonId -- logon LUID
  207. //
  208. // Returns: NTSTATUS code
  209. //
  210. // Notes: A new field (logon GUID) was added to this audit event.
  211. // In order to send this new field to LSA, we had two options:
  212. // 1) add new function (AuditLogonEx) to LSA dispatch table
  213. // 2) define a private (LsaI) function to do the job
  214. //
  215. // option#2 was chosen because the logon GUID is a Kerberos only
  216. // feature.
  217. //
  218. //--------------------------------------------------------------------------
  219. NTSTATUS
  220. KerbAuditLogon(
  221. IN NTSTATUS LogonStatus,
  222. IN NTSTATUS LogonSubStatus,
  223. IN PKERB_ENCRYPTED_TICKET pEncryptedTicket,
  224. IN PSID pUserSid,
  225. IN PUNICODE_STRING pWorkstationName,
  226. IN PLUID pLogonId
  227. )
  228. {
  229. GUID LogonGuid = { 0 };
  230. NTSTATUS Status = STATUS_SUCCESS;
  231. //PKERB_TIME pStartTime;
  232. UNICODE_STRING ClientRealm = { 0 };
  233. UNICODE_STRING ClientName = { 0 };
  234. KERBERR KerbErr = KDC_ERR_NONE;
  235. ULONG NameType;
  236. //
  237. // convert kerb style names to UNICODE_STRINGs
  238. //
  239. KerbErr = KerbConvertRealmToUnicodeString(
  240. &ClientRealm,
  241. &pEncryptedTicket->client_realm );
  242. if ( KerbErr == KDC_ERR_NONE )
  243. {
  244. KerbErr = KerbConvertPrincipalNameToString(
  245. &ClientName,
  246. &NameType,
  247. &pEncryptedTicket->client_name
  248. );
  249. }
  250. if ( KerbErr != KDC_ERR_NONE )
  251. {
  252. Status = KerbMapKerbError( KerbErr );
  253. goto Cleanup;
  254. }
  255. //
  256. // generate the logon GUID
  257. //
  258. Status = I_LsaIGetLogonGuid(
  259. &ClientName,
  260. &ClientRealm,
  261. (PBYTE)&pEncryptedTicket->KERB_ENCRYPTED_TICKET_starttime,
  262. sizeof(KERB_TIME),
  263. &LogonGuid
  264. );
  265. if (!NT_SUCCESS(Status))
  266. {
  267. goto Cleanup;
  268. }
  269. //
  270. // generate successful logon audit. use the special
  271. // LsaIAuditKerberosLogon function so that we can pass in
  272. // the generated unique logon guid
  273. //
  274. I_LsaIAuditKerberosLogon(
  275. LogonStatus,
  276. LogonSubStatus,
  277. &ClientName,
  278. &ClientRealm,
  279. pWorkstationName,
  280. pUserSid,
  281. Network,
  282. &KerberosSource,
  283. pLogonId,
  284. &LogonGuid
  285. );
  286. Cleanup:
  287. if (ClientRealm.Buffer != NULL)
  288. {
  289. KerbFreeString( &ClientRealm );
  290. }
  291. if (ClientName.Buffer != NULL)
  292. {
  293. KerbFreeString( &ClientName );
  294. }
  295. if ( !NT_SUCCESS( Status ) )
  296. {
  297. D_DebugLog((DEB_ERROR,"KerbAuditLogon: failed: %x\n", Status ));
  298. }
  299. return Status;
  300. }