c# run application as another user fails with System.ComponentModel.Win32Exception - c#

I work with emergency services and they have an application that uses map files to let them know where they need to go and it uses GPS to let them know where they are. We have to update the map files as things change and before I started here they were being done through VB scripts which started to fail. I decided to code my own app in C# to do this which works fine.
I created a package in SCCM 2012 that caches all of the files locally and then it compares the files in the cache to what is on the machine and then replaces any older files. This all works fine but the application they use called MobileCAD locks the files so I have to kill this process and then do the file copy and start the application again. We never know when an emergency happens so this update may start when they are on the road so it is important that it starts the application again as soon as possible. If it does not start the application then the emergency services people may try to do so manually but if core files are being updated then it may not start or cause issues.
I coded my application which uses an app manifest to force it to run as an administrator for the file copy. This application is run through SCCM which uses the local 'System' account to do all of the work and killing MobileCAD and copying files which works great. What I originally found was that it does start MobileCAD but it does so under the System account and the process would be there but it was not visible. I think this is the same problem they were originally having so the emergency services people would need to reboot the computer and wait for it to log back in and then start the wireless service so they could get back into MobileCAD.
To address this issue I did research and found that I could use the ProcessStartInfo in .NET and force it to use another account. As we use an automatic logon for these machines the users name, password, and domain are all in the registry so it was easy to pull it out and inject it into the code. Awesome, looks like it is easy enough so I code it up and sure enough it works perfectly when run under my admin account. In my basic testing everything worked perfectly until I try the same in SCCM, now it fails with the following error message.
System.ComponentModel.Win32Exception (0x80004005): Access is denied
at System.Diagnostics.Process.StartWithCreateProcess(ProcessStartInfo startInfo)
at System.Diagnostics.Process.Start()
at System.Diagnostics.Process.Start(ProcessStartInfo startInfo)
at UpdateFDM.Program.StartProcess(String processName)
I am sorry for all of the words but I believe it helps if you have a good understanding of the issue and what I am trying to do. I have also hard coded the user information into the code instead of pulling it from the registry but I get the same error. Again, this works fine under my admin account but fails when it is pushed through SCCM and it is only launching MobileCAD that fails.
This is the code I am using for launching MobleCAD, do you see where my issue may lie? I know SCCM confuses it but SCCM basically runs things just as you would from the command line but it uses the local System account.
Thanks for any help.
// Declares the new start instance
ProcessStartInfo process = new ProcessStartInfo();
// Gets the process to start
process.FileName = processName;
// Maximizes the process windows at start-up
process.WindowStyle = ProcessWindowStyle.Maximized;
// Gets the user name from the autologon information
process.UserName = GetDefaultUserInfo("DefaultUserName");
// Gets the domain for the user
process.Domain = GetDefaultUserInfo("DefaultDomainName");
// Holds the password for the default user
SecureString password = new SecureString();
// Gets the raw password from the registry
string rawPassword = GetDefaultUserInfo("DefaultPassword");
// Copies the password in a secure string
foreach (char ch in rawPassword)
{
password.AppendChar(ch);
}
// Sets the password
process.Password = password;
// Needed to launch the app as the logged on user
process.LoadUserProfile = true;
process.UseShellExecute = false;
// Starts the process
Process.Start(process);
// Process started, return true
return true;

Related

Requested registry allow access without security leaks

Right now i am using an web application with code to read from and write to the registry. While debugging in Visual studio everything went fine but on the online test server it didn't run. the error exception message i am getting is:
System.Security.SecurityException: Requested registry access is not
allowed.
This is the code i am using:
private RegistryKey GetWritableBaseRegistryKey(string extendedPath)
{
var path = "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
return RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default).OpenSubKey($"{path}\\{extendedPath}", true);
}
The sollutions i found where:
Solution 1
you will not be able to set AppPoolIdentity to a specific group, but
you can
create a local user (compmgmt.msc)
add the user to the administrator group (compmgmt.msc)
Set the application pool to run under that user, under Advanced Settings.
Obviously you know this is a very bad idea from a security
perspective, and should never ever ever be performed on a forward
facing server.
source
Solution 2
Create a separate console application to run the service in admin
modus so you could access the registry. This solution was performance
heavy because you need to run 2 separate applications.
Solution 3
Use this code to allow access to the registry.
RegistryPermission perm1 = new RegistryPermission(RegistryPermissionAccess.AllAccess, "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall");
perm1.Demand();
Or this code
RegistrySecurity rs = new RegistrySecurity();
string currentUserStr = Environment.UserDomainName + "\\" + Environment.UserName;
RegistryAccessRule accessRule = new RegistryAccessRule(currentUserStr, RegistryRights.WriteKey | RegistryRights.ReadKey | RegistryRights.Delete | RegistryRights.FullControl, AccessControlType.Allow);
rs.AddAccessRule(accessRule);
But these didn't work on the server however while debugging in visual studio the code ran fine.
In order for the web application to access the registry it must have sufficient permission. Consequently Solution 1 is the only one likely to work. It describes setting the web sites application pool to a user in the local administrators group. Its misses the steps about actually setting your IIS web site to use the newly created App Pool, which is why it might not work for you.
The technical process of reading a restricted registry, especially the application Uninstall registry key, inside a web server is really unlikely to be useful to you. Of what possible use is allowing a web server to access the servers own Application uninstall list going to be ?
I suspect you intend to open that registry key on the client's PC (my speculation) which is not going to be possible.

Printing any file type

I'm creating a service that will monitor a specific folder and print any file that is put in this folder. I'm having difficulties with the various file types that could be sent to the folder to be printed.
My first attempt is with Microsoft Office files. What I'm trying to do is start the office to print the file. It's more like a catch, I'm not really using a library or anything like it.
So far this approach would work, but when no Office application has ever started on the machine the Office asks for the user initials. So, in this case my application would just not work, since I'm doing this programatically.
ProcessStartInfo info = new ProcessStartInfo(myDocumentsPath);
info.Verb = "Print";
info.CreateNoWindow = true;
info.WindowStyle = ProcessWindowStyle.Hidden;
Process.Start(info);
Right now I am trying with Microsoft Office files, but I will apply the same approach for other types as well.
There is anyway to get around the Initials required by the first Office run?
Or any better approach to my problem?
Any help is appreciated, thanks in advance.
There's not really anything that you can do; for the application which will print each type of file that you're going to support, you need to make sure the application is configured correctly.
This means that for office (since it is run as an out-of-process COM server) you should run it under the account that is performing the printing so you can enter the initials and won't be prompted for it when the server attempts to print it.
The same for every other application (assuming the application is executed to print it), it needs to be run as the account the process is going to be run under and configured correctly.
Use Winternals's regmon registry activity monitor to figure out where Office stores the initials in the windows registry, then write these keys prior to printing.

Access problems to a local folder via a network share

I have a Windows service, running using the login localhost\administrator. This service is meant to invoke another executable (MyProcess.exe), which is supposed to write some stuff to a log file. The service uses Process.Start() to create the process, like so:
var p = new Process();
p.StartInfo.FileName = processFileName;
p.StartInfo.Arguments = arg;
p.Start();
Problem is, it appears that MyProcess.exe is being denied rights to write to the log file, even though localhost\administrator unquestionably has rights to the log folder. If I run MyProcess.exe from a command line, it works perfectly.
So, is it possible that the process is being executed using a different user login?
Can you think of any other reason why MyProcess.exe is being denied rights to write the log file?
UPDATE: the log file is being written to the local machine, but using a network address, i.e. \\MyPC\LogFolder. When I change the code to refer to C:\MyFolder, everything works fine. It's obviously having a problem with the network address (even though it's local).
What sharing settings do I need to put on the folder so that the local system account can access the file?
If you are using impersonating, than it impersonates a user that can be the currrent or a specified user. if not it will run under the Local System, with the privileges of the local system.
p.StartInfo.Domain = "UserName";
p.StartInfo.Password = "Passw0rd!";
You can get the username from:
Thread.CurrentPrincipal.Identity.Name
I've worked it out.
The problem, as noted in my update, is that the process was addressing the log folder using a network share address, \\MyPC\LogFolder, and when we switched the configuration so that it wrote instead to c:\Logfolder, it worked fine.
So it seems that when you address a local folder, the localhost\Administrator account is deemed to have sufficient rights. But when you go via the network share, you need to present valid network credentials, and localhost\Administrator just doesn't cut it. If you change to use MYDOMAIN\MyUser, it works even using the network share address.

Login with Admin user to some domain and copy files client machines with C#

I have got a project that can copy files to another client's desktops in my domain.There is 300+ client machine.But there is a problem.When i run this project in a non admin user account in my domain.It cant copy files getting error about Access Denied , user restrictions.I wanna do this program like this , in non admin user account when user start to copy files ;
first my program will get admin access by loggin in my admin user accoun to domain than will copy files.Than logout.How can i do this ? I wanna do this with C#.
I had a similar problem: Production needed to run one of my programs that processes files on a location on the network where they don't have any access.
I ended up using Impersonation, which allowed me to run the file processing thread under a set of credentials set at runtime by my program.
In AD I created a special user account with all required permissions for exclusive use by this program.
I know it’s not at all secure, but it works and the odds that it would even occur to someone to hack my program to get these credentials is remote.
Anyway, look into Impersonation I found these resources helpful:
Safely Impersonating Another User
Brian Low's ImpersonationHelper class
-Jay
You can switch privileges when starting the program from itself or from another program. You can do this with two programs, one that runs as the user account and then launches your privileged application. (or launch itself with a different command line to indicate the different run-mode.)
To launch a program in C# as a different user, do this,
// Create a secure version of the password
SecureString pass = new SecureString();
foreach ( char c in _pass.Text )
{
pass.AppendChar( c );
}
Process process = Process.Start( "PrivilegedProgram.exe", _arguments, _user.Text, pass, _domain.Text );
you need to change the thread to the context of an admin user. How you do that in a secure way is the challenge. This sounds like a quick utility program where the security may not be a big deal, however. Just change the admin's password once the utility has been run.

Best way to run a tool from ASP.Net page

I have a developer tool that I want to run from an internal site. It scans source code of a project and stores the information in a DB. I want user to be able to go to the site, chose their project, and hit run.
I don't want the code to be uploaded to the site because the projects can be large. I want to be able to run my assembly locally on their machine. Is there an easy way to do this?
EDIT: I should note, for the time being, this needs to be accomplished in VS2005.
EDIT 2: I am looking for similar functionality to TrendMicro's Housecall. I want the scan to run locally, but the result to be displayed in the web page
You could use a ClickOnce project (winform/wpf) - essentially a regular client app, deployed via a web-server. At the client, it can do whatever it needs. VS2005/VS2008 have this (for winform/wpf) as "Publish" - and results in a ".application" file that is recognised by the browser (or at least, some browsers ;-p).
You might be able to do the same with Silverlight, but that has a stricter sandbox, etc. It would also need to ask the web-server to do all the db work on its behalf.
I want to be able to run my assembly
locally on their machine
Sounds like you want them to download the tool and run it from their local machine, does that work for you?
Any code can scan files given the location and permissions. For a website to open an exe on a different machine and permit that to run and get access to the files contained on the web server would require a horrifically low level of security that would mean the entire system is practically completely open to attack. If your system is completely behind a firewall and hence protected from outside intererance then you want to look more at the permissions and less at the code.
To run an exe on a machine try following notepad example, though you may have to use a specified directory as well
ProcessStartInfo psi = new ProcessStartInfo("notepad.exe");
psi.WindowStyle = ProcessWindowStyle.Hidden;
Process p = new Process();
p.EnableRaisingEvents = true;
p.Exited += new EventHandler(ExitHandlerToKillProcess);
p.StartInfo = psi;
p.Start();
and when done dont forget to kill the Process. Alternately use javascript. Either way watch the security permissions and remember the risks of doing this.
I would probably write some sort of command line tool or service that does the processing and extraction of project data. Then I would use a page to update/register projects that the web server and the command line tool both have common access to. then at specified times either manually or via cron or similar mechanisms extract the data to your database. once you have this, you just use the website to display last extraction times and the extracted data.
if the projects/end users are on a different subnet etc, then you will need the end users to run the tool and then have it post the data into the database.

Categories

Resources