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.

366 lines
11 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. // pTargetName -- name of the target server
  81. //
  82. // Returns: NTSTATUS code
  83. //
  84. // Notes: This event covers credentials obtained from credman
  85. //
  86. //--------------------------------------------------------------------------
  87. NTSTATUS
  88. KerbGenerateAuditForLogonUsingExplicitCreds(
  89. IN PKERB_LOGON_SESSION pCurrentUserLogonSession,
  90. IN PKERB_PRIMARY_CREDENTIAL pNewUserPrimaryCredentials,
  91. IN LPGUID pNewUserLogonGuid,
  92. IN PKERB_INTERNAL_NAME pTargetName
  93. )
  94. {
  95. NTSTATUS Status = STATUS_SUCCESS;
  96. GUID CurrentUserLogonGuid;
  97. LPGUID pCurrentUserLogonGuid = NULL;
  98. PKERB_TICKET_CACHE_ENTRY pTicketCacheEntry = NULL;
  99. UNICODE_STRING OurDomainName = { 0 };
  100. KERB_TIME CurrentUserStartTime = { 0 };
  101. KERBERR KerbErr = KDC_ERR_NONE;
  102. PUNICODE_STRING pTargetServerName = NULL;
  103. PUNICODE_STRING pTargetFullName = NULL;
  104. UNICODE_STRING TargetFullName = { 0 };
  105. //
  106. // calculate LogonGuid for current logged on user
  107. // we need the following 3 parameters for this:
  108. // -- client name
  109. // -- client realm
  110. // -- ticket start time
  111. //
  112. if ( !(pCurrentUserLogonSession->LogonSessionFlags &
  113. (KERB_LOGON_LOCAL_ONLY | KERB_LOGON_DEFERRED)) )
  114. {
  115. Status = KerbGetOurDomainName( &OurDomainName );
  116. ASSERT( NT_SUCCESS(Status) && L"KerbGenerateAuditForLogonUsingExplicitCreds: KerbGetOurDomainName failed" );
  117. if (NT_SUCCESS(Status))
  118. {
  119. //
  120. // find the cached ticket for the local machine from
  121. // the ticket cache of the current logon session.
  122. //
  123. pTicketCacheEntry =
  124. KerbLocateTicketCacheEntry(
  125. &pCurrentUserLogonSession->PrimaryCredentials.ServerTicketCache,
  126. KerbGlobalMitMachineServiceName,
  127. &OurDomainName
  128. );
  129. if ( pTicketCacheEntry )
  130. {
  131. //
  132. // Convert start time to the format we want.
  133. //
  134. KerbConvertLargeIntToGeneralizedTime(
  135. &CurrentUserStartTime,
  136. NULL,
  137. &pTicketCacheEntry->StartTime
  138. );
  139. //
  140. // Generate the logon GUID
  141. //
  142. Status = LsaIGetLogonGuid(
  143. &pCurrentUserLogonSession->PrimaryCredentials.UserName,
  144. &pCurrentUserLogonSession->PrimaryCredentials.DomainName,
  145. (PBYTE) &CurrentUserStartTime,
  146. sizeof(KERB_TIME),
  147. &CurrentUserLogonGuid
  148. );
  149. if (NT_SUCCESS(Status))
  150. {
  151. pCurrentUserLogonGuid = &CurrentUserLogonGuid;
  152. }
  153. }
  154. else
  155. {
  156. D_DebugLog((DEB_TRACE, "KerbGenerateAuditForLogonUsingExplicitCreds: could not locate ticket"));
  157. }
  158. }
  159. //
  160. // ISSUE-2002/03/28-kumarp : this should be inside the if stmt
  161. //
  162. KerbFreeString(&OurDomainName);
  163. }
  164. #if DBG
  165. else
  166. {
  167. //
  168. // KERB_LOGON_LOCAL_ONLY indicates a logon using non Kerberos package.
  169. // Logon GUID is supported only by Kerberos therefore its generation
  170. // is skipped.
  171. //
  172. if (pCurrentUserLogonSession->LogonSessionFlags & KERB_LOGON_LOCAL_ONLY)
  173. {
  174. D_DebugLog((DEB_TRACE,"KerbGenerateAuditForLogonUsingExplicitCreds: LogonSession %p has KERB_LOGON_LOCAL_ONLY\n", pCurrentUserLogonSession));
  175. }
  176. //
  177. // KERB_LOGON_DEFERRED indicates that a logon occurred using
  178. // cached credentials because kdc was not available. In this case,
  179. // we will not have a ticket for local machine therefore generation of
  180. // the logon GUID is skipped.
  181. //
  182. if (pCurrentUserLogonSession->LogonSessionFlags & KERB_LOGON_DEFERRED)
  183. {
  184. D_DebugLog((DEB_TRACE,"KerbGenerateAuditForLogonUsingExplicitCreds: LogonSession %p has KERB_LOGON_DEFERRED\n", pCurrentUserLogonSession));
  185. }
  186. }
  187. #endif
  188. //
  189. // convert pTargetName which is in kdc format to a UNICODE_STRING
  190. //
  191. KerbErr = KerbConvertKdcNameToString(
  192. &TargetFullName,
  193. pTargetName,
  194. NULL
  195. );
  196. if ( KerbErr == KDC_ERR_NONE )
  197. {
  198. pTargetFullName = &TargetFullName;
  199. }
  200. else
  201. {
  202. pTargetFullName = NULL;
  203. }
  204. //
  205. // extract the target computer name for known cases
  206. //
  207. if ( pTargetName->NameCount == 1 )
  208. {
  209. pTargetServerName = &pTargetName->Names[0];
  210. }
  211. else if ( pTargetName->NameCount >= 2 )
  212. {
  213. pTargetServerName = &pTargetName->Names[1];
  214. }
  215. else
  216. {
  217. pTargetServerName = NULL;
  218. }
  219. //
  220. // now generate the audit
  221. //
  222. Status = I_LsaIAuditLogonUsingExplicitCreds(
  223. EVENTLOG_AUDIT_SUCCESS,
  224. &pCurrentUserLogonSession->LogonId,
  225. pCurrentUserLogonGuid,
  226. (HANDLE) (ULONG_PTR) GetCurrentProcessId(),
  227. &pNewUserPrimaryCredentials->UserName,
  228. &pNewUserPrimaryCredentials->DomainName,
  229. pNewUserLogonGuid,
  230. pTargetServerName,
  231. pTargetFullName
  232. );
  233. if ( TargetFullName.Buffer != NULL )
  234. {
  235. MIDL_user_free( TargetFullName.Buffer );
  236. }
  237. return Status;
  238. }
  239. //+-------------------------------------------------------------------------
  240. //
  241. // Function: KerbAuditLogon
  242. //
  243. // Synopsis: Generate a successful logon audit event
  244. //
  245. // Arguments: LogonStatus -- overall logon status
  246. // LogonSubStatus -- sub-category within a failed logon status
  247. // pEncryptedTicket -- ticket used
  248. // pUserSid -- user's SID
  249. // pWorkstationName -- logon workstation
  250. // pLogonId -- logon LUID
  251. // pTransittedServices -- list of transitted services
  252. //
  253. // Returns: NTSTATUS code
  254. //
  255. // Notes: A new field (logon GUID) was added to this audit event.
  256. // In order to send this new field to LSA, we had two options:
  257. // 1) add new function (AuditLogonEx) to LSA dispatch table
  258. // 2) define a private (LsaI) function to do the job
  259. //
  260. // option#2 was chosen because the logon GUID is a Kerberos only
  261. // feature.
  262. //
  263. //--------------------------------------------------------------------------
  264. NTSTATUS
  265. KerbAuditLogon(
  266. IN NTSTATUS LogonStatus,
  267. IN NTSTATUS LogonSubStatus,
  268. IN PKERB_CONTEXT Context,
  269. IN PUNICODE_STRING pWorkstationName,
  270. IN PLUID pLogonId,
  271. IN PLSA_ADT_STRING_LIST pTransittedServices
  272. )
  273. {
  274. GUID LogonGuid = { 0 };
  275. NTSTATUS Status = STATUS_SUCCESS;
  276. KERB_TIME StartTime;
  277. //
  278. // Pull this eventually. I think we're OK, though.
  279. //
  280. if (Context == NULL)
  281. {
  282. DsysAssert(FALSE);
  283. goto Cleanup;
  284. }
  285. KerbConvertLargeIntToGeneralizedTime(
  286. &StartTime,
  287. NULL,
  288. &Context->StartTime
  289. );
  290. //
  291. // generate the logon GUID
  292. //
  293. Status = I_LsaIGetLogonGuid(
  294. &Context->ClientName,
  295. &Context->ClientRealm,
  296. (PBYTE) &StartTime,
  297. sizeof(KERB_TIME),
  298. &LogonGuid
  299. );
  300. if (!NT_SUCCESS(Status))
  301. {
  302. goto Cleanup;
  303. }
  304. //
  305. // generate successful logon audit. use the special
  306. // LsaIAuditKerberosLogon function so that we can pass in
  307. // the generated unique logon guid
  308. //
  309. I_LsaIAuditKerberosLogon(
  310. LogonStatus,
  311. LogonSubStatus,
  312. &Context->ClientName,
  313. &Context->ClientRealm,
  314. pWorkstationName,
  315. Context->UserSid,
  316. Network,
  317. &KerberosSource,
  318. pLogonId,
  319. &LogonGuid,
  320. pTransittedServices
  321. );
  322. Cleanup:
  323. if ( !NT_SUCCESS( Status ) )
  324. {
  325. D_DebugLog((DEB_ERROR,"KerbAuditLogon: failed: %x\n", Status ));
  326. }
  327. return Status;
  328. }