I want to start another program which runs as user from a program running as administrator.
The problem is that the second program needs to use outlook, which is not possible if the program runs as admin. The main program needs to run as admin.
I did already come up with this two solutions:
Process.Start("cmd.exe", #"/C runas.exe /savecred /user:" + Environment.UserDomainName + "\\" + Environment.UserName + " " + "\"SomeProgram.exe" + "\"");
or
Process.Start("explorer.exe", "SomeProgram.exe");
But i have a problem with both solutions.
The first one asks the user for the password (only the first time after windows was restarted).
The second one probalby won`t work in the future, because as far as i found out it is considered as a bug and probably fixed with an future update.
So I would like to know is there any other solution, where the user does not need to enter his password?
This seems to work for me:
Process.Start("cmd.exe", #"/C runas.exe /TrustLevel:0x20000 " + "\"SomeProgram.exe" + "\"");
Process class has StartInfo property that is an instance of ProcessStartInfo class. This class exposes UserName, Domain and Password members to specify the user you want to run the process.
Process myProcess = new Process();
myProcess.StartInfo.FileName = fileName;
myProcess.StartInfo.UserName = userName;
myProcess.StartInfo.Domain = domain;
myProcess.StartInfo.Password = password;
myProcess.Start();
I was having the same issue and was not able to get the current logged user. NB: querying wmi is not a solution as many users may be logged in at that time
so my solution is to do the reverse. Launch my app as current user and if the current user is not admin, I request to run as admin.
if (IsAdministrator())
{
// run whatever you want as elevated user
}
else
{
//launch the same app as admin
ExecuteAsAdmin(PATHH_TO_THE_SAME_APP.EXE);
//execute whatever you want as current user.
}
public static void ExecuteAsAdmin(string fileName)
{
Process proc = new Process();
proc.StartInfo.FileName = fileName;
proc.StartInfo.UseShellExecute = true;
proc.StartInfo.Verb = "runas";
proc.Start();
proc.WaitForExit();
}
public static bool IsAdministrator()
{
var identity = WindowsIdentity.GetCurrent();
var principal = new WindowsPrincipal(identity);
return principal.IsInRole(WindowsBuiltInRole.Administrator);
}
Related
Were using octopus for deployment, the tentacle is running as "local system account" I would like the tentacle to add credentials for a diffrent account. However I have no luck i doing so.
So far i tried creating a c# program which starts a new process as the other user, and the calls the cmdkey.exe
private static void CallCmdKey(string runAsDomain, string runsAsUser, string runAsPass, string target, string user, string pass)
{
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo.Arguments = $"/generic:{target} /user:{user} /pass:{pass}";
proc.StartInfo.FileName = Environment.GetEnvironmentVariable("WINDIR") + "\\system32\\cmdkey.exe";
Console.Out.WriteLine(proc.StartInfo.Arguments);
proc.StartInfo.Domain = runAsDomain;
proc.StartInfo.UserName = runsAsUser;
proc.StartInfo.LoadUserProfile = true;
SecureString sec = new SecureString();
runAsPass.ToCharArray().ToList().ForEach(sec.AppendChar);
proc.StartInfo.Password = sec;
proc.StartInfo.WorkingDirectory = ".";
proc.StartInfo.UseShellExecute = false;
proc.Start();
proc.WaitForExit();
Console.Out.WriteLine("done");
}
But it fails with access denied.
Then i tried power shell and psexec like this:
$psexec = "C:\temp\psexec.exe"
Invoke-Command -ScriptBlock{&$psexec -accepteula -u $WEB02AP2User -p $GISWEB02AP2Pass cmd /c cmdkey /generic:ffff /user:mufasa /pass:yoyo}
but it fails with
Access is denied.
PsExec could not start cmd:
The remote script failed with exit code 5
For security reasons Im not allowed to change account for the tentacle service
How can i sovle this issue
I Was unable to find a solutions to this issue. Only workaround was to let the octopusservice run as a specific user account
One can run exe as user different from currently logged in one (using "run as").
For example I log in as "user1" into Windows and start executable with "run as" using credentials of "User2".
How to retreive user name/identity of "User1" (who logged in currently) and not "User2" (which the process runs under)?
I.e. System.Environment.UserName give User2 (as expected).
You can get the current identity of the user under which the current thread is running (not necessarily the logged in user) using WindowsIdentity.GetCurrent(). Alternatively you can get the logged in user name via the Environment.UserName property. It is not guaranteed to be the user running the current process however.
string userName = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
Refer http://msdn.microsoft.com/en-us/library/system.environment.username.aspx
I know this an old question but maybe this solution will be useful for someone.
You can retrieve the current session user (not the user who has runned the app) with "QWinsta" or "Query Session".
This code create a process to run QWinsta with "console" parameter, when you do this you will get a result like:
Then you can catch that result with "StartInfo.RedirectStandardOutput" and "StandardOutput.ReadToEnd()", split it and search for ">console" and save the index into a variable, finally you can get the user with "index+1" in the split array.
For security i've add "Proc.WaitForExit(2000)" to wait a maximum of 2 seconds before stop the task or it will wait forever and "Proc.ExitCode != 0" to protect against any error can ocurr.
Process Proc = new Process();
Proc.StartInfo.UseShellExecute = false;
Proc.StartInfo.CreateNoWindow = true;
Proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
Proc.StartInfo.FileName = #"qwinsta.exe";
Proc.StartInfo.Arguments = #"console";
Proc.StartInfo.RedirectStandardOutput = true;
Proc.Start();
if (!Proc.WaitForExit(2000) || Proc.ExitCode != 0)
{
try { Proc.Kill(); } catch { }
return null;
}
string Resultado = Proc.StandardOutput.ReadToEnd();
string[] Textos = Resultado.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
int Indice = 0;
foreach (string TXT in Textos) { if (TXT == ">console") { break; } else Indice++; }
return Textos[Indice + 1];
NOTE: if you want to use "QWinsta" or "Query Session" you can do it in two ways.
First: Copy QWinsta.exe from
C:\windows\system32
and put it on your app root folder (Remember use always copy option)
Second: Provide UserName and Password to process StartInfo, but you'll need admin credentials and Password must be a "system.Security.SecureString"
NOTE2: Not all versions of windows have the QWinsta.exe like Windows 10 Student N, but you can copy the "QWinsta.exe" from other windows and use it.
This code has been tested on Win10 and Win8
I'm writing a tool that can be used to manage the virtual host a web server on Ubuntu. As for many of the features I need privileged rights, I look for ways to achieve this.
Currently I realize that with "gksu" or "gksudo". This also works. The problem is that the user is prompted for any activity that requires privileged rights to enter his password.
Is it possible to retrieve this password only once and remember for the rest of the duration of the program? Is there another way to implement this?
public void OnToogledVirtualHost(object o, ToggledArgs args)
{
VirtualHost host = (VirtualHost)store.GetNode(new TreePath(args.Path));
host.Enabled = !host.Enabled;
Process process = new Process();
process.StartInfo.UseShellExecute = false;
if (host.Enabled)
{
process.StartInfo.FileName = "gksu";
process.StartInfo.Arguments = "a2ensite " + System.IO.Path.GetFileName(host.FilePath);
}
else
{
process.StartInfo.FileName = "gksu";
process.StartInfo.Arguments = "a2dissite " + System.IO.Path.GetFileName(host.FilePath);
}
process.Start();
}
AFAIK, it is a security feature of 'su' not to cache the password (more properly the authentication ticket) for more than a few seconds, and thus this is designed not to be bypassed.
You can always gksu an intermediary process and try to make the sub-processes inherit its authorization, but you'll need to secure the IPC (the communication channel between your tool frontend and the intermediary process).
So my advice is to not try to lessen the security of the overall solution, so let the user be asked as many times as needed...
There are several (at least 3) "secure" solutions to this problem:
Use "sudo", that allows for password caching. This is my preferred solution if I can install and configure sudo on the machine. Pros: sudo will cache the password. Cons: it depends on having an external dependency (sudo) correctly configured.
Write different helper executables (for example a "modify configuration and restart apache" program) and when needed ask the user to authenticated using gksu, then launch them. Pros: user gets asked for the password only once for every group of actions. Cons: The user still get asked for the password multiple times AND you have to split the program in multiple pieces.
Write a separate service that runs with root privileges and use polkit/DBUS to authenticate the user and connect to it to require services (like, "restart apache please"). Pros: credential caching and authentication dialog is managed by dekstop/polkit. Cons: more code to write and you need to run a DBUS service.
"secure" is quoted because running code (and especially managed code that depends on a large application such as Mono) as root always has security implications.
Thanks for the useful approaches. Yesterday I arrived at a solution of the problem, which I have enclosed in a static class. First, a distinction is made between normal and privilligierten processes.
Whenever a process needs to be run with elevated privileges, I check if I know the user's password already. If not, I'll get it (gksudo -p) and store it in memory.
Now I can execute commands with privilligierten rights. The stored password is then transferred via the standard input (sudo -S).
What do you think? Do you have any safety concerns?
public static class SystemProcess
{
private static string output;
private static string error;
private static string password;
public static void Start (string filename, string arguments)
{
ProcessStartInfo startInfo = SystemProcess.Prepare(filename, arguments);
using (Process process = Process.Start(startInfo)) {
SystemProcess.output = process.StandardOutput.ReadToEnd();
SystemProcess.error = process.StandardError.ReadToEnd();
process.WaitForExit();
}
}
public static void StartPrivileged (string filename, string arguments)
{
ProcessStartInfo startInfo;
if (SystemProcess.password == default(string))
{
startInfo = SystemProcess.Prepare("gksudo", "-p true -D 'MyApplication'");
using (Process process = Process.Start(startInfo)) {
SystemProcess.password = process.StandardOutput.ReadToEnd();
process.WaitForExit();
}
}
startInfo = SystemProcess.Prepare("sudo", "-S " + filename + " " + arguments);
using (Process process = Process.Start(startInfo)) {
process.StandardInput.WriteLine(SystemProcess.password);
SystemProcess.output = process.StandardOutput.ReadToEnd();
SystemProcess.error = process.StandardError.ReadToEnd();
process.WaitForExit();
}
}
private static ProcessStartInfo Prepare (string filename, string arguments)
{
ProcessStartInfo startInfo = new ProcessStartInfo (filename, arguments);
startInfo.RedirectStandardError = true;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardInput = true;
startInfo.UseShellExecute = false;
return startInfo;
}
public static string Output {
get {
return SystemProcess.output;
}
}
public static string Error {
get {
return SystemProcess.error;
}
}
}
You know, I'd not use gksu or sudo for any of this, sounds like you want to look at userv instead.
You can basically permit different users to run different programs,
How can I remove user local account of administrators group with the help of WMI in C#. (NOT using System.DirectoryServices and System.DirectoryServices.AccountManagement).
I have tried this code. but I don't know how to run it.
using (var myDeleteUser = new StreamWriter("DeleteUser.vbs"))
{
myDeleteUser.WriteLine("Set objAdminGroup = GetObject(\"WinNT://" + hostHame + "/" + Settings.AdministratorsGroup + ",group\")");
myDeleteUser.WriteLine("Set objUser = GetObject(\"WinNT://" + domain + "/" + userName + ",user\")");
myDeleteUser.WriteLine("objAdminGroup.Remove(objUser.ADsPath)");
}
EDIT:
I try to do this:
Process proc = new Process();
proc.StartInfo.FileName = "DeleteUser.vbs";
proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
proc.Start();
proc.WaitForExit();
int exitCode = proc.ExitCode;
proc.Close();
But I have an error(vbs permission denied Getobject) in VBS file.
You want the Win32_UserAccount
Note the c# code implementation here - the delete on top of should be trivial
Enumerate Windows user group members on remote system using c#
Are you looking at deleting the account, or just remove from that group?
If you want to remove from the group check out the Win32_GroupUser object.
http://msdn.microsoft.com/en-us/library/windows/desktop/aa394153%28v=vs.85%29.aspx
In an application I need to execute other programs with another user's credentials. Currently I use System.Diagnostics.Process.Start to execute the program:
public static Process Start(
string fileName,
string arguments,
string userName,
SecureString password,
string domain
)
However this function does not load the roaming profile from the net - which is required.
I could use "runas /profile ..." to load the profile and execute the command, but that would ask for a password. There must be an more elegant way...
But where?
My solution (based on leppie's hint):
Process p = new Process();
p.StartInfo.FileName = textFilename.Text;
p.StartInfo.Arguments = textArgument.Text;
p.StartInfo.UserName = textUsername.Text;
p.StartInfo.Domain = textDomain.Text;
p.StartInfo.Password = securePassword.SecureText;
p.StartInfo.LoadUserProfile = true;
p.StartInfo.UseShellExecute = false;
try {
p.Start();
} catch (Win32Exception ex) {
MessageBox.Show("Error:\r\n" + ex.Message);
}
System.Diagnostics.ProcessStartInfo.LoadUserProfile