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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <libipmi.h> 27 #include <string.h> 28 29 #include "ipmi_impl.h" 30 31 typedef struct ipmi_user_impl { 32 ipmi_list_t iu_list; 33 ipmi_user_t iu_user; 34 } ipmi_user_impl_t; 35 36 /* 37 * Get User Access. See section 22.27. 38 * 39 * See libipmi.h for a complete description of IPMI reference material. 40 */ 41 42 typedef struct ipmi_get_user_access_req { 43 DECL_BITFIELD2( 44 igua_channel :4, 45 __reserved1 :4); 46 DECL_BITFIELD2( 47 igua_uid :2, 48 __reserved2 :6); 49 } ipmi_get_user_access_req_t; 50 51 #define IPMI_CMD_GET_USER_ACCESS 0x44 52 53 typedef struct ipmi_get_user_access { 54 DECL_BITFIELD2( 55 igua_max_uid :4, 56 __reserved1 :4); 57 DECL_BITFIELD2( 58 igua_enable_status :4, 59 igua_enabled_uid :4); 60 DECL_BITFIELD2( 61 __reserved2 :4, 62 igua_fixed_uid :4); 63 DECL_BITFIELD5( 64 __reserved3 :1, 65 igua_only_callback :1, 66 igua_link_auth_enable :1, 67 igua_ipmi_msg_enable :1, 68 igua_privilege_level :4); 69 } ipmi_get_user_access_t; 70 71 #define IPMI_USER_ENABLE_UNSPECIFIED 0x00 72 #define IPMI_USER_ENABLE_SETPASSWD 0x01 73 #define IPMI_USER_DISABLE_SETPASSWD 0x02 74 75 #define IPMI_USER_CHANNEL_CURRENT 0xe 76 77 /* 78 * Get User Name. See section 22.29 79 */ 80 81 #define IPMI_CMD_GET_USER_NAME 0x46 82 83 /* 84 * Set User Password. See section 22.30 85 */ 86 87 #define IPMI_CMD_SET_USER_PASSWORD 0x47 88 89 typedef struct ipmi_set_user_password { 90 DECL_BITFIELD3( 91 isup_uid :6, 92 __reserved1 :1, 93 isup_len20 :1); 94 DECL_BITFIELD2( 95 isup_op :2, 96 __reserved2 :6); 97 char isup_passwd[20]; 98 } ipmi_set_user_password_t; 99 100 #define IPMI_PASSWORD_OP_DISABLE 0x0 101 #define IPMI_PASSWORD_OP_ENABLE 0x1 102 #define IPMI_PASSWORD_OP_SET 0x2 103 #define IPMI_PASSWORD_OP_TEST 0x3 104 105 static ipmi_get_user_access_t * 106 ipmi_get_user_access(ipmi_handle_t *ihp, uint8_t channel, uint8_t uid) 107 { 108 ipmi_cmd_t cmd, *resp; 109 ipmi_get_user_access_req_t req = { 0 }; 110 111 req.igua_channel = channel; 112 req.igua_uid = uid; 113 114 cmd.ic_netfn = IPMI_NETFN_APP; 115 cmd.ic_cmd = IPMI_CMD_GET_USER_ACCESS; 116 cmd.ic_lun = 0; 117 cmd.ic_data = &req; 118 cmd.ic_dlen = sizeof (req); 119 120 if ((resp = ipmi_send(ihp, &cmd)) == NULL) { 121 /* 122 * If sessions aren't supported on the current channel, some 123 * service processors (notably Sun's ILOM) will return an 124 * invalid request completion code (0xCC). For these SPs, we 125 * translate this to the more appropriate EIPMI_INVALID_COMMAND. 126 */ 127 if (ipmi_errno(ihp) == EIPMI_INVALID_REQUEST) 128 (void) ipmi_set_error(ihp, EIPMI_INVALID_COMMAND, 129 NULL); 130 return (NULL); 131 } 132 133 if (resp->ic_dlen < sizeof (ipmi_get_user_access_t)) { 134 (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL); 135 return (NULL); 136 } 137 138 return (resp->ic_data); 139 } 140 141 static const char * 142 ipmi_get_user_name(ipmi_handle_t *ihp, uint8_t uid) 143 { 144 ipmi_cmd_t cmd, *resp; 145 146 cmd.ic_netfn = IPMI_NETFN_APP; 147 cmd.ic_cmd = IPMI_CMD_GET_USER_NAME; 148 cmd.ic_lun = 0; 149 cmd.ic_data = &uid; 150 cmd.ic_dlen = sizeof (uid); 151 152 if ((resp = ipmi_send(ihp, &cmd)) == NULL) 153 return (NULL); 154 155 if (resp->ic_dlen < 16) { 156 (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL); 157 return (NULL); 158 } 159 160 return (resp->ic_data); 161 } 162 163 void 164 ipmi_user_clear(ipmi_handle_t *ihp) 165 { 166 ipmi_user_impl_t *uip; 167 168 while ((uip = ipmi_list_next(&ihp->ih_users)) != NULL) { 169 ipmi_list_delete(&ihp->ih_users, uip); 170 ipmi_free(ihp, uip->iu_user.iu_name); 171 ipmi_free(ihp, uip); 172 } 173 } 174 175 /* 176 * Returns user information in a well-defined structure. 177 */ 178 int 179 ipmi_user_iter(ipmi_handle_t *ihp, int (*func)(ipmi_user_t *, void *), 180 void *data) 181 { 182 ipmi_get_user_access_t *resp; 183 uint8_t i, uid_max; 184 ipmi_user_impl_t *uip; 185 ipmi_user_t *up; 186 const char *name; 187 uint8_t channel; 188 ipmi_deviceid_t *devid; 189 190 ipmi_user_clear(ihp); 191 192 channel = IPMI_USER_CHANNEL_CURRENT; 193 194 /* 195 * Get the number of active users on the system by requesting the first 196 * user ID (1). 197 */ 198 if ((resp = ipmi_get_user_access(ihp, channel, 1)) == NULL) { 199 /* 200 * Some versions of the Sun ILOM have a bug which prevent the 201 * GET USER ACCESS command from succeeding over the default 202 * channel. If this fails and we are on ILOM, then attempt to 203 * use the standard channel (1) instead. 204 */ 205 if ((devid = ipmi_get_deviceid(ihp)) == NULL) 206 return (-1); 207 208 if (!ipmi_is_sun_ilom(devid)) 209 return (-1); 210 211 channel = 1; 212 if ((resp = ipmi_get_user_access(ihp, channel, 1)) == NULL) 213 return (-1); 214 } 215 216 uid_max = resp->igua_max_uid; 217 for (i = 1; i <= uid_max; i++) { 218 if (i != 1 && (resp = ipmi_get_user_access(ihp, 219 channel, i)) == NULL) 220 return (-1); 221 222 if ((uip = ipmi_zalloc(ihp, sizeof (ipmi_user_impl_t))) == NULL) 223 return (-1); 224 225 up = &uip->iu_user; 226 227 up->iu_enabled = resp->igua_enabled_uid; 228 up->iu_uid = i; 229 up->iu_ipmi_msg_enable = resp->igua_ipmi_msg_enable; 230 up->iu_link_auth_enable = resp->igua_link_auth_enable; 231 up->iu_priv = resp->igua_privilege_level; 232 233 ipmi_list_append(&ihp->ih_users, uip); 234 235 /* 236 * If we are requesting a username that doesn't have a 237 * supported username, we may get an INVALID REQUEST response. 238 * If this is the case, then continue as if there is no known 239 * username. 240 */ 241 if ((name = ipmi_get_user_name(ihp, i)) == NULL) { 242 if (ipmi_errno(ihp) == EIPMI_INVALID_REQUEST) 243 continue; 244 else 245 return (-1); 246 } 247 248 if (*name == '\0') 249 continue; 250 251 if ((up->iu_name = ipmi_strdup(ihp, name)) == NULL) 252 return (-1); 253 } 254 255 for (uip = ipmi_list_next(&ihp->ih_users); uip != NULL; 256 uip = ipmi_list_next(uip)) { 257 if (func(&uip->iu_user, data) != 0) 258 return (-1); 259 } 260 261 return (0); 262 } 263 264 typedef struct ipmi_user_cb { 265 const char *uic_name; 266 uint8_t uic_uid; 267 ipmi_user_t *uic_result; 268 } ipmi_user_cb_t; 269 270 static int 271 ipmi_user_callback(ipmi_user_t *up, void *data) 272 { 273 ipmi_user_cb_t *cbp = data; 274 275 if (cbp->uic_result != NULL) 276 return (0); 277 278 if (up->iu_name) { 279 if (strcmp(up->iu_name, cbp->uic_name) == 0) 280 cbp->uic_result = up; 281 } else if (up->iu_uid == cbp->uic_uid) { 282 cbp->uic_result = up; 283 } 284 285 return (0); 286 } 287 288 ipmi_user_t * 289 ipmi_user_lookup_name(ipmi_handle_t *ihp, const char *name) 290 { 291 ipmi_user_cb_t cb = { 0 }; 292 293 cb.uic_name = name; 294 cb.uic_result = NULL; 295 296 if (ipmi_user_iter(ihp, ipmi_user_callback, &cb) != 0) 297 return (NULL); 298 299 if (cb.uic_result == NULL) 300 (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, 301 "no such user"); 302 303 return (cb.uic_result); 304 } 305 306 ipmi_user_t * 307 ipmi_user_lookup_id(ipmi_handle_t *ihp, uint8_t uid) 308 { 309 ipmi_user_cb_t cb = { 0 }; 310 311 cb.uic_uid = uid; 312 cb.uic_result = NULL; 313 314 if (ipmi_user_iter(ihp, ipmi_user_callback, &cb) != 0) 315 return (NULL); 316 317 if (cb.uic_result == NULL) 318 (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, 319 "no such user"); 320 321 return (cb.uic_result); 322 } 323 324 int 325 ipmi_user_set_password(ipmi_handle_t *ihp, uint8_t uid, const char *passwd) 326 { 327 ipmi_set_user_password_t req = { 0 }; 328 ipmi_cmd_t cmd; 329 330 req.isup_uid = uid; 331 req.isup_op = IPMI_PASSWORD_OP_SET; 332 333 if (strlen(passwd) > 19) 334 return (ipmi_set_error(ihp, EIPMI_INVALID_REQUEST, 335 "password length must be less than 20 characters")); 336 337 if (strlen(passwd) > 15) 338 req.isup_len20 = 1; 339 340 (void) strcpy(req.isup_passwd, passwd); 341 342 cmd.ic_netfn = IPMI_NETFN_APP; 343 cmd.ic_cmd = IPMI_CMD_SET_USER_PASSWORD; 344 cmd.ic_lun = 0; 345 cmd.ic_data = &req; 346 if (req.isup_len20) 347 cmd.ic_dlen = sizeof (req); 348 else 349 cmd.ic_dlen = sizeof (req) - 4; 350 351 if (ipmi_send(ihp, &cmd) == NULL) 352 return (-1); 353 354 return (0); 355 } 356