Background
I'm writing an web application so I can control an Ubuntu Server from a web site.
One idea I had was to run the 'screen' application from mono and redirect my input and output from there.
Running 'screen' from mono:
ProcessStartInfo info = new ProcessStartInfo("screen", "-m");
info.UseShellExecute = false;
info.RedirectStandardOutput = true;
info.RedirectStandardInput = true;
var p = new Process();
p.StartInfo = info;
p.Start();
var output = p.StandardOutput;
var input = p.StandardInput;
but running 'screen' with the RedirectStandardInput gives out the error:
Must be connected to a terminal
I've tried many different arguments and none seems to work with 'Redirecting Standard Input'
Other ideas for controlling a server will be greatly appreciated
I think this is the typical question in which you're asking how to implement your solution to a problem, instead of asking how to solve your problem. I don't think you should do hacky things like making a web app that tunnels the user actions to the server via a terminal.
I think you can bypass all that and, without writing a single line of code, take advantage of what the platform (Gtk+ in this case) already provides you:
You could run gnome-terminal in the server with the Broadway GDK backend. This way the gnome-terminal app will not run in the server, but open a web server on the port you specify. Later, you can use any WebSockets-enabled browser to control it.
This is the easiest and less hacky solution compared to the other ones offered so far. If you still are excited about using Mono for web development you still can, and you could embed this access in an iFrame or something.
(PS: If you don't want to depend on GTK being installed in the server; you could just use WebSockets in your client part of the webpage to be able to send events from the server to the client, and the library SSHNET to send the user's input directly through the wire.)
screen will need a terminal of some sort. It's also gigantically overkill.
You may wish to investigate the pty program from the Advanced Programming in the Unix Environment book (pty/ in the sources) to provide a pseudo-terminal that you can drive programmatically. (You'd probably run the pty program as-provided and write your driver in Mono if you're so inclined.) (The pty program will make far more sense if studied in conjunction with the book.)
The benefit to using the pty program, or functionality similar to it, is that you'd properly handle programs such as passwd that open("/dev/tty") to prompt the user for a password. If you simply redirect standard IO streams via pipe() and dup2() system calls, you won't have a controlling terminal for the programs that need one. (This is still a lot of useful programs but not enough to be a remote administration tool.)
There may be a Mono interface to the pty(7) system; if so, it may be more natural to use it than to use the C API, but the C API is what does the actual work, so it may be easier to just write directly in the native language.
A different approach to solve the same problem is shellinabox. Also interesting is this page from the anyterm website that compares different products that implement this kind of functionality.
Using shellinabox is very simple:
# ./shellinaboxd -s /:LOGIN
(this is the example given on their website) will start a webserver (on in your case the Ubuntu server). When you point your browser to http://yourserver:4200 you'll see a login screen, just like you would see when opening a session with ssh/putty/telnet/... but in your browser.
You could provide the required remote access functionality to the server's shell by just including an iframe that points to that service in your application's webpage.
Related
I have a small utility I am working on that deletes old user profiles from domain machines.
Basically, where I am stuck is looking for a better process to delete remote directories.
I know I can use the System.IO and delete it from the UNC path, but I am not happy with the performance of the network deletion. It can take hours to delete medium sized profiles, and if there are dozens or hundreds of profile or machines this is not feasible as a solution.
So this appears to be out of the question
The best I can find appears to be PSExec calls, but I want something managed.
Are there any .NET classes that can invoke the remote machine to complete the deletion of the directory instead of relying on the calling machine?
If your client computers don't detect this as a virus, you can use it to execute remote commands on your network computers, including folder deletions:
PsExec v1.98
Introduction
Utilities like Telnet and remote control programs like Symantec's PC
Anywhere let you execute programs on remote systems, but they can be a
pain to set up and require that you install client software on the
remote systems that you wish to access. PsExec is a light-weight
telnet-replacement that lets you execute processes on other systems,
complete with full interactivity for console applications, without
having to manually install client software. PsExec's most powerful
uses include launching interactive command-prompts on remote systems
and remote-enabling tools like IpConfig that otherwise do not have the
ability to show information about remote systems.
I have no idea how it works. In .NET code the idea would be to send RPC calls to a remote application that you control, which is easy enough provided you already have said application running on the target computers. The mechanism used would be .NET Remoting or WCF.
Inspired by this answer, I did some minor modifications. I can't get it to run 100% managed, as I get an error code 9 (The storage control block address is invalid) when I try to run the rd-command from within the code itself.
The base functionality is blindingly fast on my small test-setup, but given that you overrule the "Are you sure?" prompt, it is also fairly dangerous if you specify the wrong path, so wear your hard hat as you proceed:
If you execute echo Y | rd /S c:\Temp\test in any command shell, you'll remove C:\Temp\Test and anything below it very quickly and without warning.
But executing this solution directly in the code doesn't work. So my quick fix is to place a bat-file (called DeleteTest.bat) on the machine, containing only this line and then execute the bat file by WMI.
In my small test, it deletes ~900 files of a total of ~200 mb in a second or so.
Also, in addition to the answer cited I get the return code, so my full code becomes:
var processToRun = new[] { "c:\\Temp\\DeleteTest.bat" };
var connection = new ConnectionOptions();
connection.Username = "me";
connection.Password = "password";
var wmiScope = new ManagementScope(String.Format("\\\\{0}\\root\\cimv2", "MyRemoteMachine"), connection);
var wmiProcess = new ManagementClass(wmiScope, new ManagementPath("Win32_Process"), new ObjectGetOptions());
var result = wmiProcess.InvokeMethod("Create", processToRun);
Console.WriteLine(
"Creation of process returned: " + result);
You will obviously also need the bat file to be generated (by code or pre-generated) and copied to the destination, but that should be trivial.
I am trying to run a .NET console app from a shared network folder using method Process.Start.
Everytime the console app starts I get the message "The publisher could not be verified" and Windows asks for user confirmation. How can I disable this dialog? I do not want to buy a digital certificate.
within your .net application when you use "Process.Start"
use the feature Process.StartInfo.UseShellExecute = false.
so ...
Process proc = new Process();
proc.StartInfo.UseShellExecute = false;
what this does is it allows you to launch EXES (and only exes) directly without using the Explorer(shell).
This will bypass any IE Security Zone checks. The Explorer by default includes the IEZone check and thus will
give you a security warning if the application you are running is not 'trusted' (specifically in a trusted zone).
Now you cannot use 'false' if you want to launch a 'PDF' for example. This only works for Exes.
Last bit of information:
http://technet.microsoft.com/en-us/library/bb457006.aspx
http://technet.microsoft.com/en-us/library/dd349795(WS.10).aspx
these bits of info, which a MS rep just provided me, may provide a way to trust the publisher of a signed application by using Software Restriction Policies. I haven't looked into this yet, but for those that need to continue with this further... this looks like another way to address part (1) .
I'm working on a Mono application that will run on Linux, Mac, and Windows, and need the ability for apps (on a single os) to send simple string messages to each other.
Specifically, I want a Single Instance Application. If a second instance is attempted to be started, it will instead send a message to the single instance already running.
DBus is out, as I don't want to have that be an additional requirement.
Socket communication seems to be hard, as windows seems to not allow permission to connect.
Memory Mapped Files seems not to be supported in Mono.
Named Pipes appears not to be supported in Mono.
IPC seems not to be supported on Mono.
So, is there a simple method to send string messages on a single machine to a server app that works on each os, without requiring permissions, or additional dependencies?
On my ubuntu (10.10 mono version: 2.6.7) I've tried using WCF for interprocess communication with BasicHttpBinding, NetTcpBinding and NetNamedPipeBinding. First 2 worked fine, for NetNamedPipeBinding I got an error:
Channel type IDuplexSessionChannel is
not supported
when calling ChannelFactory.CreateChannel() method.
I've also tried using Remoting (which is a legacy technology since WCF came out) with IpcChannel; example from this msdn page started and worked without problems on my machine.
I suppose you shouldn't have problems using WCF or Remoting on Windows either, not sure about Mac though, don't have any of those around to test. Let me know if you need any code examples.
hope this helps, regards
I wrote about this on the mono-dev mailing list. Several general-purpose inter-process messaging systems were considered, including DBus, System.Threading.Mutex class, WCF, Remoting, Named Pipes... The conclusions were basically mono doesn't support Mutex class (works for inter-thread, not for inter-process) and there's nothing platform agnostic available.
I have only been able to imagine three possible solutions. All have their drawbacks. Maybe there's a better solution available, or maybe just better solutions for specific purposes, or maybe there exist some cross-platform 3rd party libraries you could include in your app (I don't know.) But these are the best solutions I've been able to find so far:
Open or create a file in a known location, with exclusive lock. (FileShare.None). Each application tries to open the file, do its work, and close the file. If failing to open, Thread.Sleep(1) and try again. This is kind of ghetto, but it works cross-platform to provide inter-process mutex.
Sockets. First application listens on localhost, some high numbered port. Second application attempts to listen on that port, fails to open (because some other process already has it) so second process sends a message to the first process, which is already listening on that port.
If you have access to a transactional database, or message passing system (sqs, rabbitmq, etc) use it.
Of course, you could detect which platform you're on, and then use whatever works on that platform.
Solved my problem with two techniques: a named mutex (so that the app can be run on the same machine by different users), and a watcher on a message file. The file is opened and written to for communication. Here is a basic solution, written in IronPython 2.6:
(mutex, locked) = System.Threading.Mutex(True, "MyApp/%s" % System.Environment.UserName, None)
if locked:
watcher = System.IO.FileSystemWatcher()
watcher.Path = path_to_user_dir
watcher.Filter = "messages"
watcher.NotifyFilter = System.IO.NotifyFilters.LastWrite
watcher.Changed += handleMessages
watcher.EnableRaisingEvents = True
else:
messages = os.path.join(path_to_user_dir, "messages")
fp = file(messages, "a")
fp.write(command)
fp.close()
sys.exit(0)
For your simple reason for needing IPC, I'd look for another solution.
This code is confirmed to work on Linux and Windows. Should work on Mac as well:
public static IList Processes()
{
IList<Process> processes = new List<Process>();
foreach (System.Diagnostics.Process process in System.Diagnostics.Process.GetProcesses())
{
Process p = new Process();
p.Pid = process.Id;
p.Name = process.ProcessName;
processes.Add(p);
}
return processes;
}
Just iterate through the list and look for your own ProcessName.
To send a message to your application, just use MyProcess.StandardInput to write to the applications standard input. This only works assuming your application is a GUI application though.
If you have problems with that, then you could maybe use a specialized "lock" file. Using the FileSystemWatcher class you can check when it changes. This way the second instance could write a message in the file and then the first instance notice that it changes and can read in the contents of the file to get a message.
Here is the premise:
I have a desktop that I need to be able to start up and stop applications on, but cannot get remote access to. What I had in mind is setting up a service on the machine that will start/stop a list of applications as told. This windows service will periodically pole a web service for new commands and execute them accordingly.
These are my questions.
1) Is this the easiest solution? What else would you recommend?
2) How hard is it to run an exe from a windows service? How about stopping one?
This isn't for a project or anything, just something I am interested in implementing (mostly for fun). Any answers or even thoughts are appreciated. General discussion is also welcome (feel free to leave comments).
As for creating the Windows service itself in C#, see my post here.
The polling mechanism would work, but in general, I prefer event-driven processes instead of polling processes. You didn't mention what version of .NET you were using, but if it is .NET 3.0/3.5, I would suggest using WCF. When the command is posted to the web service, the web service could send the command to the Windows service to be executed. Pretty straightforward. Juval Lowy, the author of Programming WCF Services, offers a bunch of WCF examples/libraries that are free to use at his website.
So I guess PsExec is out of question?
Other than that, it's not hard to implement running of programs inside a Win service. Simply use the .NET Process class to do it, sample from my code:
ProcessStartInfo processStartInfo = new ProcessStartInfo (programExePath, commandLineArgs);
consoleLogger.WriteLine (log, Level.Debug, "Running program {0} ('{1}')", programExePath, commandLineArgs);
processStartInfo.CreateNoWindow = true;
processStartInfo.ErrorDialog = false;
processStartInfo.RedirectStandardError = true;
processStartInfo.RedirectStandardOutput = true;
processStartInfo.UseShellExecute = false;
using (Process process = new Process ())
{
process.StartInfo = processStartInfo;
process.ErrorDataReceived += new DataReceivedEventHandler (process_ErrorDataReceived);
process.OutputDataReceived += new DataReceivedEventHandler (process_OutputDataReceived);
process.Start ();
process.BeginOutputReadLine ();
process.BeginErrorReadLine ();
if (false == process.WaitForExit ((int)TimeSpan.FromHours(1).TotalMilliseconds))
throw new ArgumentException("The program '{0}' did not finish in time, aborting.", programExePath);
if (process.ExitCode != 0)
throw new ArgumentException ("failed.");
}
I have done a service that starts other exe files. There are some things to consider: As a service you have no visual desktop -> no direct interaction is possible. Also, the program must be designed to run a long while.
Stopping an exe is to kill the process. Consider the usual side-effects.
It wouldn't be too difficult - you can just have it poll some webservice for a list of "banned" applications every so often, and then on another timer, have it check for a banned application that's running and kill it if it is. Here's some code to get a list of processes, and you can use the methods on the process class to launch or kill something:
http://www.vbdotnetheaven.com/UploadFile/prvn_131971/machineprocessvb11182005001454AM/machineprocessvb.aspx
The timers could run independently as well - it can check the webservice once/day for a new add/prohibited list, but then check the processes running on the computer every 2 minutes, for example.
I'll answer question 2 first:
To start or stop programs, you just need to use the System.Diagnostics.Process object, and the example code is right in the MSDN library.
For question 1:
You could have it poll a web service periodically if you want to do that.
As an alternate, you can set up the service for remoting and have it just listen on a tcp port for function calls, then write a Windows app that can use remoting to call the service. I've had to do this for a legitimate business app and it works very well.
However, I would be very irresponsible if I didn't include this warning:
Either way, setting up a computer so that it can execute arbitrary code is a bad idea and should be done very carefully. Just because it can be done doesn't mean it should be done. If you go the web service route, how are you going to ensure that someone doesn't tamper with the web service and get malicious code to execute? How do you know someone won't mess with your app.config and point the app to their own web service? In the remoting scenario, how to you ensure that some other .Net developer doesn't just create a proxy of their own?
In all honesty, I'm amazed that Microsoft even allows the System.Diagnostocs.Process to be used in a .Net application. You can literally do anything you want with it, including launching the cmd shell and executing system commands. Therefore, I'd urge you to seriously consider if this is truly necessary to do. You may be better served installing vnc or using remote desktop, or another app for remote access.
One other question you need to answer is "should the application be visible to the user on that remote machine?" If so, then you need to ensure that the service is set up to run under that user's context. otherwise, you could, for example, launch Word using the local system account, and it would never be visible to the person logged into that machine.
Here is the premise:
I have a desktop that I need to be able to start up and stop applications on, but cannot get remote access to. What I had in mind is setting up a service on the machine that will start/stop a list of applications as told. This windows service will periodically pole a web service for new commands and execute them accordingly.
These are my questions.
1) Is this the easiest solution? What else would you recommend?
2) How hard is it to run an exe from a windows service? How about stopping one?
This isn't for a project or anything, just something I am interested in implementing (mostly for fun). Any answers or even thoughts are appreciated. General discussion is also welcome (feel free to leave comments).
As for creating the Windows service itself in C#, see my post here.
The polling mechanism would work, but in general, I prefer event-driven processes instead of polling processes. You didn't mention what version of .NET you were using, but if it is .NET 3.0/3.5, I would suggest using WCF. When the command is posted to the web service, the web service could send the command to the Windows service to be executed. Pretty straightforward. Juval Lowy, the author of Programming WCF Services, offers a bunch of WCF examples/libraries that are free to use at his website.
So I guess PsExec is out of question?
Other than that, it's not hard to implement running of programs inside a Win service. Simply use the .NET Process class to do it, sample from my code:
ProcessStartInfo processStartInfo = new ProcessStartInfo (programExePath, commandLineArgs);
consoleLogger.WriteLine (log, Level.Debug, "Running program {0} ('{1}')", programExePath, commandLineArgs);
processStartInfo.CreateNoWindow = true;
processStartInfo.ErrorDialog = false;
processStartInfo.RedirectStandardError = true;
processStartInfo.RedirectStandardOutput = true;
processStartInfo.UseShellExecute = false;
using (Process process = new Process ())
{
process.StartInfo = processStartInfo;
process.ErrorDataReceived += new DataReceivedEventHandler (process_ErrorDataReceived);
process.OutputDataReceived += new DataReceivedEventHandler (process_OutputDataReceived);
process.Start ();
process.BeginOutputReadLine ();
process.BeginErrorReadLine ();
if (false == process.WaitForExit ((int)TimeSpan.FromHours(1).TotalMilliseconds))
throw new ArgumentException("The program '{0}' did not finish in time, aborting.", programExePath);
if (process.ExitCode != 0)
throw new ArgumentException ("failed.");
}
I have done a service that starts other exe files. There are some things to consider: As a service you have no visual desktop -> no direct interaction is possible. Also, the program must be designed to run a long while.
Stopping an exe is to kill the process. Consider the usual side-effects.
It wouldn't be too difficult - you can just have it poll some webservice for a list of "banned" applications every so often, and then on another timer, have it check for a banned application that's running and kill it if it is. Here's some code to get a list of processes, and you can use the methods on the process class to launch or kill something:
http://www.vbdotnetheaven.com/UploadFile/prvn_131971/machineprocessvb11182005001454AM/machineprocessvb.aspx
The timers could run independently as well - it can check the webservice once/day for a new add/prohibited list, but then check the processes running on the computer every 2 minutes, for example.
I'll answer question 2 first:
To start or stop programs, you just need to use the System.Diagnostics.Process object, and the example code is right in the MSDN library.
For question 1:
You could have it poll a web service periodically if you want to do that.
As an alternate, you can set up the service for remoting and have it just listen on a tcp port for function calls, then write a Windows app that can use remoting to call the service. I've had to do this for a legitimate business app and it works very well.
However, I would be very irresponsible if I didn't include this warning:
Either way, setting up a computer so that it can execute arbitrary code is a bad idea and should be done very carefully. Just because it can be done doesn't mean it should be done. If you go the web service route, how are you going to ensure that someone doesn't tamper with the web service and get malicious code to execute? How do you know someone won't mess with your app.config and point the app to their own web service? In the remoting scenario, how to you ensure that some other .Net developer doesn't just create a proxy of their own?
In all honesty, I'm amazed that Microsoft even allows the System.Diagnostocs.Process to be used in a .Net application. You can literally do anything you want with it, including launching the cmd shell and executing system commands. Therefore, I'd urge you to seriously consider if this is truly necessary to do. You may be better served installing vnc or using remote desktop, or another app for remote access.
One other question you need to answer is "should the application be visible to the user on that remote machine?" If so, then you need to ensure that the service is set up to run under that user's context. otherwise, you could, for example, launch Word using the local system account, and it would never be visible to the person logged into that machine.