I have a dll made in cpp which tries to read/write some Registry Keys. This code runs perfectly fine in Windows XP (32 bit environment) but it fails in Windows 7(64 bit environment).
The registry keys which this application accesses is the shared registry keys. These keys are not part of 32 bit registry cache(wow32 bit) or 64 bit registry cache.
Please provide your valuable inputs on this.
Thanks in advance.
Jits
when you say "shared" you mean for example under HKLM? Only elevated applications are allowed to write to those on Windows 7 and Vista. If this is news to you I suggest searching on User Account Control or UAC.
Check out this: RegQueryValueEx Function
And this: Registry Key Security and Access Rights
IMO you have to check your permission settings that you use to open the key. Either remove the settings that require elevated privileges or run your app in elevated mode.
Maybe you should initialize the value of "lpcbData", the last parameter of RegQueryValueEx.
Related
I have an old Windows program that reads information from the registry, like so:
CRegKey rkey;
if(rkey.Open(HKEY_LOCAL_MACHINE, "SOFTWARE\\xxx\\yyy", KEY_READ) == ERROR_SUCCESS)
{
...
}
On a Windows 10 locked down user account, this fails!
It cannot even read the registry, at least not that part of it.
I've looked on Microsoft's support site, and I could not find where it addresses this.
Can anyone point me to info, or just tell me, how accessing the registry from a (C++) program is affected by UAC in Windows 10?
I need to retract this question. Further investigation shows that the User account has read access to HKLM etc in the registry, and that is not the problem. In fact, the installer already wrote the registry entries I was looking for under HKCU (current user) where User account has both R and W permission. ... So, I blamed Windows 10 user mode unnecessarily. Issue seems to be communication from that program to another is not succeeding. We will look into it. I apologize for posting the question which, on investigation, turned out not to be the source of the problem.
I have a 32 bit program which is running in two lanes in the same store. The program tries top open a registry key for query. The operating system is Windows 8.1 64 bit.
On one lane it succeeds, and on the other it fails and regopenkeyex returns 2. GetLastError returns 0.
The key it tries to open is under WOW6432Node.
The program is running under the same Windows user on both machines, the key exists on both. the UAC is set to "Never notify" (lowest), windows version is the same. Everything is supposed to be the same...
I am deliberately not specifying KEY_WOW64_64KEY because the code is supposed to work without it. But even when I do use it I get the same result.
What could be causing this?
The code:
rc = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,
szKey,
0,
KEY_QUERY_VALUE,
&m_hKey);
Thank you.
You actually need to read about the functions you are using on MSDN. The registry functions return the error code directly, they do not use GetLastError!
2 is ERROR_FILE_NOT_FOUND so whatever you are hiding in szKey is not a valid subkey path.
WOW6432Node is a reserved key name that you really should not be using, use KEY_WOW64_32KEY if you need to access the 32-bit registry view in a 64-bit application. A 32-bit application reads keys under the WOW6432Node key by default.
Use Process Monitor to make sure you are accessing the correct key.
I am having a problem with calling the function MsiOpenDatabase (https://msdn.microsoft.com/en-us/library/aa370338(v=vs.85).aspx) from inside a program when I choose to "run as administrator". When I run it under an admin account but without explicitly starting the executable as elevated it all works just fine. This indicates that the path to MSI file etc should be correct.
So, when running elevated the MsiOpenDatabase() I get an error code of 110 (0x6e).
I have tried to call MsiGetLastErrorRecord as explained here (https://msdn.microsoft.com/en-us/library/aa370124(v=vs.85).aspx) but nothing happens when I try to print the code in a message box. It simply doesn't get there.
I do not have Visual studio for debuggning on the target machine, so debugging is a bit of a pain.
Target machine is Windows 7 x64. Application is 32-bit.
But just the pure fact that it works un-elevated but fails when run as an administrator...it feels like there should be some kind of answer to this which can be derived from this fact perhaps?
Thankful for any help!
EDIT:
I finally solved it!
Apparently I had to go to the network share where the MSI file is located (which I am trying to call MsiOpenDatabase on) and right cklick on a file there and choose "run as administrator" because then and only then did I get a UAC dialog box asking for credentials (I mean I was able to open Windows Explorer as admin and navigate to the network share without problem so I never thought that it would be what would give me these peoblems). After haing done that I was able to run my application and it did no longer fail on any MsiOpenDatabase call.
But, why must I do this procedure to get access to run file on a network share since I already had access (execute rights) with the same user but when not elevated? How come Windows needs to ask the same user for credentials if it is already running elevated on the very same account that already has access to the network share? Seems strange to me, but I suppose I am missing some crucial part?
SAMPLE CODE
LPCTSTR szPersist = MSIDBOPEN_READONLY;
MSIHANDLE handleDB;
UINT result = MsiOpenDatabase(strPath, szPersist, &handleDB); // strPath is something like _T("\\server\MSI\Setup.msi");
result variable has value 110 when this error occurrs as explained above and keep the part in the update section in mind. I find it strange, but perhaps someone knows UAC better than me and why I have to provide credentials again by going to a file on the netowrk share and choose to run as admin to get it working (since I have already provided credentials as non-admin with the same account earlier at that very same network share location)?
This is standard UAC behavior since Windows Vista and is not related to MSI at all. Do a google search for "uac network drives".
You should be closing your MSI handles though as I commented above. Use PMSIHANDLE instead of MSIHANDLE.
Ok, so we have a C++ app that runs fine in Windows XP.
It has the following code in the initialization
// Register all OLE server (factories) as running. This enables the
// OLE libraries to create objects from other applications.
COleObjectFactory::RegisterAll();
Now like i said, it works fine in Windows XP, but as far I understand the program tries to register its COM interface Which is fine in XP, but this may be a problem in Windows Vista and Windows 7 because of the UAC. Especially if its is run as a standard user (with no elevated privileges).
If i understand it correctly this is needed for the program to run properly, but it cant execute this code without elevated privileges. If it will run every time the app runs (this usually runs when CWinApp::init() is run)
Before you say just use admin privileges, the user will not have them, there is no way to change that
So, now my questions are:
1) am i correct in my assumptions?
2) if I am correct, what is the best way around this? Can i just remove this? Do i need to set up some other thing? (we changed some VB modules to use a XML file instead of stuff in the registry
PS: the modules compiles into DLLs
PPS: UAC MUST be on
Take note that:
The documentation for these functions makes no mention of any privilege requirements; and
nobody online seems to be having trouble with these functions in limited privilege environments; and
it's 2012, I think someone would have noticed if these functions didn't work under UAC by now.
So (with nothing to suggest otherwise) I'd say It Just Works.
Notwithstanding the above, I looked at the implementation of COleObjectFactory::RegisterAll() and COleObjectFactory::UpdateRegistryAll().
RegisterAll
Ultimately calling RegisterAll ends up in olefact.cpp:135 where CoRegisterClassObject is called. From MSDN:
Registers an EXE class object with OLE so other applications can connect to it.
I believe this registration will be limited to the current user's session and the lifetime of the application. The Remarks section touches on privileges (As of Windows Server 2003...) but doesn't provide anything concrete.
There's an object known as the Running Object Table (ROT) that can be retrieved via GetRunningObjectTable. The documentation has this snippet:
Each workstation has a local ROT that maintains a table of the objects that have been registered as running on that computer.
The COM Elevation Moniker has some more information about the ROT and privileges (it suggests processes of various privilege levels work fine with it). The links on the left-hand side might help, too.
Overall it seems there's nothing to suggest that CoRegisterClassObject requires administrator permissions.
UpdateRegistryAll
This function ends up in olefact.cpp:375 where it opens HKEY_CLASSES_ROOT. At this point the documentation gets a bit better:
Registry functions such as RegOpenKeyEx or RegQueryValueEx allow you to specify the HKEY_CLASSES_ROOT key. When you call these functions from a process running in the interactive user account, the system merges the default settings in HKEY_LOCAL_MACHINE\Software\Classes with the interactive user's settings at HKEY_CURRENT_USER\Software\Classes.
Further on:
If you write keys to a key under HKEY_CLASSES_ROOT, the system stores the information under HKEY_LOCAL_MACHINE\Software\Classes
The documentation doesn't define what happens when you try to write to HKEY_CLASSES_ROOT under limited privileges (i.e. a standard user can't write to HKLM), but I believe that you'll end up writing to HKCU instead.
And finally, note:
Windows Server 2003 and Windows XP/2000: Applications can register dependent COM objects to either the per-machine or per-user COM configuration store (HKEY_LOCAL_MACHINE\Software\Classes or HKEY_CURRENT_USER\Software\Classes).
So if it falls through to HKCU, you should be fine.
Caveat Implementor: Don't rely on implementation details.
I have a CComModule that is calling RegisterServer (TRUE) on DllRegisterServer and UnregisterServer (TRUE) on DllUnregisterServer. The UnregisterServer is getting a 0x8002801C (Error accessing the OLE registry.) error and leaving around registery keys. I am using a Windows Server 2k8 R2 machine with UAC enabled. The components are x86 and I am using the 32 bit regsrv32.
Does anyone know why I would be getting this error?
You must run Regsvr32.exe from a command prompt that's elevated to administrator (i.e. UAC disabled). Make a shortcut on your desktop to "cmd.exe", right-click it and choose "Run as Administrator".
If you're using ATL and VS2008 then you can register your COM object per-user which writes the necessary registry keys to HKEY_CURRENT_USER instead of HKEY_LOCAL_MACHINE. You register your object by passing a special user switch to regsvr32, e.g.:
regsvr32.exe /i:user /n yourobject.dll
COM servers can be registered with the /RegServerPerUser switch.
I asked a similar question.