CreateFile() returns ACCESS_DENIED in Windows10 when i try in my project. If i create sample application using CreateFile() it works fine. Even tried to check admin privileges before calling CreateFile(), user is in admin mode. Same code works fine in Win 7.
Below is code sample:
WCHAR userPath[] = L"C:\\test.txt";
HANDLE hFile = NULL;
hFile = ::CreateFile(userPath,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(hFile == INVALID_HANDLE_VALUE)
{
wprintf(L"Error HANDLE = 0x%x \n",hFile);
}
else
{
wprintf(L"Suceess HANDLE = 0x%x \n",hFile);
::CloseHandle(hFile);
}
The most obvious explanation is that your user simply does not have sufficient rights to create files at the root level of the system drive.
Since Windows 7, and possibly even Vista, the default security configuration of the system drive permits standard user to create folders at the root level, but not files. So, my hypothesis is that you are not running your process elevated as you claim, but are in fact running the process with standard user rights. In order for you to create a file at that location you will need to either:
Run the process with elevated rights, or
Modify the security settings of the volume.
I was running my application in browser. There was issue with IE settings. When i disabled protected mode from IE->Security->Enable protected Mode, CreateFile() worked. Another solution is adding the ip to trusted site in IE.
Related
My app needs to write to a file in \ProgramData that could be protected. This only happens once after installation.
Is there an API function that would take ACL info and prompt the user to authorize the app to access the file? In other words the app would ask Windows to prompt the user for confirmation and authorization. This should happen interactively, and allow the app to resume execution after access to the file has been authorized. The app runs as Standard User, does not require Admin privilege.
The file gets opened with CreateFile().
Edit: There is a subtle difference between my query and the others said to be duplicates. I am asking for permission to access one specific object, a file. The others are asking to elevate the privileges of the whole process. Anyway, I am grateful for all responses which include a solution.
If you don't want to elevate your entire app, you have a few options:
spawn a separate elevated process just to access the file. Use ShellExecute/Ex() with the runas verb, or CreateProcessElevated(), to run a second copy of your app, or another helper app, with command-line parameters to tell it what to do. The main process can wait for the second process to exit, if needed.
create a COM object to access the file, and then use the COM Elevation Moniker to run the COM object in an elevated state.
prompt the user for credentials using CredUIPromptForCredentials() or CredUIPromptForWindowsCredentials() (see Asking the User for Credentials for more details), then logon to the specified account using LogonUser() to get a token, impersonate that token using ImpersonateLoggedOnUser(), access the file as needed, and then stop impersonating using RevertToSelf() and close the token with CloseHandle().
Thanks to #Remy for the ShellExecuteEx suggestion, here are the sordid details. Note the use of 'cmd' and the double-command, so the user only has to reply once. Also, [1] must wait for process completion otherwise you could find yourself creating the file before it was deleted, and [2] don't wait for the process if it failed.
// delete file with Admin privilege
// 'file_name' is path of file to be deleted
SHELLEXECUTEINFO shex;
char param[512];
char *cmd = "/C \"attrib -H \"%s\" && del /F /Q \"%s\"\""; // double command
_snprintf(param, sizeof(param), cmd, file_name, file_name);
ZeroMemory(&shex, sizeof(shex));
shex.cbSize = sizeof(shex);
shex.lpVerb = "runas"; // runas, open
shex.lpFile = "cmd"; // not 'del'
shex.lpParameters = param;
shex.nShow = SW_HIDE;
shex.fMask = SEE_MASK_NOCLOSEPROCESS;
BOOL retshx = ShellExecuteEx(&shex);
// wait otherwise could return before completed
if(retshx)
{ time_t st = clock();
DWORD exitCode;
do
{ if(!GetExitCodeProcess(shex.hProcess, &exitCode))
break;
if(clock() - st > CLOCKS_PER_SEC * 5) // max 5 seconds
break;
} while(exitCode != STATUS_WAIT_0); // STILL_ACTIVE
CloseHandle(shex.hProcess);
}
Processes can only be launched with an elevated token, they can't gain it after the fact. So you can either re-launch your app elevated with a command line argument telling it what to do (simple solution), or implement an out-of-proc COM server that you can create elevated and pass instructions to it (harder).
A third solution is to leverage the built-in UAC support of the IFileOperation interface, but this doesn't let you read/write, only copy. So you could make a copy of the file you need to modify, modify the copy and then use IFileOperation to copy the temporary over the original.
I have created a Credential Launcher for Windows 7 and was able to run Windows application after the Tile button click event, it was very easy.
I added a few registry settings and *pbAutoLogon = FALSE;.
However now i am now trying to do the same for Windows XP.
Which function I should target or how to achieve the same results ?
I see you tagged your question with "Gina", so I guess you know that Credential Providers do not exist on XP.
Your answer depends on when exactly you want to run that program, especially with regards to the secure attention sequence (SAS, or when a user press CTRL-ALT-Delete)
Before the SAS, use WlxDisplaySASNotice
After the SAS, use WlxLoggedOutSAS
Since you don't want to write a whole GINA yourself, you could use a custom Gina that wraps msgina.dll. Here is one I wrote, you can find the original I started from in the Platform SDK.
Using that approch, you get a chance to execute code just before or just after certain events, like running your program after a successful logon, something like :
int WINAPI WlxLoggedOutSAS(PVOID pWlxContext, DWORD dwSasType, PLUID pAuthenticationId, PSID pLogonSid, PDWORD pdwOptions, PHANDLE phToken, PWLX_MPR_NOTIFY_INFO pMprNotifyInfo, PVOID * pProfile)
{
int result;
result = pfWlxLoggedOutSAS(pWlxContext, dwSasType, pAuthenticationId, pLogonSid, pdwOptions, phToken, pMprNotifyInfo, pProfile);
if (result == WLX_SAS_ACTION_LOGON)
{
//We have a successful logon, let's run our code
run_my_custom_code();
}
return result;
}
There are some caveats, though :
The code cannot block. Winlogon will wait, but your users might not. Spanw a process and let it run.
Your program will be running with SYSTEM privileges, which is a security risk. Sandboxing your process could be hard. If you can't break out of it, don't assume nobody can...
I'm trying to create an installer for OS X. To be able to write to directories owned by root (/Applications, /Library...) I'm using Authorization Services from the Security framework. The following code works fine with an admin user but fails with a standard user. Creation of the rights works without error message but the process still runs with lower privileges (no file is written at the mentioned position).
Of course I'm using the admin user's loginname/password for authentification.
AuthorizationRef authRef;
char rightName[] = "system.install.root.user";
AuthorizationItem kActionRight = { rightName, 0, 0, 0 };
AuthorizationRights rights = {1, &kActionRight};
AuthorizationFlags flags=kAuthorizationFlagExtendRights|kAuthorizationFlagInteractionAllowed;
OSStatus err = AuthorizationCreate(&rights, 0, flags, &authRef);
// [ write to a file in /Applications; doesn't work with standard users ]
if (authRef != 0)
AuthorizationFree(authRef, kAuthorizationFlagDestroyRights);
I know there are examples that use AuthorizationExecuteWithPrivileges(), but as this is deprecated in OS X 10.7 I'd rather avoid using it. Any idea what I'm doing wrong or what I need to do to obtain root privileges?
Thanks for any help,
Chris
Maybe you need use PackageMaker instead of writing your own installer. This save your time... And dependent of your requirement you can use HelperTools that will be automatically copy binaries to the /Library...
I am setting up a scratch desktop to run another application in a "silent mode" - the other app is noisy and throws all sorts of windows around while it processes.
I have used the info here: CreateDesktop() with vista and UAC on (C, windows)
and CreateDesktop works - I can create the other desktop, I can launch the application into the other desktop (I see it launching in task manager) - but when I try to interact with the app via DDE, the DdeConnect call hangs until it times out.
And here's how I'm calling CreateDesktop:
LPSTR desktopName = "MYDESKTOPNAME";
HDESK hDesk = CreateDesktop(desktopName , NULL, NULL, 0, DESKTOP_SWITCHDESKTOP|
DESKTOP_WRITEOBJECTS|
DESKTOP_READOBJECTS|
DESKTOP_ENUMERATE|
DESKTOP_CREATEWINDOW|
DESKTOP_CREATEMENU, NULL);
Here is CreateProcess to actually launch the app into the new desktop:
STARTUPINFO startupInfo;
GetStartupInfo(&startupInfo);
startupInfo.lpDesktop = desktopName;
PROCESS_INFORMATION procInfo;
memset(&procInfo, 0, sizeof(procInfo));
if (CreateProcess(NULL, exePath, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &startupInfo, &procInfo)){
WaitForInputIdle(procInfo.hProcess, INFINITE);
CloseHandle(procInfo.hProcess);
CloseHandle(procInfo.hThread);
}
If it matters, the call to DdeInitialize:
DWORD afCmd = APPCLASS_STANDARD | APPCMD_CLIENTONLY | CBF_SKIP_ALLNOTIFICATIONS;
UINT rslt = ::DdeInitialize(&ddeInst, NULL, afCmd, 0);
Here is the DdeConnect call (the hsz* parameters, etc... are all fine - if I launch the app into the regular desktop, the calls all work perfectly).
hConv = ::DdeConnect(ddeInst,
hszService,
hszTopic,
NULL);
This call just hangs for ~60 seconds.
Is this a security issue of some sort? i.e. the windows messages aren't passing between desktops? Or does anyone have any suggestion on how to troubleshoot this further?
The documentation for CreateDesktop contains a cross-reference to the Desktops topic, which says
Window messages can be sent only between processes that are on the same desktop.
The overview topics are important. They provide background information to help you understand the feature.
Raymond explains why the messages don't get through. In order to solve the problem, assuming you continue with the separate desktop, you will simply need to run the process that performs the DDE in the same desktop as the target app. If you need to communicate between your process on the main desktop and the target process then you will need to use some other form of IPC.
I have an application that would check for updates upon start and, if updates are found, it would copy some files over the network to the program files folder. Obviously such task can't be performed by Standard Users under normal scenarios.
I tried creating a service to do the update process but I had some security issues and I asked this question about it in superusers.
Now, considering the fact that most applications require elevated privileges to perform such task I think that might be the right approach. But how do I request elevation for the updater under all Windows version as of XP, included. I've found many topics about a manifest file, but since I need this to work with XP I can't create a solution specifically for UAC.
Privileges can only be elevated at startup for a process; a running process' privileges cannot be elevated. In order to elevate an existing application, a new instance of the application process must be created, with the verb “runas”:
private static string ElevatedExecute(NameValueCollection parameters)
{
string tempFile = Path.GetTempFileName();
File.WriteAllText(tempFile, ConstructQueryString(parameters));
try
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.UseShellExecute = true;
startInfo.WorkingDirectory = Environment.CurrentDirectory;
Uri uri = new Uri(Assembly.GetExecutingAssembly().GetName().CodeBase);
startInfo.FileName = uri.LocalPath;
startInfo.Arguments = "\"" + tempFile + "\"";
startInfo.Verb = "runas";
Process p = Process.Start(startInfo);
p.WaitForExit();
return File.ReadAllText(tempFile);
}
catch (Win32Exception exception)
{
return exception.Message;
}
finally
{
File.Delete(tempFile);
}
}
After the user confirms the execution of the program as administrator, another instance of the same application is executed without a UI; one can display a UI running without elevated privileges, and another one running in the background with elevated privileges. The first process waits until the second finishes its execution. For more information and a working example you can check out the MSDN archive.
To prevent all this dialog shenanigans in the middle of some lengthy process, you'll need to run your entire host process with elevated permissions by embedding the appropriate manifest in your application to require the 'highestAvailable' execution level: this will cause the UAC prompt to appear as soon as your app is started, and cause all child processes to run with elevated permissions without additional prompting.