I’ve modified an expect script to reset passwords for batch accounts into
a ruby script. Our sysadmin has them expire every month, so we change
them to a temporary value, then change them right back. The ruby script
works and looks neat, but it is much slower than the expect script. I was
hoping that you might have some tips on speeding it up. I’m pretty sure
that I’m not using net/telnet to it’s fullest.
Usage is simple, chgpass.rb [test|prod], the flag indicates where we’re
changing (frodo being test system, gandalf being production).
Thanks,
Mike Henderson
#! /usr/bin/env ruby
···
#####################################################################
To maintain, search for arrUsers.append. Update the list of append
statements to contain the host, user, password you’re working with
require ‘net/telnet’
#####################################################################
class UserAccount
def initialize(host, user, pass)
@host = host
@user = user
@pass = pass
@tn = nil
puts
puts " info: #{__LINE__} #{@host} #{@user} #{@pass}"
puts
#
# can change if you're testing and don't wish to really do this
#
@cmdPassword = 'passwd'
end
def Close
@tn.close if @tn
puts
puts "logged off"
puts
end
def Login
#
# attempt to connect to the host
#
begin
@tn = Net::Telnet.new(
{‘Host’ => @host,
‘Waittime’ => 0,
‘Timeout’ => 15,
‘Debug_Log’ => true}
) { |str| print str }
@tn.login(@user, @pass) { |str| print str }
rescue
raise
end
end
def ChangePassword(oldPassWord, newPassWord)
#
#/userhome/mdhender/src/mdh/spect
# mdhender@zinc > passwd
#
@tn.puts @cmdPassword
#
#ksh: passwd: not found
#
begin
@tn.waitfor("Match" => /not found|denied/, "Timeout" => 3) { |str|
print str }
puts
puts "error: #{LINE}: invalid command ‘#{@cmdPassword}’ on host
’#{@host}"
puts
return false
rescue TimeoutError
#
# wait did not find what it wanted to find. that is good in this
case
#
rescue
puts
puts "error: #{LINE}: Unknown Error"
puts
raise
end
#
#/bin/passwd: Permission denied
#
begin
@tn.waitfor("Match" => /Permission denied/, "Timeout" => 3) { |str|
print str }
puts
puts "error: #{LINE}: invalid command ‘#{@cmdPassword}’ on host
’#{@host}"
puts
return false
rescue TimeoutError
#
# wait did not find what it wanted to find. that is good in this
case
#
rescue
puts
puts "error: #{LINE}: Unknown Error"
puts
raise
end
#
#passwd: Changing password for mdhender
#Enter login password:
#
@tn.puts oldPassWord
#
#passwd(SYSTEM): Sorry, wrong passwd
#Permission denied
#
begin
@tn.waitfor("Match" => /SYSTEM/, "Timeout" => 3) { |str| print str
}
puts
puts "error: #{LINE}: invalid password"
puts
return false
rescue TimeoutError
#
# wait did not find what it wanted to find. that is good in this
case
#
rescue
puts
puts "error: #{LINE}: Unknown Error"
puts
raise
end
#
#New password:
#
@tn.puts newPassWord
#
#Re-enter new password:
#
@tn.waitfor(/password:/) { |str| print str }
@tn.puts newPassWord
#
#passwd(SYSTEM): They don't match; try again.
#passwd(SYSTEM): Password too short - must be at least 6 characters.
#passwd(SYSTEM): Too many failures - try later.
#New password:
#
#
#passwd (SYSTEM): passwd successfully changed for mdhender
#
@tn.waitfor(/passwd successfully changed/) { |str| print str }
return true
#
#/userhome/mdhender/src/mdh/spect
# mdhender@zinc >
#
end
def Reset
begin
self.Login
rescue TimeoutError
#
# unable to log in
#
return " failed: #{@user}@#{@host} -- invalid password
#{@pass}"
rescue
puts
puts "error: #{LINE}: Unknown Error"
puts
raise
end
#
# use a temporary (but known) password for the update
#
if !ChangePassword(@pass, 'tmpWrd12')
puts
puts "error: #{__LINE__}: unable to baboozle password for
#{@user}@#{@host}"
puts
return " failed: #{@user}@#{@host}"
else
if !ChangePassword('tmpWrd12', @pass)
puts
puts "error: #{__LINE__}: unable to reset password for
#{@user}@#{@host}"
puts "error: #{LINE}: #{@user}@#{@host} password is
’tmpWrd12’ and is corrupted"
puts
return " FAILED: #{@user}@#{@host} – corrupted – unix01"
end
return "succeed: #{@user}@#{@host}"
end
end
end
#####################################################################
create an array to hold the list of user account information
class UserList
def initialize
@users = Array.new
@results = Array.new
end
def append(host, user, password)
@users.push([ host, user, password ])
end
def
return @users[key] if key.kind_of?(Integer)
return @users.find { |aUser| aUser.name = key }
end
def each
@users.each { |anEntry|
host = anEntry[0]
user = anEntry[1]
pass = anEntry[2]
yield host, user, pass
}
end
def sort
@users.sort!
end
def push(str)
@results.push(str)
end
def Results
puts
puts @results
puts
end
end
arrUsers = UserList.new
#####################################################################
specify the accounts to work with
- format is host_______ user__________ password______
arrUsers.append( ‘frodo’, ‘hobbit’, ‘daRing@’ )
arrUsers.append( ‘gandalf’, ‘greyone’, ‘eag1e’ )
#####################################################################
sort the users array to make output look nicer
arrUsers.sort
#####################################################################
attempt to reset the password for each user in the array
jArgs = ARGV.dup
if jArgs
while thisArg = jArgs.shift do
if thisArg == “test”
arrUsers.each { |host, user, pass|
begin
if host =~ /frodo|gandalf/
acct = UserAccount.new(host, user, pass)
arrUsers.push(acct.Reset)
end
ensure
if acct
acct.Close
end
end
}
arrUsers.Results
end
if thisArg == "prod"
arrUsers.each { |host, user, pass|
begin
if host =~ /frodo|gandalf/
acct = UserAccount.new(host, user, pass)
arrUsers.push(acct.Reset)
end
ensure
if acct
acct.Close
end
end
}
arrUsers.Results
end
end
end