Expect-like functionality to IO.gets? - shell

For example, if I wanted to automate authorizing a hex user. Something like
mix hex.user auth
#!/usr/bin/expect -f
expect "Username: "
send -- "$HEX_USERNAME\r"
expect "Password: "
send -- "$HEX_PASSWORD\r"
mix hex.user auth asks for Username: and Password: but I don't think expect works for this

Given the following script:
u = IO.gets("Username: ") |> String.strip
p = IO.gets("Password: ") |> String.strip
IO.puts ""
IO.puts "#{u} - #{p}"
You can pass input like this:
$ export HEX_USERNAME="hexuser"
$ export HEX_PASSWORD="hexpass"
$ echo "$HEX_USERNAME\n$HEX_PASSWORD" | elixir test.exs
Username: Password:
hexuser - hexpass
So, you could use
echo "$HEX_USERNAME\n$HEX_PASSWORD" | mix hex.user auth

Related

Create single backslash in Ruby

I would like to execute:
echo aA1.-_#*~^%\':\;?!#=/ | passwd --stdin user
It can be logged in with "aA1.-_#*~^%':;?!#=/".
I tried
str = "aA1.-_#*~^%':;?!#=/"
password = str.gsub("'", "\\\\'").gsub(";", "\\;")
passwd_command = "echo" +
" #{password}" +
" | passwd" +
" --stdin user"
but the result was:
echo aA1.-_#*~^%\\':\\;?!#=/ | passwd --stdin aaa
I executed it:
[root#localhost ~]# echo aA1.-_#*~^%\\':\\;?!#=/ | passwd --stdin aaa
>
The command has not finished. Do you have any suggestions?
I suggest Shellwords#escape because this is its purpose.
require 'shellwords'
Shellwords.escape("aA1.-_#*~^%':;?!#=/")
#=> "aA1.-_\\#\\*\\~\\^\\%\\':\\;\\?\\!#\\=/"
I don't know shellwords, but aren't the default Ruby methods sufficient? Like %q and %x?
See for example: https://simpleror.wordpress.com/2009/03/15/q-q-w-w-x-r-s/

Changing an AIX password via script?

I am trying to change a password of a user via script. I cannot use sudo as there is a feature that requires the user to change the password again if another user changes their password.
AIX is running on the system.
unfortunately, chpasswd is unavailable.
I have expected installed, but I am having trouble with that also.
here is what I thought would work
echo "oldpassword\nnewpasswd123\nnewpasswd123" | passwd user
However once run the script I am prompted with please enter user's old password
shouldn't they all be echoed in?
I am a beginner with shell scripting and this has been baffled.
You can try:
echo "USERNAME:NEWPASSWORD" | chpasswd
Use GNU passwd stdin flag.
From the man page:
--stdin
This option is used to indicate that passwd should read the new password from standard input, which can be a pipe.
NOTE: Only for root user.
Example
$ adduser foo
$ echo "NewPass" |passwd foo --stdin
Changing password for user foo.
passwd: all authentication tokens updated successfully.
Alternatively you can use expect, this simple code will do the trick:
#!/usr/bin/expect
spawn passwd foo
expect "password:"
send "Xcv15kl\r"
expect "Retype new password:"
send "Xcv15kl\r"
interact
Results
$ ./passwd.xp
spawn passwd foo
Changing password for user foo.
New password:
Retype new password:
passwd: all authentication tokens updated successfully.
In addition to the other suggestions, you can also achieve this using a HEREDOC.
In your immediate case, this might look like:
$ /usr/bin/passwd root <<EOF
test
test
EOF
You need echo -e for the newline characters to take affect
you wrote
echo "oldpassword\nnewpasswd123\nnewpasswd123" | passwd user
you should try
echo -e "oldpassword\nnewpasswd123\nnewpasswd123" | passwd user
more than likely, you will not need the oldpassword\n portion of that command, you should just need the two new passwords. Don't forget to use single quotes around exclamation points!
echo -e "new"'!'"passwd123\nnew"'!'"passwd123" | passwd user
You can try :
echo -e "newpasswd123\nnnewpasswd123" | passwd user
Just this
passwd <<EOF
oldpassword
newpassword
newpassword
EOF
Actual output from ubuntu machine (sorry no AIX available to me):
user#host:~$ passwd <<EOF
oldpassword
newpassword
newpassword
EOF
Changing password for user.
(current) UNIX password: Enter new UNIX password: Retype new UNIX password:
passwd: password updated successfully
user#host:~$
This is from : Script to change password on linux servers over ssh
The script below will need to be saved as a file (eg ./passwdWrapper) and made executable (chmod u+x ./passwdWrapper)
#!/usr/bin/expect -f
#wrapper to make passwd(1) be non-interactive
#username is passed as 1st arg, passwd as 2nd
set username [lindex $argv 0]
set password [lindex $argv 1]
set serverid [lindex $argv 2]
set newpassword [lindex $argv 3]
spawn ssh $serverid passwd
expect "assword:"
send "$password\r"
expect "UNIX password:"
send "$password\r"
expect "password:"
send "$newpassword\r"
expect "password:"
send "$newpassword\r"
expect eof
Then you can run ./passwdWrapper $user $password $server $newpassword which will actually change the password.
Note: This requires that you install expect on the machine from which you will be running the command. (sudo apt-get install expect) The script works on CentOS 5/6 and Ubuntu 14.04, but if the prompts in passwd change, you may have to tweak the expect lines.
Here is the script...
#!/bin/bash
echo "Please enter username:"
read username
echo "Please enter the new password:"
read -s password1
echo "Please repeat the new password:"
read -s password2
# Check both passwords match
if [ $password1 != $password2 ]; then
echo "Passwords do not match"
exit
fi
# Does User exist?
id $username &> /dev/null
if [ $? -eq 0 ]; then
echo "$username exists... changing password."
else
echo "$username does not exist - Password could not be updated for $username"; exit
fi
# Change password
echo -e "$password1\n$password1" | passwd $username
Refer the link below as well...
http://www.putorius.net/2013/04/bash-script-to-change-users-password.html
You can try
LINUX
echo password | passwd username --stdin
UNIX
echo username:password | chpasswd -c
If you dont use "-c" argument, you need to change password next time.
If you can use ansible, and set the sudo rights in it, then you can easily use this script. If you're wanting to script something like this, it means you need to do it on more than one system. Therefore, you should try to automate that as well.
For me this worked in a vagrant VM:
sudo /usr/bin/passwd root <<EOF
12345678
12345678
EOF
printf "oldpassword/nnewpassword/nnewpassword" | passwd user
#!/usr/bin/python
import random
import string
import smtplib
import sys
import os
from subprocess import call
import socket
user = sys.argv[1]
receivers = ["%s#domain.com" %user]
'''This will generate a 30 character random password'''
def genrandpwd():
return ''.join(random.SystemRandom().choice(string.ascii_lowercase + string.digits + string.ascii_uppercase + string.punctuation) for _ in range(30))
def change_passwd(user, password):
p = os.popen("/usr/bin/passwd %s" %user, "w")
p.write(password)
p.write("\n")
p.write(password)
p.close()
def chage(user):
agepasswd = call(["/usr/bin/chage", "-d", "0", "%s" %user])
def mailpwd(user, password):
sender = "admin#%s" %socket.gethostname()
subj = "!!!IMPORTANT!!!, Unix password changed for user %s" %user
text = "The password for the %s user has changed, the new password is:\n\n %s \n\n Note: The system will force to change the password upon initial login. Please use the password provided in the mail as your current password and type the password of your choice as the New password" %(user, password)
message = message = 'Subject: %s\n\n%s' % (subj, text)
smtpObj = smtplib.SMTP('mailrelay-server.domain.com')
smtpObj.sendmail(sender, receivers, message)
smtpObj.quit()
def main():
newpwd = genrandpwd()
change_passwd(user, newpwd)
chage(user)
mailpwd(user, newpwd)
if __name__ == "__main__":
main()

Using expect to confirm a password

What I'm trying to do is write an expect script that backs up all databases on a server, then create an encrypted zip file (I couldn't get my tar/openssl command to run properly in expect) containing the sql file.
This is just an exercise to learn about expect, not a real backup solution.
I'm obviously lacking some understanding here. What I want to do is:
Back up all databases to a file (done)
Run the zip command to create an encrypted zip file (done... sorta)
Respond to "Enter password: "
Then response to the confirmation "Verify password: "
#!/usr/bin/expect -f
exp_internal 1
set backupdir "/mnt/db-backups/"
set now [clock seconds]
set date [clock format $now -format {%Y-%m-%d}]
set filename $date
append filename "_dbbackups.sql"
exec mysqldump -u root --all-databases --events > $backupdir$filename
spawn zip -e $backupdir$filename.enc.zip $backupdir$filename
expect {
"Enter password: " { send "monkey"
exp_continue
}
"Verify password: " {send "monkey"
exp_continue
}
}
And the output is
$expect encrypt.sh
spawn zip -e /mnt/db-backups/2013-12-11_dbbackups.sql.enc.zip /mnt/db-backups/2013-12-11_dbbackups.sql
parent: waiting for sync byte
parent: telling child to go ahead
parent: now unsynchronized from child
spawn: returns {15733}
expect: does "" (spawn_id exp6) match glob pattern "Enter password: "? no
"Verify password: "? no
Enter password:
expect: does "Enter password: " (spawn_id exp6) match glob pattern "Enter password: "? yes
expect: set expect_out(0,string) "Enter password: "
expect: set expect_out(spawn_id) "exp6"
expect: set expect_out(buffer) "Enter password: "
send: sending "monkey" to { exp6 }
expect: continuing expect
expect: does "" (spawn_id exp6) match glob pattern "Enter password: "? no
"Verify password: "? no
monkey
expect: does "monkey" (spawn_id exp6) match glob pattern "Enter password: "? no
"Verify password: "? no
-- then I exited --
It's a pretty simple script... but I'm sucking at it.
The problem is simple:
You have to press return. So just change the command
send "monkey"
to
send "monkey\r"
(both of them)
DRY:
spawn zip -e $backupdir$filename.enc.zip $backupdir$filename
expect {
"* password: " {
send "monkey\r"
exp_continue
}
eof
}
[...] write an expect script [...]
Not how I'd do it.
zip -P password [...]
Knowing nothing about your Zip version ("zip -v"), it's hard to say
if you simply didn't look at the documentation ("zip -h2", "man zip").
Putting a password into a script is a sufficient security hazard that
"-P" was left undocumented until Zip 3.0 (when the developers got tired
of answering the how-do-I questions). But putting a password into a
script once can hardly be worse than putting a password into a script
twice.
Expect is a really ugly and troublesome solution for this.
For the mysqldump part, add your database connection information and the password in ~/.my.cnf following this format:
[client]
database=dbname
user=dbuser
password=dbpass
host=dbhost
If you work with multiple databases, then you'll have to create one file per database, for example ~/.my.cnf.dbname, and call mysqldump like this:
mysqldump --defaults-file=~/.my.cnf.$dbname $dbname | gzip >"$target"
Make sure to do chmod 600 on this file to make it as secure as possible.
And when you encrypt with openssl, you can put the password on the command line like this:
... | openssl des3 -pass pass:monkey >"$target"
You can put this after gzip in the earlier command. Of course, use a different cipher instead of des3 if you want more security. Also, instead of passing the password on the command line, you might want to use file:pathname option instead to get the password from the first line of the file instead.

ruby execute bash command with variables

I need to execute a Bash command in a Ruby script. There are about 6 ways to do this according to "6 Ways to Run Shell Commands in Ruby" by Nate Murray and a few other googled sources.
print "enter myid: "
myID = gets
myID = myID.downcase
myID = myID.chomp
print "enter host: "
host = gets
host = host.downcase
host = host.chomp
print "winexe to host: ",host,"\n"
command = "winexe -U domain\\\\",ID," //",host," \"cmd\""
exec command
For what it's worth you can actually chain those methods, and puts will print a newline for you, so this could just be:
print "enter myid: "
myID = STDIN.gets.downcase.chomp
print "enter host: "
host = STDIN.gets.downcase.chomp
puts "winexe to host: #{host}"
command = "winexe -U dmn1\\\\#{myID} //#{host} \"cmd\""
exec command
It looks like there may have been trouble with how you were putting your command string together.
Also, I had to refer to STDIN directly.
# Minimal changes to get it working:
print "enter myid: "
myID = STDIN.gets
myID = myID.downcase
myID = myID.chomp
print "enter host: "
host = STDIN.gets
host = host.downcase
host = host.chomp
print "winexe to host: ",host,"\n"
command = "echo winexe -U dmn1\\\\#{myID} //#{host} \"cmd\""
exec command
Compact version:
print "enter myid: "
myID = STDIN.gets.downcase.chomp
print "enter host: "
host = STDIN.gets.downcase.chomp
puts "winexe to host: #{host}"
exec "echo winexe -U dmn1\\\\#{myID} //#{host} \"cmd\""
Last two lines with printf style:
puts "winexe to host: %s" % host
exec "echo winexe -U dmn1\\\\%s //%s \"cmd\"" % [myID, host]
Last two lines with plus string concatenation:
puts "winexe to host: " + host
exec "echo winexe -U dmn1\\\\" + myID + " //" + host + " \"cmd\""
Last two lines with C++ style append:
puts "winexe to host: " << host
exec "echo winexe -U dmn1\\\\" << myID << " //" << host << " \"cmd\""

Ruby $stdin.gets without showing chars on screen

I want to ask users to type in a password, but I don't want the chars to appear on screen as they type.
How do I do this in Ruby?
You can use the STDIN.noecho method from the IO/console module:
require 'io/console'
pw = STDIN.noecho(&:gets).chomp
If you're on a system with stty:
`stty -echo`
print "Password: "
pw = gets.chomp
`stty echo`
puts ""
There is a gem for such user interaction: highline.
password = ask("Password: ") { |q| q.echo = false }
Or even:
password = ask("Password: ") { |q| q.echo = "*" }
You want to make sure your code is idempotent... other solutions listed here assume you want to exit this chunk of functionality with echo turned back on. Well, what if it was turned off before entering the code, and it's expected to stay off?
stty_settings = %x[stty -g]
print 'Password: '
begin
%x[stty -echo]
password = gets
ensure
%x[stty #{stty_settings}]
end
puts
print 'regular info: '
regular_info = gets
puts "password: #{password}"
puts "regular: #{regular_info}"
This is solution for UNIX systems:
begin
system "stty -echo"
print "Password: "; pass1 = $stdin.gets.chomp; puts "\n"
print "Password (repeat): "; pass2 = $stdin.gets.chomp; puts "\n"
if pass1 == pass2
# DO YOUR WORK HERE
else
STDERR.puts "Passwords do not match!"
end
ensure
system "stty echo"
end
Similar answer as glenn but more complete: http://dmathieu.com/articles/development/ruby-console-ask-for-a-password/

Resources