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