I have a C# application which stores it's settings in ProgramData subfolder such as
C:\ProgramData\Manufacturer\Product\Version\Settings.xml
I noticed that the application can't save settings changes, getting a permission denied error. My work-around was to manually change security settings and give Everyone full control on the folder tree and file. This works, but I'd like a more robust method.
Using suggestions from SO, I created the following code:
private void set_permissions()
{
try
{
// Create security idenifier for all users (WorldSid)
SecurityIdentifier sid = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
// get file info and add write, modify permissions
FileInfo fi = new FileInfo(settingsFile);
FileSecurity fs = fi.GetAccessControl();
FileSystemAccessRule fsar =
new FileSystemAccessRule(sid, FileSystemRights.FullControl, InheritanceFlags.None, PropagationFlags.None, AccessControlType.Allow);
fs.AddAccessRule(fsar);
fi.SetAccessControl(fs);
LogIt.LogInfo("Set permissions on Settings file");
}
catch(Exception ex)
{
LogIt.LogError(ex.Message);
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
When I step through the code, I get
Attempted to perform an unauthorized operation exception
when I execute this statement:
fi.SetAccessControl(fs);
If I close Visual Studio 2015 and open it as administrator, then my code will execute properly and the file security now has an entry for Everyone with full control.
So finally, here comes the question:
I'm following suggestion of putting the above code in my application, then in the setup project I add a custom action to run the newly installed application with an Install command-line option. My application, if it sees "Install" argument, will run the above code. Since I'm using a setup project which installs for all users by default, it automatically gives the administrator prompt before install. Does that mean the entire session, including the special action to run the application after install, is running under administrator rights?
If so, this should work, right?
But if the person installing changes it to "This user" then it would not be running with admin rights, and my code will fail. If needed, I could always be the one to do the final install and therefore would always use the administrator prompt, but I hate to depend on that.
Is there a more proper way to do this?
Thanks...
It seems that your program is not running elevated and therefore cannot update files in that location, and I assume that you want your users to not require admin privilege that you could add using an elevation manifest in your program.
So why choose that location to store the data? Why not just use User's Application Data folder?
As for that code, it's probably more robust to add it as an installer class custom action rather than run an executable. In an Everyone install that runs elevated the code will run privileged with the local system account.
Related
I am relatively new to using files and creating directories in C#, but I have been stuck for a while. I receive the following error: System.UnauthorizedAccessException: 'Access to the path 'C:\Program Files\Skyroom' is denied.'
Here is my code in case it helps:
if (File.Exists(#"C:\Program Files\Skyroom\gamedata.txt"))
{
Console.WriteLine("Game loading. Please wait..");
Thread.Sleep(500);
Console.Clear();
Console.WriteLine("Game loading. Please wait...");
Thread.Sleep(500);
Console.Clear();
Console.WriteLine("Game loading. Please wait.");
Thread.Sleep(500);
Console.Clear();
Console.WriteLine("Game loading. Please wait..");
Thread.Sleep(500);
Console.Clear();
Console.WriteLine("Game loading. Please wait...");
Thread.Sleep(500);
Console.Clear();
}
else
{
Directory.CreateDirectory(#"C:\Program Files\Skyroom");
File.Create(#"C:\Program Files\Skyroom\gamedata.txt");
Main();
}
Thank you. Any info needed, just ask.
You're getting that error because your app isn't running as administrator and is trying to write to Program Files which is for admins only.
Unless you're writing an installer, your application will never need to run as administrator so it can write to Program Files. Program files is not intended for applications to write runtime data to. It's a secure location intended for an administrator to install applications into. This process protects trusted application files from being maliciously changed.
You should not be writing your data to the ProgramFiles directory. Windows has a variety of directories for writing data to, such as %TEMP%, %APPDATA%, and %LOCALAPPDATA%.
Windows Environment Variables
Your problem is the windows user you are running the application under does not have permission to the folder C:\Program Files\Skyroom\.
You have a few options. One is to grant read/write permissions to the user at the time you create the directory:
var skyroomDirectory = Directory.CreateDirectory(#"C:\Program Files\Skyroom");
DirectorySecurity security = skyroomDirectory.GetAccessControl();
security.AddAccessRule(new FileSystemAccessRule(#"MYDOMAIN\JohnDoe",
FileSystemRights.Modify,
AccessControlType.Allow));
skyroomDirectory.SetAccessControl(security);
File.Create(#"C:\Program Files\Skyroom\gamedata.txt");
Using the appropriate AccessControlType(s) for your needs. You should use the least amount of privilege necessary to perform the necessary tasks. https://learn.microsoft.com/en-us/dotnet/api/system.security.accesscontrol.filesystemrights?view=netframework-4.7.2
Another option is to save the file in a user folder that the user will have permissions to. But the issue is a user will see a weird file and possibly delete it.
According to File.Create, An UnauthorizedAccessException means one of 2 things:
The caller does not have the required permission.
-or-
path specified a file that is read-only.
For Directory.CreateDirectory, it means:
The caller does not have the required permission.
I wouldn't create a directory under Program Files or Program File x(86). It is advisable to create under like C:\Users\ where you will have permissions.
If still need to create in program files, run visual studio as Administrator or change your manifest like below:
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
Im hosting an asp.net application in IIS8 on windows server 2012.
this application suppose to execute an batch file.
it works perfect if i execute the application with visual studio in debug mode. but when i upload it to the IIS the application cant execute the batch file.
i tried to change the batch file with exe file. same problem.
the batch file suppose to execute from the application(WCF application) that in the IIS:
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo.WorkingDirectory = #"C:\path";
proc.StartInfo.FileName = #"C:\path\executer.bat";
proc.Start();
proc.Close();
please help,
Most likely the problem you are experiencing is due to permissions. You need to check what account the IIS Application Pool that your app is running under is configured for and whether that account has rights to run your batch file or the commands within that batch file.
When running in Visual Studio you're likely running IIS Express as the interactive user.
When running under IIS by default you're running under ApplicationPoolUser identity which has no rights to execute code, has no file access or anything else. Unless you've explicitly set a different account with appropriate file access rights to the batch file, and rights to execute the commands inside of the batch file, you won't be able to run the batch file from within IIS. To change that change the Application Pool user identity to a user that does have rights to both read and execute the batch file on disk and has any rights required to run what's executing in the batch file.
Make sure any folder or file accessed by your application have permissions granted to the AppPoolUser account. It is also important to check your applications resource folders too. For example, if you are writing logs, make sure you give the appPool user account enough permission to write to that file.
Your code is working fine . May be there is some issue in batch file i faced before .My batch file is
start "" BATCHLOG.exe
where BATCHLOG.exe is the executable
Some times batchfile named only
BATCHLOG.exe
does not work correctly on windows scheduler so may be in that case of yours
I'm trying to start a few applications for the current user only when Windows starts up.
I can accomplish this with the following:
RegistryKey oKey = Registry.CurrentUser.OpenSubKey("Software", true);
oKey = oKey.OpenSubKey("Microsoft", true);
oKey = oKey.OpenSubKey("Windows", true);
oKey = oKey.OpenSubKey("CurrentVersion", true);
oKey = oKey.OpenSubKey("Run", true);
oKey.SetValue("Application 1", "C:\\path\\to\\ap1.exe");
oKey.SetValue("Application 2", "C:\\path\\to\\ap2.exe");
But I'm trying to run this as part of a Visual Studio Installer Project. I've added my custom action, the program starts like it should, and the installer works great in XP.
In Windows 7, the installer gets elevated privileges, and does everything but insert the entries into the registry for the current user. How ever, it does insert the registry entries when ran as a standalone application (outside of the installer project) and it does not get elevated privileges.
The only thing I can figure is that with the elevated privileges, it's trying to insert the entries into the Administrators account instead of the current user? or is there something else I'm missing? and is there another way I can achieve my goal here?
Is there a reason to not use the startup folder for the user?
More than likely the problem is the user the installer is executing under. If the user isn't the admin the elevated installer will run under the context of the user who elevated the process.
It would be a safer choice to add your application to the startup folder or to add the registry key on first launch.
If the installer is getting elevated permissions, why write the setting to HKCU? Write it to HKLM instead. It will then take effect for all users.
The scenario:
I have a Java based installer.
The Java based installer calls a C# program, whose job is to create a shortcut.
The shortcut location depends on if the installer is running as administrator or as a regular user. When running as admin, I'm trying to create a shortcut to "%ALLUSERSPROFILE%\Desktop", else I write to "%USERPROFILE%\Desktop".
My impression is that the issue seems to be a loss of administrative privilege when my Java program calls my C# shortcut maker program.
Notes:
I run my Java based installer as administrator (right click, run as administrator).
I'm able to verify the installer is running with administrator privileged because I can read registry keys that require administrative privilege.
I'm calling my C# program via 'Process process = Runtime.getRuntime().exec(command);'
When running the command manually through an administrative command prompt, the command works fine. (When outputting to "%ALLUSERSPROFILE%\Desktop")
When running the the same command manually, from a normal command prompt, I get System.UnauthorizedAccessException. (Which is to be expected). The program crashes in a similar was that it does when run from the installer.
The Exception:
Unhandled Exception: System.UnauthorizedAccessException: Access is
denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED)) at
IWshRuntimeLibrary.IWshShortcut.Save()
Any thoughts on what I'm missing? The installer needs to be flexible to run as both a normal user and as an administrator. How can I ensure this behavior?
Update 1
I attached a debugger to the C# program at runtime. It is throwing a:
DirectoryNoFoundException was unhandled
The system cannot find the path specified. (Exception from HRESULT: 0x80070003)
I added "mkdir" commands before my shortcutmaker commands. The mkdir commands, just ensure that the directories exist before trying to write to them.
Rebuilt the installer, ran it and when trying to mkdir "%ALLUSERSPROFILE%\Desktop", java throws an exception of
java.io.IOException: Cannot run program "mkdir": CreateProcess error=2, The system cannot find the file specified
java.io.IOException: Cannot run program "mkdir": CreateProcess error=2, The system cannot find the file specified
at java.lang.ProcessBuilder.start(Unknown Source)
at java.lang.Runtime.exec(Unknown Source)
at java.lang.Runtime.exec(Unknown Source)
at java.lang.Runtime.exec(Unknown Source)
At this point, it looks like my process isn't getting admin access
Process process = Runtime.getRuntime().exec(command);
I'm going to see if I can find anything else.
Update 2
The following gave me some info that I tried: Enterprise Logging not translating environment variables in XML Trace Listener fileName specification
It suggested that %ALLUSERSPROFILE% was not getting translated.
Instead of %ALLUSERSPROFILE%, I got the environment variable values via:
String allUsersProfile = System.getenv("ALLUSERSPROFILE");
String userProfile = System.getenv("USERPROFILE");
I was then able to supply the actual values to the C# program. But I'm still having issues.
From a admin console I can navigate to "c:\ProgramData\Start Menu", but if I run "explorer" with administrative priviledges, I can navigate to "c:\ProgramData" but not see anything past that... Through some looking, I found out that "c:\ProgramData\Start Menu" is a protected operating system file. So I turned on the setting to see it. So now I can see it, but not go into it.
Using system internals, I elevated an explorer.exe to "system" access and still can't go into the folder (System internal elevation reference: http://verbalprocessor.com/2007/12/05/running-a-cmd-prompt-as-local-system/)
I right clicked on the folder and checked out the security tab. It looks like even my "System" user has limited access. I find this a bit baffling, that I can run the command from an admin command prompt that will write the shortcut to the desktop, but going through this other process I cannot... I also find the access to be a bit inconsistent.
I'm able to successfully uninstall a third-party application via the command line and via a custom Inno Setup installer.
Command line Execution:
MSIEXEC.exe /x {14D74337-01C2-4F8F-B44B-67FC613E5B1F} /qn
Inno Setup Command:
[Run]
Filename: msiexec.exe; Flags: runhidden waituntilterminated;
Parameters: "/x {{14D74337-01C2-4F8F-B44B-67FC613E5B1F} /qn";
StatusMsg: "Uninstalling Service...";
I am also able to uninstall the application programmatically when executing the following C# code in debug mode.
C# Code:
string fileName = "MSIEXEC.exe";
string arguments = "/x {14D74337-01C2-4F8F-B44B-67FC613E5B1F} /qn";
ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments)
{
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardOutput = true
};
Process process = Process.Start(psi);
string errorMsg = process.StandardOutput.ReadToEnd();
process.WaitForExit();
The same C# code, however, produces the following failure output when run as a compiled, deployed Windows Service:
"This action is only valid for products that are currently installed."
Additional Comments:
The Windows Service which is issuing
the uninstall command is running on
the same machine as the code being
tested in Debug Mode. The Windows
Service is running/logged on as the
Local system account.
I have consulted my application logs
and I have validated that the
executed command arguments are thhe
same in both debug and release mode.
I have consulted the Event Viewer
but it doesn't offer any clues.
Thoughts? Any help would be greatly appreciated. Thanks.
Step 1: Check the MSI error log files
I'm suspicious that your problem is due to running as LocalSystem.
The Local System account is not the same as a normal user account which happens to have admin rights. It has no access to the network, and its interaction with the registry and file system is quite different.
From memory any requests to read/write to your 'home directory' or HKCU under the registry actually go into either the default user profile, or in the case of temp dirs, c:\windows\temp
I've come across similar problems in the past with installation, a customer was using the SYSTEM account to install and this was causing all sorts of permission problems for non-administrative users.
MSI log files aren't really going to help if the application doesn't appear "installed", I'd suggest starting with capturing the output of MSIINV.EXE under the system account, that will get you an "Inventory" of the currently installed programs (or what that user sees installed) http://blogs.msdn.com/brada/archive/2005/06/24/432209.aspx
I think you probably need to go back to the drawing board and see if you really need the windows service to do the uninstall. You'll probably come across all sorts of Vista UAC issues if you haven't already...
Thanks to those offering help. This appears to be a permissions issue. I have updated my service to run under an Administrator account and it was able to successfully uninstall the third-party application. To Orion's point, though the Local System account is a powerful account that has full access to the system -- http://technet.microsoft.com/en-us/library/cc782435.aspx -- it doesn't seem to have the necessary rights to perform the uninstall.
[See additional comments for full story regarding the LocalSystem being able to uninstall application for which it installed.]
This is bizarre. LocalSystem definitely has the privileges to install applications (that's how Windows Update and software deployment in Active Directory work), so it should be able to uninstall as well.
Perhaps the application is initially installed per-user instead of per-machine?
#Paul Lalonde
The app's installer is wrapped within a custom InnoSetup Installer. The InnoSetup installer, in turn, is manually executed by the logged in user. That said, the uninstall is trigged by a service running under the Local System account.
Apparently, you were on to something. I put together a quick test which had the service running under the LocalSystem account install as well as uninstall the application and everything worked flawlessly. You were correct. The LocalSystem account has required uninstall permissions for applications in which it installs. You saved the day. Thanks for the feedback!