pyipmi/messaging.py
# Copyright (c) 2016 Kontron Europe GmbH
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
from enum import Enum
from .session import Session
from .msgs import create_request_by_name
from .utils import check_completion_code, check_rsp_completion_code
from .state import State
class PasswordOperation(int, Enum):
DISABLE = 0b00
ENABLE = 0b01
SET_PASSWORD = 0b10
TEST_PASSWORD = 0b11
class UserPrivilegeLevel(str, Enum):
RESERVED = "reserved"
CALLBACK = "callback"
USER = "user"
OPERATOR = "operator"
ADMINISTRATOR = "administrator"
OEM = "oem"
NO_ACCESS = "no access"
CONVERT_RAW_TO_USER_PRIVILEGE = {
0x00: UserPrivilegeLevel.RESERVED,
0x01: UserPrivilegeLevel.CALLBACK,
0x02: UserPrivilegeLevel.USER,
0x03: UserPrivilegeLevel.OPERATOR,
0x04: UserPrivilegeLevel.ADMINISTRATOR,
0x05: UserPrivilegeLevel.OEM,
0x0F: UserPrivilegeLevel.NO_ACCESS
}
CONVERT_USER_PRIVILEGE_TO_RAW = {
UserPrivilegeLevel.RESERVED: 0x00,
UserPrivilegeLevel.CALLBACK: 0x01,
UserPrivilegeLevel.USER: 0x02,
UserPrivilegeLevel.OPERATOR: 0x03,
UserPrivilegeLevel.ADMINISTRATOR: 0x04,
UserPrivilegeLevel.OEM: 0x05,
UserPrivilegeLevel.NO_ACCESS: 0x0F
}
class Messaging(object):
def get_channel_authentication_capabilities(self, channel, priv_lvl):
req = create_request_by_name('GetChannelAuthenticationCapabilities')
req.channel.number = channel
req.privilege_level.requested = priv_lvl
rsp = self.send_and_receive(req)
check_completion_code(rsp.completion_code)
caps = ChannelAuthenticationCapabilities(rsp)
return caps
def set_username(self, userid=0, username=''):
req = create_request_by_name('SetUserName')
req.userid.userid = userid
req.user_name = username.ljust(16, '\x00')
rsp = self.send_message(req)
check_completion_code(rsp.completion_code)
def get_username(self, userid=0):
req = create_request_by_name('GetUserName')
req.userid.userid = userid
rsp = self.send_message(req)
check_completion_code(rsp.completion_code)
return rsp.user_name
def get_user_access(self, userid=0, channel=0):
req = create_request_by_name('GetUserAccess')
req.userid.userid = userid
req.channel.channel_number = channel
rsp = self.send_message(req)
check_completion_code(rsp.completion_code)
return UserAccess(rsp)
def set_user_access(self, userid, ipmi_msg, link_auth, callback_only,
priv_level, channel=0, enable_change=1, user_session_limit=0):
req = create_request_by_name('SetUserAccess')
req.channel_access.channel_number = channel
req.channel_access.ipmi_msg = ipmi_msg
req.channel_access.link_auth = link_auth
req.channel_access.callback = callback_only
req.channel_access.enable_change = enable_change
req.userid.userid = userid
req.privilege.privilege_level = CONVERT_USER_PRIVILEGE_TO_RAW.get(
priv_level, 0x0F)
req.session_limit.simultaneous_session_limit = user_session_limit
rsp = self.send_message(req)
check_completion_code(rsp.completion_code)
def set_user_password(self, userid, password=''):
if len(password) > 16:
raise ValueError("Password length cannot be greater than 20.")
req = create_request_by_name('SetUserPassword')
req.userid.userid = userid
req.operation.operation = PasswordOperation.SET_PASSWORD
req.password = password.ljust(16, '\x00')
rsp = self.send_message(req)
check_rsp_completion_code(rsp)
def enable_user(self, userid):
req = create_request_by_name('SetUserPassword')
req.userid.userid = userid
req.operation.operation = PasswordOperation.ENABLE
rsp = self.send_message(req)
check_completion_code(rsp.completion_code)
def disable_user(self, userid):
req = create_request_by_name('SetUserPassword')
req.userid.userid = userid
req.operation.operation = PasswordOperation.DISABLE
rsp = self.send_message(req)
check_completion_code(rsp.completion_code)
class ChannelAuthenticationCapabilities(State):
_functions = {
'none': Session.AUTH_TYPE_NONE,
'md2': Session.AUTH_TYPE_MD2,
'md5': Session.AUTH_TYPE_MD5,
'straight': Session.AUTH_TYPE_PASSWORD,
'oem_proprietary': Session.AUTH_TYPE_OEM,
}
def _from_response(self, rsp):
self.channel = rsp.channel_number
self.auth_types = []
self.ipmi_1_5 = False
self.ipmi_2_0 = False
if rsp.support.ipmi_2_0:
self.ipmi_2_0 = True
else:
self.ipmi_1_5 = True
for function in self._functions.keys():
if hasattr(rsp.support, function):
if getattr(rsp.support, function):
self.auth_types.append(function)
def get_max_auth_type(self):
for auth_type in ('md5', 'md2', 'straight', 'oem_proprietary', 'none'):
if auth_type in self.auth_types:
return self._functions[auth_type]
return None
def __str__(self):
s = 'Authentication Capabilities:\n'
s += ' IPMI v1.5: %s\n' % self.ipmi_1_5
s += ' IPMI v2.0: %s\n' % self.ipmi_2_0
s += ' Auth. types: %s\n' % ' '.join(self.auth_types)
s += ' Max Auth. type: %s\n' % self.get_max_auth_type()
return s
class UserAccess(State):
def _from_response(self, rsp):
self.user_count = rsp.max_user.max_user
self.enabled_user_count = rsp.enabled_user.count
self.enabled_status = rsp.enabled_user.status
self.fixed_name_user_count = rsp.fixed_names.count
self.privilege_level = CONVERT_RAW_TO_USER_PRIVILEGE.get(rsp.channel_access.privilege, UserPrivilegeLevel.RESERVED)
self.ipmi_messaging = rsp.channel_access.ipmi_msg == 1
self.link_auth = rsp.channel_access.link_auth == 1
self.callback_only = rsp.channel_access.callback == 1
def __str__(self):
s = 'User Access:\n'
s += ' Max user number: %i\n' % self.user_count
s += ' Enabled user: %i\n' % self.enabled_user_count
s += ' Enabled status: %i\n' % self.enabled_status
s += ' Fixed name user: %i\n' % self.fixed_name_user_count
s += ' Privilege level: %s\n' % self.privilege_level
s += ' IPMI messaging: %s\n' % self.ipmi_messaging
s += ' Link Auth.: %s\n' % self.link_auth
s += ' Callback only: %s' % self.callback_only