# $Revision:: 16 $
# $Date:: 2010-01-25 20:01:49 -0500 (Mon, 25 Jan 2010) $
# $Author:: wkumari $
# Copyright: Warren Kumari (warren@kumari.net) -- 2010
#
"""
This tries to connect to a DRAC4 card in a Dell server and
resets the password, IP, mask and gateway.
It assumes that the DRAC card will show up on /dev/ttyS1
and that you have pySerial installed.
It is neither pretty nor elegant, but I needed to reset the
DRAC card on a bunch ofservers and this just works.
It does no error checking, make completely brick your system,
may cuase early baldness, etc.
Options:
--ip: The IP address to set the DRAC to.
--mask: The netmask (dotted quad).
--gw: The gateway to use.
Example:
./rac_reset.py --ip=192.168.0.12 --mask=255.255.255.0 --gw=192.168.0.1
"""
import getopt
import sys
import time
try:
import serial
except:
print ('Unable to import pySerial module.\n'
'On Ubuntu (and similar) you may be able to fix this with:\n'
'apt-get install python-serial')
sys.exit(-1)
PORT = '/dev/ttyS1'
FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.' for x in range(256)])
OK_STRING = '\x02\x60\x0A\x00\x00\x00\x00\x00\x00\x00\x96\x03'
CALVIN_MD5 = 'e6e66b8981c1030d5650da159e79539a'
def rac_connect():
s = serial.Serial(PORT, timeout = 10)
if s.isOpen():
print 'Connected to: %s' % s.portstr
else:
print "Unable to open: %s", s.portstr
sys.exit(-1)
return s
def xmit(str):
s=rac_connect()
print 'Going to send: %s' % str
s.write(str)
time.sleep(1)
data = ''
if s.inWaiting:
data = data + s.read(s.inWaiting())
time.sleep(0.5)
while s.inWaiting():
data = data + s.read(s.inWaiting())
time.sleep(0.5)
if data:
if data == OK_STRING:
print 'Success!'
else:
print "Got an error: %s\n" % dump(data, len(data))
else:
print 'Got no reply!'
s.close()
# And give the serial port a bit to settle down.
time.sleep(2)
def dump(src, length):
"""Prints the input in hex notation."""
N=0; result=''
while src:
s,src = src[:length],src[length:]
hexa = ' '.join(["%02X"%ord(x) for x in s])
s = s.translate(FILTER)
result += "%04X %-*s %s\n" % (N, length*3, hexa, s)
N+=length
return result
def checksum(str):
"""Takes a string an calculates the RAC checksum.
The RAC checksum seems to be made by adding all
the charaters in the string mod 256 and then
negating that..
Args:
str: A string that we want the checksum for.
Returns: A char to be appended to the str to
make the checksum correct.
"""
a = 0
for char in str:
a = a + ord (char)
a = a % 256
checksum = 256 - a
return chr(checksum)
def make_str(command, cmd_no):
"""Returns a string suitable to be handed to the RAC.
It looks like the DRAC expects a struct with various
bits filled in with, um, something. This takes a
command (like "racdump") and returns it embedded in
the struct.
Args:
command: A string containing a command (e.g: "racdump")
cmd_no : An integer, how many cammands we have run. It
appears that the DRAC *may* uses this so that it can
have multiple outstanding commands. Looks like not
actually used.
Returns:
A string, suitable to be passed to the DRAC socket. Includes
checksum."""
PREFIX = "\2"
PAD = "\0"
SUFFIX = "\3"
length = chr(len(command) + 6)
command_str = ("P" + length + PAD + chr(cmd_no) + \
command + PAD)
str = (PREFIX + command_str)
str = str + checksum(command_str) + SUFFIX
return str
def usage():
print '%s' % __doc__
if __name__ == "__main__":
try:
opts, args = getopt.getopt(sys.argv[1:], "hi:m:g:v",
["help", "ip=", 'mask=', 'gw='])
except getopt.GetoptError, err:
print 'Option %s' % err
sys.exit(2)
verbose = False
ip = ''
mask = ''
gw = ''
for o, a in opts:
if o == "-v":
verbose = True
elif o in ("-h", "--help"):
usage()
sys.exit()
elif o in ("-i", "--ip"):
ip = a
elif o in ("-m", "--mask"):
mask = a
elif o in ("-g", "--gw"):
gw = a
else:
assert False, "unhandled option"
if not ip or not mask or not gw:
print 'Error: must supply --ip, --mask and --gw!'
sys.exit(-1)
print 'Welcome to the RAC reset utility.'
print 'This will reset the DRAC4 root password to "calvin",'
print 'the IP to %s, the mask to %s and the gateway to %s\n' % (
ip, mask, gw)
# ip = raw_input('Please enter IP: ')
# mask = raw_input('Please enter mask: ')
# gw = raw_input('Please enter gateway: ')
cmd_no = 0
xmit(make_str('setoid -g cfgUserAdmin -o cfgUserAdminPassword -i 1 %s' % CALVIN_MD5, cmd_no))
xmit(make_str('setoid -g cfgLanNetworking -o cfgNicGateway %s' % gw.strip(),cmd_no))
xmit(make_str('setoid -g cfgLanNetworking -o cfgNicNetmask %s' % mask.strip(),cmd_no))
xmit(make_str('setoid -g cfgLanNetworking -o cfgNicIpAddress %s' % ip.strip(), cmd_no))
print 'Done!'
Here is a direct link: rac_reset.py