I am trying to set the owner of a file to another user programmatically in C++.
I have definitely enabled the SeRestorePrivilege for my process. I can confirm this using Process Explorer. I start the process, it is disabled, I run my code to enable it, ProcExp reports it as enabled, I go just up to the point where the owner is to be set, and it is still enabled (i.e. I am not accidentally disabling it).
What other caused can there be for this access is denied message? What have I not considered?
std::wstring fileSystemObject = L"C:\test.txt";
*status_code = SetNamedSecurityInfo((wchar_t*)fileSystemObject.c_str(), SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION, pSID, NULL, NULL, NULL);
if (*status_code == ERROR_SUCCESS)
{
Log(L"Successfully set owner for " + fileSystemObject);
return true;
}
else
{
Log(L"Failed to set owner for " + fileSystemObject + L". Error code: ", *status_code);
return false;
}
Thank you.
EDIT: Thank you very much for your continued assistance. It is greatly appreciated.
I used your code for all of the following tests. Basically, I am also getting Access Denied messages from your code, however, I have tracked it down a little more.
Firstly, "C:\test.txt" was not my real code, and unfortunately the missing backslash is not the cause of my problem. Thank you for your keen eyes though :)
Also, I am running an administrator account with UAC disabled, and my program has requireAdministrator set in the manifest.
However, I have noticed that both my code and yours work for simple files. After much testing, I have discovered that I only get AccessDenied messages in the following scenarios:
1: I am not the owner, and the "Take Ownership" permissions is set to Deny for e.g. Everyone.
2: I am the owner, and the "Take Ownership" permissions is set to Deny for e.g. Everyone. Curiously, in this second instance, despite the failure code, the ownership change does actually occur.
I don't see why this is happening. I, and you, have set SE_RESTORE_NAME in the process token. I should be allowed to arbitrarily set the owner SID. But it seems that I can't.
It seems that any Deny on TakeOwnership DACLs overrides my ability to take ownership. However, I can't change permissions until I can take ownership! sigh.
I might try setting SeTakeOwnershipPrivilege as you initially recommended, taking ownership to myself, changing permissions, setting ownership externally. What a pain. And I am not even very confident it will work.
I also found this: http://us.generation-nt.com/setnamedsecurityinfo-failing-rc-1307-help-59729462.html
He seems to be in a similar situation (I get 1307 if I don't set up the process token properly). But CreatePrivateObjectSecurityEx takes a whole lot more setting up.
Hmmmm. Thanks for your time.
The problem here is that security subsystem and model are defending the object from unreasonable ownership changes, and even having administrator permissions one needs to correctly overcome the obstacles.
There are two privileges involved in taking ownership of a file: SE_TAKE_OWNERSHIP_NAME and SE_RESTORE_NAME. The former allows taking someone's object and the latter allows setting owner who is not the setter himself.
It might look like SE_RESTORE_NAME is a more powerful privilege and is sufficient for the task, however it appears that it is not. Yes it allows to set someone's ownership, as MSDN states:
If the caller does not have the SeRestorePrivilege constant (see
Privilege Constants), this SID must be contained in the caller's
token, and must have the SE_GROUP_OWNER permission enabled. The
SecurityInfo parameter must include the OWNER_SECURITY_INFORMATION
flag. To set the owner, the caller must have WRITE_OWNER access to the
object or have the SE_TAKE_OWNERSHIP_NAME privilege enabled.
However it does not let you overcome DACL item that explicitly prevents from ownership change. In this case you need that other privilege as well (that is, you need to enable both), which enables you to take ownership from someone before you decide whom you are going to give it then to.
I am copying the link to C++/ATL source code from comment above: SetFileOwner.cpp. When permissions/DACL has a Deny item, an exception takes place and enabling second privilege resolves the problem.
Related
A windows service creates a registry value (for an Excel add-in) under HKEY_CURRENT_USER registry key for each logged on user (by calling ImpersonateLoggedOnUser() and RegSetValueEx()).
I need to delete this registry value when a user logs off, including system shutdown.
If it is not deleted at log off, and the software is uninstalled by one user then the entry in the registry remains for any other user that logged on during the lifetime of the service which causes a message box error to be displayed each time Excel begins because it is attempting to load an add-in that no longer exists.
Considered but rejected the following:
SetConsoleCtrlHandler() because there is no indication of what user is logging off.
REG_OPTION_VOLATILE because it is effective only when creating keys and I am only creating a value (did not thoroughly investigate so may not have been solution even if I was creating a key).
Are there any other mechanisms that would provide a solution to this? Windows versions are XP, Vista and 7.
Since you are already on a service, your life (should be) is easy.
In fact you can register yourself to receive the SERVICE_CONTROL_SESSIONCHANGE event. In particular, you will want to look for the WTS_SESSION_LOGOFF reason.
You have to register for these events in your service control routine, at startup, adding SERVICE_ACCEPT_SESSIONCHANGE. When the event is SERVICE_CONTROL_SESSIONCHANGE, the lpEventData parameter is a pointer to a WTSSESSION_NOTIFICATION structure, with information about the session currently terminating (thus, about the user logging off).
Check out the details on MSDN1, MSDN2, MSDN3 - the data structure that contains the dwSessionId of the interesting session
Check out this related (but not duplicate) question too
That said, I find João Augusto solution cleaner; I would use that for a similar problem; however, I wanted to add this solution for having an answer to the wider question (for future reference readers)
EDIT: Another method is to use SENS, check this MSDN article
An easier approach would be to put a command removing the value in question into the user's RunOnce key, e.g.,
reg.exe delete HKCU\Software\xyzzy /v myvalue /f
so that the unwanted value will be removed when the user next logs in. Note, however, that this might interfere with the creation of the value depending on how you are handling that.
There seems to be two methods of setting and getting a user screensaver parameters on a Windows platform:
1: Via the SystemParametersInfo() API:
//To read
SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &bScreensaverAcrtive, NULL);
SystemParametersInfo(SPI_GETSCREENSAVETIMEOUT, 0, &nScreensaverTimeout, NULL);
//No API to get the screensaver file used
//To set
SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, 0, bScreensaverAcrtive, NULL);
SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, 0, nScreensaverTimeout, NULL);
//No API to change the screensaver file
2: Through the system registry keys:
HKCU\Control Panel\Desktop - "ScreenSaveActive"
HKCU\Control Panel\Desktop - "ScreenSaveTimeOut"
HKCU\Control Panel\Desktop - "SCRNSAVE.EXE"
But since there're two competing methods that seem to do the same, what is the recommended way to use?
PS. I highly favor method #2 (or writing directly into registry) due to the following reasons:
A. If you read the explanation of a bug in the SPI_GETSCREENSAVEACTIVE flag, you'll see that MS themselves recommend to use registry.
B. If you read the documentation for the SPI_SETSCREENSAVEACTIVE and SPI_SETSCREENSAVETIMEOUT flags, there's this mystical line that says, "*If the machine has entered power saving mode or system lock state, an ERROR_OPERATION_IN_PROGRESS exception occurs.*" I first ignored this situation until it actually started happening on my test installation of Windows 8. This is the most asinine error, I should tell you. There's absolutely no graceful way of interpreting what it means or do any workaround (except, writing directly into the registry.)
Use the API. Asking that is like asking if you should wait for the traffic light to turn green before crossing the road. I won't call the cops if I see you crossing at red, but if you ask me, I'll tell you you have to wait. And you are the one taking the risk of bad things happening.
The API is documented, the registry locations are not. Microsoft is in no obligation to preserve the registry locations or their functionality.
The SPI_GETSCREENSAVEACTIVE flag affects Windows 2000. If you support Windows 2000 as a target platform, I would apply the registry read to that version only (OSVERSIONINFO.dwMajor=5, .dwMinor=0)
ERROR_OPERATION_IN_PROGRESS I'd try to figure out under what circumstances this happens (e.g. screensaver already active, or system about to enter a power saving state).
Generally, I'd find it questionable if activating / deactivating the screensaver is not at least related to a user action, in which case the system should be ready to accept a change.
What are you trying to achieve? Why do you need to modify screensaver activity? Maybe there's some better method to achieve your goal
Use the API. The registry format changes often.
As for the power state changes, screen savers are really a 20th century feature. Laptops turn off the screen entirely, for obvious reasons. In that power saving state SPI_SETSCREENSAVEACTIVE obviously should fail. Not a lot of interpreting to do.
So, check for GUID_VIDEO_POWERDOWN_TIMEOUT first.
edit
I just realized that Group Policy screensavers are also unlikely to be in the registry, and certainly would override HKCU. Not a real issue for Windows 2000, of course, but today the API method would be even more advisable. Of course, do realize that this is just another reason why SPI_SETSCREENSAVEACTIVE may return an error. Still an improvement over the registry approach, which fails silently in the presence of Group Policy.
"To set" above is incorrect. It should be:
//To set
SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, bScreensaverAcrtive, NULL, NULL);
SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, nScreensaverTimeout, NULL, NULL);
What I want to achieve:
I would like to count the instances of my application to a fixed number.
if more instances of the application are started, it should only work as a "Viewer"
Her is the code of the sample application
boost named_semaphore example
The problem:
it works fine if all processe are started from only one user
But I get a Security exception if I start the application with another user!!
(Access not allowed)
Somebody can point me in the right direction, the boost documentation is a little bit lacking on this topic ;-)
What permissions must be set to allow access from every other logged on user?
I found the solution
Looks like the docu for Boost isn't that bad :-/
http://www.boost.org/doc/libs/1_47_0/doc/html/boost/interprocess/permissions.html
Just have to pass the permission and set it to "unrestricted"
boost::interprocess::permissions permtest;
permtest.set_unrestricted();
_getch();
boost::interprocess::named_semaphore
the_semphore(boost::interprocess::open_or_create,"test_semaphore",3,permtest);
Unfortunately boost uses default security attributes for semaphore and there is no way to change it. Use ATL::CSemaphore or CSemaphore from MFC or even CreateSemaphore from WinApi and construct security descriptor which allows access for everyone.
I'm not exactly a Windows expert, so I can't tell you the answer by heart, but you need to know how named_semaphores are implemented (see "Some basic explanations" documentation of boost.interprocess) and then look up the permission policy for this resource to grant system-wide access. So, read the boost.named_semaphore code, and if they use a file, update that file's permissions, and if they use a system call, read the Windows API documentation for that system call.
Greetings!
When I try to use GetThreadContext() on a thread that I've started with CreateProcess(), I receive an error of 998: ERROR_NOACCESS
You can find a contrived but functional code example of this problem here: http://pastebin.com/tamDhYza
Based on the MSDN article regarding "Thread Security and Access Rights", my assumption is that I need to first pass the THREAD_GET_CONTEXT property into the lpThreadAttributes parameter of CreateProcess(). The type required by this argument is LPSECURITY_ATTRIBUTES, which appears to be a long pointer to the struct SECURITY_ATTRIBUTES. Unfortunately, I've not had much luck in figuring out how to add rights to this structure.
Could anyone help point me in the right direction?
I think you probably need to adjust the privileges of the calling code so that you can access the remote process. I suspect that you need to enable the SE_DEBUG_NAME privilege (see here) before you try and get the remote thread context. I'm not sure though as I usually use the debug API and call CreateProcess() with DEBUG_PROCESS which requires SE_DEBUG_NAME anyway...
If you do need to create a security descriptor then what you're doing is creating a DACL (discretionary access control list) which is a SECURITY_ATTRIBUTES structure that's populated with ACLs (access control lists) which allow or deny access to the resource by various principals (users, computers, etc). This used to be quite complex with lots of complicated API calls to make but now it's much easier, see http://msdn.microsoft.com/en-us/library/ms717798(VS.85).aspx for details.
Everything I've been able to find about escalating to the appropriate privileges for my needs has agreed with my current methods, but the problem exists. I'm hoping maybe someone has some Windows Vista/Windows 7 internals experience that might shine some light where there is only darkness. I'm sure this will get long, but please bear with me.
Context
I'm working on an application that requires accessing the memory of other processes on the current machine. This, obviously, requires administrator rights. It also requires SeDebugPrivilege (no, it is not a misspelling of SetDebugPrivilege), which I believe myself to be acquiring correctly, although I question if more privileges aren't necessary and thus the cause of my problems. Code has so far worked successfully on all versions of Windows XP, and on my test Vista 32 bit and Windows 7 64 bit environments.
Process
Program will Always be run with Administrator Rights. This can be assumed throughout this post.
Escalating the current process's Access Token to include SeDebugPrivilege rights.
Using EnumProcesses to create a list of current PIDs on the system
Opening a handle using OpenProcess with PROCESS_ALL_ACCESS access rights
Using ReadProcessMemory to read the memory of the other process.
Problem:
Everything has been working fine during development and my personal testing (including Windows XP 32 & 64, Windows Vista 32, and Windows 7 x64). However, during a test deployment onto both Windows Vista (32-bit) and Windows 7 (64-bit) machines of a colleague, there seems to be a privilege/rights problem with OpenProcess failing with a generic Access Denied error. This occurs both when running as a limited User (as would be expected) and also when run explicitly as Administrator (Right-click → Run as Administrator and when run from an Administrator level command prompt).
However, this problem has been unreproducible for myself in my test environment. I have witnessed the problem first hand, so I trust that the problem exists. The only difference that I can discern between the actual environment and my test environment is that the actual error is occurring when using a Domain Administrator account at the UAC prompt, whereas my tests (which work with no errors) use a local administrator account at the UAC prompt.
It appears that although the credentials being used allow UAC to 'run as administrator', the process is still not obtaining the correct rights to be able to OpenProcess on another process. I am not familiar enough with the internals of Vista/Windows 7 to know what this might be, and I am hoping someone has an idea of what could be the cause.
The Kicker
The person who has reported this error, and who's environment can regularly reproduce this bug, has a small application named along the lines of RunWithDebugEnabled which is a small bootstrap program which appears to escalate its own privileges and then launch the executable passed to it (thus inheriting the escalated privileges). When run with this program, using the same Domain Administrator credentials at UAC prompt, the program works correctly and is able to successfully call OpenProcess and operates as intended.
So this is definitely a problem with acquiring the correct privileges, and it is known that the Domain Administrator account is an administrator account that should be able to access the correct rights. (Obviously obtaining this source code would be great, but I wouldn't be here if that were possible).
Notes
As noted, the errors reported by the failed OpenProcess attempts are Access Denied. According to MSDN documentation of OpenProcess:
If the caller has enabled the SeDebugPrivilege privilege, the requested access is granted regardless of the contents of the security descriptor.
This leads me to believe that perhaps there is a problem under these conditions either with (1) Obtaining SeDebugPrivileges or (2) Requiring other privileges which have not been mentioned in any MSDN documentation, and which might differ between a Domain Administrator account and a Local Administrator account
Sample Code:
void sample()
{
/////////////////////////////////////////////////////////
// Note: Enabling SeDebugPrivilege adapted from sample
// MSDN # http://msdn.microsoft.com/en-us/library/aa446619%28VS.85%29.aspx
// Enable SeDebugPrivilege
HANDLE hToken = NULL;
TOKEN_PRIVILEGES tokenPriv;
LUID luidDebug;
if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken) != FALSE)
{
if(LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luidDebug) != FALSE)
{
tokenPriv.PrivilegeCount = 1;
tokenPriv.Privileges[0].Luid = luidDebug;
tokenPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if(AdjustTokenPrivileges(hToken, FALSE, &tokenPriv, 0, NULL, NULL) != FALSE)
{
// Always successful, even in the cases which lead to OpenProcess failure
cout << "SUCCESSFULLY CHANGED TOKEN PRIVILEGES" << endl;
}
else
{
cout << "FAILED TO CHANGE TOKEN PRIVILEGES, CODE: " << GetLastError() << endl;
}
}
}
CloseHandle(hToken);
// Enable SeDebugPrivilege
/////////////////////////////////////////////////////////
vector<DWORD> pidList = getPIDs(); // Method that simply enumerates all current process IDs
/////////////////////////////////////////////////////////
// Attempt to open processes
for(int i = 0; i < pidList.size(); ++i)
{
HANDLE hProcess = NULL;
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pidList[i]);
if(hProcess == NULL)
{
// Error is occurring here under the given conditions
cout << "Error opening process PID(" << pidList[i] << "): " << GetLastError() << endl;
}
CloseHandle(hProcess);
}
// Attempt to open processes
/////////////////////////////////////////////////////////
}
Thanks!
If anyone has some insight into what possible permissions, privileges, rights, etc. that I may be missing to correctly open another process (assuming the executable has been properly "Run as Administrator"ed) on Windows Vista and Windows 7 under the above conditions, it would be most greatly appreciated.
I wouldn't be here if I weren't absolutely stumped, but I'm hopeful that once again the experience and knowledge of the group shines bright. I thank you for taking the time to read this wall of text. The good intentions alone are appreciated, thanks for being the type of person that makes Stack Overflow so useful to all!
So after a lot of debugging and bothering a lot of people for information, I was finally able to track down the guy who wrote the RunWithDebugEnabled application and get a rundown of how it operates.
The problem, in this case, is that Debug programs privilege in the local policy for the domain administrator had been removed, and thus the SeDebugPrivilege token was not present in the process's access token. It can't be enabled if it's not present at all, and I still know of no way to add the privilege to an existing access token.
How the current magic works:
So the RunWithDebugEnabled magic application would use its Administrator rights to install itself as a service and start itself, thus running under the SYSTEM user account rather than the Domain Administrator. With SYSTEM privileges, the app then creates a new access token that is identical to the Administrator token, only with the SeDebugPrivilege token present. This new token is used to CreateProcessAsUser() and run the program with the newly enabled SeDebugPrivilege that was missing before.
I actually do not like this "solution" here, and have been continuing my search for a 'cleaner' way to obtain this privilege. I will be posting this as another question here on SO, which I will try to remember to link here as well to help others follow along and for future reference.
EDIT: Impersonate SYSTEM (or equivalent) from Administrator Account
I thank you all for your time and energies in helping to debug and solve this problem. It really is much appreciated!