NoteThis 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.
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.
I am currently trying to make a script that calls the "Change a password" screen without hitting Ctrl+Alt+Delete/End. The problem is we have people in the field using all different keyboard layouts and the "End" isn't always in the most user friendly spot. So I want to cut out the middle man and just let our end users run a script that will bring up the screen and let them change the password.
There is a non-trivial security problem posed by your solution. The reason that CTL-ALT-DEL is pressed in the first place is that it is NOT catchable by a program and thus you are assured that you are typing to the Operating System (windows) and not some yo-ho program that is pretending to change passwords and actually collecting them.
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.
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):
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:
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'.
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.
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.
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.
Return true (or an object containing the last_password_reset property) if the password change operation succeeded. If the last_password_reset property is present in the object, it will be updated on the user's profile.
If the change password operation succeeded, return the callback function, and pass a null value as the error parameter and an object value as the profile parameter. If last_password_reset attribute is provided in the object, it will be updated on the user's profile.
I have this requirement to change the password for other servers remotely from one server. So, I installed public keys on all servers and wrote the following script to do the job. Something appears to be wrong with my loop, as it only changes one server and ignores the rest. I'm testing the script with a test data file with about 5 servers in it. The data file is the command-line argument to the script. Can you please tell me what's wrong and how to fix it?
I think that this behaviour is being caused by the use of a 'while read' loop to drive the 'ssh' command. The way input is read in and processed in this particular script may not actually be what you'd expect. Instead of it looping nicely around, the entirety of your arguments end up being passed to 'ssh' in one glob, and it's just doing the first one.
Just checking, but are you running it with the filename as an argument ? e.g. ./script.sh serverlist.txt or something like that ? The script takes the first argument ($1) as the filename to be read and processed.
I ask becasue if you were just running ./script.sh on its own will never return a prompt, which is what you describe. In that usage case it would be sitting waiting for you to type in the input yourself, and would only proceed with execution after you did a Ctrl-D or otherwise indicated the end of input.
With the while loop, it did read the pwchange.dat file, but it only changed the password for one server. And I got the prompt back.
With the for loop, ctrl-D does nothing, but ctrl-C breaks out of the script and give me the prompt back w/o doing anything.
Also, my environment is a mix of Solaris 10 and Linux (RHEL & SUSE). My script with the while loop does change one password, it changes either Solaris or Linux server. So, looks like the ssh & passwd commands are both OK.
OK, thanks for the feedback. If you try running it with the '-x' flag to Bash, which will make it show you each step as it executes, where does it hang ? So you'd want to run bash -x ./pwchange.sh pwchange.dat and see the line it's freezing on.
So, ssh is tried for each server, but it fails name resolution because obviously it doesn't know what to do with #, but it does attempt all of them and it does change that one server who is not commented out correctly. STRANGE! But, when I uncomment all the servers in the .dat file, then it hangs.
That at least is easy to explain. You can't really 'comment out' input. So what is happening is that 'ssh' is attempting to connect to the hosts whose names start with a hash symbol, and DNS resolution is failing for what are invalid hostnames. If you want them not to be considered by the script, you'd have to remove them entirely. Commenting out only works in scripts, and not in the input files handled by scripts (unless you yourself write the appropriate code to handle that).
In terms of the part of the script that is hanging, it does seem it's something to do with the actual core 'passwd' section itself. Before digging any further: if you manually try to run echo -e "TestPW12345!\nTestPW12345!" passwd mchavoshi on the target server yourself at a Bash prompt, and not as part of a script, does it actually work, or does it hang even when you run it yourself ?
Note: if you use openssl passwd (i.e. no password on the command line).
It will prompt on the terminal for password and a verification which is preferable to hard-coding it in the script as it won't be visible to utilities like ps
@Rudic, as previously stated, there is nothing wrong with the way it changes the password. There is something wrong with the loop. Everything the way it is, correctly changes one password for one server, but it doesn't catch the rest of the servers.
Good to know that the problem is now identified and that you have a working solution for the Linux systems, at least. As for the Solaris one, you'll most likely have to find an alternative way of re-setting the password for that one host, or find one other common method that works across all platforms. The 'chpasswd' and 'usermod' ideas mentioned by RudiC and Chubler_XL would certainly be the best place to start.
OK guys, thanks so much @drysdalk for your excellent trouble shooting idea (running every command individually on the command line). The script works perfect, the way it is, it only hangs on stupid Solaris and since the Solaris box was on the top of the data file, it would hang on it and not go further. I removed the Solaris box from my data file and everything ran just fine. Please see below. I guess the problem now gets reduced to how to do this **** on Solaris?
Thanks, everyone, you guys are great.
So, apparently (as far as I can tell) Solaris doesn't have the chpasswd command and doesn't support "usermod -w" switch to change passwords non-interactively. Strange, but true (again, as far as I can tell).
I've looked into this a bit further, although I don't myself have a full Oracle Solaris system to test on; rather, at home I have a system running Tribblix, an Illumos distro. So there will certainly be some differences beween that and Oracle's Solaris, which I can't really legitimately run for free at the moment due to the licensing requirements it has.
Anyway, I tend to agree that based on both my own findings on my system and what I've read elsewhere that you're going to have to find a more complicated solution here. An expect script might be the kind of road you have to go down, or a Perl script or somesuch. As an absolute last resort you could do something that directly manipulates /etc/passwd and /etc/shadow , but I can't stress how strongly enough I recommend not doing that.
I am writing a script to add a large amount of users to a system. Part of this involves setting default passwords for each user. How can I set users' passwords without it prompting me for the password up front?
3a8082e126