Programatically allowing Windows service to decrypt config file - c#

I've got a Windows service that needs to decrypt a config file, which I've encrypted on the same computer. (It doesn't need to be exportable.) I've been trying to overcome the ol' "The RSA key container could not be opened" error. I was able to do it manually:
c:\Windows\Microsoft.NET\Framework\v2.0.50727>aspnet_regiis -pa "NetFrameworkConfigurationKey" "NT AUTHORITY\NETWORK SERVICE"
but I need to accomplish this programatically. Based on two posts (one from SO and the other from CodeProject), I tried this:
private void GrantAccessToDecryptConfigFile()
{
// programatically execute this command:
// c:\Windows\Microsoft.NET\Framework\v2.0.50727>aspnet_regiis -pa "NetFrameworkConfigurationKey" "NT AUTHORITY\NETWORK SERVICE"
string command = "-pa";
string keyName = "NetFrameworkConfigurationKey";
string userName = #"NT AUTHORITY\NETWORK SERVICE";
string arguments = string.Format("{0} \"{1}\" \"{2}\"", command, keyName, userName);
var psi = new ProcessStartInfo(#"C:\Windows\Microsoft.NET\Framework\v2.0.50727\aspnet_regiis.exe")
{
Arguments = arguments,
UseShellExecute = false,
CreateNoWindow = true
};
Process.Start(psi);
}
...but I'm still getting the same error when the Windows service tries to read the config file. What am I doing wrong?

I think all you need is a user with administrator privileges to run the Windows service. I'm guessing you run that command on an elevated command prompt because that's the only way I could make it work.
Similarly when I tried to run it on Visual Studio I got the same error. I started the Visual Studio with "Run as Administrator" and it succeeded.

Related

Getting "Access is Denied" error on Process.Start() on an application running an executable with all permissions granted

The context here is that we have a C# service that normally runs scheduled jobs, but an executable was created that allows jobs to be triggered manually via command line. We put that executable on a separate IIS server, and did NOT install it as a service. The code inside the app to determine how it's being run is simply:
if (Environment.UserInteractive)
{
//parse the parameters and run the specified job
}
else
{
//start the service jobs
}
I made an API as a wrapper to call that executable, which uses the following code to run the executable with arguments as a user of the machine.
var proc = new Process
{
StartInfo = new ProcessStartInfo
{
WorkingDirectory = (absolute path of the folder that contains the exe),
FileName = (absolute path to the exe),
Arguments = (args),
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true,
Domain = (domain),
UserName = (username),
Password = (password),
Verb = "runas"
}
};
proc.Start();
proc.WaitForExit();
The API and the exe live in the same base folder. The API runs in IIS under an app pool user that is the same user it is running the process with. This user has Full Access permissions to the folder and executable, as well as the app pool user. We also added the user to the Administrator's group on that machine.
Running the exe via command line locally on that machine works fine. Only when calling from this application do we get the following error:
System.ComponentModel.Win32Exception (5): Access is denied
at System.Diagnostics.Process.StartWithCreateProcess(ProcessStartInfo startInfo)
at System.Diagnostics.Process.Start()
I've confirmed that we are targeting the right file, that my SessionId is not 0 (I would get an error saying the service was not installed whenever I didn't start the process as a specified user), and that the app pool user and windows user have permissions to execute the file. UAC is off, and the API and exe are not on the C:/ drive. After hours of googling and trying different things, I'm out of ideas. Any help would be very appreciated.

How to do Silent installation without UAC or App Is running as admin?

I want to do Silent installation. I know the command which do that "msiexec.exe /qn", but i can't do that if my application isn't running as administrator.
note:- my msi installer is created using WIX Toolset
Process process = new Process
{
StartInfo =
{
FileName = #"msiexec.exe",
Arguments = string.Format(#"/i ""E:\Build 16\ColiboConnect.msi"" /qn"),
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = false
}
};
process.Start();
process.WaitForExit();
You are requesting silent MSI installation therefore MSI will not display any UI - nor the UAC dialog.
Your parent process must already run with elevated privileges, or you must request elevation from Windows and use the privileges token to run new process.
We solved our problem using Windows Service. Our app will download the new msi, then call a WCF service, passing the path of the installer and the Service will install the new version without any problems because our service run under local account system and i think this is the only supported solution

Under which user account does Process.Start start?

I run on the machine as admin, but with the UAC set to default mode.
I start an installation program (using "Run as administrator"). From the installation process (using Wix) I start a client program that creates some files on the disc (C:\ProgramData...).
var startInfo = new ProcessStartInfo()
{
WorkingDirectory = installLocation,
FileName = fullPath
};
Process.Start(startInfo);
This first time the program runs, I can access all the data stored on the local disc without problems.
If I close it and start it again, I receive this error message:
Access to the path 'C:\ProgramData...' is denied.
If I start again the application using "Run as administrator" I can access the files from local disc; no error this time. The access path error appears only when I start the application directly.
Is this due to the settings from UAC or it is related that the local files where created under a more privileged user account?
Yes, the application will run without elevated privileges which are required to access ProgramData and other sensitive system folders or user related folders.
Any process you spawn from within your application will inherit the privileges your application has.
You need to create a manifest for your application to request elevated rights upon starting so you will have access to those folders.
Yes, as you say the local files are created under a more privileged user account.
You can check this passing the admin credential with ProcessStartInfo
var startInfo = new ProcessStartInfo()
{
WorkingDirectory = installLocation,
FileName = fullPath,
UserName = "Administrator",
Password = "password"
};
You can bypass this simply creating the ProgramData folder with lower privileges:
Add "Everyone" privilege to folder using C#.NET
or you can force that the application has to be started with administrator rights..
Project - Add New Item - "Application Manifest File".
change
<requestedExecutionLevel>
to
<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
When starting a new process, it inherits the privileges of the current process.
So if your process was elevated, the created process is elevated too. Second time you run your program, if it's not elevated, the spawned process won't be too.
You can specify the runas verb to force the display of the UAC pop-up that will allow to manually elevate your spawned process:
ProcessStartInfo startInfo = new ProcessStartInfo
{
UseShellExecute = true,
FileName = "cmd.exe",
Verb = "runas"
};

SC.EXE - Calling from C# - Access Denied

I have a batch file I wrote (proof of concept) to install a sample service I also created. It contains the following command line:
sc create serviceTest binPath= C:\Sandbox\ServiceTest\ServiceTest.exe DisplayName= "Service Test"
When I right click and select 'Run as Administrator' everything runs as expected. Running the batch file without doing this gives 'Access Denied'. This is proof that the command works.
I have also tried running the sc command via Process.Start():
const string sc = #"sc";
const string arguments = #"create serviceTest binpath= {0} DisplayName= ""Service Test""";
FileInfo fi = new FileInfo(this.txtServiceLocation.Text);
if (fi.Exists)
{
ProcessStartInfo psi = new ProcessStartInfo()
{
FileName = sc,
Arguments = string.Format(arguments, fi.FullName),
UserName = "admin",
Password = "secret".ToSecureString(),
Domain = "MYDOMAIN",
WorkingDirectory = fi.DirectoryName,
CreateNoWindow = true,
UseShellExecute = false
};
Process.Start(psi);
}
else
MessageBox.Show("The service exe could not be found.");
I need to be able to do this programatically. What do I need to do to get this to work?
CLARIFICATION: I need to be able to do this without a user being prompted. This code will be running under a custom tfs build process.
In Windows 7 by default, runs most applications with least privilege access (non-admin) control. As your application is trying to modify the system, it needs to be elevated to Admin privilege in order to run successfully. If you want to make this app to run in admin privilege permanently, please follow the instructions as in the link
http://www.groovypost.com/howto/microsoft/automatically-run-any-application-as-admin-in-windows-7/
You need to add a UAC manifest file to your assembly in order to force UAC to run the process as an administrator. For a reference to other solutions, you can see UAC need for console application.
While I never got this to work I can still use impersonation via code and also ensure that the tfs build account has appropriate access. This is what I had to do.

Install service and add registry entry under Vista+

I have a program that runs as a desktop application, but can also be installed as a windows service. The installation is done by using an "install as service" button on the GUI. The event handler for this button looks like this:
ProcessStartInfo psi = new ProcessStartInfo("sc", "description " +
this.ServiceName + " \"" +
((AssemblyDescriptionAttribute)attributes[0]).Description + "\"")
psi.CreateNoWindow = true;
psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
psi.Verb = "runas";
Process.Start(psi).WaitForExit();
What I would like to do now is to add some additional registry entries under say:
HKLM\SOFTWARE\MyCompany\Services
which also needs elevated privileges. But if I use the same procedure as described above with the command "REG ADD" the UAC dialog would appear more than once - and I don't want that.
So whats the best way to install a windows service and add a registry entry under HKLM with only having the UAC prompt once?
Create a small exe or a batch file that does both things (the sc and the reg update). Launch that instead of sc.
As for installing service.
You can try topshelf. It is easy to use and very powerful.
I ended up calling myself with admin priviliges and a special parameter myprogram.exe -i and then branch into a special method which uses the ServiceInstaller class to install the program as a service (instead of calling sc).

Categories

Resources