static BOOL OpenUserRegistryPathPerProcessId(DWORD ProcessId, PHKEY hResult, REGSAM samDesired) { BOOL bRet = TRUE; HANDLE hProcessToken = NULL; HANDLE hProcess; BYTE Buffer[256]; DWORD Length = 0; UNICODE_STRING SidName; PTOKEN_USER TokUser; hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | READ_CONTROL, FALSE, ProcessId); if (!hProcess) { DPRINT1("Error: OpenProcess failed(0x%x)\n", GetLastError()); return FALSE; } if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hProcessToken)) { DPRINT1("Error: OpenProcessToken failed(0x%x)\n", GetLastError()); CloseHandle(hProcess); return FALSE; } if (!GetTokenInformation(hProcessToken, TokenUser, (PVOID)Buffer, sizeof(Buffer), &Length)) { DPRINT1("Error: GetTokenInformation failed(0x%x)\n",GetLastError()); CloseHandle(hProcessToken); CloseHandle(hProcess); return FALSE; } TokUser = ((PTOKEN_USER)Buffer)->User.Sid; if (!NT_SUCCESS(RtlConvertSidToUnicodeString(&SidName, TokUser, TRUE))) { DPRINT1("Error: RtlConvertSidToUnicodeString failed(0x%x)\n", GetLastError()); CloseHandle(hProcessToken); CloseHandle(hProcess); return FALSE; } /* * Might fail for LiveCD... Why ? Because only HKU\.DEFAULT exists. */ bRet = (RegOpenKeyExW(HKEY_USERS, SidName.Buffer, 0, samDesired, hResult) == ERROR_SUCCESS); RtlFreeUnicodeString(&SidName); CloseHandle(hProcessToken); CloseHandle(hProcess); return bRet; }
// Largely based off of undelete.c from sysinternals BOOLEAN GetUserSIDFromProcess(EPROCESS *pProcess, UNICODE_STRING *pusSID) { NTSTATUS status; ULONG RetLen; HANDLE hToken; PTOKEN_USER tokenInfoBuffer; PACCESS_TOKEN Token; Token = PsReferencePrimaryToken(pProcess); status = ObOpenObjectByPointer(Token, 0, NULL, TOKEN_QUERY, NULL, KernelMode, &hToken); ObDereferenceObject(Token); if(!NT_SUCCESS(status)) return FALSE; // Get the size of the sid. status = ZwQueryInformationToken(hToken, TokenUser, NULL, 0, &RetLen); if(status != STATUS_BUFFER_TOO_SMALL) { ZwClose(hToken); return FALSE; } tokenInfoBuffer = (PTOKEN_USER)ExAllocatePoolWithTag(NonPagedPool, RetLen, HELPER_POOL_TAG); if(tokenInfoBuffer) status = ZwQueryInformationToken(hToken, TokenUser, tokenInfoBuffer, RetLen, &RetLen); if(!NT_SUCCESS(status) || !tokenInfoBuffer ) { DBGOUT(("Error getting token information: %x\n", status)); if(tokenInfoBuffer) ExFreePool(tokenInfoBuffer); ZwClose(hToken); return FALSE; } ZwClose(hToken); status = RtlConvertSidToUnicodeString(pusSID, tokenInfoBuffer->User.Sid, FALSE); ExFreePool(tokenInfoBuffer); if(!NT_SUCCESS(status)) { DBGOUT(("Unable to convert SID to UNICODE: %x\n", status )); return FALSE; } return TRUE; }
/****************************************************************************** * ConvertSidToStringSidW [ADVAPI32.@] */ BOOL WINAPI ConvertSidToStringSidW(PSID sid, LPWSTR* stringSid) { NTSTATUS ret; UNICODE_STRING str = { 0, 0, NULL }; ret = RtlConvertSidToUnicodeString(&str, sid, TRUE); if (ret == STATUS_NO_MEMORY) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } /* FIXME: error codes for other ret values, * which don't exist in NTDLL yet */ *stringSid = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, (str.Length+1)*sizeof(WCHAR)); lstrcpynW(*stringSid, str.Buffer, str.Length + 1); RtlFreeUnicodeString(&str); return TRUE; }
FLT_POSTOP_CALLBACK_STATUS claimsmanPostOperation( _Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_opt_ PVOID CompletionContext, _In_ FLT_POST_OPERATION_FLAGS Flags ) /*++ Routine Description: This routine is the post-operation completion routine for this miniFilter. This is non-pageable because it may be called at DPC level. Arguments: Data - Pointer to the filter callbackData that is passed to us. FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing opaque handles to this filter, instance, its associated volume and file object. CompletionContext - The completion context set in the pre-operation routine. Flags - Denotes whether the completion is successful or is being drained. Return Value: The return value is the status of the operation. --*/ { UNREFERENCED_PARAMETER(Data); UNREFERENCED_PARAMETER(CompletionContext); UNREFERENCED_PARAMETER(Flags); NTSTATUS status; PFLT_FILE_NAME_INFORMATION nameInfo = NULL; PUNICODE_STRING fileName = NULL; PTOKEN_USER pTokenUser = NULL; UNICODE_STRING sidString; LARGE_INTEGER Timeout; Timeout.QuadPart = (LONGLONG)1 * 10 * 1000 * 1000; // If there is no client registered, bail out immediately! // If the event is from kernel, bail out immediately! // If the event check for existence of file, bail out immediately! if ( (ClaimsmanData.ClientPort == NULL) || (Data->RequestorMode == KernelMode) || (Data->IoStatus.Information == FILE_DOES_NOT_EXIST) || (Data->IoStatus.Information == FILE_EXISTS) ) { return FLT_POSTOP_FINISHED_PROCESSING; } // We got a log record, if there is a file object, get its name. if (FltObjects->FileObject != NULL) { status = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &nameInfo); } else { // Can't get a name when there's no file object status = STATUS_UNSUCCESSFUL; } if (NT_SUCCESS(status)) { FltParseFileNameInformation(nameInfo); fileName = &nameInfo->Name; // Produces way too much logging //PT_DBG_PRINT(PTDBG_TRACE_ROUTINES, // ("claimsman!claimsmanPostOperation: fileName=%wZ\n", fileName)); } else { // No point continuing because we obviously did not get a filename anyways return FLT_POSTOP_FINISHED_PROCESSING; } //The only IRP you can trust for user information is IRP_MJ_CREATE. Things //like write can be in arbitrary thread context, and even if the call works //you can get the wrong SID. status = SeQueryInformationToken(SeQuerySubjectContextToken(&(Data->Iopb->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext)), TokenUser, &pTokenUser); if (STATUS_SUCCESS == status && RtlValidSid(pTokenUser->User.Sid)) { // Interesting extension? if (ClaimsmanCheckExtension(&nameInfo->Extension)) { CLAIMSMAN_MESSAGE msg; status = RtlConvertSidToUnicodeString(&sidString, pTokenUser->User.Sid, TRUE); if (NT_SUCCESS(status)) { PT_DBG_PRINT(PTDBG_TRACE_ROUTINES, ("claimsman!claimsmanPostOperation: SID=%wZ\n", &sidString)); } else { // No point continuing because we obviously did not get a valid SID FltReleaseFileNameInformation(nameInfo); ExFreePool(pTokenUser); return FLT_POSTOP_FINISHED_PROCESSING; } if (ClaimsmanCheckUserIgnore(&sidString)) { // Ignored user! Bail out! FltReleaseFileNameInformation(nameInfo); ExFreePool(pTokenUser); RtlFreeUnicodeString(&sidString); return FLT_POSTOP_FINISHED_PROCESSING; } LONGLONG size; LONGLONG modified; getSizeModified(FltObjects->Instance, fileName, &size, &modified); InitializeMessage(&msg, &sidString, fileName, FltObjects->FileObject->ReadAccess, FltObjects->FileObject->WriteAccess, FltObjects->FileObject->DeleteAccess, size, modified, Data->IoStatus.Status); // Ready, send the message! // But only if there's a client connected if (ClaimsmanData.ClientPort != NULL) { FltSendMessage(ClaimsmanData.Filter, &ClaimsmanData.ClientPort, &msg, sizeof(msg), NULL, 0, &Timeout ); PT_DBG_PRINT(PTDBG_TRACE_ROUTINES, ("claimsman!claimsmanPostOperation: sent message=%d\n", status)); } else { PT_DBG_PRINT(PTDBG_TRACE_ROUTINES, ("claimsman!claimsmanPostOperation: no client connected!")); } RtlFreeUnicodeString(&sidString); } } FltReleaseFileNameInformation(nameInfo); if (pTokenUser != NULL) { ExFreePool(pTokenUser); } return FLT_POSTOP_FINISHED_PROCESSING; }
DWORD WINAPI PlayLogonSoundThread( IN LPVOID lpParameter) { BYTE TokenUserBuffer[256]; PTOKEN_USER pTokenUser = (TOKEN_USER*)TokenUserBuffer; ULONG Length; HKEY hKey; WCHAR wszBuffer[MAX_PATH] = {0}; WCHAR wszDest[MAX_PATH]; DWORD dwSize = sizeof(wszBuffer), dwType; SERVICE_STATUS_PROCESS Info; UNICODE_STRING SidString; NTSTATUS Status; ULONG Index = 0; SC_HANDLE hSCManager, hService; // // FIXME: Isn't it possible to *JUST* impersonate the current user // *AND* open its HKCU?? // /* Get SID of current user */ Status = NtQueryInformationToken((HANDLE)lpParameter, TokenUser, TokenUserBuffer, sizeof(TokenUserBuffer), &Length); if (!NT_SUCCESS(Status)) { ERR("NtQueryInformationToken failed: %x!\n", Status); return 0; } /* Convert SID to string */ RtlInitEmptyUnicodeString(&SidString, wszBuffer, sizeof(wszBuffer)); Status = RtlConvertSidToUnicodeString(&SidString, pTokenUser->User.Sid, FALSE); if (!NT_SUCCESS(Status)) { ERR("RtlConvertSidToUnicodeString failed: %x!\n", Status); return 0; } /* Build path to logon sound registry key. Note: We can't use HKCU here, because Winlogon is owned by SYSTEM user */ if (FAILED(StringCbCopyW(wszBuffer + SidString.Length/sizeof(WCHAR), sizeof(wszBuffer) - SidString.Length, L"\\AppEvents\\Schemes\\Apps\\.Default\\WindowsLogon\\.Current"))) { /* SID is too long. Should not happen. */ ERR("StringCbCopyW failed!\n"); return 0; } /* Open registry key and query sound path */ if (RegOpenKeyExW(HKEY_USERS, wszBuffer, 0, KEY_READ, &hKey) != ERROR_SUCCESS) { ERR("RegOpenKeyExW(%ls) failed!\n", wszBuffer); return 0; } if (RegQueryValueExW(hKey, NULL, NULL, &dwType, (LPBYTE)wszBuffer, &dwSize) != ERROR_SUCCESS || (dwType != REG_SZ && dwType != REG_EXPAND_SZ)) { ERR("RegQueryValueExW failed!\n"); RegCloseKey(hKey); return 0; } RegCloseKey(hKey); if (!wszBuffer[0]) { /* No sound has been set */ ERR("No sound has been set\n"); return 0; } /* Expand environment variables */ if (!ExpandEnvironmentStringsW(wszBuffer, wszDest, MAX_PATH)) { ERR("ExpandEnvironmentStringsW failed!\n"); return 0; } /* Open the service manager */ hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); if (!hSCManager) { ERR("OpenSCManager failed (%x)\n", GetLastError()); return 0; } /* Open the wdmaud service */ hService = OpenServiceW(hSCManager, L"wdmaud", GENERIC_READ); if (!hService) { /* The service is not installed */ TRACE("Failed to open wdmaud service (%x)\n", GetLastError()); CloseServiceHandle(hSCManager); return 0; } /* Wait for wdmaud to start */ do { if (!QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&Info, sizeof(SERVICE_STATUS_PROCESS), &dwSize)) { TRACE("QueryServiceStatusEx failed (%x)\n", GetLastError()); break; } if (Info.dwCurrentState == SERVICE_RUNNING) break; Sleep(1000); } while (Index++ < 20); CloseServiceHandle(hService); CloseServiceHandle(hSCManager); /* If wdmaud is not running exit */ if (Info.dwCurrentState != SERVICE_RUNNING) { WARN("wdmaud has not started!\n"); return 0; } /* Sound subsystem is running. Play logon sound. */ TRACE("Playing logon sound: %ls\n", wszDest); PlaySoundRoutine(wszDest, TRUE, SND_FILENAME); return 0; }
BOOL GetUserSidStringFromToken(HANDLE hToken, PUNICODE_STRING SidString) { PTOKEN_USER UserBuffer, nsb; ULONG Length; NTSTATUS Status; Length = 256; UserBuffer = LocalAlloc(LPTR, Length); if (UserBuffer == NULL) return FALSE; Status = NtQueryInformationToken(hToken, TokenUser, (PVOID)UserBuffer, Length, &Length); if (Status == STATUS_BUFFER_TOO_SMALL) { nsb = LocalReAlloc(UserBuffer, Length, LMEM_MOVEABLE); if (nsb == NULL) { LocalFree(UserBuffer); return FALSE; } UserBuffer = nsb; Status = NtQueryInformationToken(hToken, TokenUser, (PVOID)UserBuffer, Length, &Length); } if (!NT_SUCCESS (Status)) { LocalFree(UserBuffer); SetLastError(RtlNtStatusToDosError(Status)); return FALSE; } DPRINT("SidLength: %lu\n", RtlLengthSid (UserBuffer->User.Sid)); Status = RtlConvertSidToUnicodeString(SidString, UserBuffer->User.Sid, TRUE); LocalFree(UserBuffer); if (!NT_SUCCESS(Status)) { SetLastError(RtlNtStatusToDosError(Status)); return FALSE; } DPRINT("SidString.Length: %lu\n", SidString->Length); DPRINT("SidString.MaximumLength: %lu\n", SidString->MaximumLength); DPRINT("SidString: '%wZ'\n", SidString); return TRUE; }
/* Move a file handle to recycle bin * The pathname must be a valid NT file name generated using filename_to_nt_pathname() */ static NTSTATUS move_to_recycle_bin(HANDLE handle, WCHAR *pathname) { IO_STATUS_BLOCK status_block; NTSTATUS status; /* TODO: Handle the case when recycle bin does not exist (according to cygwin) */ /* TODO: Handle when the file is inside recycle bin */ WCHAR recyclepath[512]; UNICODE_STRING recycle; RtlInitEmptyUnicodeString(&recycle, recyclepath, sizeof(recyclepath)); /* Root directory, should look like "\??\C:\", 7 characters */ UNICODE_STRING root; RtlInitCountedUnicodeString(&root, pathname, sizeof(WCHAR) * 7); RtlAppendUnicodeStringToString(&recycle, &root); RtlAppendUnicodeToString(&recycle, L"$Recycle.Bin\\"); WCHAR renamepath[512]; UNICODE_STRING rename; RtlInitEmptyUnicodeString(&rename, renamepath, sizeof(renamepath)); RtlAppendUnicodeStringToString(&rename, &recycle); /* Append user sid */ { WCHAR buf[256]; UNICODE_STRING sid; RtlInitEmptyUnicodeString(&sid, buf, sizeof(buf)); RtlConvertSidToUnicodeString(&sid, get_user_sid(), FALSE); RtlAppendUnicodeStringToString(&rename, &sid); RtlAppendUnicodeToString(&rename, L"\\"); } /* Generate an unique file name by append file id and a hash of the pathname, * To allow unlinking multiple hard links of the same file */ RtlAppendUnicodeToString(&rename, L".flinux"); /* Append file id */ { FILE_INTERNAL_INFORMATION info; status = NtQueryInformationFile(handle, &status_block, &info, sizeof(info), FileInternalInformation); if (!NT_SUCCESS(status)) { log_error("NtQueryInformationFile(FileInternalInformation) failed, status: %x", status); return status; } RtlAppendInt64ToString(info.IndexNumber.QuadPart, 16, &rename); RtlAppendUnicodeToString(&rename, L"_"); } /* Append file path hash */ { UNICODE_STRING path; RtlInitUnicodeString(&path, pathname); ULONG hash; RtlHashUnicodeString(&path, FALSE, HASH_STRING_ALGORITHM_DEFAULT, &hash); RtlAppendIntegerToString(hash, 16, &rename); } /* Rename file */ char buf[512]; FILE_RENAME_INFORMATION *info = (FILE_RENAME_INFORMATION *)buf; info->ReplaceIfExists = FALSE; info->RootDirectory = NULL; info->FileNameLength = rename.Length; memcpy(info->FileName, rename.Buffer, rename.Length); status = NtSetInformationFile(handle, &status_block, info, sizeof(*info) + info->FileNameLength, FileRenameInformation); if (!NT_SUCCESS(status)) { log_error("NtSetInformationFile(FileRenameInformation) failed, status: %x", status); return status; } return STATUS_SUCCESS; }
int wmain(int argc, LPWSTR *argv) { SetOemPrintFLineLength(GetStdHandle(STD_ERROR_HANDLE)); DWORD (WINAPI *pConvertStringSidToSid)(LPCWSTR, PSID*) = (DWORD (WINAPI *)(LPCWSTR, PSID*)) GetProcAddress(GetModuleHandleA("advapi32.dll"), "ConvertStringSidToSidW"); if (argc < 2) { if (pConvertStringSidToSid != NULL) fputs("Utility to display basic account information about a user account given a user\r\n" "name or SID.\r\n" "\n" "Syntax:\r\n" "lookupacc [computer] S-n-n-n\r\n" "lookupacc [computer] [domain\\]username\r\n" "lookupacc [computer] username[@fqdn]\r\n", stderr); else fputs("Utility to display basic account information about a user account given a user\r\n" "name.\r\n" "\n" "Syntax:\r\n" "lookupacc [computer] [domain\\]username\r\n", stderr); return 1; } if (argc > 3) { fputs("Too many parameters.\r\n", stderr); return 1; } LPWSTR computername = NULL; if (argc > 2) { computername = argv[1]; argc--; argv++; } SID_NAME_USE SIDnameuse; WCHAR userdomain[260] = L""; DWORD userdomainsiz = sizeof userdomain; WCHAR username[260] = L""; DWORD usernamesiz = sizeof username; BYTE userSID[260] = { 0 }; DWORD userSIDsiz = sizeof userSID; LPWSTR wczUsername = L"(unknown)"; PSID sidLookup = NULL; UNICODE_STRING StringSID = { 0 }; BOOL bConversionResult = FALSE; if (pConvertStringSidToSid == NULL) bConversionResult = FALSE; else bConversionResult = pConvertStringSidToSid(argv[1], &sidLookup); if (bConversionResult) { if (!LookupAccountSid(computername, sidLookup, username, &usernamesiz, userdomain, &userdomainsiz, &SIDnameuse)) { win_perror(); return 1; } RtlInitUnicodeString(&StringSID, argv[1]); wczUsername = username; } else { if (!LookupAccountName(computername, argv[1], &userSID, &userSIDsiz, userdomain, &userdomainsiz, &SIDnameuse)) { win_perror(); return 1; } RtlConvertSidToUnicodeString(&StringSID, &userSID, TRUE); wczUsername = argv[1]; } LPSTR czSIDnameuse; switch (SIDnameuse) { case SidTypeUser: czSIDnameuse = "User"; break; case SidTypeGroup: czSIDnameuse = "Group"; break; case SidTypeDomain: czSIDnameuse = "Domain"; break; case SidTypeAlias: czSIDnameuse = "Alias"; break; case SidTypeWellKnownGroup: czSIDnameuse = "Well known group"; break; case SidTypeDeletedAccount: czSIDnameuse = "Deleted account"; break; case SidTypeInvalid: czSIDnameuse = "Invalid"; break; case SidTypeUnknown: czSIDnameuse = "Unknown"; break; case SidTypeComputer: czSIDnameuse = "Computer"; break; default: czSIDnameuse = "Not known"; break; } oem_printf(stdout, "Account type: %1%%n" "User domain: %2!ws!%%n" "User name: %3!ws!%%n" "SID: %4!.*ws!%%n", czSIDnameuse, userdomain, wczUsername, StringSID.Length, StringSID.Buffer); return 0; }