1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <libipmi.h> 29 #include <string.h> 30 31 #include "ipmi_impl.h" 32 33 /* 34 * Get User Access. See section 22.27. 35 * 36 * See libipmi.h for a complete description of IPMI reference material. 37 */ 38 39 typedef struct ipmi_get_user_access_req { 40 #if defined(_BIT_FIELDS_LTOH) 41 uint8_t igua_channel:4; 42 uint8_t __reserved1:4; 43 uint8_t igua_uid:2; 44 uint8_t __reserved2:6; 45 #else 46 uint8_t __reserved1:4; 47 uint8_t igua_channel:4; 48 uint8_t __reserved2:2; 49 uint8_t igua_uid:6; 50 #endif 51 } ipmi_get_user_access_req_t; 52 53 #define IPMI_CMD_GET_USER_ACCESS 0x44 54 55 typedef struct ipmi_get_user_access { 56 #if defined(_BIT_FIELDS_LTOH) 57 uint8_t igua_max_uid:4; 58 uint8_t __reserved1:4; 59 uint8_t igua_enable_status:4; 60 uint8_t igua_enabled_uid:4; 61 uint8_t __reserved2:4; 62 uint8_t igua_fixed_uid:4; 63 uint8_t __reserved3:1; 64 uint8_t igua_only_callback:1; 65 uint8_t igua_link_auth_enable:1; 66 uint8_t igua_ipmi_msg_enable:1; 67 uint8_t igua_privilege_level:4; 68 #else 69 uint8_t __reserved1:4; 70 uint8_t igua_max_uid:4; 71 uint8_t igua_enabled_uid:4; 72 uint8_t igua_enable_status:4; 73 uint8_t igua_fixed_uid:4; 74 uint8_t __reserved2:4; 75 uint8_t igua_privilege_level:4; 76 uint8_t igua_ipmi_msg_enable:1; 77 uint8_t igua_link_auth_enable:1; 78 uint8_t igua_only_callback:1; 79 uint8_t __reserved3:1; 80 #endif 81 } ipmi_get_user_access_t; 82 83 #define IPMI_USER_ENABLE_UNSPECIFIED 0x00 84 #define IPMI_USER_ENABLE_SETPASSWD 0x01 85 #define IPMI_USER_DISABLE_SETPASSWD 0x02 86 87 #define IPMI_USER_CHANNEL_CURRENT 0xe 88 89 /* 90 * Get User Name. See section 22.29 91 */ 92 93 #define IPMI_CMD_GET_USER_NAME 0x46 94 95 /* 96 * Set User Password. See section 22.30 97 */ 98 99 #define IPMI_CMD_SET_USER_PASSWORD 0x47 100 101 typedef struct ipmi_set_user_password { 102 #if defined(_BIT_FIELDS_LTOH) 103 uint8_t isup_uid:6; 104 uint8_t __reserved1:1; 105 uint8_t isup_len20:1; 106 uint8_t isup_op:2; 107 uint8_t __reserved2:6; 108 #else 109 uint8_t isup_len20:1; 110 uint8_t __reserved1:1; 111 uint8_t isup_uid:6; 112 uint8_t __reserved2:6; 113 uint8_t isup_op:2; 114 #endif 115 char isup_passwd[20]; 116 } ipmi_set_user_password_t; 117 118 #define IPMI_PASSWORD_OP_DISABLE 0x0 119 #define IPMI_PASSWORD_OP_ENABLE 0x1 120 #define IPMI_PASSWORD_OP_SET 0x2 121 #define IPMI_PASSWORD_OP_TEST 0x3 122 123 static ipmi_get_user_access_t * 124 ipmi_get_user_access(ipmi_handle_t *ihp, uint8_t channel, uint8_t uid) 125 { 126 ipmi_cmd_t cmd, *resp; 127 ipmi_get_user_access_req_t req = { 0 }; 128 129 req.igua_channel = channel; 130 req.igua_uid = uid; 131 132 cmd.ic_netfn = IPMI_NETFN_APP; 133 cmd.ic_cmd = IPMI_CMD_GET_USER_ACCESS; 134 cmd.ic_lun = 0; 135 cmd.ic_data = &req; 136 cmd.ic_dlen = sizeof (req); 137 138 if ((resp = ipmi_send(ihp, &cmd)) == NULL) { 139 /* 140 * If sessions aren't supported on the current channel, some 141 * service processors (notably Sun's ILOM) will return an 142 * invalid request completion code (0xCC). For these SPs, we 143 * translate this to the more appropriate EIPMI_INVALID_COMMAND. 144 */ 145 if (ipmi_errno(ihp) == EIPMI_INVALID_REQUEST) 146 (void) ipmi_set_error(ihp, EIPMI_INVALID_COMMAND, 147 NULL); 148 return (NULL); 149 } 150 151 if (resp->ic_dlen < sizeof (ipmi_get_user_access_t)) { 152 (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL); 153 return (NULL); 154 } 155 156 return (resp->ic_data); 157 } 158 159 static const char * 160 ipmi_get_user_name(ipmi_handle_t *ihp, uint8_t uid) 161 { 162 ipmi_cmd_t cmd, *resp; 163 164 cmd.ic_netfn = IPMI_NETFN_APP; 165 cmd.ic_cmd = IPMI_CMD_GET_USER_ACCESS; 166 cmd.ic_lun = 0; 167 cmd.ic_data = &uid; 168 cmd.ic_dlen = sizeof (uid); 169 170 if ((resp = ipmi_send(ihp, &cmd)) == NULL) 171 return (NULL); 172 173 if (resp->ic_dlen < 16) { 174 (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL); 175 return (NULL); 176 } 177 178 return (resp->ic_data); 179 } 180 181 void 182 ipmi_user_clear(ipmi_handle_t *ihp) 183 { 184 ipmi_user_t *up, *next; 185 186 while ((up = ihp->ih_users) != NULL) { 187 next = up->iu_next; 188 ipmi_free(ihp, up->iu_name); 189 ipmi_free(ihp, up); 190 ihp->ih_users = next; 191 } 192 } 193 194 /* 195 * Returns user information in a well-defined structure. 196 */ 197 int 198 ipmi_user_iter(ipmi_handle_t *ihp, int (*func)(ipmi_user_t *, void *), 199 void *data) 200 { 201 ipmi_get_user_access_t *resp; 202 uint8_t i; 203 ipmi_user_t *up; 204 const char *name; 205 206 ipmi_user_clear(ihp); 207 208 /* 209 * First get the number of active users on the system by requesting the 210 * reserved user ID (0). 211 */ 212 if ((resp = ipmi_get_user_access(ihp, 213 IPMI_USER_CHANNEL_CURRENT, 0)) == NULL) 214 return (-1); 215 216 for (i = 1; i <= resp->igua_max_uid; i++) { 217 if ((resp = ipmi_get_user_access(ihp, 218 IPMI_USER_CHANNEL_CURRENT, i)) == NULL) 219 return (-1); 220 221 if ((up = ipmi_zalloc(ihp, sizeof (ipmi_user_t))) == NULL) 222 return (-1); 223 224 up->iu_enabled = resp->igua_enabled_uid; 225 up->iu_uid = i; 226 up->iu_ipmi_msg_enable = resp->igua_ipmi_msg_enable; 227 up->iu_link_auth_enable = resp->igua_link_auth_enable; 228 up->iu_priv = resp->igua_privilege_level; 229 up->iu_next = ihp->ih_users; 230 ihp->ih_users = up; 231 232 if ((name = ipmi_get_user_name(ihp, i)) == NULL) 233 return (-1); 234 235 if (*name != '\0' && 236 (up->iu_name = ipmi_strdup(ihp, name)) == NULL) 237 return (-1); 238 } 239 240 for (up = ihp->ih_users; up != NULL; up = up->iu_next) { 241 if (func(up, data) != 0) 242 return (-1); 243 } 244 245 return (0); 246 } 247 248 typedef struct ipmi_user_cb { 249 const char *uic_name; 250 uint8_t uic_uid; 251 ipmi_user_t *uic_result; 252 } ipmi_user_cb_t; 253 254 static int 255 ipmi_user_callback(ipmi_user_t *up, void *data) 256 { 257 ipmi_user_cb_t *cbp = data; 258 259 if (cbp->uic_result != NULL) 260 return (0); 261 262 if (up->iu_name) { 263 if (strcmp(up->iu_name, cbp->uic_name) == 0) 264 cbp->uic_result = up; 265 } else if (up->iu_uid == cbp->uic_uid) { 266 cbp->uic_result = up; 267 } 268 269 return (0); 270 } 271 272 ipmi_user_t * 273 ipmi_user_lookup_name(ipmi_handle_t *ihp, const char *name) 274 { 275 ipmi_user_cb_t cb = { 0 }; 276 277 cb.uic_name = name; 278 cb.uic_result = NULL; 279 280 if (ipmi_user_iter(ihp, ipmi_user_callback, &cb) != 0) 281 return (NULL); 282 283 if (cb.uic_result == NULL) 284 (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, 285 "no such user"); 286 287 return (cb.uic_result); 288 } 289 290 ipmi_user_t * 291 ipmi_user_lookup_id(ipmi_handle_t *ihp, uint8_t uid) 292 { 293 ipmi_user_cb_t cb = { 0 }; 294 295 cb.uic_uid = uid; 296 cb.uic_result = NULL; 297 298 if (ipmi_user_iter(ihp, ipmi_user_callback, &cb) != 0) 299 return (NULL); 300 301 if (cb.uic_result == NULL) 302 (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, 303 "no such user"); 304 305 return (cb.uic_result); 306 } 307 308 int 309 ipmi_user_set_password(ipmi_handle_t *ihp, uint8_t uid, const char *passwd) 310 { 311 ipmi_set_user_password_t req = { 0 }; 312 ipmi_cmd_t cmd; 313 314 req.isup_uid = uid; 315 req.isup_op = IPMI_PASSWORD_OP_SET; 316 317 if (strlen(passwd) > 19) 318 return (ipmi_set_error(ihp, EIPMI_INVALID_REQUEST, 319 "password length must be less than 20 characters")); 320 321 if (strlen(passwd) > 15) 322 req.isup_len20 = 1; 323 324 (void) strcpy(req.isup_passwd, passwd); 325 326 cmd.ic_netfn = IPMI_NETFN_APP; 327 cmd.ic_cmd = IPMI_CMD_SET_USER_PASSWORD; 328 cmd.ic_lun = 0; 329 cmd.ic_data = &req; 330 if (req.isup_len20) 331 cmd.ic_dlen = sizeof (req); 332 else 333 cmd.ic_dlen = sizeof (req) - 4; 334 335 if (ipmi_send(ihp, &cmd) == NULL) 336 return (-1); 337 338 return (0); 339 } 340