SSH executing create user command and send command if user exists - perl

I have a website that send commands to a server via SSH2
Im trying to figure out 1 of 2 things. either
A. Set a username for the registered account that sends the command (IN SSH if username = exist then send command else create user by $username, set privileges to execute PERL command ONLY and then send the command)
OR
B. Set the sent perl commands pid to $username
The basic concept of this is, I want to be able to kill the command based off of the process ID set
OR
register a username and let the command run there so the user can kill the commands via that unique username, but ONLY allow kill perl and perl script execution on that username.
Example: perl $username script.pl command command2 command3 (This sets the username for the users process ID)
Example2: kill $username (This kills the process based off of that ID)
P.S. my server that is using ssh is running CentOS 6 if that helps any?
Here is my current script which i would like to modify:
<?php
set_time_limit(0);
ignore_user_abort(true);
if (!function_exists("ssh2_connect")) die("function ssh2_connect doesn't exist");
// log in at url/ip on port 22
if(!($con = ssh2_connect("************", 22))){
echo "fail: unable to establish connection\n";
} else {
// try to authenticate with username, password
if(!ssh2_auth_password($con, "**********", "***********")) {
echo "fail: unable to authenticate\n";
} else {
// execute a command
if (!($stream = ssh2_exec($con, "perl i.pl ".$_GET['command1']." ".$_GET['command2']." ".$_GET['command3']))) {
echo "fail: unable to execute command\n";
} else {
echo "" . stream_get_contents($stream);
echo "Commands have been executed successfully!";
}
}
}
?>

You can use the id command to check if a given username exists.
You can then use the useradd commands to create a new user. Check out useradd man page for the various options available.
It is not easily possible to create a user with the privilege to only execute just a single script. You can setup a chroot jail, but in most cases that's probably more trouble than it's worth. However, considering that you're trying to execute command with input from a web request, it's probably inevitable that you'll have to create a jail, because what you're trying to right now is basically opening up your remote server for malicious user to ransack to their heart's content.
You can use sudo with the -u option to run a script as another user. Example: sudo -u username ls
You can run a process in the background and get the process id by using the $! variable. Example: ls > /dev/null & echo $!. This process id can be used later to kill the process. Be careful however, since process id can get recycled, you may accidentally kill the wrong process. Running the kill command as the same unprivileged user as the command itself (as opposed to a user with higher privileges) is a good idea to at least prevent the kill command from accidentally killing another user's process.
All these steps are no different whether you execute it locally or from SSH.

Related

How to ask for administrative privilege only once in OSX?

So I have an app that runs shell command twice, once to disable sleep and then a few moments later to enable sleep. The code looks as follows:
NSAppleScript(source: "do shell script \"sudo pmset -a disablesleep 1\" with administrator " +
"privileges")!.executeAndReturnError(nil)
// and then same code with with '0' instead of 1 to disable it
However the issue is I don't want the user to enter their password EVERYTIME they call these commands. It's making for a poor user experience. Is there a way I can grant the entire app admin privilege and run shell commands however I want? Or is there a way to run this shell command without the user authorization?

Get the output of a command executed via $self->send() on a remote host in Perl Expect module

I am using Expect module in Perl to do an interactive activity and execute a command on a remote machine. Request your help on this
Here are the steps I used
Do a switch user to another account.
Sends the password to login.
Once I get the shell for the new user, execute a ssh command to connect to a remote machine.
Then I want to execute a command in that remote machine and get its response.
I am able to execute the command on the remote machine. I am seeing the output on my terminal too.
But I am not able to capture it in a variable so that I can compare it against a value.
use Expect;
my $exp = Expect->new;
$exp->raw_pty(1);
$exp->spawn('su - crazy_user') or die "Cannot spawn switch user cmd: $!\n"
$exp->expect($timeout,
[ qr/Password:/i,
sub { my $self = shift;
$self->send("$passwd\n");
exp_continue;
}],
[ qr/\-bash\-4.1\$/i,
sub { my $self = shift;
$self->send("ssh $REMOTE_MACHINE\n");
$self->send("$COMMAND1\n");
exp_continue;
}]
);
$exp->soft_close();
How can I get the result of the $COMMAND1 that I executed on the remote machine via $self->send("$COMMAND1\n") ?
I am by no means an expert on this but as noone else has answered so far, let me attempt it.
Your expect command is the su and as such, normal expecting will only work on whatever that command answers back to your original shell. That however is only the password prompt and maybe some error messages. You can still send commands, but their responses show up on the shell of the new user, not the shell the expect command has been executed in. That is why they show up on screen but not in the stream available to your expect object. Note that you would likely encounter the very same problem if you where to ssh directly (i am not sure why you would su and then ssh anyways, could you not directly ssh crazy-user#remote_machine?).
The solution is probably to get rid of the su and ssh directly into the user you need on the remote machine employing Net::SSH::Expect instead of plain Expect as it gives you everything written to the remote console in its output stream. But be careful, if i remember correctly, the syntax for inspecting the stream is slightly different.

PuTTY scripting to log onto host

I'm using PuTTY to remotely log onto my school's host. Upon logging in, we are required to do these steps:
enter username
enter password
command "add oracle"
command "sqlplus"
enter username
enter password
I will be logging into this host a lot over the course of this semester and I was hoping to create a script that would eliminate the redundancy of the above steps. Ignoring the obvious security oversights of having my password in the script, how would I achieve this? I have zero experience with scripting, so your feedback is greatly appreciated. Thanks!
Edit: I played around with the command-line options for Putty and I was able to bypass steps 1-2 using:
putty -load "host" -l username -pw password
I've also created a shell file that looks like so:
#!/bin/bash
add oracle10g
sqlplus username password
When I try to add this option to the command-line using the -m option, it looks like PuTTY logs into the host and then immediately exits. Is there a way to keep my session open after running the shell file or am I using the -m option wrongly? Here is a link to a PuTTY guide that I have been following: http://the.earth.li/~sgtatham/putty/0.60/htmldoc/Chapter3.html.
Here is the total command that I am trying to run from the command-line:
putty -load "host" -l username -pw password -m c:\test.sh
Figured this out with the help of a friend. The -m PuTTY option will end your session immediately after it executes the shell file. What I've done instead is I've created a batch script called putty.bat with these contents on my Windows machine:
#echo off
putty -load "host" -l username -pw password
This logs me in remotely to the Linux host. On the host side, I created a shell file called sql with these contents:
#!/bin/tcsh
add oracle10g
sqlplus username password
My host's Linux build used tcsh. Other Linux builds might use bash, so simply replace tcsh with bash and you should be fine.
To summarize, automating these steps are now done in two easy steps:
Double-click putty.bat. This opens PuTTY and logs me into the host.
Run command tcsh sql. This adds the oracle tool to my host, and logs me into the sql database.
I'm not sure why previous answers haven't suggested that the original poster set up a shell profile (bashrc, .tcshrc, etc.) that executed their commands automatically every time they log in on the server side.
The quest that brought me to this page for help was a bit different -- I wanted multiple PuTTY shortcuts for the same host that would execute different startup commands.
I came up with two solutions, both of which worked:
(background) I have a folder with a variety of PuTTY shortcuts, each with the "target" property in the shortcut tab looking something like:
"C:\Program Files (x86)\PuTTY\putty.exe" -load host01
with each load corresponding to a PuTTY profile I'd saved (with different hosts in the "Session" tab). (Mostly they only differ in color schemes -- I like to have each group of related tasks share a color scheme in the terminal window, with critical tasks, like logging in as root on a production system, performed only in distinctly colored windows.)
The folder's Windows properties are set to very clean and stripped down -- it functions as a small console with shortcut icons for each of my frequent remote PuTTY and RDP connections.
(solution 1)
As mentioned in other answers the -m switch is used to configure a script on the Windows side to run, the -t switch is used to stay connected, but I found that it was order-sensitive if I wanted to get it to run without exiting
What I finally got to work after a lot of trial and error was:
(shortcut target field):
"C:\Program Files (x86)\PuTTY\putty.exe" -t -load "SSH Proxy" -m "C:\Users\[me]\Documents\hello-world-bash.txt"
where the file being executed looked like
echo "Hello, World!"
echo ""
export PUTTYVAR=PROXY
/usr/local/bin/bash
(no semicolons needed)
This runs the scripted command (in my case just printing "Hello, world" on the terminal) and sets a variable that my remote session can interact with.
Note for debugging: when you run PuTTY it loads the -m script, if you edit the script you need to re-launch PuTTY instead of just restarting the session.
(solution 2)
This method feels a lot cleaner, as the brains are on the remote Unix side instead of the local Windows side:
From Putty master session (not "edit settings" from existing session) load a saved config and in the SSH tab set remote command to:
export PUTTYVAR=GREEN; bash -l
Then, in my .bashrc, I have a section that performs different actions based on that variable:
case ${PUTTYVAR} in
"")
echo ""
;;
"PROXY")
# this is the session config with all the SSH tunnels defined in it
echo "";
echo "Special window just for holding tunnels open." ;
echo "";
PROMPT_COMMAND='echo -ne "\033]0;Proxy Session #master01\$\007"'
alias temppass="ssh keyholder.example.com makeonetimepassword"
alias | grep temppass
;;
"GREEN")
echo "";
echo "It's not easy being green"
;;
"GRAY")
echo ""
echo "The gray ghost"
;;
*)
echo "";
echo "Unknown PUTTYVAR setting ${PUTTYVAR}"
;;
esac
(solution 3, untried)
It should also be possible to have bash skip my .bashrc and execute a different startup script, by putting this in the PuTTY SSH command field:
bash --rcfile .bashrc_variant -l
When you use the -m option putty does not allocate a tty, it runs the command and quits. If you want to run an interactive script (such as a sql client), you need to tell it to allocate a tty with -t, see 3.8.3.12 -t and -T: control pseudo-terminal allocation. You'll avoid keeping a script on the server, as well as having to invoke it once you're connected.
Here's what I'm using to connect to mysql from a batch file:
#mysql.bat
start putty -t -load "sessionname" -l username -pw password -m c:\mysql.sh
#mysql.sh
mysql -h localhost -u username --password="foo" mydb
https://superuser.com/questions/587629/putty-run-a-remote-command-after-login-keep-the-shell-running
I want to suggest a common solution for those requirements, maybe it is a use for you: AutoIt. With that program, you can write scripts on top of any window like Putty and execute all commands you want to (like button pressing or mouse clicking in textboxes or buttons).
This way you can emulate all steps you are always doing with Putty.
entering a command after you logged in can be done by going through SSH section at the bottom of putty and you should have an option Remote command (data to send to the server) separate the two commands with ;
mputty can do that but it does not seem to work always. (if that wait period is too slow)
mputty uses putty and it extends putty.
There is an option to run a script.
If it does not work, make sure that wait period before typing is a high value or increase that value. See putty sessions , then name of session, right mouse button,properties/script page.
For me it works this way:
putty -ssh root#1.1.1.1 22 -pw password
putty, protocol, user name # ip address port and password. To connect in less than a second.
You can use the -i privatekeyfilelocation in case you are using a private key instead of password based.

Running a shell command from perl and allowing interaction

I need to be able to run a commandline command from my perl script and I want the user to be able to interact with it like normal.
For example, the script I want to run is ssh $user#$box '. ./.profile 1>/dev/null 2>&1 && AnotherScript.pl'
I want the user to be able to interact and see the ssh command just as if he/she had executed it themselves. I don't care what happens during the command, I just want execution passed back to my perl script when it's finished.
system 'ssh', "$user\#$box", '. ./.profile 1>/dev/null 2>&1 && AnotherScript.pl';
See http://perldoc.perl.org/functions/system.html for details about the built-in system function.

How to successfully run Perl script with setuid() when used as cgi-bin?

I have a Perl script that is called either via Apache or on the command-line.
For testing purposes, I pass it the username I want the Perl script to operate with, and use POSIX::setuid to set the uid.
If I run the script from the command line, then the uid is set properly:
use CGI::Pretty qw/:standard/;
use POSIX qw(setuid getuid);
...
my ($pwName, $pwCode, $pwUid, $pwGid, $pwQuota, $pwComment,
$pwGcos, $pwHome, $pwLogprog) = getpwnam($username);
if ((defined $pwUid) && (getuid() == $pwUid)) {
setuid($pwUid);
print header;
print Dumper $<;
}
else {
print header(-status => 401);
print "Could not setuid to correct uid (currently: )".getuid()."\n";
}
The command-line output shows the correct uid of the specified $username, instead of the uid of the test account that started running the script.
If I call the script via Apache, then the uid remains set to the id of the apache user, and never changes.
I don't believe I can use suExec here, because, after reading the documentation:
I can't put a copy of this script into http://www.example.com/~username for every $username. The script needs to run from one location, and I need to specify the uid from within the script.
I need to have the script run as the specified username at runtime, and not as a single username specified once in a virtual host directive in an Apache configuration file. Changing this configuration file and restarting Apache every time a new user runs this script is not realistic.
How do I get a Perl script running as a cgi-bin to change the uid correctly, when using setuid()?
The only way you can setuid to an arbitrary uid is to run as root.[1]
I don't know about you, but the idea of a CGI program running as root gives me nightmares.
What is this code supposed to actually do after changing uid? Perhaps there's a way to accomplish this without having to setuid?
[1] Depending on your code and its security model, you may be able to collect the user's password and use su/sudo[2] to run a separate command-line program to run the actual operations outside of the web server environment, but su/sudo are able to do this because they're suid root and it would still open up most/all of the issues associated with running CGI code as root anyhow. Even if you filter out root as an invalid username, being able to masquerade as any arbitrary user opens up plenty of opportunities for abuse.
[2] sudo could even be configured to allow it without requiring a password, but there be dragons down that path. Be sure you know what you're doing if you attempt it, lest you give your users free reign to impersonate each other at will.