How to set bash profile remotely using perl and run a script - ssh

i have a perl script which connects to remote server , edits a file ,runs some scripts in the remote server.
Here is the code
my $host= mx4d4;
my $FILE1 = 'Abc.conf' ;#this is a ; separted file
my $FILE2 = 'MyCode.py'; #python script
sub do_operation()
{
my $server="197.0.0.1"; #Just for the sake of example , this gets populated at my end
#Run the commands remotely
#change 3rd and 4th column to NEWSTR
system(
'ssh' => ('-q', $server),
'sed' => ('-i -E', qq('/$host/s#([^;]+;[^;]+;)[^;]+;[^;]+#\\1NEWSTR,NEWSTR #)'),$FILE1),
#change 4th and 5th column to STR
system(
'ssh' => ('-q', $server),
'sed' => ('-i -E', qq('/$host/s#([^;]+;[^;]+;[^;]+;[^;]+;)[^;]+;[^;]+#\\1NEWSTR,NEWSTR #'),$FILE1),
#Run python script
system(
'ssh' => ('-q', $server),
'$FILE2' => ('--run'),
)
}
Issues :
In the 3rd System command above , i am not able to run the PYTHON SCRPT successfully as i need to set the remote environment profile (using set_profile.sh )before running the python script , how to set the profile and run the python script at the same time in same system call.
Is it possible to have all 3 operations under only one system call

The command you execute with ssh is run using the default shell on the remote machine. According to the manual:
If a command is specified, it will be executed on the remote host
instead of a login shell. A complete command line may be specified
as command, or it may have additional arguments. If supplied, the
arguments will be appended to the command, separated by spaces,
before it is sent to the server to be executed.
So you can do for example the following to run multiple commands in a single session:
system "ssh", $server, "echo \$SHELL; echo \$HOSTNAME; export FOO=bar; echo \$FOO";
Example output
/bin/bash
openssh-server
bar

Related

ssh to a server and create a directory based off a variable - all in one line

so i have a simple script that lists the folder and file structure of the current directory and spits it out to a file in the current users home directory, then rsyncs that file to a remote server into a specific folder.
the first part of the script SSH's into the remote server and creates a unique folder that the later part of the script transfers the file into.
#ssh -p 12345 sftp.domain.com ' bash -c "mkdir incoming/[foldername]" '
my question is, how can i pass a variable to this? i would usually put this in the script, and then run the script like this "copy.sh $1":
#ssh -p 12345 sftp.domain.com ' bash -c "mkdir incoming/folder-$1" '
however it doesn't work like i might hope it would. all i end up with is a folder on the remote server named "folder-" as it presumably doesn't pass the variable along with the rest when it ssh's in.
is there a better way to make this work?
the rest of the script would also reference the variable $1 to actually copy the file into the folder created on the remote server earlier in the script.
If I understand the problem correctly, the parameter you are trying to reference is set on the local client side (the command line from where you initiate the ssh connection), but you want to reference it in the command line that is to run on the remote server side. This really has nothing to do with ssh and everything to do with shell parameter/variable expansion on the local client side.
The problem is with your usage of single quotes vs. double quotes. Most Unix command shells, including bash which is likely the shell you are running on the local client side, perform environment variable expansion inside of double quotes but not inside of single quotes. So in your command line you should be able to accomplish your goal by changing the single quotes to double quotes and then escaping the embedded double quote characters like this:
#ssh -p 12345 sftp.domain.com " bash -c \"mkdir incoming/folder-$1\" "
Here is a similar example that shows this in action:
$ export EXAMPLE=abc
$ ssh localhost ' bash -c "echo $EXAMPLE def" '
def
$ ssh localhost " bash -c \"echo $EXAMPLE def\" "
abc def

ssh to remote server with arguments to run scripts

I have lots of data that needs to be processed, and have access to 3 separate remote servers. The logic is to split up the data crunching among the 3 different servers instead of running on a single one. Note, that all three remote servers are able to point to a single directory, which is where I have the master scripts to process all of the data. The problem I am have is carrying over my arguments when I call different bash scripts.
For example, I have the master script which looks something like:
processing stuff
more stuff
# call the first script
$scriptdir/step1.csh $date $time $name
Within step1.csh, if I have something very simple where I am able to connect to one of the remote servers and output the hostname to a text file, such as:
#!/bin/bash
ssh name#hostname bash -c '
echo `hostname` > host.txt
I get the desired outcome, where 'host.txt' will be the hostname of the desired connected hostname. However, If step1.csh looks like:
#!/bin/bash
mydate=$1
mytime=$2
myname=$3
ssh name#hostname bash '
echo `hostname` > host.txt
echo ${mydate} > host.txt
I get the error saying that 'mydate: undefined variable'
Furthermore, If I do something along the lines of:
#!/bin/bash
mydate=$1
mytime=$2
myname=$3
ssh name#hostname "python /path/to/somewhere/to/run/${mydate}/and/${mytime}
It still runs on the local, and not remote server. What am I missing here?
So the first part:
#!/bin/bash
mydate=$1
mytime=$2
myname=$3
ssh name#hostname bash '
echo `hostname` > host.txt
echo ${mydate} > host.txt
The solution is:
#!/bin/bash
mydate=$1
mytime=$2
myname=$3
ssh -T name#hostname << EOF
echo `hostname` > host.txt
echo ${mydate} > host.txt
EOF
However, I am still having issues as in where I try to run a python script on the remote server; it is always ran on the local server.

SSH – Force Command execution on login even without Shell

I am creating a restricted user without shell for port forwarding only and I need to execute a script on login via pubkey, even if the user is connected via ssh -N user#host which doesn't asks SSH server for a shell.
The script should warn admin on connections authenticated with pubkey, so the user connecting shouldn't be able to skip the execution of the script (e.g., by connecting with ssh -N).
I have tried to no avail:
Setting the command at /etc/ssh/sshrc.
Using command="COMMAND" in .ssh/authorized_keys (man authorized_keys)
Setting up a script with the command as user's shell. (chsh -s /sbin/myscript.sh USERNAME)
Matching user in /etc/ssh/sshd_config like:
Match User MYUSERNAME
ForceCommand "/sbin/myscript.sh"
All work when user asks for shell, but if logged only for port forwarding and no shell (ssh -N) it doesn't work.
The ForceCommand option runs without a PTY unless the client requests one. As a result, you don't actually have a shell to execute scripts the way you might expect. In addition, the OpenSSH SSHD_CONFIG(5) man page clearly says:
The command is invoked by using the user's login shell with the -c option.
That means that if you've disabled the user's login shell, or set it to something like /bin/false, then ForceCommand can't work. Assuming that:
the user has a sensible shell defined,
that your target script is executable, and
that your script has an appropriate shebang line
then the following should work in your global sshd_config file once properly modified with the proper username and fully-qualified pathname to your custom script:
Match User foo
ForceCommand /path/to/script.sh
If you only need to run a script you can rely on pam_exec.
Basically you reference the script you need to run in the /etc/pam.d/sshd configuration:
session optional pam_exec.so seteuid /path/to/script.sh
After some testing you may want to change optional to required.
Please refer to this answer "bash - How do I set up an email alert when a ssh login is successful? - Ask Ubuntu" for a similar request.
Indeed in the script only a limited subset on the environment variables is available:
LANGUAGE=en_US.UTF-8
PAM_USER=bitnami
PAM_RHOST=192.168.1.17
PAM_TYPE=open_session
PAM_SERVICE=sshd
PAM_TTY=ssh
LANG=en_US.UTF-8
LC_ALL=en_US.UTF-8
PWD=/
If you want to get the user info from authorized_keys this script could be helpful:
#!/bin/bash
# Get user from authorized_keys
# pam_exec_login.sh
# * [ssh - What is the SHA256 that comes on the sshd entry in auth.log? - Server Fault](https://serverfault.com/questions/888281/what-is-the-sha256-that-comes-on-the-sshd-entry-in-auth-log)
# * [bash - How to get all fingerprints for .ssh/authorized_keys(2) file - Server Fault](https://serverfault.com/questions/413231/how-to-get-all-fingerprints-for-ssh-authorized-keys2-file)
# Setup log
b=$(basename $0| cut -d. -f1)
log="/tmp/${b}.log"
function timeStamp () {
echo "$(date '+%b %d %H:%M:%S') ${HOSTNAME} $b[$$]:"
}
# Check if opening a remote session with sshd
if [ "${PAM_TYPE}" != "open_session" ] || [ $PAM_SERVICE != "sshd" ] || [ $PAM_RHOST == "::1" ]; then
exit $PAM_SUCCESS
fi
# Get info from auth.log
authLogLine=$(journalctl -u ssh.service |tail -100 |grep "sshd\[${PPID}\]" |grep "${PAM_RHOST}")
echo ${authLogLine} >> ${log}
PAM_USER_PORT=$(echo ${authLogLine}| sed -r 's/.*port (.*) ssh2.*/\1/')
PAM_USER_SHA256=$(echo ${authLogLine}| sed -r 's/.*SHA256:(.*)/\1/')
# Get details from .ssh/authorized_keys
authFile="/home/${PAM_USER}/.ssh/authorized_keys"
PAM_USER_authorized_keys=""
while read l; do
if [[ -n "$l" && "${l###}" = "$l" ]]; then
authFileSHA256=$(ssh-keygen -l -f <(echo "$l"))
if [[ "${authFileSHA256}" == *"${PAM_USER_SHA256}"* ]]; then
PAM_USER_authorized_keys=$(echo ${authFileSHA256}| cut -d" " -f3)
break
fi
fi
done < ${authFile}
if [[ -n ${PAM_USER_authorized_keys} ]]
then
echo "$(timeStamp) Local user: ${PAM_USER}, authorized_keys user: ${PAM_USER_authorized_keys}" >> ${log}
else
echo "$(timeStamp) WARNING: no matching user in authorized_keys" >> ${log}
fi
I am the author of the OP; I came to the conclusion that what I need to achieve is not possible using SSH only to the date (OpenSSH_6.9p1 Ubuntu-2, OpenSSL 1.0.2d 9 Jul 2015), but I found a great piece of software that uses encrypted SPAuthentication to open SSH port and it's new version (to the date of this post, it's GitHub master branch) has a feature to execute a command always that a user authorizates successfully.
FWKNOP - Encrypted Single Packet Authorization
FWKNOP set iptables rules that allow access to given ports upon a single packet encrypted which is sent via UDP. Then after authorization it allow access for the authorized user for a given time, for example 30 seconds, closing the port after this, leaving the connection open.
1. To install on an Ubuntu linux:
The current version (2.6.0-2.1build1) on Ubuntu repositories to the date still doesn't allow command execution on successful SPA; (please use 2.6.8 from GitHub instead)
On client machine:
sudo apt-get install fwknop-client
On server side:
sudo apt-get install fwknop-server
Here is a tutorial on how to setup the client and server machines
https://help.ubuntu.com/community/SinglePacketAuthorization
Then, after it is set up, on server side:
Edit /etc/default/fwknop-server
Change the line START_DAEMON="no" to START_DAEMON="yes"
Then run:
sudo service fwknop-server stop
sudo service fwknop-server start
2. Warning admin on successful SPA (email, pushover script etc)
So, as stated above the current version present in Ubuntu repositories (2.6.0-2.1build1) cannot execute command on successful SPA. If you need this feature as of the OP, but it will be released at fwknop version (2.6.8), as can it is stated here:
https://github.com/mrash/fwknop/issues/172
So if you need to use it right now you can build from github branch master which have the CMD_CYCLE_OPEN option.
3. More resources on fwknop
https://help.ubuntu.com/community/SinglePacketAuthorization
https://github.com/mrash/fwknop/ (project on GitHub)
http://www.cipherdyne.org/fwknop/ (project site)
https://www.digitalocean.com/community/tutorials/how-to-use-fwknop-to-enable-single-packet-authentication-on-ubuntu-12-04 (tutorial on DO's community)
I am the author of the OP. Also, you can implement a simple logwatcher as the following written in python3, which keeps reading for a file and executes a command when line contains pattern.
logwatcher.python3
#!/usr/bin/env python3
# follow.py
#
# Follow a file like tail -f.
import sys
import os
import time
def follow(thefile):
thefile.seek(0,2)
while True:
line = thefile.readline()
if not line:
time.sleep(0.5)
continue
yield line
if __name__ == '__main__':
logfilename = sys.argv[1]
pattern_string = sys.argv[2]
command_to_execute = sys.argv[3]
print("Log filename is: {}".format(logfilename))
logfile = open(logfilename, "r")
loglines = follow(logfile)
for line in loglines:
if pattern_string in line:
os.system(command_to_execute)
Usage
Make the above script executable:
chmod +x logwatcher.python3
Add a cronjob to start it after reboot
crontab -e
Then write this line there and save it after this:
#reboot /home/YOURUSERNAME/logwatcher.python3 "/var/log/auth.log" "session opened for user" "/sbin/myscript.sh"
The first argument of this script is the log file to watch, and the second argument is the string for which to look in it. The third argument is the script to execute when the line is found in file.
It is best if you use something more reliable to start/restart the script in case it crashes.

ORA-12545: Connect failed because target host or object does not exist while connecting through the shell

I am trying to run the sql scripts from shell. My scripts are working fine. It is getting connected to database and applying the sql files. Only thing I am not able to understand is why the below error message is getting logged every time.
Error Message :
ERROR:
ORA-12545: Connect failed because target host or object does not exist
Shell Script:
/opt/ORACLE/app/oracle/product/11.2.0/client_1/bin/sqlplus -s <<eoj >>$LOG_FIL 2>&1
${DBUSER1}/${DBPASS}#${hostBillingDBSID}
#${SQLParm} $RPT_FIL
eoj
try the below.
Shell Script:
#let's include oracle installation in the PATH variable
export PATH=$PATH:/opt/ORACLE/app/oracle/product/11.2.0/client_1/bin
#now just use sqlplus, instead of full path reference.
sqlplus -s ${DBUSER1}/${DBPASS}#${hostBillingDBSID} <<eoj >>$LOG_FIL 2>&1
#${SQLParm} $RPT_FIL
eoj
The user/password(connection string) has to be passed as command line arguments to sqlplus.

Unable to run a postgresql script from bash

I am learning the shell language. I have creating a shell script whose function is to login into the DB and run a .sql file. Following are the contents of the script -
#!/bin/bash
set -x
echo "Login to postgres user for autoqa_rpt_production"
$DB_PATH -U $POSTGRESS_USER $Auto_rpt_production$TARGET_DB -p $TARGET_PORT
echo "Running SQL Dump - auto_qa_db_sync"
\\i auto_qa_db_sync.sql
After running the above script, I get the following error
./autoqa_script.sh: 39: ./autoqa_script.sh: /i: not found
Following one article, I tried reversing the slash but it didn't worked.
I don't understand why this is happening. Because when I try manually running the sql file, it works properly. Can anyone help?
#!/bin/bash
set -x
echo "Login to postgres user for autoqa_rpt_production and run script"
$DB_PATH -U $POSTGRESS_USER $Auto_rpt_production$TARGET_DB -p $TARGET_PORT -f auto_qa_db_sync.sql
The lines you put in a shell script are (moreless, let's say so for now) equivalent to what you would put right to the Bash prompt (the one ending with '$' or '#' if you're a root). When you execute a script (a list of commands), one command will be run after the previous terminates.
What you wanted to do is to run the client and issue a "\i ./autoqa_script.sh" comand in it.
What you did was to run the client, and after the client terminated, issue that command in Bash.
You should read about Bash pipelines - these are the way to run programs and input text inside them. Following your original idea to solving the problem, you'd write something like:
echo '\i auto_qa_db_sync.sql' | $DB_PATH -U $POSTGRESS_USER $Auto_rpt_production$TARGET_DB -p $TARGET_PORT
Hope that helps to understand.