Net/Telnet Script Tuning question

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