Usually I install msmtp as the local mailer, setup is much easier than postfix/others and it's quite capable.
With this content in /etc/msmtprc
defaults
tls_trust_file /etc/ssl/certs/ca-bundle.crt
account default
host smtp.gmail.com
port 587
tls on
auth on
user redacted#example.com
password password
from redacted#example.com
logfile /var/log/msmtp.log
aliases /etc/aliases
I am having the error:
CROND[1587]: (ec2-user) MAIL (mailed 580 bytes of output but got status 0x004e#012)
For all the cron that should send email for ec2-user
Sending with mailx works fine:
echo "TEX" | mailx -s "TEST" redacted#example.com
Any tips on debugging this issue? I can't find much information about the status code I'm getting
Answering myself, I found a way to trigger the error on a verbose way, basically you have to send a mail using sendmail:
echo "From: root \
To: ec2-user \
Subject: Hello World \
\
This is the email body" | sudo sendmail -d -t ec2-user
On the error message I'm getting there the error explanation:
sendmail: /etc/aliases: line 11: invalid address 'postmaster'
Because there where some entries created on the /etc/aliases file (probably they where already there in the ec2 image) with an structure like this:
mailer-daemon: postmaster
Since postmaster does not have any meaning for msmtp, it's throwing the error. After commenting out this lines (#) the mail is being sent normally
I am using SSH command to execute the bash scripts remotely:
ssh user#server 'bash -s' < $script_dir/script.sh
And inside the script.sh, I will have the command like below:
ssh-keygen -t rsa
ssh-copy-id postgres#$sqlserver
ssh postgres#$sqlserver -C true
And also
printf "Creating user in postgresql server...\n"
createuser -s -P username
Which need user's input, but I found when I execute the command from the remote server, it will skip getting the users' input and failed.
Another one is:
printf "Please enter your barman server name: \n" ; read -s barmanserver
Which cannot read user's input neither
I know that the script seems cannot read the other terminal's input, but can anyone help me find a solution if I need the user input to continue?
Thanks a lot!!
Eva
I have used something like this in the past. I am not quite sure why I installed sshpass though.
apt-get install sshpass -y
echo "Adding users to new VMs"
adduser adminuser
echo "changing user password"
echo "adminuser:password" | chpasswd
adduser adminuser sudo
It does work, but it gives you some warning.
I am running a python script in my linux PC and use 'mailx' command to send email when script fails. The command is as mentioned below,
os.system(" mailx -a 'Content-Type: text/html' -s 'Failure: Log script status' abc#domain.com def#domain.com < ../report/log_output.html")
In this case user 'abc' & 'def' gets email in his outlook client with sender as
Alert User <alertuser#x26611-testbuntu04.unassigned-domain>
(which is a dummy email).
When any of the user try to do reply all, it will send a copy to
Alert User <alertuser#x26611-testbuntu04.unassigned-domain>
as well. I dont want this to happen.
How can I write mailx command by specifying my own Reply-To email list while sending script failure email itself.
I am using below,
Distribution: Ubuntu 14.04.5 LTS (GNU/Linux 3.13.0-135-generic x86_64)
&
Edited
$ dpkg -s mailutils
Package: mailutils
Status: install ok installed
Priority: optional
Section: mail
Installed-Size: 1674
Maintainer: Ubuntu Developers <ubuntu-devel-discuss#lists.ubuntu.com>
Architecture: amd64
Version: 1:2.99.98-1.1
Provides: mail-reader, mailx
If the version of mailx you are using supports adding custom headers with the -a option like you already do with -a 'Content-type: text/html' then you can just supply it a second time with the header you want; -a 'Reply-to: you#example.net'
Relying on mailx is somewhat brittle and a huge portability problem because there are multiple incompatible mailx implementations in common use.
I am cobbling my first Linux shell command. This command runs a yum command and email results in a periodic cron bash shell job. I am OK up to the email part where I get a "No such file or dir" error on email address(!). Can someone unravel syntax and provide method that works. Can be other shell scripting language if bash is not best for this. Seem to be having trouble with multiple line commands.
#!/bin/bash
body="Some Text"
## output yum command to a work file
echo $body > /home/security_check.txt
yum --security check-update >> /home/security_check.txt
## this works!
## mail -s 'Linux Security patches required' bob#example.com < /home/security_check.txt
## this does not
mail \
-a "From: root#example.com" \
-a "MIME-Version: 1.0" \
-a "Content-Type: text/html" \
-s "Linux Security patches required" \
bob#example.com \
< /home/security_check.txt
## error message:
## From: root#example.com: No such file or directory
Take a look at this post on sending HTML email with Unix mail.
https://unix.stackexchange.com/questions/15405/how-do-i-send-html-email-using-linux-mail-command
Seems that your need for the -a flag is to send HTML mail.
Here is solution that worked for me. Requires the mailx, yum and yum-plugin-security modules. It seems that mailx behaves differently on different distributions. Comments welcome
#!/bin/bash
## script name: yum_security_patch_report.sh
## description: emails list of security patches, saved in /etc/cron.monthly so it will be sent monthly
## generate yum security report
yum --security check-update > /home/security_check.txt
## get server hostname
HOSTNAME=echo hostname
## compose subject
SUBJECT="List of Linux security patches required - for server $HOSTNAME"
## set up TO and CC
TO="bob#example.com"
CC="sue#example.com"
## get report summary from file saved, uses $(code) notation to catch as variable
SUMMARY=$(grep 'needed for security' /home/yum_security_check.txt)
RUNFROM=($"$0")
## compose body of email
MAILBODY="Find enclosed report of Linux modules that require security patches.
$SUMMARY
This report comes from server: $HOSTNAME. This script is being run from: $RUNFROM"
## send email with mailx command
echo "$MAILBODY" | mailx -v -s "$SUBJECT" -c "$CC" -a /home/security_check.txt "$TO"
We have a number of Red Hat linux servers in our IT environment. I am being asked by my team members to write a script (preferably shell script) to change a user's password on each one of those in a single go, using SSH.
I have tried to find a solution but many of the scripts I found are using Expect. We do not have Expect installed on our servers and the system admins have refused to let us install it. Also, the users do not have root access so passwd --stdin or chpasswd cannot be used.
Is there any way a script can be written so that a user can run it and change the password of only his own user on all the servers in a list?
The remote machine(s) do not need expect installed. You can install expect on a local workstation or VM (virtualbox) or whichever *nix box, and write a wrapper that calls this .ex (expect) script (there may be small changes from distro to distro, this tested on CentOS 5/6):
#!/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
You do not need root access to use passwd.
This shoud work just fine.
passwd <<EOF
old password
new password
new password
EOF
You should try pssh (parallel ssh at the same time).
cat>~/ssh-hosts<<EOF
user100#host-foo
user200#host-bar
user848#host-qux
EOF
pssh -h ~/pssh-hosts 'printf "%s\n" old_pass new_pass new_pass | passwd'
Building on squashbuff's example, I tried the following, which worked well for me:
#!/bin/bash
for server in `cat hostlist`; do
echo $server;
ssh username#$server 'passwd <<EOF
old_password
new_password
new_password
EOF';
done
Security wise, Could be improved to take input without echoing to the screen OR saving the plaintext to disk.
echo "name:password" | chpasswd
Another possibility: change it manually on one server. Get the encrypted password out of /etc/shadow. Now, do something like this:
for host in $HOST_LIST; do
ssh $host "passwd -p 'encrypted_passwd' user"
done
Of course, 'encrypted_passwd" is what you got out of /etc/shadow where you manually changed the password. And $HOST_LIST is a list of hosts where you want the password changed. That could be created simply with:
export HOST_LIST="server1 server2 server15 server67"
Or perhaps with a file (as others have suggested):
export HOST_LIST=`cat host_list.txt`
Where the file "host_list.txt" has a list of all the systems where you want the password changed.
Edit: if your version of passwd doesn't support the -p option, you might have the 'usermod' program available. The example above remains the same, simply replace 'passwd' with 'usermod'.
Furthermore, you might consider the useful tool pdsh, which would simplify the above example to something like this:
echo $HOST_LIST | pdsh -Rssh -w- "usermod -p 'encrypted_passwd' user"
One last "gotcha" to look out for: the encrypted password likely contains the dollar sign character ('$') as a field separator. You'll probably have to escape those in your for loop or pdsh command (i.e. "$" becomes "\$").
Install sshpass on any of the server from where you want to execute the script.
yum -y install sshpass
Prepare a text file in which you have to pass details like Host, User Name, Password and Port. (Based on your requirement).
192.168.1.2|sachin|dddddd|22
Prepare a script file using below details.
#!/bin/bash
FILE=/tmp/ipaddress.txt
MyServer=""
MyUser=""
MyPassword=""
MyPort=""
exec 3<&0
exec 0<$FILE
while read line
do
MyServer=$(echo $line | cut -d'|' -f1)
MyUser=$(echo $line | cut -d'|' -f2)
MyPassword=$(echo $line | cut -d'|' -f3)
MyPort=$(echo $line | cut -d'|' -f4)
HOST=$MyServer
USR=$MyUser
PASS=$MyPassword
sshpass -p $PASS ssh -p $MyPort -o StrictHostKeychecking=no $USR#$HOST \
-T "echo 'sachin#patel' | passwd --stdin root" \
< /dev/null | tee -a output.log
done
exec 0<&3
An alternative you may want to present to your peers would be to have them use password-less authentication. They'd generate a public/private key pair and register their public key in the ~/.ssh/authorized_keys file on each of the servers they log into.
Can you use Perl?
Here there is an script that changes the password in a set of hosts.
If requires some Perl modules (Net::OpenSSH::Parallel, Expect and their dependencies) installed on the local machine running the script but nothing on the remote servers where the password has to be changed.
Have you tried App::Unix::RPasswd
The passmass script (man page) that comes with Expect doesn't require Expect to be installed on the remote machines.
I just implemented a small tool that changes password for many users/hosts at once. It's java based application so it works on both Windows and Linux. It's free, enjoy :)
Thought I should put my solution in an answer field - not sure if this should be a part of the question..
OK, I have put together a partially working solution using Dennis' suggestion.
servers.txt looks like:
server1
server2
server3
.
.
.
I am using:
for server in `cat servers.txt`; do
ssh $server -l user 'passwd <<EOF
old_pass
new_pass
new_pass
EOF';
done
This produces:
user#server1's password: **<Type password manually>**
(current) UNIX password: New UNIX password: Retype new UNIX password: Changing password for user user.
Changing password for user
passwd: all authentication tokens updated successfully.
user#server2's password: **<Type password manually>**
(current) UNIX password: New UNIX password: Retype new UNIX password: Changing password for user user.
Changing password for user
passwd: all authentication tokens updated successfully.
So here, I still need to type my old password once for each server. Can this be avoided?
If you have ssh, why have passwords in the first place? Push the user's public ssh key to all the servers they're authorized to use and be done with it. This also lets you easily grant and revoke access all you want.
At a previous $dayjob, where we had literally tens of thousands of servers, they had a database of which engineers were allowed on which servers, and the installation of ssh keys was an automated process. Almost NOBODY had a password on ANY machine.
echo -e "wakka2\nwakka2\n" | passwd root
cat /tmp/passwords | ssh $server sudo chpasswd -e
if the password is encrypted, or
cat /tmp/passwords | ssh $server sudo chpasswd
if the password is not encrypted.
/tmp/passwords should have format of "user:password"
The real question is why were they not using some sort of name services? NIS/Yellow Pages or LDAP and you're not having to manually change passwords across a bunch of servers. A user changes their password once and it's done across the domain master.