Home | History | Annotate | Download | only in common
      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