1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
|
package ipmi
import (
"context"
"fmt"
)
// 22.27 Get User Access Command
type GetUserAccessRequest struct {
ChannelNumber uint8
UserID uint8
}
type GetUserAccessResponse struct {
// Maximum number of User IDs. 1-based. Count includes User 1. A value of 1
// indicates only User 1 is supported.
MaxUsersIDCount uint8
// [7:6] - User ID Enable status (for IPMI v2.0 errata 3 and later implementations).
// 00b = User ID enable status unspecified. (For backward compatibility
// with pre-errata 3 implementations. IPMI errata 3 and later
// implementations should return the 01b and 10b responses.)
// 01b = User ID enabled via Set User Password command.
// 10b = User ID disabled via Set User Password command.
// 11b = reserved
EnableStatus uint8
// [5:0] - count of currently enabled user IDs on this channel (Indicates how
// many User ID slots are presently in use.)
EnabledUserIDsCount uint8
// Count of User IDs with fixed names, including User 1 (1-based). Fixed names
// in addition to User 1 are required to be associated with sequential user IDs
// starting from User ID 2.
FixedNameUseIDsCount uint8
// [6] - 0b = user access available during call-in or callback direct connection
// 1b = user access available only during callback connection
CallbackOnly bool
// [5] - 0b = user disabled for link authentication
// 1b = user enabled for link authentication
LinkAuthEnabled bool
// [4] - 0b = user disabled for IPMI Messaging
// 1b = user enabled for IPMI Messaging
IPMIMessagingEnabled bool
// [3:0] - User Privilege Limit for given Channel
MaxPrivLevel PrivilegeLevel
}
func (req *GetUserAccessRequest) Command() Command {
return CommandGetUserAccess
}
func (req *GetUserAccessRequest) Pack() []byte {
return []byte{req.ChannelNumber, req.UserID}
}
func (res *GetUserAccessResponse) CompletionCodes() map[uint8]string {
return map[uint8]string{}
}
func (res *GetUserAccessResponse) Unpack(msg []byte) error {
if len(msg) < 4 {
return ErrUnpackedDataTooShortWith(len(msg), 4)
}
res.MaxUsersIDCount, _, _ = unpackUint8(msg, 0)
b1, _, _ := unpackUint8(msg, 1)
res.EnableStatus = b1 & 0xc0 >> 6
res.EnabledUserIDsCount = b1 & 0x3f
b2, _, _ := unpackUint8(msg, 2)
res.FixedNameUseIDsCount = b2 & 0x3f
b3, _, _ := unpackUint8(msg, 3)
res.CallbackOnly = isBit6Set(b3)
res.LinkAuthEnabled = isBit5Set(b3)
res.IPMIMessagingEnabled = isBit4Set(b3)
res.MaxPrivLevel = PrivilegeLevel(b3 & 0x0f)
return nil
}
func (res *GetUserAccessResponse) Format() string {
return "" +
fmt.Sprintf("Maximum IDs : %d\n", res.MaxUsersIDCount) +
fmt.Sprintf("Enabled User Count : %d\n", res.EnabledUserIDsCount) +
fmt.Sprintf("Fixed Name Count : %d\n", res.FixedNameUseIDsCount)
}
func (c *Client) GetUserAccess(ctx context.Context, channelNumber uint8, userID uint8) (response *GetUserAccessResponse, err error) {
request := &GetUserAccessRequest{
ChannelNumber: channelNumber,
UserID: userID,
}
response = &GetUserAccessResponse{}
err = c.Exchange(ctx, request, response)
return
}
func (c *Client) GetUsers(ctx context.Context, channelNumber uint8) ([]*User, error) {
var users = make([]*User, 0)
var userID uint8 = 1
var username string
for {
res, err := c.GetUserAccess(ctx, channelNumber, userID)
if err != nil {
return nil, fmt.Errorf("GetUserAccess for userID %d failed, err: %w", userID, err)
}
res2, err := c.GetUsername(ctx, userID)
if err != nil {
if respErr, ok := isResponseError(err); ok {
if respErr.CompletionCode() == CompletionCodeRequestDataFieldInvalid {
// Completion Code is 0xcc, means this UserID is not set.
username = ""
}
} else {
return nil, fmt.Errorf("GetUsername for userID %d failed, err: %w", userID, err)
}
} else {
username = res2.Username
}
user := &User{
ID: userID,
Name: username,
Callin: !res.CallbackOnly,
LinkAuthEnabled: res.LinkAuthEnabled,
IPMIMessagingEnabled: res.IPMIMessagingEnabled,
MaxPrivLevel: res.MaxPrivLevel,
}
users = append(users, user)
if userID >= res.MaxUsersIDCount {
break
}
userID += 1
}
return users, nil
}
type User struct {
ID uint8
Name string
Callin bool
LinkAuthEnabled bool
IPMIMessagingEnabled bool
MaxPrivLevel PrivilegeLevel
}
func FormatUsers(users []*User) string {
rows := make([]map[string]string, len(users))
for i, user := range users {
rows[i] = map[string]string{
"ID": fmt.Sprintf("%d", user.ID),
"Name": user.Name,
"Callin": fmt.Sprintf("%v", user.Callin),
"Link Auth": fmt.Sprintf("%v", user.LinkAuthEnabled),
"IPMI Msg": fmt.Sprintf("%v", user.IPMIMessagingEnabled),
"Channel Priv Limit": user.MaxPrivLevel.String(),
}
}
headers := []string{
"ID",
"Name",
"Callin",
"Link Auth",
"IPMI Msg",
"Channel Priv Limit",
}
return RenderTable(headers, rows)
}
|