2
0
mirror of https://opendev.org/x/pyghmi synced 2025-04-09 17:35:20 +00:00

Implement Python3 compatibility

Do strictly the changes associated with
supporting Python 3, no functional changes.

Change-Id: I8b12d48504b67b3a51f3d114d0d3c371b67dc9b4
This commit is contained in:
Jarrod Johnson 2016-05-05 10:58:03 -04:00
parent 98798b2372
commit 657608ca60
9 changed files with 112 additions and 78 deletions

View File

@ -29,6 +29,11 @@ import pyghmi.ipmi.sdr as sdr
import socket
import struct
try:
xrange
except NameError:
xrange = range
boot_devices = {
'net': 4,
@ -1487,7 +1492,7 @@ class Command(object):
data = response['data']
if len(data) == 16:
# convert int array to string
n = ''.join(chr(data[i]) for i in range(0, len(data)))
n = ''.join(chr(data[i]) for i in xrange(0, len(data)))
# remove padded \x00 chars
n = n.rstrip("\x00")
if len(n) > 0:
@ -1584,7 +1589,7 @@ class Command(object):
channel = self.get_network_channel()
uid_list = []
max_ids = self.get_channel_max_user_count(channel)
for uid in range(1, max_ids):
for uid in xrange(1, max_ids):
if name == self.get_user_name(uid=uid):
uid_list.append(uid)
return uid_list
@ -1609,7 +1614,7 @@ class Command(object):
channel = self.get_network_channel()
names = {}
max_ids = self.get_channel_max_user_count(channel)
for uid in range(1, max_ids+1):
for uid in xrange(1, max_ids+1):
name = self.get_user_name(uid=uid)
if name is not None:
names[uid] = self.get_user(uid=uid, channel=channel)

View File

@ -22,6 +22,11 @@ import pyghmi.ipmi.private.constants as ipmiconst
import struct
import time
try:
xrange
except NameError:
xrange = range
psucfg_errors = {
0: 'Vendor mismatch',

View File

@ -44,6 +44,10 @@ import pyghmi.util.webclient as wc
import socket
import struct
import weakref
try:
xrange
except NameError:
xrange = range
inventory.register_inventory_category(cpu)
inventory.register_inventory_category(dimm)
@ -367,7 +371,7 @@ class OEMHandler(generic.OEMHandler):
)
except Exception:
# If we can't parse an inventory category, ignore it
print traceback.print_exc()
print(traceback.print_exc())
continue
for item in items:
@ -377,7 +381,7 @@ class OEMHandler(generic.OEMHandler):
self.oem_inventory_info[key] = item
except Exception:
# If we can't parse an inventory item, ignore it
print traceback.print_exc()
print(traceback.print_exc())
continue
def get_leds(self):
@ -522,7 +526,7 @@ class OEMHandler(generic.OEMHandler):
def get_oem_domain_name(self):
if self.has_tsm:
name = ''
for i in range(1, 5):
for i in xrange(1, 5):
rsp = self.ipmicmd.xraw_command(netfn=0x32, command=0x6b,
data=(4, i))
name += rsp['data'][:]
@ -536,7 +540,7 @@ class OEMHandler(generic.OEMHandler):
# set the domain name content
name = name.ljust(256, "\x00")
for i in range(0, 4):
for i in xrange(0, 4):
data = [4, i+1]
offset = i*64
data.extend([ord(x) for x in name[offset:offset+64]])

View File

@ -18,6 +18,11 @@ import pyghmi.constants as pygconst
import pyghmi.ipmi.sdr as sdr
import struct
try:
xrange
except NameError:
xrange = range
def fpc_read_ac_input(ipmicmd):
rsp = ipmicmd.xraw_command(netfn=0x32, command=0x90, data=(1,))

View File

@ -37,23 +37,23 @@ class ServerSession(ipmisession.Session):
return object.__new__(cls)
def create_open_session_response(self, request):
clienttag = ord(request[0])
clienttag = request[0]
# role = request[1]
self.clientsessionid = list(struct.unpack('4B', request[4:8]))
self.clientsessionid = request[4:8]
# TODO(jbjohnso): intelligently handle integrity/auth/conf
#for now, forcibly do cipher suite 3
self.managedsessionid = list(struct.unpack('4B', os.urandom(4)))
self.managedsessionid = os.urandom(4)
#table 13-17, 1 for now (hmac-sha1), 3 should also be supported
#table 13-18, integrity, 1 for now is hmac-sha1-96, 4 is sha256
#confidentiality: 1 is aes-cbc-128, the only one
self.privlevel = 4
response = ([clienttag, 0, self.privlevel, 0] +
response = (bytearray([clienttag, 0, self.privlevel, 0]) +
self.clientsessionid + self.managedsessionid +
[
bytearray([
0, 0, 0, 8, 1, 0, 0, 0, # auth
1, 0, 0, 8, 1, 0, 0, 0, # integrity
2, 0, 0, 8, 1, 0, 0, 0, # privacy
])
]))
return response
def __init__(self, authdata, kg, clientaddr, netsocket, request, uuid,
@ -77,7 +77,7 @@ class ServerSession(ipmisession.Session):
self.sockaddr = clientaddr
self.pktqueue = collections.deque([])
ipmisession.Session.bmc_handlers[clientaddr] = self
response = self.create_open_session_response(request)
response = self.create_open_session_response(bytearray(request))
self.send_payload(response,
constants.payload_types['rmcpplusopenresponse'],
retry=False)
@ -98,31 +98,28 @@ class ServerSession(ipmisession.Session):
if namepresent == 0:
#ignore null username for now
return
usernamebytes = data[28:]
self.username = struct.pack('%dB' % len(usernamebytes), *usernamebytes)
if self.username not in self.authdata:
self.username = bytes(data[28:])
if self.username.decode('utf-8') not in self.authdata:
# don't think about invalid usernames for now
return
uuidbytes = self.uuid.bytes
uuidbytes = list(struct.unpack('%dB' % len(uuidbytes), uuidbytes))
self.uuiddata = uuidbytes
self.Rc = list(struct.unpack('16B', os.urandom(16)))
self.Rc = os.urandom(16)
hmacdata = (self.clientsessionid + self.managedsessionid +
self.Rm + self.Rc + uuidbytes +
[self.rolem, len(self.username)])
hmacdata = struct.pack('%dB' % len(hmacdata), *hmacdata)
bytearray([self.rolem, len(self.username)]))
hmacdata += self.username
self.kuid = self.authdata[self.username]
self.kuid = self.authdata[self.username.decode('utf-8')].encode(
'utf-8')
if self.kg is None:
self.kg = self.kuid
authcode = hmac.new(
self.kuid, hmacdata, hashlib.sha1).digest()
authcode = list(struct.unpack('%dB' % len(authcode), authcode))
# regretably, ipmi mandates the server send out an hmac first
# akin to a leak of /etc/shadow, not too worrisome if the secret
# is complex, but terrible for most likely passwords selected by
# a human
newmessage = ([clienttag, 0, 0, 0] + self.clientsessionid +
newmessage = (bytearray([clienttag, 0, 0, 0]) + self.clientsessionid +
self.Rc + uuidbytes + authcode)
self.send_payload(newmessage, constants.payload_types['rakp2'],
retry=False)
@ -136,17 +133,17 @@ class ServerSession(ipmisession.Session):
# respond correctly a TODO(jjohnson2), since Kg being used
# yet incorrect is a scenario why rakp3 could be bad
# even if rakp2 was good
RmRc = struct.pack('B' * len(self.Rm + self.Rc), *(self.Rm + self.Rc))
RmRc = self.Rm + self.Rc
self.sik = hmac.new(self.kg,
RmRc +
struct.pack("2B", self.rolem,
len(self.username)) +
self.username, hashlib.sha1).digest()
self.k1 = hmac.new(self.sik, '\x01' * 20, hashlib.sha1).digest()
self.k2 = hmac.new(self.sik, '\x02' * 20, hashlib.sha1).digest()
self.k1 = hmac.new(self.sik, b'\x01' * 20, hashlib.sha1).digest()
self.k2 = hmac.new(self.sik, b'\x02' * 20, hashlib.sha1).digest()
self.aeskey = self.k2[0:16]
hmacdata = struct.pack('B' * len(self.Rc), *self.Rc) +\
struct.pack("4B", *self.clientsessionid) +\
hmacdata = self.Rc +\
self.clientsessionid +\
struct.pack("2B", self.rolem,
len(self.username)) +\
self.username
@ -159,9 +156,7 @@ class ServerSession(ipmisession.Session):
if data[1] != 0:
# client did not like our response, so ignore the rakp3
return
self.localsid = struct.unpack('<I',
struct.pack(
'4B', *self.managedsessionid))[0]
self.localsid = struct.unpack('<I', self.managedsessionid)[0]
self.ipmicallback = self.handle_client_request
self._send_rakp4(clienttag, 0)
@ -186,11 +181,12 @@ class ServerSession(ipmisession.Session):
pass
def _send_rakp4(self, tagvalue, statuscode):
payload = [tagvalue, statuscode, 0, 0] + self.clientsessionid
payload = bytearray(
[tagvalue, statuscode, 0, 0]) + self.clientsessionid
hmacdata = self.Rm + self.managedsessionid + self.uuiddata
hmacdata = struct.pack('%dB' % len(hmacdata), *hmacdata)
authdata = hmac.new(self.sik, hmacdata, hashlib.sha1).digest()[:12]
payload += struct.unpack('%dB' % len(authdata), authdata)
payload += authdata
self.send_payload(payload, constants.payload_types['rakp4'],
retry=False)
self.confalgo = 'aes'
@ -272,14 +268,14 @@ class IpmiServer(object):
ipmisession.Session.bmc_handlers[self.serversocket] = self
def send_auth_cap(self, myaddr, mylun, clientaddr, clientlun, sockaddr):
header = '\x06\x00\xff\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10'
headerdata = (clientaddr, clientlun | (7 << 2))
header = bytearray(
b'\x06\x00\xff\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10')
headerdata = [clientaddr, clientlun | (7 << 2)]
headersum = ipmisession._checksum(*headerdata)
header += struct.pack('BBBBBB',
*(headerdata + (headersum, myaddr, mylun, 0x38)))
header += bytearray(headerdata + [headersum, myaddr, mylun, 0x38])
header += self.authcap
bodydata = struct.unpack('B' * len(header[17:]), header[17:])
header += chr(ipmisession._checksum(*bodydata))
header.append(ipmisession._checksum(*bodydata))
ipmisession._io_sendto(self.serversocket, header, sockaddr)
def process_pktqueue(self):
@ -298,13 +294,14 @@ class IpmiServer(object):
"""
if len(data) < 22:
return
if not (data[0] == '\x06' and data[2:4] == '\xff\x07'): # not ipmi
data = bytearray(data)
if not (data[0] == 6 and data[2:4] == b'\xff\x07'): # not ipmi
return
if data[4] == '\x06': # ipmi 2 payload...
if data[4] == 6: # ipmi 2 payload...
payloadtype = data[5]
if payloadtype not in ('\x00', '\x10'):
if payloadtype not in (0, 16):
return
if payloadtype == '\x10': # new session to handle conversation
if payloadtype == 16: # new session to handle conversation
ServerSession(self.authdata, self.kg, sockaddr,
self.serversocket, data[16:], self.uuid,
bmc=self)
@ -314,7 +311,7 @@ class IpmiServer(object):
netfn = (netfnlun & 0b11111100) >> 2
mylun = netfnlun & 0b11
if netfn == 6: # application request
if data[19] == '\x38': # cmd = get channel auth capabilities
if data[19] == 0x38: # cmd = get channel auth capabilities
verchannel, level = struct.unpack('2B', data[20:22])
version = verchannel & 0b10000000
if version != 0b10000000:

View File

@ -33,6 +33,15 @@ from Crypto.Cipher import AES
import pyghmi.exceptions as exc
from pyghmi.ipmi.private import constants
try:
dict.iteritems
def dictitems(d):
return d.iteritems()
except AttributeError:
def dictitems(d):
return d.items()
initialtimeout = 0.5 # minimum timeout for first packet to retry in any given
# session. This will be randomized to stagger out retries
@ -63,7 +72,7 @@ def define_worker():
Session._cleanup()
self.running = False
iosockets[0].sendto(
'\x01', (myself, iosockets[0].getsockname()[1]))
b'\x01', (myself, iosockets[0].getsockname()[1]))
super(_IOWorker, self).join()
def run(self):
@ -139,7 +148,7 @@ def _io_wait(timeout, myaddr=None, evq=None):
# it piggy back on the select() in the io thread, which is a truly
# lazy wait even with eventlet involvement
if deadline < selectdeadline:
iosockets[0].sendto('\x01', (myself, iosockets[0].getsockname()[1]))
iosockets[0].sendto(b'\x01', (myself, iosockets[0].getsockname()[1]))
evt.wait()
@ -308,7 +317,8 @@ class Session(object):
@classmethod
def _cleanup(cls):
for session in cls.bmc_handlers.itervalues():
for sesskey in cls.bmc_handlers:
session = cls.bmc_handlers[sesskey]
session.cleaningup = True
session.logout()
@ -324,7 +334,7 @@ class Session(object):
# slots to be recycled
sorted_candidates = None
if server is None:
sorted_candidates = sorted(cls.socketpool.iteritems(),
sorted_candidates = sorted(dictitems(cls.socketpool),
key=operator.itemgetter(1))
if sorted_candidates and sorted_candidates[0][1] < MAX_BMCS_PER_SOCKET:
cls.socketpool[sorted_candidates[0][0]] += 1
@ -357,7 +367,7 @@ class Session(object):
# be there
try:
iosockets[0].sendto(
'\x01', ('::1', iosockets[0].getsockname()[1]))
b'\x01', ('::1', iosockets[0].getsockname()[1]))
myself = '::1'
except socket.error:
# AF_INET6, but no '::1', try the AF_INET6 version of 127
@ -1034,7 +1044,7 @@ class Session(object):
# no more time than that, so that whatever part(ies) need to service in
# a deadline, will be honored
if timeout != 0:
for session, parms in cls.waiting_sessions.iteritems():
for session, parms in dictitems(cls.waiting_sessions):
if parms['timeout'] <= curtime:
timeout = 0 # exit after one guaranteed pass
break
@ -1042,7 +1052,7 @@ class Session(object):
timeout < parms['timeout'] - curtime):
continue # timeout smaller than the current session needs
timeout = parms['timeout'] - curtime # set new timeout value
for session, parms in cls.keepalive_sessions.iteritems():
for session, parms in dictitems(cls.keepalive_sessions):
if parms['timeout'] <= curtime:
timeout = 0
break
@ -1069,7 +1079,7 @@ class Session(object):
relsession.process_pktqueue()
sessionstodel = []
sessionstokeepalive = []
for session, parms in cls.keepalive_sessions.iteritems():
for session, parms in dictitems(cls.keepalive_sessions):
# if the session is busy inside a command, defer invoking keepalive
# until incommand is no longer the case
if parms['timeout'] < curtime and not session._isincommand():
@ -1078,7 +1088,7 @@ class Session(object):
sessionstokeepalive.append(session)
for session in sessionstokeepalive:
session._keepalive()
for session, parms in cls.waiting_sessions.iteritems():
for session, parms in dictitems(cls.waiting_sessions):
if parms['timeout'] < curtime: # timeout has expired, time to
# give up on it and trigger timeout
# response in the respective
@ -1151,8 +1161,9 @@ class Session(object):
def process_pktqueue(self):
while self.pktqueue:
pkt = self.pktqueue.popleft()
if not pkt[0][0] == '\x06' and pkt[0][2:4] == '\xff\x07':
pkt = list(self.pktqueue.popleft())
pkt[0] = bytearray(pkt[0])
if not (pkt[0][0] == 6 and pkt[0][2:4] == b'\xff\x07'):
continue
if pkt[1] in self.bmc_handlers:
self._handle_ipmi_packet(pkt[0], sockaddr=pkt[1])
@ -1180,24 +1191,24 @@ class Session(object):
return # here, we might have sent an ipv4 and ipv6 packet to kick
# things off ignore the second reply since we have one
# satisfactory answer
if data[4] in ('\x00', '\x02'): # This is an ipmi 1.5 paylod
remsequencenumber = struct.unpack('<I', data[5:9])[0]
if data[4] in (0, 2): # This is an ipmi 1.5 paylod
remsequencenumber = struct.unpack('<I', bytes(data[5:9]))[0]
if (hasattr(self, 'remsequencenumber') and
remsequencenumber < self.remsequencenumber):
return -5 # remote sequence number is too low, reject it
self.remsequencenumber = remsequencenumber
if ord(data[4]) != self.authtype:
if data[4] != self.authtype:
return -2 # BMC responded with mismatch authtype, for
# mutual authentication reject it. If this causes
# legitimate issues, it's the vendor's fault
remsessid = struct.unpack("<I", data[9:13])[0]
remsessid = struct.unpack("<I", bytes(data[9:13]))[0]
if remsessid != self.sessionid:
return -1 # does not match our session id, drop it
# now we need a mutable representation of the packet, rather than
# copying pieces of the packet over and over
rsp = list(struct.unpack("!%dB" % len(data), data))
rsp = list(struct.unpack("!%dB" % len(data), bytes(data)))
authcode = False
if data[4] == '\x02': # we have authcode in this ipmi 1.5 packet
if data[4] == 2: # we have authcode in this ipmi 1.5 packet
authcode = data[13:29]
del rsp[13:29]
# this is why we needed a mutable representation
@ -1210,7 +1221,7 @@ class Session(object):
if expectedauthcode != authcode:
return
self._parse_ipmi_payload(payload)
elif data[4] == '\x06':
elif data[4] == 6:
self._handle_ipmi2_packet(data)
else:
return # unrecognized data, assume evil
@ -1226,9 +1237,7 @@ class Session(object):
def _got_rmcp_openrequest(self, data):
pass
def _handle_ipmi2_packet(self, rawdata):
data = list(struct.unpack("%dB" % len(rawdata), rawdata))
#now need mutable array
def _handle_ipmi2_packet(self, data):
ptype = data[5] & 0b00111111
# the first 16 bytes are header information as can be seen in 13-8 that
# we will toss out
@ -1254,17 +1263,17 @@ class Session(object):
encrypted = 0
if data[5] & 0b10000000:
encrypted = 1
authcode = rawdata[-12:]
authcode = data[-12:]
if self.k1 is None: # we are in no shape to process a packet now
return
expectedauthcode = hmac.new(
self.k1, rawdata[4:-12], hashlib.sha1).digest()[:12]
self.k1, bytes(data[4:-12]), hashlib.sha1).digest()[:12]
if authcode != expectedauthcode:
return # BMC failed to assure integrity to us, drop it
sid = struct.unpack("<I", rawdata[6:10])[0]
sid = struct.unpack("<I", bytes(data[6:10]))[0]
if sid != self.localsid: # session id mismatch, drop it
return
remseqnumber = struct.unpack("<I", rawdata[10:14])[0]
remseqnumber = struct.unpack("<I", bytes(data[10:14]))[0]
if (hasattr(self, 'remseqnumber') and
(remseqnumber < self.remseqnumber) and
(self.remseqnumber != 0xffffffff)):
@ -1273,8 +1282,8 @@ class Session(object):
psize = data[14] + (data[15] << 8)
payload = data[16:16 + psize]
if encrypted:
iv = rawdata[16:32]
decrypter = AES.new(self.aeskey, AES.MODE_CBC, iv)
iv = data[16:32]
decrypter = AES.new(self.aeskey, AES.MODE_CBC, bytes(iv))
decrypted = decrypter.decrypt(
struct.pack("%dB" % len(payload[16:]),
*payload[16:]))
@ -1394,8 +1403,8 @@ class Session(object):
struct.pack("2B", self.nameonly | self.privlevel,
userlen) +
self.userid, hashlib.sha1).digest()
self.k1 = hmac.new(self.sik, '\x01' * 20, hashlib.sha1).digest()
self.k2 = hmac.new(self.sik, '\x02' * 20, hashlib.sha1).digest()
self.k1 = hmac.new(self.sik, b'\x01' * 20, hashlib.sha1).digest()
self.k2 = hmac.new(self.sik, b'\x02' * 20, hashlib.sha1).digest()
self.aeskey = self.k2[0:16]
self.sessioncontext = "EXPECTINGRAKP4"
self.lastpayload = None
@ -1641,5 +1650,5 @@ if __name__ == "__main__":
ipmis = Session(bmc=sys.argv[1],
userid=sys.argv[2],
password=os.environ['IPMIPASS'])
print ipmis.raw_command(command=2, data=[1], netfn=0)
print get_ipmi_error({'command': 8, 'code': 128, 'netfn': 1})
print(ipmis.raw_command(command=2, data=[1], netfn=0))
print(get_ipmi_error({'command': 8, 'code': 128, 'netfn': 1}))

View File

@ -17,6 +17,11 @@
import socket
import struct
try:
xrange
except NameError:
xrange = range
def decode_wireformat_uuid(rawguid):
"""Decode a wire format UUID

View File

@ -733,4 +733,4 @@ if __name__ == "__main__": # test code
continue
reading = sdr.sensors[number].decode_sensor_reading(rsp['data'])
if reading is not None:
print repr(reading)
print(repr(reading))

View File

@ -18,8 +18,12 @@
__author__ = 'jjohnson2'
import Cookie
import httplib
try:
import Cookie
import httplib
except ImportError:
import http.client as httplib
import http.cookies as Cookie
import json
import pyghmi.exceptions as pygexc
import socket