Expect script ends without error at the New Password prompt - tcl

I have Solaris servers of which I'm not sure if I changed the password to a particular account. Either I'm going to authenticate successfully because I already changed the password or I'm going to authenticate with the old password and it will prompt me to change my password after I authenticate with the old password because it expired.
Warning: Your password has expired, please change it now.
New Password:
The script will stop at the New Password: prompt and exits w/o an error.
#!/bin/bash
NewPassword="cccccc"
OtherPassword="ffffffff"
for i in `cat x.txt`
do
/opt/csw/bin/expect -f <(cat << EOF
spawn ssh -o StrictHostKeyChecking=no adminuser#$i
expect "Password: "
send "$NewPassword\r"
expect {
"$ " {
## new password worked
send "uname -a\r"
}
"Password: " {
## The new password did not work
send "$OtherPassword\r"
expect "$ "
}
"New Password: " {
## after authenticating, my old password expired need to change it now
send ${NewPassword}\r
expect "Re-enter new Password: "
send ${NewPassword}\r
expect "$ "
}
}
EOF
)
done

The order of clauses in the expect matters; the internal matcher tries the different matching rules in the order you specify. This is important here because the rule for Password: also matches what New Password: will match, and so will have priority over it.
Swap the two clauses or rewrite them so that they can't both match the same input text (probably by including the newline or changing to using anchored regular expressions). Swapping them is far easier.

In addition to Donal's cogent advice, a couple of notes:
In the shell part, don't read lines with for
using a process substitution and cat and a here document is overkill: you just need the here-doc
use exp_continue to handle the exceptional cases that occur before you see the prompt
exit your login session and expect to see it close so you don't have to wait around to timeout.
#!/bin/bash
NewPassword="cccccc"
OtherPassword="ffffffff"
while read server; do
/opt/csw/bin/expect << EOF
spawn ssh -o StrictHostKeyChecking=no adminuser#$server
expect "Password: "
send "$NewPassword\r"
set count 0
expect {
"New Password: " {
## after authenticating, my old password expired need to change it now
send ${NewPassword}\r
expect "Re-enter new Password: "
send ${NewPassword}\r
exp_continue
}
"Password: " {
if {[incr count] == 2} {
error "neither new password nor old password worked for $server"
}
## The new password did not work
send "$OtherPassword\r"
exp_continue
}
"$ "
}
send "uname -a\r"
expect "$ "
send "exit\r"
expect eof
EOF
done < x.txt

Related

Expect: SSH into a remote host, run a command, and save its output to a variable

I'm trying to ssh into a server, run a command, and save its output to a variable, with no success.
spawn $env(SHELL)
expect "\$ "
send "ls\r"
expect "\$ "
send "ssh myserver1\r"
expect "\$ "
send "cd /tmp/remotedir1\r"
expect "\$ "
send "ls\r"
expect "\$ "
set myvar1 [exec ls]
puts "The value of \$myvar1 is: "
puts $myvar1
send "exit\r"
expect "\$ "
send "exit\r"
expect eof
When I run it, I get:
spawn /bin/bash
$ ls
localfile1 localfile2 localfile3
$ ssh myserver1
Last login: Tue Sep 10 15:45:07 2017 from 192.168.0.100
myserver1$ cd /tmp/remotedir1
myserver1$ ls
remotefile1
myserver1$ The value of $myvar1 is:
localfile1
localfile2
localfile3
exit
logout
Connection to myserver1 closed.
bash-3.2$ exit
exit
Apparently, instead of setting $myvar1 to "remotefile1", it sets to those 3 files in the $cwd on the local host.
Thank you for your help in advance!
Using exec will execute the command locally.
Upon sending the ls command, you have to make use of the expect_out array to get the response.
set prompt "(.*)(#|%|>|\\\$) $"
send "ls\r"
expect -re $prompt
puts $expect_out(1,string)

Perl codes always connecting to same MySQL database although it is configured to connect to different server

Perl codes always connecting to same MySQL(local but in error showing FQDN of server) database although it is configured to connect to different server.
please see the codes.
$datasetname="DBI:mysql:database=applications;host=entdb"
$$dbobject = DBI -> connect ($datasetname, $username, $password,
{RaiseError => 0, PrintError => 0})
or $errflg2 = 1;
print TT (" : ".time()."\n");
close (TT);
if ($errflg2 > 0)
{
$errmsg = "ERROR opening up the database: $datasetname\n";
$errmsg .= " Error number: " . $DBI::err . "\n";
$errmsg .= " Error text : " . $DBI::errstr . "\n";
print "$errmsg";
ilog ($ifile, $errmsg);
mail_it ($errmsg);
if ($debug != 0) { close (DB); }
exit (1);
}
else
{ print "Opened the '" . $datasetname . "' database.\n"; }**
enter code here
error
ERROR opening up the database: DBI:mysql:database=applications;host=entdb
Error number: 1045
Error text : Access denied for user 'entdb'#'vpl121' (using password: YES)
see in code i referred entdb, but Perl connecting to VPL121. Perl codes are running on vpl121.
In mysql all user accounts are identified via username#hostname format, where hostname is the host name or ip address of the computer from which the code connects to the mysql database.
You did write that the perl code runs on vpl121, therefore this is the hostname that mysql uses. Apparently, you do not have any user account that matches the 'entdb'#'vpl121' or the password is incorrect or the given user does not have access to the entdb database.
My guess is that you do not have any matching user accounts. Consider perhaps creating an 'entdb'#'%' user account, where % as hostname stands for any host name or ip address.

Bash - Break up returned value from MySQL query

I am trying to break up a returned value from a mysql call in a shell script. Essentially what I have done so far is query the database for IP addresses that I have stored in a specific table. From there I store that returned value into a bash variable. The code is below:
#!/bin/bash
# This file will be used to obtain the system details for given ip address
retrieve_details()
{
# get all the ip addresses in the hosts table to pass to snmp call
host_ips=$(mysql -u user -ppassword -D honours_project -e "SELECT host_ip FROM hosts" -s)
echo "$host_ips"
# break up the returned host ip values
# loop through array of ip addresses
# while [ ]
# do
# pass ip values to snmp command call
# store details into mysql table host_descriptions
# done
}
retrieve_details
So this returns the following:
192.168.1.1
192.168.1.100
192.168.1.101
These are essentially the values I have in my hosts table. So what I am trying to do is break up each value such that I can get an array that looks like the following:
arr[0]=192.168.1.1
arr[1]=192.168.1.100
arr[2]=192.168.1.101
...
I have reviewed this link here: bash script - select from database into variable but I don't believe this applies to my situation. Any help would be appreciated
host_ips=($(mysql -u user -ppassword -D honours_project -e "SELECT host_ip FROM hosts" -s));
outer () will convert that in array. But you need to change your IFS (Internal Field Separator) to a newline first.
IFS=$'\n';
host_ips=($(mysql -u user -ppassword -D honours_project -e "SELECT host_ip FROM hosts" -s));
unset IFS;
for i in ${host_ips[#]} ; do echo $i ; done;
to print with key
for i in "${!host_ips[#]}"
do
echo "key :" $i "value:" ${host_ips[$i]}
done
wspace#lw:~$ echo $host_ips
192.168.1.1 192.168.1.100 192.168.1.101
wspace#lw:~$ arr=($(echo $host_ips))
wspace#lw:~$ echo ${arr[0]}
192.168.1.1
wspace#lw:~$ echo ${arr[1]}
192.168.1.100
wspace#lw:~$ echo ${arr[2]}
192.168.1.101
wspace#lw:~$ echo ${arr[#]}
192.168.1.1 192.168.1.100 192.168.1.101
wspace#lw:~$
maybe this is what you want

Tcl Expect Keep SSH Spawn open

I want to open a spawn SSH connection and then query a MySQL Server for new users (in a loop), and if a new user is found a command should be sent to this SSH Connection via Expect.
I don't know if this is possible, up until now i allways kill ssh.exe when i try the "send" command after the MySQL Query.
I want the SSH to be open because it takes 10 seconds to login with Expect (Host ist slow) and i don't want that pause everytime a create a user.
How can i do this?
What i am doing:
...
set db [::mysql::connect -host 127.0.0.1 -user root -password **** -db test]
spawn ssh admin#192.168.1.2
expect {
timeout { send_user "\nFalscher SSH User admin!\n"; exit 1 }
"User:"
}
send "admin\r"
expect {
timeout { send_user "\nFalscher SSH User admin!\n"; exit 1 }
"Password:"
}
send "******\r"
set x = 1
while {$x>0} {
set query [::mysql::query $db {SELECT username, passwort FROM users WHERE erstellt='0'}]
while {[set row [::mysql::fetch $query]]!=""} {
set username [lindex $row 0]
set passwort [lindex $row 1]
send "create user...;\r"
}
::mysql::endquery $query
after 2000
}
I solved this by saving the expect output into a file.
After starting in the background, ssh wanted to verify my ssl fingerprint.
After accepting that, it worked fine.

MySQL password input in bash script

I have a bash script that needs to perform a couple actions in MySQL. So far I have something like this:
#!/bin/sh
read -p "Enter your MySQL username: " $sqluname
read -sp "Enter your MySQL password (ENTER for none): " $sqlpasswd
/usr/bin/mysql -u $sqluname -p $sqlpasswd << eof
*some SQL stuff*
eof
This works well until it's used with a MySQL username that has a blank password. The user hits ENTER at my password prompt, but then they receive another prompt to "Enter your password" again from MySQL.
How can I avoid this second password prompt and make the script deal with both blank and non-blank passwords?
Check if the password is blank or not, and if it is, then omit the -p switch altogether.
read -p "Enter your MySQL username: " $sqluname
read -sp "Enter your MySQL password (ENTER for none): " $sqlpasswd
if [ -n "$sqlpasswd" ]; then
/usr/bin/mysql -u $sqluname -p $sqlpasswd << eof
else
/usr/bin/mysql -u $sqluname << eof
fi
Later edit to avoid a whole if-then-else block:
command="/usr/bin/mysql -u $sqluname"
[ -n "$sqlpasswd" ] && command="$command -p$sqlpasswd"
eval $command
You'd need to specify the -n switch if $sqlpasswd is empty (instead of -p $sqlpasswd).