Permission issue getting uptime with performance counters - c++

I'm trying to read the system uptime using performance counters in C++. I want to support both XP and Windows 7 at minimum.
The following code works fine on Windows XP...
HQUERY hQuery; HCOUNTER hCounter;
PDH_FMT_COUNTERVALUE Value;
int ret = 0;
if (PdhOpenQuery(NULL, 0, &hQuery) == ERROR_SUCCESS) {
if ((status = PdhAddCounter(hQuery, queryURI, 0, &hCounter)) == ERROR_SUCCESS) {
if ((status = PdhCollectQueryData(hQuery)) == ERROR_SUCCESS) {
if ((status = PdhGetFormattedCounterValue(hCounter, PDH_FMT_LARGE, NULL, &Value)) == ERROR_SUCCESS) {
ret = (DWORD)(Value.largeValue);
}
}
PdhRemoveCounter(hCounter);
}
PdhCloseQuery(hQuery);
}
return ret;
..but it fails on Windows 7. Specifically, PdhCollectQueryData returns PDH_NO_DATA regardless of whether or not i run as administrator.
How can i get the system uptime on both Windows 7 and XP? I expect the times to be much larger than the 49-day overflow of GetTickCount, and i would rather not have separate PDH versions for XP and GetTickCount64 versions for 7 if at all possible...

So the help for PdhCollectQueryData indicates that PDH_NO_DATA can be returned if the process doing the query lacks the appropriate elevated token to allow the query. See if you can check exactly what user permissions the process itself has been allocated, regardless of whether you are logged in as admin or not. Windows 7 has a lot of granularity to this concept, especially with UAC turned on. There can be a distinction also between the local Administrator account created with the OS & a member of the Administrators group in terms of what permissions the account ends up with, though I've not encountered a specific one on performance counters.
Try an explicit 'Run as administrator' on the process, for example, and ensure the administrator account you're using really does have that permission (I'm not sure from your question whether you have already tried this or not). Try a user account in the Performance Logs User Group. Try the account that was created when the OS was installed. Try with UAC off. These hopefully should help nail down the source of the problem.
From the Microsoft help on the subject:
Only the administrator of the computer or users in the Performance Logs User Group can log and view counter data. Users in the Administrator group can log and view counter data only if the tool they use to log and view counter data is started from a Command Prompt window that is opened with Run as administrator.... Users in the Performance Monitoring Users group can view counter data.

Related

PdhEnumObjectsW issue

I have an issue with enumerating performance counter objects. My code worked well for a few years, but recently I have found it started to fail to get counter objects with the following error:
PDH_CSTATUS_NO_MACHINE The path did not contain a computer name, and the function was unable to retrieve the local computer name.
DWORD bufLength = 0;
const DWORD detailLevel = PERF_DETAIL_WIZARD;
PDH_STATUS objStatus = PdhEnumObjectsW(nullptr, nullptr, nullptr, &bufLength, detailLevel, TRUE);
qDebug() << ManageApp::getPdhStatusMsg(objStatus);
qDebug() << "bufLength: " << bufLength;
std::wstring namebuf(bufLength, '\0');
PDH_STATUS status = PdhEnumObjectsW(nullptr, nullptr, &namebuf[0], &bufLength, detailLevel, FALSE);
qDebug() << ManageApp::getPdhStatusMsg(status);
I have tried to get the computer name and set it in the PdhEnumObjectsW() call:
PDH_STATUS objStatus = PdhEnumObjectsW(nullptr, machineName.toStdWString().c_str(), nullptr, &bufLength, detailLevel, TRUE);
WCHAR computerName[MAX_COMPUTERNAME_LENGTH + 1];
DWORD computerNameSize = _countof(computerName);
bool isComputerName = GetComputerNameExW(ComputerNameDnsFullyQualified, computerName, &computerNameSize);
qDebug() << isComputerName;
QString machineName = "";
I have removed the Windows 10 update and switched back to 19044.1645, but it still displays the PDH_CSTATUS_NO_MACHINE error. Also, I have checked it in a VM - Windows 10 build 19043, Windows 11 and Windows 11 Insider Preview, so it works well there.
From the docs, I get following error description:
PDH_CSTATUS_NO_MACHINE
Unable to connect to the specified computer. Could be caused by the computer not being on, not supporting PDH, not being connected to the network, or having the permissions set on the registry that prevent remote connections or remote performance monitoring by the user.
So, I think it's somehow related to registry permissions. Any ideas how to verify that all registry permissions for PDH are properly set on my machine?
I have checked out the registry permissions for Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib, and all permissions are set properly. So, I do not think, it is related to the registry permissions.
Any ideas what could cause such PDH_CSTATUS_NO_MACHINE issue?
I have fixed it by rebuilding the performance counters.
Instructions:
Set "Disable Performance Counters" to 0 using this command:
Reg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PerfProc\Performance /v "Disable Performance Counters" /t REG_DWORD /d 0
Rebuild all performance counters:
%windir%\system32\lodctr /R
%windir%\sysWOW64\lodctr /R
When running the first command - %windir%\system32\lodctr /R, you will get:
Error: Unable to rebuild performance counter setting from system
backup store, error code is 2
In such case, feel free run this command first - %windir%\sysWOW64\lodctr /R and then run %windir%\system32\lodctr /R. The second time after this command: %windir%\sysWOW64\lodctr /R it will complete successfully for %windir%\system32\lodctr /R:
Info: Successfully rebuilt performance counter setting from system
backup store
Resync the counters with Windows Management Instrumentation (WMI): %windir%\system32\wbem\winmgmt.exe /resyncperf
Stop and restart the Performance Logs and Alerts service with the following commands:
net stop pla
net start pla
Stop and restart the Windows Management Instrumentation (WMI) service by using these commands:
net stop winmgmt
net start winmgmt
So, the issue is resolved. Thanks.

Accessing Max Input Delay with C++ on Windows

I am having trouble obtaining certain data from Windows Performance Counters with C++. I will preface my question by stating that I am new to both C++ and to developing for Windows, but I have spent some time on this issue already so I feel familiar with the concepts I am discussing here.
Question:
How do I use Windows PDH (Performance Data Helper) C++ to obtain Max Input Delay--either per session or per process? Are there certain Performance Counters that are not available outside of perfmon?
Progress so far:
I have used this example to log some Performance Counters successfully, but the ones I want produce the error code 0xC0000BB8: "The specified object is not found on the system." This confuses me because I can access the objects--"User Input Delay per Process" or "User Input Delay per Session"--fine through perfmon. I even went as far as enabling the counter in the registry as outlined in the article I linked in my question, despite being on a build of Windows 10 that should have it enabled by default. I had to make a small change to get the code to compile, but I have changed only the definition of COUNTER_PATH during my testing because, again, the code works as advertised except when it comes to the counter I want to access. Specifically:
Does not compile:
CONST PWSTR COUNTER_PATH = L"\\Processor(0)\\% Processor Time";
Does compile and log:
CONST wchar_t *COUNTER_PATH = L"\\Processor(0)\\% Processor Timee";
OR
CONST PWSTR COUNTER_PATH = const_cast<PWSTR>(TEXT( "\\Processor(0)\\% Processor Time" ));
Compiles, but throws error code 0xC0000BB8 at runtime (This is the Counter I want to access):
CONST PWSTR COUNTER_PATH = const_cast<PWSTR>(TEXT( "\\User Input Delay per Session(1)\\Max Input Delay" ));
The hardcoded session ID of 1 in the string was for troubleshooting purposes, but wildcard (*) and 0 were also used with the same result. The counter path matches that shown in perfmon.
Essentially, all Performance Counters that I have attempted to access with this code--about 5 completely different ones--have successfully logged the data being requested, but the one I want to access continues to be evasive.
I asked this same question on Microsoft Q&A and received the answer:
The Performance Counters in question require administrator privileges to access. All I had to do was run this program in administrator command prompt, and that solved my issue.

ChangeWindowMessageFilterEx() Returns Error Code 5

I want to get the status of a checkbox in a window.
So I used SendMessage(hwnd, BM_GETCHECK, NULL, NULL), but it always returns 0. To know why, I used GetLastError() and it returned 5.
In Microsoft's documentation, it says that "When a message is blocked by UIPI the last error, retrieved with GetLastError, is set to 5 (access denied)."
So, after some research I used ChangeWindowMessageFilterEx(hwnd, BM_GETCHECK, MSGFLT_ALLOW, 0) to bypass the privilege issues.
But ChangeWindowMessageFilterEx() also gives error code 5 and returns false.
However, when I use ChangeWindowMessageFilter() it returns true and gives the error code 0. But still SendMessage(hwnd, BM_GETCHECK, NULL, NULL) gives error code 5.
Approach 1
status = ChangeWindowMessageFilterEx(hwnd, BM_GETCHECK, MSGFLT_ALLOW, 0); //returns false
error = ::GetLastError(); // gives error code 5
chk_state = SendMessage(hwnd, BM_GETCHECK, NULL, NULL);
Approach 2
status = ChangeWindowMessageFilter(BM_GETCHECK, MSGFLT_ADD); //returns true
error = ::GetLastError() // gives error code 0
chk_state = SendMessage(hwnd, BM_GETCHECK, NULL, NULL);
error = ::GetLastError(); // gives error code 5
What am I doing wrong here?
Finally found an alternate way to get the check box status. The inspect.exe was the savior. Thanks to #Rita Han - MSFT for suggesting inspect.exe. As changing privilege/access or bypassing UIPI restrictions are little complicated, we decided to go with UIAutomation. We retrieved all the data in the settings window using UIAutomation!
There are two ways to get the status of checkbox for the this scenario.
Run your program with same or high integrity level than the target program, for example run the program in the elevated mode maybe helpful since most of program is running under high integrity. You can also specify the level in the manifest like below(refer /MANIFESTUAC)
/MANIFESTUAC:level=_level
Bypass UIPI restrictions on SendMessage across privilege levels is available for UI automation programs using a special security attribute in the program’s application manifest, known as UIAccess.The following is an example of an application manifest entry for a UIAccess program.
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel
level="asInvoker"
UIAccess="true" />
</requestedPrivileges>
</security>
</trustInfo>
By specifying UIAccess=”true” in the requestedPrivileges attribute, the application is stating a requirement to bypass UIPI restrictions on sending window messages across privilege levels. Windows Vista implements the following policy checks before starting an application with UIAccess privilege.
The application must have a digital signature that can be verified
using a digital certificate that chains up to a trusted root in the
local machine Trusted Root Certification Authorities certificate
store.
The application must be installed in a local folder application
directory that is writeable only by administrators, such as the
Program Files directory. The allowed directories for UI automation
applications are:
%ProgramFiles% and its subdirectories.
%WinDir% and its subdirectories, except a few subdirectories that are excluded because standard users have write access.
Please refer the docs about about details:
Mandatory Integrity Control
But the only problem now is the check box status is retrieved only after mouse over on that element. I'm trying to find a solution for that. Anyway if you could shed any light on this that would be great.
Instead of get the element after mouse over, we can get the element by windows handler. Here is the code to get state of checkbox for your reference:
CoInitialize(NULL);
IUIAutomation * UIAutomation;
InitializeUIAutomation(&UIAutomation);
IUIAutomationElement *targetIUIAutomationElement;
UIAutomation->ElementFromHandle((UIA_HWND)0x513F8,&targetIUIAutomationElement);
VARIANT checkboxState;
targetIUIAutomationElement->GetCurrentPropertyValue(UIA_ToggleToggleStatePropertyId,&checkboxState);
if(checkboxState.lVal== ToggleState_Off)
std::cout << "The check box is not checked...\n";
else if(checkboxState.lVal == ToggleState_On)
std::cout << "The check box is checked...\n";
else
std::cout << "The checkbox is in indeterminate...\n";
If you just want to interrogate the state of a checkbox, instead of using a SendMessage, you could just inspect the accessibilitiy tree. That is, use the same APIs that a screen reader would use.
Start with AccessibleObjectFromWindow and friends.

First call to Windows Performance Counters (PDH) sometimes fails

I'm having a problem where sometimes my code will function correctly, but other times it will fail.
This is the first bit of PDH related code that I run:
const std::wstring pidWildcardPath = L"\\Process(*)\\ID Process";
DWORD bufferSize = 0;
LPTSTR paths = NULL;
PDH_STATUS status = PdhExpandCounterPath(
pidWildcardPath.c_str(),
paths,
&bufferSize);
checkPDHStatus(status, PDH_MORE_DATA, L"Expected request for more data.");
The result of the PdhExpandCounterPath function call is 0x800007D0 (PDH_CSTATUS_NO_MACHINE). The checkPDHStatus function is a simple function that I wrote that asserts that the status is equal to the second parameter. In this case, I expect the result to be PDH_MORE_DATA because paths is NULL and bufferSize is 0. The goal of this call is to determine the size of the buffer I must allocate to store all of the results for a subsequent call to PdhExpandCounterPath. This is described in the PDH documentation under the Remarks section.
The list of PDH error codes describes PDH_MORE_DATA as "Unable to connect to the specified computer, or the computer is offline." As you can see by the performance counter path in the code above, I am not even trying to connect to a different computer than my own.
It is interesting the way that this code fails. Sometimes it works fine and then other times, it will fail on multiple back-to-back executions of my application. I have #include <pdh.h> in my header file and I have a section in my property sheet for this DLL that looks like this:
<Tool
Name="VCLinkerTool"
AdditionalDependencies="pdh.lib"
/>
I'm not sure if it matters, but this program is built by Visual Studio 2005 and run on Windows XP. Am I doing something incorrectly?
I'm a co-worker of Dave's and have discovered the following during my investigation:
the code above runs fine when run from a logged-in interactive session
the code runs fine when initiated as a Scheduled Task AND the user is logged in at the time the scheduled task is fired off
the code FAILS only when run as a Scheduled Task AND the user is NOT logged in at the time the task starts
the code continues to fail if the user logs in after the failing task has started but while it is still running (because it is looping "endlessly" until it gets a PDH_MORE_DATA status back).
In the failing instances, the following environment variables have not been established/set for the program: APPDATA, HOMEDRIVE and HOMEPATH ... I don't think this is a problem. However, the failing program also lacks the SeCreateGlobalPrivilege from its token; the passing programs all have this privilege in the token and PERFMON shows it as "Default Enabled". The other difference is that failing program has the NT_AUTH\BATCH user group in the token, while the passing program has NT_AUTH\INTERACTIVE instead ... all other user groups and privileges are the same for both cases. I think the global privilege is coming from the interactive login, but don't know if it has any bearing on PDH operation.
I cannot find anything in the Performance Counter/PDH documentation that talks about needing any special permissions or privileges for this functionality to succeed. Is the global privilege required to use Performance Counters ?
Or is there some other context/environment difference between running Scheduled Tasks (as a specific user) when that user is/isn't logged in at the time the task starts, that would account for the PDH call succeeding/failing respectively ?
Try this format, indicating the local computer:
const std::wstring pidWildcardPath = L"\\.\Process(*)\ID Process";

How to programmatically gain root privileges?

I am writing some software (in C++, for Linux/Mac OSX) which runs as a non-privileged user but needs root privileges at some point (to create a new virtual device).
Running this program as root is not a option (mainly for security issues) and I need to know the identity (uid) of the "real" user.
Is there a way to mimic the "sudo" command behavior (ask for user password) to temporarily gain root privileges and perform the particular task ? If so, which functions would I use ?
Thank you very much for your help !
If you need root privileges every time, the best thing is to start your program as root and drop them (in a subprocess) with setuid and setgid. That's what apache does when it needs to bind to the restricted port 80.
If gaining root rights is the exception instead of the rule and the program is run interactively, another way is to write a program add_interface and execute
sudo add_interface args
and let sudo handle authentication for you. Instead of sudo, you may want to use a graphical frontend like gksu, gksudo, kdesu, or kdesudo. I wouldn't try to implement secure password input myself; it can be a tricky problem and you'll probably leave gaping security holes and functionality problems (Do you support fingerprint readers?).
Another alternative is polkit, previously called PolicyKit.
Original answer
You might consider the setuid switch on the executable itself. Wikipedia has an article on it which even shows you the difference between geteuid() and getuid() quite effectively, the former being for finding out who you're "emulating" and the latter for who you "are". The sudo process, for example, geteuid should return 0 (root) and getuid your user's id, however, its sub-processes do truly run as root (you can verify this with sudo id -u -r).
I don't think there's a way to easily programmatically gain root access - after all, applying the principle of least privilege, why would you need to? Common practise is to run only limited parts of code with elevated privileges. A lot of daemons etc are also set up under modern systems to run as their own user with most of the privileges they need. It's only for very specific operations (mounting etc) that root privileges are truly needed.
2013 update
My original answer stands (although my 2013 self might make a better job of it than my 2010 one), but if you are designing an application that requires root access, you may want to consider exactly what sort of root access is needed and consider the use of POSIX Capabilities (man page). These are different to capability-based security as implemented in L4 et al. POSIX capabilities allow your application to be granted a subset of root's powers. For example CAP_SYS_MODULE will allow you to insert kernel modules, but give you no other root powers. This is in use in distributions e.g. Fedora has a feature to completely remove setuid binaries with indiscriminate root access.
This matters because as a programmer, your code is obviously perfect! But, the libraries on which you depend (sigh, if only you'd written them!) might have vulnerabilities in them. Using capabilities, you can limit the use of this exploit, and save yourself and your company from security-related scrutiny. This makes everyone happier.
You can't gain root privileges, you must start out with them and reduce your privileges as needed. The usual way that you do this is to install the program with the "setuid" bit set: this runs the program with the effective userid of the file owner. If you run ls -l on sudo, you'll see that it is installed that way:
-rwsr-xr-x 2 root root 123504 2010-02-25 18:22 /usr/bin/sudo
While your program is running with root privileges, you can call the setuid(2) system call to change your effective userid to some non-privileged user. I believe (but haven't tried this) that you could install your program as root with the setuid bit on, immediately reduce privilege, and then restore privilege as needed (it's possible, however, that once you lower your privilege you won't be able to restore it).
A better solution is to break out the piece of your program that needs to run as root, and install it with the setuid bit turned on. You will, of course, need to take reasonable precautions that it can't be invoked outside of your master program.
Normally this is done by making your binary suid-root.
One way of managing this so that attacks against your program are hard is to minimize the code that runs as root like so:
int privileged_server(int argc, char **argv);
int unprivileged_client(int argc, char **argv, int comlink);
int main(int argc, char **argv) {
int sockets[2];
pid_t child;
socketpair(AF_INET, SOCK_STREAM, 0); /* or is it AF_UNIX? */
child = fork();
if (child < 0) {
perror("fork");
exit(3);
} elseif (child == 0) {
close(sockets[0]);
dup2(sockets[1], 0);
close(sockets[1]);
dup2(0, 1);
dup2(0, 2); /* or not */
_exit(privileged_server(argc, argv));
} else {
close(sockets[1]);
int rtn;
setuid(getuid());
rtn = unprivileged_client(argc, argv, sockets[0]);
wait(child);
return rtn;
}
}
Now the unprivileged code talks to the privileged code via the fd comlink (which is a connected socket). The corresponding privileged code uses stdin/stdout as its end of the comlink.
The privileged code needs to verify the security of every operation it needs to do but as this code is small compared to the unprivileged code this should be reasonably easy.
You might want to take a look at these APIs:
setuid, seteuid, setgid, setegid, ...
They're defined in the header <unistd.h> in Linux systems (don't know much about MAC, but you should have a similar header there too).
One problem that I can see is that the process must have sufficient privileges to change its user-/group- IDs. Otherwise calls to the above functions will result in an error with errorno set to EPERM.
I would suggest that you run your program as the root user, change effective user ID (using seteuid) to an underprivileged user at the very beginning. Then, whenever you need to elevate permissions, prompt for a password then use seteuid again to revert to the root user.
On OS X, you can use the AuthorizationExecuteWithPrivileges function. The page on Authorization Services Tasks has some elaborate discussion of this (and related) functions.
Here's a bit of C++ code to execute a program with administrator privileges:
static bool execute(const std::string &program, const std::vector<std::string> &arguments)
{
AuthorizationRef ref;
if (AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &ref) != errAuthorizationSuccess) {
return false;
}
AuthorizationItem item = {
kAuthorizationRightExecute, 0, 0, 0
};
AuthorizationRights rights = { 1, &item };
const AuthorizationFlags flags = kAuthorizationFlagDefaults
| kAuthorizationFlagInteractionAllowed
| kAuthorizationFlagPreAuthorize
| kAuthorizationFlagExtendRights;
if (AuthorizationCopyRights(ref, &rights, kAuthorizationEmptyEnvironment, flags, 0) != errAuthorizationSuccess) {
AuthorizationFree(ref, kAuthorizationFlagDestroyRights);
return false;
}
std::vector<char*> args;
for (std::vector<std::string>::const_iterator it = arguments.begin(); it != arguments.end(); ++it) {
args.push_back(it->c_str());
}
args.push_back(0);
OSStatus status = AuthorizationExecuteWithPrivileges(ref, program.c_str(), kAuthorizationFlagDefaults, &args[0], 0);
AuthorizationFree(ref, kAuthorizationFlagDestroyRights);
return status == errAuthorizationSuccess;
}
You can try launching the command to create the virtual device (including sudo) through a background shell. Ask for the users password in a dialog of your own and pipe that into the shell when sudo asks for it. There are other solutions like using gksu, but those are not guaranteed to be available on every machine.
You don't run your entire program as root, but only the small part of it that needs root. You should spawn a separate process for that and sudo may be of assistance to you.