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