I know how to get the SID for the current user. Conceptually the answer is:
Use OpenThreadToken (or OpenProcessToken) to get the security TOKEN of the running user
use GetTokenInformation to get the TOKEN_USER structure
and then TOKEN_USER.Sid is the Sid
So in pseudocode:
String GetCurrentUserSid()
{
// Get the calling thread's access token.
TOKEN hToken;
if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, true, out hToken)
{
if (GetLastError() != ERROR_NO_TOKEN)
RaiseLastWin32Error();
// No thread token exists, try again against the process token
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, out hToken)
RaiseLastWin32Error();
}
try
{
// Obtain the size of the user information in the token.
DWORD cbReturned;
GetTokenInformation(hToken, TokenUser, nil, 0, out cbReturned);
//Allocate memory and try again for real
TOKEN_USER* tiUser = GetMemory(cbReturned);
if (!GetTokenInformation(hToken, TokenUser, tiUser, cbReturned, out cbReturned))
RaiseLastWin32Error();
}
finally
{
CloseHandle(hToken);
}
//Convert the structure to a string
return SidToString(tiUser.User.Sid);
}
But how to do it for the current machine?
String GetCurrentMachineSid()
{
// TODO: Ask Stackoverflow
}
Bonus Reading
The Machine SID Duplication Myth (and Why Sysprep Matters) 🕗
Machine SIDs and Domain SIDs 🕗
How to find SID of computer 🕗
You can see the machine SID on your computer by running Sysinternals
PsGetSid with no parameters
so i simply look under debugger how PsGetSid do this.
it get SID from POLICY_ACCOUNT_DOMAIN_INFO - DomainSid : Pointer to the SID of the account domain
code can be next
LSA_HANDLE PolicyHandle;
LSA_OBJECT_ATTRIBUTES ObjectAttributes = { sizeof(ObjectAttributes) };
NTSTATUS status = LsaOpenPolicy(0, &ObjectAttributes, POLICY_VIEW_LOCAL_INFORMATION, &PolicyHandle);
if (0 <= status)
{
POLICY_ACCOUNT_DOMAIN_INFO* ppadi;
status = LsaQueryInformationPolicy(PolicyHandle, PolicyAccountDomainInformation, (void**)&ppadi);
if (0 <= status)
{
PWSTR szSid;
BOOL b = ConvertSidToStringSidW(ppadi->DomainSid, &szSid);
LsaFreeMemory(ppadi);
if (b)
{
DbgPrint("%S\n", szSid);
LocalFree(szSid);
}
}
LsaClose(PolicyHandle);
}
Related
I have a question about the KMDF Ramdisk sample of Microsoft.
How do create more than one ramdisk device? How will the PnP manager know to call EvtDeviceAdd and can I control how many times it is called?
WdfDeviceCreate() is used to create ramdisk device in RamDiskEvtDeviceAdd(), but I can not install more than one instance of this ramdisk driver.
NTSTATUS
RamDiskEvtDeviceAdd(
IN WDFDRIVER Driver,
IN PWDFDEVICE_INIT DeviceInit
) {
WDF_OBJECT_ATTRIBUTES deviceAttributes;
NTSTATUS status;
WDFDEVICE device;
WDF_OBJECT_ATTRIBUTES queueAttributes;
WDF_IO_QUEUE_CONFIG ioQueueConfig;
PDEVICE_EXTENSION pDeviceExtension;
PQUEUE_EXTENSION pQueueContext = NULL;
WDFQUEUE queue;
DECLARE_CONST_UNICODE_STRING(ntDeviceName, NT_DEVICE_NAME);
DECLARE_CONST_UNICODE_STRING(MY_SDDL_STRING, L"D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;WD)(A;;GA;;;RC)");
PAGED_CODE();
UNREFERENCED_PARAMETER(Driver);
// Set name
status = WdfDeviceInitAssignName(DeviceInit, &ntDeviceName);
if (!NT_SUCCESS(status)) {
return status;
}
// Set permission
status = WdfDeviceInitAssignSDDLString(DeviceInit, &MY_SDDL_STRING);
if (!NT_SUCCESS(status)) {
return status;
}
WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_DISK);
WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect);
WdfDeviceInitSetExclusive(DeviceInit, FALSE);
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_EXTENSION);
deviceAttributes.EvtCleanupCallback = RamDiskEvtDeviceContextCleanup;
status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device);
if (!NT_SUCCESS(status)) {
return status;
}
pDeviceExtension = DeviceGetExtension(device);
WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE (
&ioQueueConfig,
WdfIoQueueDispatchSequential
);
ioQueueConfig.EvtIoDeviceControl = RamDiskEvtIoDeviceControl;
ioQueueConfig.EvtIoRead = RamDiskEvtIoRead;
ioQueueConfig.EvtIoWrite = RamDiskEvtIoWrite;
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&queueAttributes, QUEUE_EXTENSION);
__analysis_assume(ioQueueConfig.EvtIoStop != 0);
status = WdfIoQueueCreate( device,
&ioQueueConfig,
&queueAttributes,
&queue );
__analysis_assume(ioQueueConfig.EvtIoStop == 0);
if (!NT_SUCCESS(status)) {
return status;
}
// Context is the Queue handle
pQueueContext = QueueGetExtension(queue);
// Set the context for our default queue as our device extension.
pQueueContext->DeviceExtension = pDeviceExtension;
// Now do any RAM-Disk specific initialization
pDeviceExtension->DiskRegInfo.DriveLetter.Buffer =
(PWSTR) &pDeviceExtension->DriveLetterBuffer;
pDeviceExtension->DiskRegInfo.DriveLetter.MaximumLength =
sizeof(pDeviceExtension->DriveLetterBuffer);
// Get the disk parameters from the registry
RamDiskQueryDiskRegParameters(
WdfDriverGetRegistryPath(WdfDeviceGetDriver(device)),
&pDeviceExtension->DiskRegInfo
);
// Allocate memory for the disk image.
pDeviceExtension->DiskImage = ExAllocatePoolWithTag(
NonPagedPool,
pDeviceExtension->DiskRegInfo.DiskSize,
RAMDISK_TAG
);
if (pDeviceExtension->DiskImage) {
UNICODE_STRING deviceName;
UNICODE_STRING win32Name;
RamDiskFormatDisk(pDeviceExtension);
status = STATUS_SUCCESS;
// Now try to create a symbolic link for the drive letter.
RtlInitUnicodeString(&win32Name, DOS_DEVICE_NAME);
RtlInitUnicodeString(&deviceName, NT_DEVICE_NAME);
pDeviceExtension->SymbolicLink.Buffer = (PWSTR)
&pDeviceExtension->DosDeviceNameBuffer;
pDeviceExtension->SymbolicLink.MaximumLength =
sizeof(pDeviceExtension->DosDeviceNameBuffer);
pDeviceExtension->SymbolicLink.Length = win32Name.Length;
RtlCopyUnicodeString(&pDeviceExtension->SymbolicLink, &win32Name);
RtlAppendUnicodeStringToString(&pDeviceExtension->SymbolicLink,
&pDeviceExtension->DiskRegInfo.DriveLetter);
status = WdfDeviceCreateSymbolicLink(device,
&pDeviceExtension->SymbolicLink);
}
return status;
Please help me! Thanks
I understand this is an old post, but since there are no useful answers, I thought I might add my thoughts.
EvtDeviceAdd is called by the KMDF framework when a device matches a hardware ID that your INF supports. (https://msdn.microsoft.com/en-us/library/windows/hardware/ff541693%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396).
According to the VirtualVolume documentation (https://code.msdn.microsoft.com/windowshardware/VirtualVolume-83334efd), the only way to create a device is to call devcon install virtvol.inf virtvol.
You can make multiple RAMDisks by calling devcon install multiple times.
I want at least to distinguish cases when my software is being ran as batch job (LOGON32_LOGON_BATCH) from being ran interactively (LOGON32_LOGON_INTERACTIVE).
HANDLE hToken;
// Open the current process's token
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
{
// Get the token statistics, which include the logon session id
TOKEN_STATISTICS stats;
DWORD length;
if (GetTokenInformation(hToken, TokenStatistics, &stats, sizeof(stats), &length))
{
// Get data about the logon session, which includes the logon type
PSECURITY_LOGON_SESSION_DATA pData;
if (LsaGetLogonSessionData(&stats.AuthenticationId, &pData) == 0)
{
// From SECURITY_LOGON_TYPE enumeration
switch (pData->LogonType)
{
case Interactive:
wprintf(L"Interactive\n");
break;
case Batch:
wprintf(L"Batch\n");
break;
default:
wprintf(L"Other: %i\n", pData->LogonType);
break;
}
LsaFreeReturnBuffer(pData);
}
}
CloseHandle(hToken);
}
Im trying to create new file on D: drive with c/c++
I found this code to get windows write privileges but it does not working
Can anybody help me i am new in c++?
BOOL SetPrivilege(
HANDLE hToken, // access token handle
LPCTSTR lpszPrivilege, // name of privilege to enable/disable
BOOL bEnablePrivilege // to enable (or disable privilege)
)
{
// Token privilege structure
TOKEN_PRIVILEGES tp;
// Used by local system to identify the privilege
LUID luid;
if(!LookupPrivilegeValue(
NULL, // lookup privilege on local system
lpszPrivilege, // privilege to lookup
&luid)) // receives LUID of privilege
{
printf("LookupPrivilegeValue() error: %u\n", GetLastError());
return FALSE;
}
else
printf("LookupPrivilegeValue() is OK\n");
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
// Don't forget to disable the privileges after you enabled them,
// or have already completed your task. Don't mess up your system :o)
if(bEnablePrivilege)
{
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
printf("tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED\n");
}
else
{
tp.Privileges[0].Attributes = 0;
printf("tp.Privileges[0].Attributes = 0\n");
}
// Enable the privilege (or disable all privileges).
if(!AdjustTokenPrivileges(
hToken,
FALSE, // If TRUE, function disables all privileges, if FALSE the function modifies privilege based on the tp
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES) NULL,
(PDWORD) NULL))
{
printf("AdjustTokenPrivileges() error: %u\n", GetLastError());
return FALSE;
}
else
{
printf("AdjustTokenPrivileges() is OK, last error if any: %u\n", GetLastError());
printf("Should be 0, means the operation completed successfully = ERROR_SUCCESS\n");
}
return TRUE;
}
my Main Function
int main()
{
LPCTSTR lpszPrivilege = L"SeSecurityPrivilege";
// Change this BOOL value to set/unset the SE_PRIVILEGE_ENABLED attribute
BOOL bEnablePrivilege = TRUE;
HANDLE hToken;
// Open a handle to the access token for the calling process. That is this running program
if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
{
printf("OpenProcessToken() error %u\n", GetLastError());
return FALSE;
}
else
printf("OpenProcessToken() is OK\n");
// Call the user defined SetPrivilege() function to enable and set the needed privilege
BOOL test = SetPrivilege(hToken, lpszPrivilege, bEnablePrivilege);
printf("The SetPrivilege() return value: %d\n\n", test);
ofstream myFile;
myFile.open("C:\\test.txt");
myFile << "I am C";
myFile.close();
bEnablePrivilege = FALSE;
BOOL test1 = SetPrivilege(hToken, lpszPrivilege, bEnablePrivilege);
printf("The SetPrivilage() return value: %d\n", test1);
system("PAUSE");
return 0;
}
the output in console looks like this:
OpenProcessToken() is OK
LookupPrivilegeValue() is OK
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED
AdjustTokenPrivileges() is OK, last error if any: 1300
Should be 0, means the operation completed successfully = ERROR_SUCCESS
The SetPrivilege() return value: 1
LookupPrivilegeValue() is OK
tp.Privileges[0].Attributes = 0
AdjustTokenPrivileges() is OK, last error if any: 1300
Should be 0, means the operation completed successfully = ERROR_SUCCESS
The SetPrivilage() return value: 1
Press any key to continue . . .
SeSecurityPrivilege is the "Manage auditing and security log" user right (see the list of privilege constants). It has absolutely nothing to do with writing files. In fact, under normal circumstances, you don't need to enable any privilege to write a file to the root of a drive, although the process does need to be running as an administrator.
Error 1300 means "Not all privileges or groups referenced are assigned to the caller." That is, the privilege was not successfully enabled, because the process isn't entitled to it. This will be because the process isn't being run as an administrator.
So, first, you can remove almost all the code in your example, everything but the four lines that actually write the file. Then you just need to run the application as an administrator.
To do this, right-click on the executable file and select "Run as administrator". If you run the application in this way it will be able to write the file. (Note: in Windows XP, you don't need to do this, but you do need to be logged in as a user with administrative rights.)
AdjustTokenPrivileges cannot add or remove privileges from the token. It can only enable existing privileges that are currently disabled or disable existing privileges that are currently enabled.
ERROR 1300 means that you are not already have "SeSecurityPrivilege".So you can't enable or disable it.
For more information check:
Changing Privileges in a Token
I'm developing an application which will display information derived from the EDID blocks (monitor model, ID, S/N, etc.) on a dialog on the corresponding monitor.
This code works for finding the EDID information for displays. It extracts the EDID information by enumerating the DISPLAY keys under HKLM\SYSTEM\CurrentControlSet\Enum\DISPLAY\[Monitor]\[PnPID]\Device Parameters\EDID.
Update: The above code is relying on "side effects" of PnP use of the registry. I am now using the SetupAPI to enumerate monitors, which correctly handles monitors being attached/removed (unlike the code from the link above.)
I am trying to correlate each Screen in Windows.Forms.Screen.AllScreens[] (\\.\DISPLAY1, \\.\DISPLAY2, etc.) with the entries returned from the above registry inspection.
Note: In the code block below, DisplayDetails.GetMonitorDetails() has now been replaced with more robust registry enumeration code using the SetupAPI, but the data returned is the same.
e.g.
private void Form1_Load(object sender, EventArgs e)
{
Console.WriteLine("Polling displays on {0}:", System.Environment.MachineName);
int i = 0;
foreach ( DisplayDetails dd in DisplayDetails.GetMonitorDetails())
{
Console.WriteLine( "Info: Model: {0}, MonitorID: {1}, PnPID: {2}, Serial#:{3}", dd.Model, dd.MonitorID, dd.PnPID, dd.SerialNumber );
Console.WriteLine( "Does this correlate to Screen: {0}?", Screen.AllScreens[i++].DeviceName );
}
}
Output:
Info: Model: DELL P2411H, MonitorID: DELA06E, PnPID: 5&2e2fefea&0&UID1078018, Serial#:F8NDP0C...PU
Does this correlate to Screen: \\.\DISPLAY1?
Info: Model: DELL P2411H, MonitorID: DELA06E, PnPID: 5&2e2fefea&0&UID1078019, Serial#:F8NDP0C...AU
Does this correlate to Screen: \\.\DISPLAY2?
Answer: NO
In testing, I've found these don't reliably correlate (I have a system in which the first display enumerated is \\.\DISPLAY2).
My Question:
Is there a way to reliably get the EDID information for a given Forms.Screen? I can get the EDID block, but have found no path to correlate this up to the UI top-level Form. Prompting the user is undesirable, as in my use case the two (or more) monitors will likely be the same model and resolution, and only differ by a few digits in the S/N.
I've looked for paths following the Forms.Screen API, Win32 EnumDisplay, other registry GUIDs (PnP and driver-related), but haven't found any promising paths.
I have also investigated the WMI Win32_DesktopMonitor API (Windows 7), however it doesn't appear to have any more information that would help me correlate it to the Windows.Forms.Screen.AllScreens[] entries.
I suspect if there is a way to do this, it's through the SetupAPI, however I haven't found it yet.
A method to resolve the GDI to SetupAPI is available in the EnumDisplayDevices API. If you pass in the EDD_GET_DEVICE_INTERFACE_NAME in for dwFlags, the monitor enumeration will return DeviceID information of the form:
Monitor 0 info:
DeviceName: \\.\DISPLAY1
MonitorInfo: Dell P2411H(Digital)
DeviceID: \\?\DISPLAY#DELA06E#5&2e2fefea&0&UID1078018#{e6f07b5f-ee97-4a90-b076-3
3f57bf4eaa7}
Monitor 1 info:
DeviceName: \\.\DISPLAY2
MonitorInfo: Dell P2411H(Digital)
DeviceID: \\?\DISPLAY#DELA06E#5&2e2fefea&0&UID1078019#{e6f07b5f-ee97-4a90-b076-3
3f57bf4eaa7}
The DeviceID fields now match the results from the didd.DevicePath, as retrieved in the C# fragment below:
Guid MonitorGUID = new Guid(Win32.GUID_DEVINTERFACE_MONITOR);
// We start at the "root" of the device tree and look for all
// devices that match the interface GUID of a monitor
IntPtr h = Win32.SetupDiGetClassDevs(ref MonitorGUID, IntPtr.Zero, IntPtr.Zero, (uint)(Win32.DIGCF_PRESENT | Win32.DIGCF_DEVICEINTERFACE));
if (h.ToInt64() != Win32.INVALID_HANDLE_VALUE)
{
bool Success = true;
uint i = 0;
while (Success)
{
// create a Device Interface Data structure
Win32.SP_DEVICE_INTERFACE_DATA dia = new Win32.SP_DEVICE_INTERFACE_DATA();
dia.cbSize = (uint)Marshal.SizeOf(dia);
// start the enumeration
Success = Win32.SetupDiEnumDeviceInterfaces(h, IntPtr.Zero, ref MonitorGUID, i, ref dia);
if (Success)
{
// build a DevInfo Data structure
Win32.SP_DEVINFO_DATA da = new Win32.SP_DEVINFO_DATA();
da.cbSize = (uint)Marshal.SizeOf(da);
// build a Device Interface Detail Data structure
Win32.SP_DEVICE_INTERFACE_DETAIL_DATA didd = new Win32.SP_DEVICE_INTERFACE_DETAIL_DATA();
didd.cbSize = (uint)(4 + Marshal.SystemDefaultCharSize); // trust me :)
// now we can get some more detailed information
uint nRequiredSize = 0;
uint nBytes = Win32.BUFFER_SIZE;
if (Win32.SetupDiGetDeviceInterfaceDetail(h, ref dia, ref didd, nBytes, out nRequiredSize, ref da))
{
// Now we get the InstanceID
IntPtr ptrInstanceBuf = Marshal.AllocHGlobal((int)nBytes);
Win32.CM_Get_Device_ID(da.DevInst, ptrInstanceBuf, (int)nBytes, 0);
string InstanceID = Marshal.PtrToStringAuto(ptrInstanceBuf);
Console.WriteLine("InstanceID: {0}", InstanceID );
Marshal.FreeHGlobal(ptrInstanceBuf);
Console.WriteLine("DevicePath: {0}", didd.DevicePath );
}
i++;
}
}
}
Win32.SetupDiDestroyDeviceInfoList(h);
}
Sample Output:
InstanceID: DISPLAY\DELA06E\5&2E2FEFEA&0&UID1078018
DevicePath: \\?\display#dela06e#5&2e2fefea&0&uid1078018#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}
The DeviceName from the original EnumDisplayDevices matches the Forms.Screen.DeviceName property.
With these two pieces of information, it is now possible to read the EDID block during the SetupDIEnumDeviceInterface traversal using a fragment like the below:
private static byte[] GetMonitorEDID(IntPtr pDevInfoSet, SP_DEVINFO_DATA deviceInfoData)
{
IntPtr hDeviceRegistryKey = SetupDiOpenDevRegKey(pDevInfoSet, ref deviceInfoData,
DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);
if (hDeviceRegistryKey == IntPtr.Zero)
{
throw new Exception("Failed to open a registry key for device-specific configuration information");
}
IntPtr ptrBuff = Marshal.AllocHGlobal((int)256);
try
{
RegistryValueKind lpRegKeyType = RegistryValueKind.Binary;
int length = 256;
uint result = RegQueryValueEx(hDeviceRegistryKey, "EDID", 0, ref lpRegKeyType, ptrBuff, ref length);
if (result != 0)
{
throw new Exception("Can not read registry value EDID for device " + deviceInfoData.ClassGuid);
}
}
finally
{
RegCloseKey(hDeviceRegistryKey);
}
byte[] edidBlock = new byte[256];
Marshal.Copy(ptrBuff, edidBlock, 0, 256);
Marshal.FreeHGlobal(ptrBuff);
return edidBlock;
}
Which, finally, can be parsed for the VESA descriptor blocks, as shown in the DisplayDetails.GetMonitorDetails() method in this code.
I am trying to understand better how Windows sessions (TS sessions and log on sessions) works (currently in XP), so maybe my whole question or what I am trying to do is impossible.
I am running a Windows service (in XP), which runs in session 0, and I am trying to get the username attached to this session using WTSQueryUserToken().
Now, in session 0 there are several usernames: SYSTEM, theuser (logged on user),NETWORK SERVICE, LOCAL SERVICE.
When I use WTSQueryUserToken() I get "theuser" (which is the Active session), but I am trying to get the username of my service (which is SYSTEM).
Is that possible or did I simply get it all wrong?
I use the following code to get user token for my process
HANDLE GetProcessOwnerToken(DWORD pid)
{
if (!pid) return NULL;
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (!hProcess) return NULL;
HANDLE hToken = NULL;
if(OpenProcessToken(hProcess, MAXIMUM_ALLOWED, &hToken))
{
HANDLE result = INVALID_HANDLE_VALUE;
if(DuplicateTokenEx(hToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &result))
{
if(result != INVALID_HANDLE_VALUE)
{
CloseHandle(hToken);
CloseHandle(hProcess);
return result;
}
}
CloseHandle(hToken);
}
CloseHandle(hProcess);
return NULL;
}
I have no idea if it works for services as well, I think it should.