Bash script not waiting on read - bash

I'm trying to run commands as another user and read input as that user. For some reason the script doesn't pause on the read command, I'm unsure as to why. Here's an example of the script:
#!/bin/bash
username='anthony'
sudo -H -u "$username" bash << 'END_COMMAND'
# Commands to be run as new user
# -------------------------------
echo "#! Running as new user $USER..."
echo "#! Gathering setup information for $USER..."
echo -n "Enter your name and press [ENTER]: "
read name
echo -n "Enter your email and press [ENTER]: "
read email
END_COMMAND
echo "Done"
Any ideas as to why this isn't stopping on read name or read email?

read is reading from stdin, and bash is inheriting its stdin from sudo, which is coming from the heredoc. If you want it to come from somewhere else, you need to be explicit. For example:
bash 3<&0 << 'END_COMMAND'
...
read <&3
...
This does not work with sudo, however, since sudo closes the non-standard file descriptors. But sudo does not close stderr, so if you can get away with reusing that file descriptor, you might be able to do:
sudo -H -u "$username" bash 2<&0 << 'END_COMMAND'
...
read -u 2 email
...
But it's probably much safer to do:
sudo -H -u "$username" bash << 'END_COMMAND'
...
read email < /dev/tty
...

Can you have this script check if it's running as sudo, and if it's not, exec itself with sudo?
#!/bin/bash
username='anthony'
if [[ -z "${SUDO_USER}" ]]; then
exec sudo -H -u "${username}" -- $0
fi
echo "
# Commands to be run as new user
# -------------------------------
"
echo "#! Running as new user $USER..."
echo "#! Gathering setup information for $USER..."
echo -n "Enter your name and press [ENTER]: "
read name
echo -n "Enter your email and press [ENTER]: "
read email

Related

How to use encrypted password with sftp login?

I want to write a shell script where user interaction is not allowed and I want to use sftp login with in the script. Now I have few challenges to execute this approach.
There is no user interaction so I can only provide the options as a argument while executing the script. Script can be like this.
#!/bin/bash
if [[ "${#}" -lt 4 ]]; then
echo -e "Usage: ${0} <sftpUser> <sftpPassword> <sftpHost> <sftpPort>"
exit 1
fi
sftpUser=${1}
sftpPassword=${2}
sftpHost=${3}
sftpPort=${4}
remote_dir="/home/vagrant"
source_dir="/home/vagrant/sftpDir"
sftpFile="/tmp/tempfile"
echo "cd ${remote_dir}" >> ${sftpFile}
echo "mget * ${source_dir}" >> ${sftpFile}
echo "quit" >> ${sftpFile}
expect -c "
spawn sftp -P ${sftpPort} -o "BatchMode=no" -b "${sftpFile}" ${sftpUser}#${sftpHost}
expect -nocase \"*Password:\" { send \"${sftpPassword}\r\"; interact }
"
rm -rf ${sftpFile}
$ ./shellscript.sh user1 password#123 192.168.0.1 22
Here, we need to provide the argument with the script itself and here we are using the plain text format for password password#123
How can we use the encrypted password in the argument as this can be a risk to expose the password?
Is there any other approach to execute this scenario?
I am not able to find any approach to pass the encrypted password with SFTP login.

How to fix chpasswd: line 5: missing new password error [duplicate]

I need to have the ability to create user accounts on my Linux (Fedora 10) and automatically assign a password via a bash script(or otherwise, if need be).
It's easy to create the user via Bash e.g.:
[whoever#server ]# /usr/sbin/useradd newuser
Is it possible to assign a password in Bash, something functionally similar to this, but automatically:
[whoever#server ]# passwd newuser
Changing password for user testpass.
New UNIX password:
Retype new UNIX password:
passwd: all authentication tokens updated successfully.
[whoever#server ]#
You could also use chpasswd:
echo username:new_password | chpasswd
so, you change password for user username to new_password.
You can run the passwd command and send it piped input. So, do something like:
echo thePassword | passwd theUsername --stdin
I was asking myself the same thing, and didn't want to rely on a Python script.
This is the line to add a user with a defined password in one bash line:
useradd -p $(openssl passwd -crypt $PASS) $USER
The code below worked in Ubuntu 14.04. Try before you use it in other versions/linux variants.
# quietly add a user without password
adduser --quiet --disabled-password --shell /bin/bash --home /home/newuser --gecos "User" newuser
# set password
echo "newuser:newpassword" | chpasswd
I liked Tralemonkey's approach of echo thePassword | passwd theUsername --stdin though it didn't quite work for me as written. This however worked for me.
echo -e "$password\n$password\n" | sudo passwd $user
-e is to recognize \n as new line.
sudo is root access for Ubuntu.
The double quotes are to recognize $ and expand the variables.
The above command passes the password and a new line, two times, to passwd, which is what passwd requires.
If not using variables, I think this probably works.
echo -e 'password\npassword\n' | sudo passwd username
Single quotes should suffice here.
The following works for me and tested on Ubuntu 14.04. It is a one liner that does not require any user input.
sudo useradd -p $(openssl passwd -1 $PASS) $USERNAME
Taken from #Tralemonkey
Single liner to create a sudo user with home directory and password.
useradd -m -p $(openssl passwd -1 ${PASSWORD}) -s /bin/bash -G sudo ${USERNAME}
You can use the -p option.
useradd -p encrypted_password newuser
Unfortunately, this does require you to hash the password yourself (where passwd does that for you). Unfortunately, there does not seem to be a standard utility to hash some data so you'll have to write that yourself.
Here's a little Python script I whipped up to do the encryption for you. Assuming you called it pcrypt, you would then write your above command line to:
useradd -p $(pcrypt ${passwd}) newuser
A couple of warnings to be aware of.
While pcrypt is running, the plaintext will be visible to any user via the ps command.
pcrypt uses the old style crypt function - if you are using something more moderns like an MD5 hash, you'll need to change pcrypt.
and here's pcrypt:
#!/usr/bin/env python
import crypt
import sys
import random
saltchars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
def salt():
return random.choice(saltchars) + random.choice(saltchars)
def hash(plain):
return crypt.crypt(arg, salt())
if __name__ == "__main__":
random.seed()
for arg in sys.argv[1:]:
sys.stdout.write("%s\n" % (hash(arg),))
--stdin doesn't work on Debian. It says:
`passwd: unrecognized option '--stdin'`
This worked for me:
#useradd $USER
#echo "$USER:$SENHA" | chpasswd
Here we can find some other good ways:
http://www.debian-administration.org/articles/668
You can use expect in your bash script.
From http://www.seanodonnell.com/code/?id=21
#!/usr/bin/expect
#########################################
#$ file: htpasswd.sh
#$ desc: Automated htpasswd shell script
#########################################
#$
#$ usage example:
#$
#$ ./htpasswd.sh passwdpath username userpass
#$
######################################
set htpasswdpath [lindex $argv 0]
set username [lindex $argv 1]
set userpass [lindex $argv 2]
# spawn the htpasswd command process
spawn htpasswd $htpasswdpath $username
# Automate the 'New password' Procedure
expect "New password:"
send "$userpass\r"
expect "Re-type new password:"
send "$userpass\r"
I know I'm coming at this years later, but I can't believe no one suggested usermod.
usermod --password `perl -e "print crypt('password','sa');"` root
Hell, just in case someone wants to do this on an older HPUX you can use usermod.sam.
/usr/sam/lbin/usermod.sam -F -p `perl -e "print crypt('password','sa');"` username
The -F is only needed if the person executing the script is the current user. Of course you don't need to use Perl to create the hash. You could use openssl or many other commands in its place.
I've tested in my own shell script.
$new_username means newly created user
$new_password means newly password
For CentOS
echo "$new_password" | passwd --stdin "$new_username"
For Debian/Ubuntu
echo "$new_username:$new_password" | chpasswd
For OpenSUSE
echo -e "$new_password\n$new_password" | passwd "$new_username"
Here is a script that will do it for you .....
You can add a list of users (or just one user) if you want, all in one go and each will have a different password. As a bonus you are presented at the end of the script with a list of each users password. .... If you want you can add some user maintenance options
like:
chage -m 18 $user
chage -M 28 $user
to the script that will set the password age and so on.
=======
#!/bin/bash
# Checks if you have the right privileges
if [ "$USER" = "root" ]
then
# CHANGE THIS PARAMETERS FOR A PARTICULAR USE
PERS_HOME="/home/"
PERS_SH="/bin/bash"
# Checks if there is an argument
[ $# -eq 0 ] && { echo >&2 ERROR: You may enter as an argument a text file containing users, one per line. ; exit 1; }
# checks if there a regular file
[ -f "$1" ] || { echo >&2 ERROR: The input file does not exists. ; exit 1; }
TMPIN=$(mktemp)
# Remove blank lines and delete duplicates
sed '/^$/d' "$1"| sort -g | uniq > "$TMPIN"
NOW=$(date +"%Y-%m-%d-%X")
LOGFILE="AMU-log-$NOW.log"
for user in $(more "$TMPIN"); do
# Checks if the user already exists.
cut -d: -f1 /etc/passwd | grep "$user" > /dev/null
OUT=$?
if [ $OUT -eq 0 ];then
echo >&2 "ERROR: User account: \"$user\" already exists."
echo >&2 "ERROR: User account: \"$user\" already exists." >> "$LOGFILE"
else
# Create a new user
/usr/sbin/useradd -d "$PERS_HOME""$user" -s "$PERS_SH" -m "$user"
# passwdgen must be installed
pass=$(passwdgen -paq --length 8)
echo $pass | passwd --stdin $user
# save user and password in a file
echo -e $user"\t"$pass >> "$LOGFILE"
echo "The user \"$user\" has been created and has the password: $pass"
fi
done
rm -f "$TMPIN"
exit 0
else
echo >&2 "ERROR: You must be a root user to execute this script."
exit 1
fi
===========
Hope this helps.
Cheers,
Carel
The solution that works on both Debian and Red Hat. Depends on perl, uses sha-512 hashes:
cat userpassadd
#!/usr/bin/env bash
salt=$(cat /dev/urandom | tr -dc A-Za-z0-9/_- | head -c16)
useradd -p $(perl -e "print crypt('$2', '\$6\$' . '$salt' . '\$')") $1
Usage:
userpassadd jim jimslongpassword
It can effectively be used as a one-liner, but you'll have to specify the password, salt and username at the right places yourself:
useradd -p $(perl -e "print crypt('pass', '\$6\$$salt\$')") username
From IBM (https://www.ibm.com/support/knowledgecenter/ssw_aix_61/com.ibm.aix.cmds1/chpasswd.htm):
Create a text file, say text.txt and populate it with user:password pairs as follows:
user1:password1
user2:password2
...
usern:passwordn
Save the text.txt file, and run
cat text.txt | chpassword
That's it. The solution is (a) scalable and (b) does not involve printing passwords on the command line.
Tralemonkey's solution almost worked for me as well ... but not quite. I ended up doing it this way:
echo -n '$##password##$' | passwd myusername --stdin
2 key details his solution didn't include, the -n keeps echo from adding a \n to the password that is getting encrypted, and the single quotes protect the contents from being interpreted by the shell (bash) in my case.
BTW I ran this command as root on a CentOS 5.6 system in case anyone is wondering.
{ echo $password; echo $password; } | passwd $username
For RedHat / CentOS here's the code that creates a user, adds the passwords and makes the user a sudoer:
#!/bin/sh
echo -n "Enter username: "
read uname
echo -n "Enter password: "
read -s passwd
adduser "$uname"
echo $uname:$passwd | sudo chpasswd
gpasswd wheel -a $uname
usage: ./my_add_user.sh USER PASSWD
code:
#!/bin/bash
# my_add_user.sh
if [ "$#" -lt 2 ]
then
echo "$0 username passwd"
exit
fi
user=$1
passwd=$2
useradd $user -d /data/home/$user -m ;
echo $passwd | passwd $user --stdin;
Kindly run below script with sudo permission for creating a user by script.
Note: This script supports all linux OSs like Redhat, Centos, Ubuntu, suse, kali, Arch, Bitname, BSD....etc
#!/bin/bash
#author: bablish jaiswal
#purpos: Linux user creation with a storng password
clear
#echo "Hi, I am a function to create sudo user with strong password. Kindly share following information"
echo -e "\n\n\n"
printf "\e[6;33mHi, I am a function to create sudo user with a strong password. Kindly share following information\e[0m";echo
read -p "user name:- " name #input name
read -p "complete path for $name home directory? example: /home/$name :- " home #user home path
( useradd -m -d $home $name -s /bin/bash ) > /dev/null 2>&1
pass=$(cat /dev/urandom |tr -dc "[[:graph:]]" |head -c16)
(echo -e "$pass\n$pass" | passwd $name ) > /dev/null 2>&1
echo " "
printf "\e[6;33m-----------------------------Copy below credentials-------------------------\e[0m";echo
echo -e "User:- $name\nHomeDir:- $home\npassword:- $pass"
#svalue=$(cat /etc/sudoers |grep -i root |grep -i all|tail -n1 |awk '{$1=""}1')
svalue=$(cat /etc/sudoers |grep -i root |grep -i all|tail -n1 |awk '{print $2}')
echo "${name} ${svalue} NOPASSWD:ALL" >> /etc/sudoers && echo “Remark:- User $name is a sudo user”

Bash Scripting - User Input a Command

Very easy question but I really can't find this when I Google. Sorry!
I'm trying to write a script that runs a user's command that he or she enters but I can't run the command that the user enters.
#!/bin/bash
echo -e "Enter a Command: "
read $COMMAND
echo "Output: $COMMAND" # I can't figure how to implement and print the command
Enter a Command: ls
Output: folder1 folder2 folder3 test.txt)
All you need is to delete the dollar sign from the read command
#!/bin/bash
echo "Enter a Command: "
read COMMAND
echo "Output: $COMMAND"
Happy scripting!, please don't forget to marked as answered ;)
Use eval to execute a command from a variable.
Also, you don't put $ before the variable name in the read command. That's only used when you want to get the variable's value.
#!/bin/bash
echo -e "Enter a Command: "
read COMMAND
echo Output:
eval "$COMMAND"
DEMO
Thanks! This answered my question:
#!/bin/bash
echo -e "Enter a Command: "
read COMMAND
echo Output:
eval "$COMMAND"

Answer prompts in bash

I am often in the need of running a bash script that needs inputs from me and im trying to improve my workflow by automating this.
In my case my bash script is in need of 3 inputs from me:
What interface should i use?
1
Enter the password:
mypass
Please restart the program:
sudo bash restart
How can i make my bash script file auto input theses values? I have tried figuring this out but all the answer are about inputing yes or no.
If that is all the input your program needs, then you can simply put the inputs, one per line, in a text file, then run it like this:
$> ./yourscript.sh < yourtextfile.txt
For your example, the text file would contain
1
mypass
sudo bash restart
If you have such a script.sh:
#!/bin/bash
read -p "What intergace should i use?"$'\n' interfacenum
echo
read -p "Enter the password:"$'\n' pass
echo
read -p "Please restaart the program:"$'\n' prog
echo
echo "Values:"
for i in interfacenum pass prog; do
echo $'\t'"$i=\"${!i}\""
done
You can 'input' the values into the script using echo or printf:
echo -ne "1\nmypass\nsudo bash restart\n" | ./script.sh
You can use expect and autoexpect to achieve your task.
Let's say this is your file:
cat hello.sh
#!/usr/local/bin/bash
read -p "Select the interface: " interface
echo "interface selected: $interface"
read -p "Enter the username: " username
echo "username: $username"
You don't have to even write the scripts. You can you autoexpect to generate the script for you.
autoexpect ./hello.sh
autoexpect started, file is script.exp
Select the interface: 1
interface selected: 1
...(more input and output to generate the script)
Examine the generated script.
tail -n7 script.exp
expect -exact "Select the interface: "
send -- "1\r"
expect -exact "1\r
interface selected: 1\r
Enter the username: "
send -- "vivek\r"
expect eof
Now sit back and run the generated script
./script.exp
spawn ./hello.sh
Select the interface: 1
interface selected: 1
Enter the username: vivek
username: vivek

Pass variables from one Bash script to another after SSH

Okay, so I am new to bash scripting, about 2 whole hours and I'm banging my head against a wall. I need to carry some variables from one script to another and can't seem to get it to work.
This works fine
script1.sh
echo "Enter your name"
read name
export name
./script2.sh
sript2.sh
echo $name
This does not
script1.sh
echo "Enter your name"
read name
export name
ssh $user#$domain "bash -s" < ./script2.sh
sript2.sh
echo $name
The code is dumb, I get that but basically what I want to do is pass database variables to script 2 to use on the server I've SSH'd into. I would do this all in one script but it seems the only way that I can get the server commands to run is to call a second script after the login, otherwise it runs the server commands locally and fails. I'm doing this from a Mac if that makes any difference at all.
Help?
** Update with more legitimate code ****
login.sh
#!/bin/bash
echo "Enter server username:"
read user
echo "Enter server domain"
read domain
echo "Enter your password"
read password
echo "Enter database name"
read database
export database
export user
export domain
export password
ssh $user#$domain "bash -s" < ./create_files.sh
create_files.sh
#!/bin/bash
cd public_html
tar -zcvf test.tar.gz test.html
echo "db:"$database
mysqldump -u $user -p"$password" $database > $database.sql
The goal here is to use the details from login.sh in create_files.sh after this is done I also need to use the login details to scp the created files back to my local machine. Hope this clarifies the problem.
When invoking ssh, it creates a new shell process which is not inheriting the new variables that you exported in the first script. Instead, try adding them as commandline parameters to the second script, like so:
#!/bin/bash
echo "Enter server username:"
read user
echo "Enter server domain"
read domain
echo "Enter your password"
read password
echo "Enter database name"
read database
ssh $user#$domain "bash -s" < ./create_files.sh "$user" "$password" "$database"
Then modify your second script to look like this:
#!/bin/bash
cd public_html
tar -zcvf test.tar.gz test.html
echo "db:$3"
mysqldump -u "$1" -p"$2" "$3" > "$3".sql

Resources