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.

790 lines
20 KiB

  1. /*++
  2. Copyright (c) 1991-1994 Microsoft Corporation
  3. Module Name:
  4. logclear.c
  5. Abstract:
  6. Contains functions used to log an event indicating who cleared the log.
  7. This is only called after the security log has been cleared.
  8. Author:
  9. Dan Lafferty (danl) 01-July-1994
  10. Environment:
  11. User Mode -Win32
  12. Revision History:
  13. 01-July-1994 danl & robertre
  14. Created - Rob supplied the code which I fitted into the eventlog.
  15. --*/
  16. #include <nt.h>
  17. #include <ntrtl.h>
  18. #include <nturtl.h>
  19. #include <windows.h>
  20. #include <stdio.h>
  21. #include <msaudite.h>
  22. #include <eventp.h>
  23. #include <tstr.h>
  24. #include <winsock2.h>
  25. #define NUM_STRINGS 6
  26. //
  27. // LOCAL FUNCTION PROTOTYPES
  28. //
  29. BOOL
  30. GetUserInfo(
  31. IN HANDLE Token,
  32. OUT LPWSTR *UserName,
  33. OUT LPWSTR *DomainName,
  34. OUT LPWSTR *AuthenticationId,
  35. OUT PSID *UserSid
  36. );
  37. LPWSTR
  38. ElfpGetComputerName(
  39. VOID
  40. );
  41. LPWSTR
  42. GetNameFromIPAddress(
  43. LPWSTR pszComputerNameFromBinding);
  44. BOOL
  45. IsLocal(
  46. VOID
  47. );
  48. VOID
  49. ElfpGenerateLogClearedEvent(
  50. IELF_HANDLE LogHandle
  51. )
  52. /*++
  53. Routine Description:
  54. This function generates an event indicating that the log was cleared.
  55. Arguments:
  56. LogHandle -- This is a handle to the log that the event is to be placed in.
  57. It is intended that this function only be called when the SecurityLog
  58. has been cleared. So it is expected the LogHandle will always be
  59. a handle to the security log.
  60. Return Value:
  61. None -- Either it works or it doesn't. If it doesn't, there isn't much
  62. we can do about it.
  63. --*/
  64. {
  65. LPWSTR UserName = NULL;
  66. LPWSTR DomainName = NULL;
  67. LPWSTR AuthenticationId = NULL;
  68. LPWSTR ClientUserName = NULL;
  69. LPWSTR ClientDomainName = NULL;
  70. LPWSTR ClientAuthenticationId = NULL;
  71. PSID UserSid = NULL;
  72. PSID ClientSid = NULL;
  73. LPWSTR ComputerName = NULL;
  74. DWORD i;
  75. BOOL Result;
  76. HANDLE Token;
  77. PUNICODE_STRING StringPtrArray[NUM_STRINGS];
  78. UNICODE_STRING StringArray[NUM_STRINGS];
  79. NTSTATUS Status;
  80. LARGE_INTEGER Time;
  81. ULONG EventTime;
  82. ULONG LogHandleGrantedAccess;
  83. UNICODE_STRING ComputerNameU;
  84. DWORD dwStatus;
  85. //
  86. // Get information about the Eventlog service (i.e., LocalSystem)
  87. //
  88. Result = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &Token);
  89. if (!Result)
  90. {
  91. ELF_LOG1(ERROR,
  92. "ElfpGenerateLogClearedEvent: OpenProcessToken failed %d\n",
  93. GetLastError());
  94. return;
  95. }
  96. Result = GetUserInfo(Token,
  97. &UserName,
  98. &DomainName,
  99. &AuthenticationId,
  100. &UserSid);
  101. CloseHandle(Token);
  102. if (!Result)
  103. {
  104. ELF_LOG1(ERROR,
  105. "ElfpGenerateLogClearedEvent: GetUserInfo failed %d\n",
  106. GetLastError());
  107. return;
  108. }
  109. ELF_LOG3(TRACE,
  110. "ElfpGenerateLogClearedEvent: GetUserInfo returned: \n"
  111. "\tUserName = %ws,\n"
  112. "\tDomainName = %ws,\n"
  113. "\tAuthenticationId = %ws\n",
  114. UserName,
  115. DomainName,
  116. AuthenticationId);
  117. //
  118. // Now impersonate in order to get the client's information.
  119. // This call should never fail.
  120. //
  121. dwStatus = RpcImpersonateClient(NULL);
  122. if (dwStatus != RPC_S_OK)
  123. {
  124. ELF_LOG1(ERROR,
  125. "ElfpGenerateLogClearedEvent: RpcImpersonateClient failed %d\n",
  126. dwStatus);
  127. goto CleanExit;
  128. }
  129. Result = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &Token);
  130. if (Result)
  131. {
  132. Result = GetUserInfo(Token,
  133. &ClientUserName,
  134. &ClientDomainName,
  135. &ClientAuthenticationId,
  136. &ClientSid);
  137. CloseHandle(Token);
  138. if (!Result)
  139. {
  140. ELF_LOG1(ERROR,
  141. "ElfpGenerateLogClearedEvent: GetUserInfo (call 2) failed %d\n",
  142. GetLastError());
  143. goto CleanExit;
  144. }
  145. }
  146. else
  147. {
  148. //
  149. // We're impersonating here, so this should never
  150. // happen but just in case, use dashes
  151. //
  152. ELF_LOG1(ERROR,
  153. "ElfpGenerateLogClearedEvent: OpenThreadToken failed %d\n",
  154. GetLastError());
  155. ASSERT(FALSE);
  156. ClientUserName = L"-";
  157. ClientDomainName = L"-";
  158. ClientAuthenticationId = L"-";
  159. }
  160. ELF_LOG3(TRACE,
  161. "ElfpGenerateLogClearedEvent: GetUserInfo (call 2) returned: \n"
  162. "\tUserName = %ws,\n"
  163. "\tDomainName = %ws,\n"
  164. "\tAuthenticationId = %ws\n",
  165. ClientUserName,
  166. ClientDomainName,
  167. ClientAuthenticationId);
  168. RtlInitUnicodeString(&StringArray[0], UserName);
  169. RtlInitUnicodeString(&StringArray[1], DomainName);
  170. RtlInitUnicodeString(&StringArray[2], AuthenticationId);
  171. RtlInitUnicodeString(&StringArray[3], ClientUserName);
  172. RtlInitUnicodeString(&StringArray[4], ClientDomainName);
  173. RtlInitUnicodeString(&StringArray[5], ClientAuthenticationId);
  174. //
  175. // Create an array of pointers to UNICODE_STRINGs.
  176. //
  177. for (i = 0; i < NUM_STRINGS; i++)
  178. {
  179. StringPtrArray[i] = &StringArray[i];
  180. }
  181. //
  182. // Generate the time of the event. This is done on the client side
  183. // since that is where the event occurred.
  184. //
  185. NtQuerySystemTime(&Time);
  186. RtlTimeToSecondsSince1970(&Time, &EventTime);
  187. //
  188. // Generate the ComputerName of the client.
  189. // We have to do this in the client side since this call may be
  190. // remoted to another server and we would not necessarily have
  191. // the computer name there.
  192. //
  193. ComputerName = ElfpGetComputerName();
  194. if(ComputerName == NULL)
  195. goto CleanExit; // ElfpGetComputerName dumps error msg
  196. RtlInitUnicodeString(&ComputerNameU, ComputerName);
  197. //
  198. // Since all processes other than LSA are given read-only access
  199. // to the security log, we have to explicitly give the current
  200. // process the right to write the "Log cleared" event
  201. //
  202. LogHandleGrantedAccess = LogHandle->GrantedAccess;
  203. LogHandle->GrantedAccess |= ELF_LOGFILE_WRITE;
  204. Status = ElfrReportEventW (
  205. LogHandle, // Log Handle
  206. EventTime, // Time
  207. EVENTLOG_AUDIT_SUCCESS, // Event Type
  208. (USHORT)SE_CATEGID_SYSTEM, // Event Category
  209. SE_AUDITID_AUDIT_LOG_CLEARED, // EventID
  210. NUM_STRINGS, // NumStrings
  211. 0, // DataSize
  212. &ComputerNameU, // ComputerNameU
  213. UserSid, // UserSid
  214. StringPtrArray, // *Strings
  215. NULL, // Data
  216. 0, // Flags
  217. NULL, // RecordNumber
  218. NULL); // TimeWritten
  219. LogHandle->GrantedAccess = LogHandleGrantedAccess;
  220. CleanExit:
  221. //
  222. // We only come down this path if we know for sure that these
  223. // first three have been allocated.
  224. //
  225. ElfpFreeBuffer(UserName);
  226. ElfpFreeBuffer(DomainName);
  227. ElfpFreeBuffer(AuthenticationId);
  228. ElfpFreeBuffer(UserSid);
  229. ElfpFreeBuffer(ClientUserName);
  230. ElfpFreeBuffer(ClientDomainName);
  231. ElfpFreeBuffer(ClientAuthenticationId);
  232. ElfpFreeBuffer(ClientSid);
  233. ElfpFreeBuffer(ComputerName);
  234. //
  235. // Stop impersonating
  236. //
  237. dwStatus = RpcRevertToSelf();
  238. if (dwStatus != RPC_S_OK)
  239. {
  240. ELF_LOG1(ERROR,
  241. "ElfpGenerateLogClearedEvent: RpcRevertToSelf failed %d\n",
  242. GetLastError());
  243. }
  244. }
  245. BOOL
  246. GetUserInfo(
  247. IN HANDLE Token,
  248. OUT LPWSTR *UserName,
  249. OUT LPWSTR *DomainName,
  250. OUT LPWSTR *AuthenticationId,
  251. OUT PSID *UserSid
  252. )
  253. /*++
  254. Routine Description:
  255. This function gathers information about the user identified with the
  256. token.
  257. Arguments:
  258. Token - This token identifies the entity for which we are gathering
  259. information.
  260. UserName - This is the entity's user name.
  261. DomainName - This is the entity's domain name.
  262. AuthenticationId - This is the entity's Authentication ID.
  263. UserSid - This is the entity's SID.
  264. NOTE:
  265. Memory is allocated by this routine for UserName, DomainName,
  266. AuthenticationId, and UserSid. It is the caller's responsibility to
  267. free this memory.
  268. Return Value:
  269. TRUE - If the operation was successful. It is possible that
  270. UserSid did not get allocated in the successful case. Therefore,
  271. the caller should test prior to freeing.
  272. FALSE - If unsuccessful. No memory is allocated in this case.
  273. --*/
  274. {
  275. PTOKEN_USER Buffer = NULL;
  276. LPWSTR Domain = NULL;
  277. LPWSTR AccountName = NULL;
  278. SID_NAME_USE Use;
  279. BOOL Result;
  280. DWORD RequiredLength;
  281. DWORD AccountNameSize;
  282. DWORD DomainNameSize;
  283. TOKEN_STATISTICS Statistics;
  284. WCHAR LogonIdString[256];
  285. DWORD Status = ERROR_SUCCESS;
  286. *UserSid = NULL;
  287. Result = GetTokenInformation(Token, TokenUser, NULL, 0, &RequiredLength);
  288. if (!Result)
  289. {
  290. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  291. {
  292. ELF_LOG1(TRACE,
  293. "GetUserInfo: GetTokenInformation needs %d bytes\n",
  294. RequiredLength);
  295. Buffer = ElfpAllocateBuffer(RequiredLength);
  296. if (Buffer == NULL)
  297. {
  298. ELF_LOG0(ERROR,
  299. "GetUserInfo: Unable to allocate memory for token\n");
  300. return FALSE;
  301. }
  302. Result = GetTokenInformation(Token,
  303. TokenUser,
  304. Buffer,
  305. RequiredLength,
  306. &RequiredLength);
  307. if (!Result)
  308. {
  309. ELF_LOG1(ERROR,
  310. "GetUserInfo: GetTokenInformation (call 2) failed %d\n",
  311. GetLastError());
  312. return FALSE;
  313. }
  314. }
  315. else
  316. {
  317. ELF_LOG1(ERROR,
  318. "GetUserInfo: GetTokenInformation (call 1) failed %d\n",
  319. GetLastError());
  320. return FALSE;
  321. }
  322. }
  323. AccountNameSize = 0;
  324. DomainNameSize = 0;
  325. Result = LookupAccountSidW(L"",
  326. Buffer->User.Sid,
  327. NULL,
  328. &AccountNameSize,
  329. NULL,
  330. &DomainNameSize,
  331. &Use);
  332. if (!Result)
  333. {
  334. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  335. {
  336. AccountName = ElfpAllocateBuffer((AccountNameSize + 1) * sizeof(WCHAR));
  337. Domain = ElfpAllocateBuffer((DomainNameSize + 1) * sizeof(WCHAR));
  338. if (AccountName == NULL)
  339. {
  340. ELF_LOG1(ERROR,
  341. "GetUserInfo: Unable to allocate %d bytes for AccountName\n",
  342. AccountNameSize);
  343. goto ErrorCleanup;
  344. }
  345. if (Domain == NULL)
  346. {
  347. ELF_LOG1(ERROR,
  348. "GetUserInfo: Unable to allocate %d bytes for Domain\n",
  349. DomainNameSize);
  350. goto ErrorCleanup;
  351. }
  352. Result = LookupAccountSidW(L"",
  353. Buffer->User.Sid,
  354. AccountName,
  355. &AccountNameSize,
  356. Domain,
  357. &DomainNameSize,
  358. &Use
  359. );
  360. if (!Result)
  361. {
  362. ELF_LOG1(ERROR,
  363. "GetUserInfo: LookupAccountSid (call 2) failed %d\n",
  364. GetLastError());
  365. goto ErrorCleanup;
  366. }
  367. }
  368. else
  369. {
  370. ELF_LOG1(ERROR,
  371. "GetUserInfo: LookupAccountsid (call 1) failed %d\n",
  372. GetLastError());
  373. goto ErrorCleanup;
  374. }
  375. }
  376. else
  377. {
  378. ELF_LOG0(ERROR,
  379. "GetUserInfo: LookupAccountSid succeeded unexpectedly\n");
  380. goto ErrorCleanup;
  381. }
  382. ELF_LOG2(TRACE,
  383. "GetUserInfo: Name = %ws\\%ws\n",
  384. Domain,
  385. AccountName);
  386. Result = GetTokenInformation(Token,
  387. TokenStatistics,
  388. &Statistics,
  389. sizeof(Statistics),
  390. &RequiredLength);
  391. if (!Result)
  392. {
  393. ELF_LOG1(ERROR,
  394. "GetUserInfo: GetTokenInformation (call 3) failed %d\n",
  395. GetLastError());
  396. goto ErrorCleanup;
  397. }
  398. swprintf(LogonIdString,
  399. L"(0x%X,0x%X)",
  400. Statistics.AuthenticationId.HighPart,
  401. Statistics.AuthenticationId.LowPart);
  402. ELF_LOG1(TRACE,
  403. "GetUserInfo: LogonIdString = %ws\n",
  404. LogonIdString);
  405. *AuthenticationId = ElfpAllocateBuffer(WCSSIZE(LogonIdString));
  406. if (*AuthenticationId == NULL)
  407. {
  408. ELF_LOG0(ERROR,
  409. "GetUserInfo: Unable to allocate memory for AuthenticationId\n");
  410. goto ErrorCleanup;
  411. }
  412. wcscpy(*AuthenticationId, LogonIdString);
  413. //
  414. // Return accumulated information
  415. //
  416. *UserSid = ElfpAllocateBuffer(GetLengthSid(Buffer->User.Sid));
  417. if (*UserSid == NULL)
  418. {
  419. ELF_LOG0(ERROR,
  420. "GetUserInfo: Unable to allocate memory for UserSid\n");
  421. goto ErrorCleanup;
  422. }
  423. Result = CopySid(GetLengthSid(Buffer->User.Sid),
  424. *UserSid,
  425. Buffer->User.Sid);
  426. ElfpFreeBuffer(Buffer);
  427. *DomainName = Domain;
  428. *UserName = AccountName;
  429. return TRUE;
  430. ErrorCleanup:
  431. ElfpFreeBuffer(Buffer);
  432. ElfpFreeBuffer(Domain);
  433. ElfpFreeBuffer(AccountName);
  434. ElfpFreeBuffer(*UserSid);
  435. ElfpFreeBuffer(*AuthenticationId);
  436. return FALSE;
  437. }
  438. LPWSTR
  439. GetNameFromIPAddress(
  440. LPWSTR pszComputerNameFromBinding)
  441. /*++
  442. Routine Description:
  443. Examines a string and determines if it looks like an ip address. If it
  444. does, then it converts it to a fqdn
  445. Arguments:
  446. Machine name: Could be xxx.xxx.xxx.xxx or anything else!
  447. Return Value:
  448. If successful, returns a fully qualified domain name which the caller
  449. will free. Returns NULL if there are any problems.
  450. --*/
  451. {
  452. LPWSTR pComputerName = NULL;
  453. DWORD dwAddr;
  454. char cName[17]; // should be plenty of room
  455. size_t NumConv;
  456. HOSTENT FAR * pEnt;
  457. DWORD dwSize;
  458. WORD wVersionRequested;
  459. WSADATA wsaData;
  460. int error;
  461. NumConv = wcstombs(cName, pszComputerNameFromBinding, 16);
  462. if(NumConv == -1 || NumConv == 0)
  463. return NULL;
  464. // convert the string into a network order dword representation
  465. dwAddr = inet_addr(cName);
  466. if(dwAddr == INADDR_NONE)
  467. return NULL;
  468. // initialize sockets.
  469. wVersionRequested = MAKEWORD( 2, 2 );
  470. error = WSAStartup( wVersionRequested, &wsaData );
  471. if(error != 0)
  472. {
  473. ELF_LOG1(TRACE,
  474. "GetNameFromIPAddress: failed to initialize sockets, error = 0x%x\n", error);
  475. return NULL;
  476. }
  477. pEnt = gethostbyaddr((char FAR *)&dwAddr, 4, PF_INET);
  478. if(pEnt == NULL || pEnt->h_name == NULL)
  479. {
  480. ELF_LOG1(TRACE,
  481. "GetNameFromIPAddress: failed gethostbyaddr, error = 0x%x\n",
  482. WSAGetLastError());
  483. WSACleanup();
  484. return NULL;
  485. }
  486. dwSize = strlen(pEnt->h_name) + 1 ;
  487. pComputerName = ElfpAllocateBuffer(2*dwSize);
  488. if(pComputerName == NULL)
  489. {
  490. ELF_LOG0(ERROR,
  491. "GetNameFromIPAddress: failed trying to allocate memory\n");
  492. WSACleanup();
  493. return NULL;
  494. }
  495. pComputerName[0] = 0;
  496. mbstowcs(pComputerName, pEnt->h_name, dwSize);
  497. WSACleanup();
  498. return pComputerName;
  499. }
  500. BOOL
  501. IsLocal(
  502. VOID
  503. )
  504. /*++
  505. Routine Description:
  506. Determines if the caller is local.
  507. Arguments:
  508. NONE
  509. Return Value:
  510. TRUE if definately local.
  511. --*/
  512. {
  513. UINT LocalFlag;
  514. RPC_STATUS RpcStatus;
  515. RpcStatus = I_RpcBindingIsClientLocal(0, &LocalFlag);
  516. if( RpcStatus != RPC_S_OK )
  517. {
  518. ELF_LOG1(ERROR,
  519. "IsLocal: I_RpcBindingIsClientLocal failed %d\n",
  520. RpcStatus);
  521. return FALSE;
  522. }
  523. if(LocalFlag == 0)
  524. return FALSE;
  525. else
  526. return TRUE;
  527. }
  528. LPWSTR
  529. ElfpGetComputerName(
  530. VOID
  531. )
  532. /*++
  533. Routine Description:
  534. This routine gets the LPWSTR name of the computer.
  535. Arguments:
  536. NONE
  537. Return Value:
  538. Returns a pointer to the computer name, or a NULL. Note that the caller
  539. is expected to free this via
  540. --*/
  541. {
  542. RPC_STATUS RpcStatus;
  543. handle_t hServerBinding = NULL;
  544. LPWSTR pszBinding = NULL;
  545. LPWSTR pszComputerNameFromBinding = NULL;
  546. LPWSTR pszComputerName = NULL;
  547. DWORD dwSize;
  548. BOOL bOK;
  549. // Check if the connection is local. If it is, then just
  550. // call GetComputerName
  551. if(IsLocal())
  552. {
  553. dwSize = MAX_COMPUTERNAME_LENGTH + 1 ;
  554. pszComputerName = ElfpAllocateBuffer(2*dwSize);
  555. if(pszComputerName == NULL)
  556. {
  557. ELF_LOG0(ERROR,
  558. "ElfpGetComputerName: failed trying to allocate memory\n");
  559. return NULL;
  560. }
  561. bOK = GetComputerNameW(pszComputerName, &dwSize);
  562. if(bOK == FALSE)
  563. {
  564. ElfpFreeBuffer(pszComputerName);
  565. ELF_LOG1(ERROR,
  566. "ElfpGetComputerName: failed calling GetComputerNameW, last error 0x%x\n",
  567. GetLastError());
  568. return NULL;
  569. }
  570. else
  571. return pszComputerName;
  572. }
  573. RpcStatus = RpcBindingServerFromClient( NULL, &hServerBinding );
  574. if( RpcStatus != RPC_S_OK )
  575. {
  576. ELF_LOG1(ERROR,
  577. "ElfpGetComputerName: RpcBindingServerFromClient failed %d\n",
  578. RpcStatus);
  579. return NULL;
  580. }
  581. // This gets us something like "ncacn_np:xxx.xxx.xxx.xxx" or
  582. // "ncacn_np:localMachine"
  583. RpcStatus = RpcBindingToStringBinding( hServerBinding, &pszBinding );
  584. if( RpcStatus != ERROR_SUCCESS )
  585. {
  586. ELF_LOG1(ERROR,
  587. "ElfpGetComputerName: RpcBindingToStringBinding failed %d\n",
  588. RpcStatus);
  589. goto CleanExitGetCompName;
  590. }
  591. // Acquire just the network address. That will be something like
  592. // "xxx.xxx.xxx.xxx" or "mymachine"
  593. RpcStatus = RpcStringBindingParse( pszBinding,
  594. NULL,
  595. NULL,
  596. &pszComputerNameFromBinding,
  597. NULL,
  598. NULL );
  599. if( RpcStatus != ERROR_SUCCESS || pszComputerNameFromBinding == NULL)
  600. {
  601. ELF_LOG1(ERROR,
  602. "ElfpGetComputerName: RpcStringBindingParse failed %d\n",
  603. RpcStatus);
  604. goto CleanExitGetCompName;
  605. }
  606. // sometimes the name is an ip address. If it is, then the following determines
  607. // that and returns the right string.
  608. pszComputerName = GetNameFromIPAddress(pszComputerNameFromBinding);
  609. if(pszComputerName == NULL)
  610. {
  611. dwSize = wcslen(pszComputerNameFromBinding) + 1;
  612. pszComputerName = ElfpAllocateBuffer(2*dwSize);
  613. if(pszComputerName == NULL)
  614. {
  615. ELF_LOG0(ERROR,
  616. "ElfpGetComputerName: failed trying to allocate memory\n");
  617. }
  618. else
  619. wcscpy(pszComputerName, pszComputerNameFromBinding);
  620. }
  621. CleanExitGetCompName:
  622. if(hServerBinding)
  623. RpcStatus = RpcBindingFree(&hServerBinding);
  624. if(pszBinding)
  625. RpcStatus = RpcStringFree(&pszBinding);
  626. if(pszComputerNameFromBinding)
  627. RpcStatus = RpcStringFree(&pszComputerNameFromBinding);
  628. return pszComputerName;
  629. }