20

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?

Cristian Ciupitu
  • 20,270
  • 7
  • 50
  • 76
squashbuff
  • 357
  • 1
  • 2
  • 10

17 Answers17

24

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
Randy Katz
  • 264
  • 2
  • 3
  • Using this code, you would want to make this code something like ./passwdWrapper and then in your bash file add ./passwdWrap $user $password $server $newpassword – Loren May 15 '15 at 16:07
  • If it's the first time you connect to this server you might be prompted to verify the fingerprint, to get around this update line 10 from ```spawn ssh $serverid passwd``` to ```spawn ssh -o "StrictHostKeyChecking no" $serverid passwd``` – Conrad Jul 04 '19 at 10:43
12

You do not need root access to use passwd.

This shoud work just fine.

passwd <<EOF
old password
new password
new password
EOF
Dennis
  • 14,264
  • 2
  • 48
  • 57
  • Thank you Dennis, as per your post, passwd works well once the user is logged on the desired server. However, I have a list of servers stored in a file servers.txt and I would like to run a script, provide old password and new password once, and then the script should change my password on all the servers in that list. Any ideas with that? – squashbuff Nov 23 '11 at 03:01
  • 1
    `ssh user@server 'command to change password'` does just that. – Dennis Nov 23 '11 at 03:12
  • Thank you Dennis, I have made an edit to my question showing what I have tried. It is still not there yet, but it's a good start. Thank you.. :) – squashbuff Nov 23 '11 at 04:08
  • @CristianCiupitu: The questions mentions that `passwd --stdin` can't be used *because the users don't have root access*. My answer explains that this premise is false; root access is not required. – Dennis May 15 '14 at 13:27
9

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'
Gilles Quénot
  • 173,512
  • 41
  • 224
  • 223
  • Thanks, this could be a good solution, but again, we do not have pssh on our servers.... :( – squashbuff Nov 23 '11 at 03:52
  • 1
    You can run this command on any distro like an Android device, a laptop, your desktop. You just need to install it on client side and just have ssh as server side. I see no problem ;) You can iterate too for simple need with a for loop : for i in foo bar base; do ssh "$i" "command line"; done – Gilles Quénot Nov 23 '11 at 03:54
  • Interesting, I will definitely look into it. Thanks :) – squashbuff Nov 23 '11 at 04:24
  • If you feel that reply is usefull, you can "upvote" it. If it fits your needs, you should "accept" the reply, that's how stackoverflow works. – Gilles Quénot Nov 23 '11 at 04:27
  • ok, sorry about that. I haven't participated in many questions here, so please bear with me :) – squashbuff Nov 23 '11 at 04:30
  • I know, that's why I tell you this, no worries ;) – Gilles Quénot Nov 23 '11 at 04:38
7

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 &lt&ltEOF
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.

fsckin
  • 215
  • 4
  • 8
4
echo "name:password" | chpasswd
Poma
  • 8,174
  • 18
  • 82
  • 144
3

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 "\$").

Matt
  • 952
  • 2
  • 8
  • 17
  • 1
    There's no `-p` option for passwd-0.77-4.el6 (Enterprise Linux 6) or passwd-0.79-2.fc20 (Fedora 20). – Cristian Ciupitu May 15 '14 at 13:06
  • 1
    Take a look at the 'usermod' program... on CentOS (clone of RHEL) 5.x and 6.x, it supports the -p option. I edited my response to include more detail. – Matt May 16 '14 at 13:44
  • Worked great for me. Just to clarify: you must escape ALL $ characters in your encrypted_passwd, not only the first. – lobi Feb 29 '16 at 22:04
2
  1. Install sshpass on any of the server from where you want to execute the script.

    yum -y install sshpass
    
  2. 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
    
  3. 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
    
Cristian Ciupitu
  • 20,270
  • 7
  • 50
  • 76
1

The passmass script (man page) that comes with Expect doesn't require Expect to be installed on the remote machines.

Cristian Ciupitu
  • 20,270
  • 7
  • 50
  • 76
1

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 :)

Azat
  • 11
  • 3
1

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.

phatfingers
  • 9,770
  • 3
  • 30
  • 44
  • 1
    Thank you, I already use the public/private keys for authentication but even with password-less authentication, when the password expires after 2 months (in my case), I still have to log on to each server, use 'passwd', type old password and type new password twice. This is a bit inefficient. That's why I am trying to put together this solution. – squashbuff Nov 23 '11 at 03:39
  • Excellent. That simplifies matters. – phatfingers Nov 23 '11 at 03:52
  • You probably have sudo on these servers, right? If you give them sudo rights to a script to change their password, the script could run passwd for their account with the --stdin param. – phatfingers Nov 23 '11 at 04:04
  • yeah, tried all those things, but I was told that I cannot get sudo for 'passwd'. I have sudo for some other commands but not this one. System guys are draconian... :| – squashbuff Nov 23 '11 at 04:07
1

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.

salva
  • 9,943
  • 4
  • 29
  • 57
  • This could be useful for some people. It's the particular way in which the environment is set up that restricts me from using this solution. I cannot access these servers directly from my client machine. I have to log on to a jumphost which has port forwarding disabled. So the script needs to run on that jumphost, which has all these restrictions in place. Thanks for the info though. – squashbuff Nov 23 '11 at 23:23
  • @squashbuff: I am currently working on another Perl module [Net::OpenSSH::Gateway](https://github.com/salva/p5-Net-OpenSSH-Gateway) that allows [Net::OpenSSH](http://search.cpan.org/perldoc?Net::OpenSSH) to jump over gateways transparently, but it is still a work in progress. – salva Nov 24 '11 at 09:36
1

Have you tried App::Unix::RPasswd

richsage
  • 26,912
  • 8
  • 58
  • 65
Kris
  • 11
  • 1
0

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.

Edward Falk
  • 9,991
  • 11
  • 77
  • 112
  • 1
    Thanks Edward, however the infrastructure management has been outsourced and I do not have any say in making those decisions. I have to make this work without making big infrastructure changes. That is not an option. – squashbuff Aug 06 '12 at 02:18
0

echo -e "wakka2\nwakka2\n" | passwd root

Lance Badger
  • 791
  • 8
  • 13
0
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"

  • As mentioned in the question, users do not have root access. So 'sudo chpasswd' cannot be used. To be honest, if the sysadmin allows users to run 'sudo chpasswd' then it's a big security issue in my opinion. – squashbuff Oct 18 '16 at 00:38
0

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?

squashbuff
  • 357
  • 1
  • 2
  • 10
  • Did you ever find a way to avoid typing your old password once for each server? – Lizz Oct 11 '14 at 07:06
  • 1
    @Lizz I ended up using expect. Not the ideal solution in terms of security but something had to be done quickly. Check out the accepted answer by Randy Katz. – squashbuff Oct 13 '14 at 00:10
-3

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.

Stan
  • 1
  • I am working in the present environment with restrictions already in place. I am not a domain admin and I don't have a say in the architectural changes required to make your solution work. I am putting a solution together for end users like myself working in the same restrictive environment. – squashbuff Jun 08 '15 at 22:44