Changing an AIX password via script? - bash

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

Related

Multiple Aliases for different commands

I am attempting to create a bash script that will ssh into remote network devices, run commands based on the model, and then save the output.
At this time I have my expect file that contains the following:
#!/user/bin/expect
set pw xxxxxxx
set timeout 5
spawn ssh [lindex $argv 0]
expect "TACACS Password:"
send "$pw\r"
interact
I have my .sh file that contains variables which allows me to login to separate "host" files based on Model type. It contains:
shopt -s expand_aliases
fpath="path where scripts are located"
opath="MAC_Results.log"
for i in $( cat $fpath/3560hosts )
do
expect script.exp $i >> "$opath"
done
When I run my .sh, everything operates as expected. My issue lies in I do not know how to call my aliases. I have edited the .bashrc and have sourced it. The .bashrc contains the following:
# .bashrc
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
# User specific aliases and functions
alias loc3560="term length 0; show mac address-table | ex Gi|CPU|Po; exit"
alias locx="term length 0; show mac address-table | ex Gi[1|2]/1|CPU|Vl99|Po1|dynamic|system; exit"
I have also added the aliases within my .sh aliases. but cant seem to get the right syntax. I have tried the following variations but with no success...
for i in $( cat $fpath/3560hosts )
do
expect script.exp $i $loc3560 >> "$opath"
done
and
for i in $( cat $fpath/3560hosts )
do
expect script.exp $i >> "$opath";
$loc3560
done
Would appreciate any suggestions on where to put these to call to them.
Unfortunately I was not able to figure out how to call my functions or aliases within my main .sh script. With that though I found a way to achieve what I wanted via my expect file . Code listed below and it works like a charm. My subdirectory of 21 files has now been reduced to 3!
set loc3560 "show mac address-table | ex Gi|CPU|Po
exit"
set locx "show mac address-table | ex Gi1/1|Gi2/1|CPU|Vl99|Po1|dynamic|system
exit"
set loc4500 "show mac address-table | ex 1/3|1/5|Port-channel|Switch|1/1|1/2|dynamic|system
exit"
set loc888 "show mac-address-table | i FastEthernet
exit"
set loces2 "show mac address-table | i Fa0
exit"
spawn ssh [lindex $argv 0]
expect "TACACS Password:"
send "$pw\r"
expect "#"
send "$ver\r"
expect {
"C3560-IPSERVICESK9-M" {
send "$loc3560\r"
exp_continue
}
"CAT3K_CAA-UNIVERSALK9" {
send "$locx\r"
exp_continue
}
"C3750E-UNIVERSALK9-M" {
send "$locx\r"
exp_continue
}
"CISCO888-SEC-K9" {
send "$loc888\r"
exp_continue
}
"bootflash:/cat4500e" {
send "$loc4500\r"
exp_continue
}
"SM-ES2-24" {
send "$loces2\r"
exp_continue
}
}
interact
expect "#"
send "exit\r"
end
From here I am then able to call my script and output it to a log file in my directory via:
./script.sh >> Results.log

Jacl script behaves wrongly in case of special characters \ ! ; $

Hi I have written one jacl script which is not working properly in case of ; $ ! \
test.jacl
set password [ lindex $argv 1 ]
puts "Hello your entered password is $password"
Script OUTPUT
When I run
../test.jacl testUser Foo\b4r*
it returns
Hello your entered password is Foob4r*
CASE 2:
../test.jacl testUser Foo$b4r*
OUTPUT
Hello your entered password is Foo*
CASE 3:
../test.jacl testUser Foo;b4r*
OUTPUT
Hello your entered password is Foo
CASE 3:
../test.jacl testUser Foo!b4r*
OUTPUT
-bash: !b4r*: event not found
Kindly suggest best way to overcome this problem

Hide password using expect script

I used the script to log into the power broker and connected
ssh through the network. As per my knowledge every single more is
tracked. I am ok with that.
My question is how to hide the password, below sample I tried:
#!/usr/bin/expect -f
set timeout 2
spawn pbrun /bin/su - big_admin
expect {
"Password for casper#BIG_BANK.COM:" {send "foobar_pass!\r" ; exp_continue }
"*$*" ;
}
interact
I tried storing my password in a /home/casper/.password and then doing a chmod 400 on it and then
putting it in the {send "/home/casper/.password\r" exp continue}, but it did not work.
Any ideas?
Source : http://wiki.tcl.tk/3594
Procedure to encrypt device passwords
Takes pd (password list to be encrypted) and filename (name of file for resulting encrypted password list) as input
Returns nothing
Format of the list of passwords (current and older generations by device type?) depends on how calling program needs them - suggest separated by \n character for readability
proc utility_encrypt {pd filename} {
global key HOME
#catch [exec echo "$pd" | des -e -k $key -b > $HOME/pwdir/$filename]
catch [exec des -e -k $key -b > [file join $HOME pwdir $filename] << $pd]
return
}
Procedure to decrypt device passwords
Takes filename (name of password file to decrypt)
Returns dpd (list of passwords in plaintext)
proc utility_decrypt filename {
global key HOME
catch {exec cat $HOME/pwdir/$filename | des -d -b -k $key} dpd
# Some people write the previous command as
# catch {exec des -d -b -k $key < $HOME/pwdir/$filename} dpd
return $dpd
}

SQUID3 - using multiple auth_param like basic_ncsa_auth & basic_ldap_auth

i tried to setup squid3 with multiple auth_param. Basically, the first choice should be basic_ldap_auth and if this doesnt return OK it should try basic_ncsa_auth with the same values. As far as i know squid doesnt support it however there is the possibility to use "external" ACL
auth_param basic program /usr/lib/squid3/basic_fake_auth
external_acl_type MultAuth %SRC %LOGIN %{Proxy-Authorization} /etc/squid3/multAuth.pl
acl extAuth external MultAuth
my "multAuth.pl"
use URI::Escape;
use MIME::Base64;
$|=1;
while (<>) {
($ip,$user,$auth) = split();
# Retrieve the password from the authentication header
$auth = uri_unescape($auth);
($type,$authData) = split(/ /, $auth);
$authString = decode_base64($authData);
($username,$password) = split(/:/, $authString);
# do the authentication and pass results back to Squid.
$ldap = `/bin/bash auth/ldap.sh`;
if ($ldap == "OK") {
print "OK";
}
$ncsa = `/bin/bash auth/ncsa.sh`;
if ($ncsa == "OK") {
print "OK";
} else {
print "ERR";
}
}
now i am trying to run with ncsa.sh and ldap.sh the "normal" shell command for these auth methods.
./basic_ldap_auth -R -b "dc=domain,dc=de" -D "CN=Administrator,CN=Users,DC=domain,DC=de" -w "password" -f sAMAccountName=%s -h domain.de
user password
and
./basic_ncsa_auth /etc/squid3/users
user password
Therefor i ran:
auth/ncsa.sh
#!/usr/bin/expect
eval spawn [lrange $argv 0 end]
expect ""
send [lindex $argv 1]
send '\r'
expect {
"OK" {
echo OK
exp_continue
}
"ERR" {
echo ERR
exp_continue
}
interact
with
./ncsa.sh "/usr/lib/squid3/basic_ncsa_auth /etc/squid3/users" "user password"
and i generate the following error:
couldn't execute "/usr/lib/squid3/basic_ncsa_auth /etc/squid3/users": no such file or directory
while executing
"spawn {/usr/lib/squid3/basic_ncsa_auth /etc/squid3/users} {user password}"
("eval" body line 1)
invoked from within
"eval spawn [lrange $argv 0 end]"
(file "./ncsa.sh" line 2)
Besides this error, i am not sure how to pass the variables (username & password) forward and i am also not sure how to answer the shell questions like for example the user & pw input for basic_ldap_auth .
Is there a nice way how to solve that? or any other good plan ?
thanks!
FWIW, the following script helped me transition from passwd based to LDAP based authentication.
Contrary to your requirements, my script acts the other way around: It first checks passwd, then LDAP.
#!/usr/bin/env bash
# multiple Squid basic auth checks
# originally posted here: https://github.com/HackerHarry/mSquidAuth
#
# credits
# https://stackoverflow.com/questions/24147067/verify-user-and-password-against-a-file-created-by-htpasswd/40131483
# https://stackoverflow.com/questions/38710483/how-to-stop-ldapsearch1-from-base64-encoding-userpassword-and-other-attributes
#
# requires ldap-utils, openssl and perl
# tested with Squid 4 using a "auth_param basic program /usr/lib/squid/mSquidAuth.sh" line
# authenticate first against squid password file
# if this fails, try LDAP (Active Directory) and also check group membership
# variables
# sLOGFILE=/var/log/squid/mSquidAuth.log
sPWDFILE="/etc/squid/passwd"
sLDAPHOST="ldaps://dc.domain.local:636"
sBASE="DC=domain,DC=local"
sLDS_OPTIONS="-o ldif-wrap=no -o nettimeout=7 -LLL -P3 -x "
sBINDDN="CN=LDAP-read-user,OU=Users,DC=domain,DC=local"
sBINDPW="read-user-password"
sGROUP="Proxy-Users"
# functions
function _grantAccess {
# echo "access granted - $sUSER" >>$sLOGFILE
echo "OK"
}
function _denyAccess {
# echo "access denied - $sUSER" >>$sLOGFILE
echo "ERR"
}
function _setUserAndPass {
local sAuth="$1"
local sOldIFS=$IFS
IFS=' '
set -- $sAuth
IFS=$sOldIFS
# set it globally
sUSER="$1"
sPASS="$2"
}
# loop
while (true); do
read -r sAUTH
sUSER=""
sPASS=""
sSALT=""
sUSERENTRY=""
sHASHEDPW=""
sUSERDN=""
iDNCOUNT=0
if [ -z "$sAUTH" ]; then
# echo "exiting" >>$sLOGFILE
exit 0
fi
_setUserAndPass "$sAUTH"
sUSERENTRY=$(grep -E "^${sUSER}:" "$sPWDFILE")
if [ -n "$sUSERENTRY" ]; then
sSALT=$(echo "$sUSERENTRY" | cut -d$ -f3)
if [ -n "$sSALT" ]; then
sHASHEDPW=$(openssl passwd -apr1 -salt "$sSALT" "$sPASS")
if [ "$sUSERENTRY" = "${sUSER}:${sHASHEDPW}" ]; then
_grantAccess
continue
fi
fi
fi
# LDAP is next
iDNCOUNT=$(ldapsearch $sLDS_OPTIONS -H "$sLDAPHOST" -D "$sBINDDN" -w "$sBINDPW" -b "$sBASE" "(|(sAMAccountName=${sUSER})(userPrincipalName=${sUSER}))" dn 2>/dev/null | grep -cE 'dn::? ')
if [ $iDNCOUNT != 1 ]; then
# user needs a unique account
_denyAccess
continue
fi
# get user's DN
# we need the extra grep in case we get lines back starting with "# refldap" :/
sUSERDN=$(ldapsearch $sLDS_OPTIONS -H "$sLDAPHOST" -D "$sBINDDN" -w "$sBINDPW" -b "$sBASE" "(|(sAMAccountName=${sUSER})(userPrincipalName=${sUSER}))" dn 2>/dev/null | perl -MMIME::Base64 -n -00 -e 's/\n +//g;s/(?<=:: )(\S+)/decode_base64($1)/eg;print' | grep -E 'dn::? ' | sed -r 's/dn::? //')
# try and bind using that DN to check password validity
# also test if that user is member of a particular group
# backslash in DN needs special treatment
if ldapsearch $sLDS_OPTIONS -H "$sLDAPHOST" -D "$sUSERDN" -w "$sPASS" -b "$sBASE" "name=${sGROUP}" member 2>/dev/null | perl -MMIME::Base64 -n -00 -e 's/\n +//g;s/(?<=:: )(\S+)/decode_base64($1)/eg;print' | grep -q "${sUSERDN/\\/\\\\}"; then
_grantAccess
continue
fi
_denyAccess
done

How to use bash/expect to check if an SSH login works

My team manages many servers, and company policy dictates that the passwords on these servers must be changed every couple of weeks. Sometimes, our official database of passwords gets out of date for whatever reason (people forget to update it, usually), but we cannot identify this sometimes until months later, since we don't consistently use every server.
I want to write a script that will scrape the passwords from the database, and use those passwords to attempt an (ssh) login to each server every night, and send an email with the results to the team. I am able to scrape the database for login information, but I'm not sure how to check whether ssh login was successful or not in expect.
I cannot use public key authentication for this task. I want password authentication so I can verify the passwords.
I disable public-key authentication by specifying the following file:
PasswordAuthentication=yes
PubkeyAuthentication=no
My attempts at the expect script:
# $1 = host, $2 = user, $3 = password, $4 = config file
expect -c "spawn ssh $2#$1 -F $4
expect -re \".*?assword.*?\"
send \"$3\n\"
...
send \'^D\'"
I thought maybe exit status could indicate the success? Couldn't find anything in the man pages though.
I've been using something like the script below for a similar task.
#!/bin/sh
# Run using expect from path \
exec expect -f "$0" "$#"
# Above line is only executed by sh
set i 0; foreach n $argv {set [incr i] $n}
set pid [ spawn -noecho ssh $1#$3 $4 ]
set timeout 30
expect {
"(yes/no)" {
sleep 1
send "yes\n"
exp_continue
}
"(y/n)" {
sleep 1
send "y\n"
exp_continue
}
password {
sleep 1
send "$2\n"
exp_continue
}
Password {
sleep 1
send "$2\n"
exp_continue
}
"Last login" {
interact
}
"Permission denied" {
puts "Access not granted, aborting..."
exit 1
}
timeout {
puts "Timeout expired, aborting..."
exit 1
}
eof {
#puts "EOF reached."
}
}
set status [split [wait $pid]]
set osStatus [lindex $status 2]
set procStatus [lindex $status 3]
if { $osStatus == 0 } {
exit $procStatus
} else {
exit $procStatus
}
Do you specifically need to check if you can obtain a shell or is trying to execute a command also OK ?
If you just want to check authentication, you may want to do ssh asimplecommand (using echo, hostname, or something as such) and check if you get the expected result.
You may also want to launch ssh with -v option, and look for Authentication succeeded (at the debug1 log level).
crowbent has provided you an expect script to test ssh login however I would recommend using Non-interactive ssh password auth for testing out ssh/sftp. sshpass is much more secured and less error prone than expect.
The solution to the underlying problem (password database getting out of sync) is to use public key authentication. For everyone. Do NOT bother with passwords when it comes to SSH.
Successful login could be checked like this:
ssh -o PasswordAuthentication=no USER#HOST 'exit' || echo "SSH login failed."

Resources