xref: /onnv-gate/usr/src/lib/libipmi/common/ipmi_user.c (revision 10516:73cc1414bac0)
15345Seschrock /*
25345Seschrock  * CDDL HEADER START
35345Seschrock  *
45345Seschrock  * The contents of this file are subject to the terms of the
55345Seschrock  * Common Development and Distribution License (the "License").
65345Seschrock  * You may not use this file except in compliance with the License.
75345Seschrock  *
85345Seschrock  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95345Seschrock  * or http://www.opensolaris.org/os/licensing.
105345Seschrock  * See the License for the specific language governing permissions
115345Seschrock  * and limitations under the License.
125345Seschrock  *
135345Seschrock  * When distributing Covered Code, include this CDDL HEADER in each
145345Seschrock  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155345Seschrock  * If applicable, add the following below this CDDL HEADER, with the
165345Seschrock  * fields enclosed by brackets "[]" replaced with your own identifying
175345Seschrock  * information: Portions Copyright [yyyy] [name of copyright owner]
185345Seschrock  *
195345Seschrock  * CDDL HEADER END
205345Seschrock  */
215345Seschrock /*
22*10516SEric.Schrock@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
235345Seschrock  * Use is subject to license terms.
245345Seschrock  */
255345Seschrock 
265345Seschrock #include <libipmi.h>
275345Seschrock #include <string.h>
285345Seschrock 
295345Seschrock #include "ipmi_impl.h"
305345Seschrock 
316070Srobj typedef struct ipmi_user_impl {
326070Srobj 	ipmi_list_t	iu_list;
336070Srobj 	ipmi_user_t	iu_user;
346070Srobj } ipmi_user_impl_t;
356070Srobj 
365345Seschrock /*
375345Seschrock  * Get User Access.  See section 22.27.
385345Seschrock  *
395345Seschrock  * See libipmi.h for a complete description of IPMI reference material.
405345Seschrock  */
415345Seschrock 
425345Seschrock typedef struct ipmi_get_user_access_req {
435621Seschrock 	DECL_BITFIELD2(
445621Seschrock 	    igua_channel		:4,
455621Seschrock 	    __reserved1			:4);
465621Seschrock 	DECL_BITFIELD2(
475621Seschrock 	    igua_uid			:2,
485621Seschrock 	    __reserved2			:6);
495345Seschrock } ipmi_get_user_access_req_t;
505345Seschrock 
515345Seschrock #define	IPMI_CMD_GET_USER_ACCESS	0x44
525345Seschrock 
535345Seschrock typedef struct ipmi_get_user_access {
545621Seschrock 	DECL_BITFIELD2(
555621Seschrock 	    igua_max_uid		:4,
565621Seschrock 	    __reserved1			:4);
575621Seschrock 	DECL_BITFIELD2(
585621Seschrock 	    igua_enable_status		:4,
595621Seschrock 	    igua_enabled_uid		:4);
605621Seschrock 	DECL_BITFIELD2(
615621Seschrock 	    __reserved2			:4,
625621Seschrock 	    igua_fixed_uid		:4);
635621Seschrock 	DECL_BITFIELD5(
645621Seschrock 	    __reserved3			:1,
655621Seschrock 	    igua_only_callback		:1,
665621Seschrock 	    igua_link_auth_enable	:1,
675621Seschrock 	    igua_ipmi_msg_enable	:1,
685621Seschrock 	    igua_privilege_level	:4);
695345Seschrock } ipmi_get_user_access_t;
705345Seschrock 
715345Seschrock #define	IPMI_USER_ENABLE_UNSPECIFIED	0x00
725345Seschrock #define	IPMI_USER_ENABLE_SETPASSWD	0x01
735345Seschrock #define	IPMI_USER_DISABLE_SETPASSWD	0x02
745345Seschrock 
755345Seschrock #define	IPMI_USER_CHANNEL_CURRENT	0xe
765345Seschrock 
775345Seschrock /*
785345Seschrock  * Get User Name.  See section 22.29
795345Seschrock  */
805345Seschrock 
815345Seschrock #define	IPMI_CMD_GET_USER_NAME		0x46
825345Seschrock 
835345Seschrock /*
845345Seschrock  * Set User Password.  See section 22.30
855345Seschrock  */
865345Seschrock 
875345Seschrock #define	IPMI_CMD_SET_USER_PASSWORD	0x47
885345Seschrock 
895345Seschrock typedef struct ipmi_set_user_password {
905621Seschrock 	DECL_BITFIELD3(
915621Seschrock 	    isup_uid		:6,
925621Seschrock 	    __reserved1		:1,
935621Seschrock 	    isup_len20		:1);
945621Seschrock 	DECL_BITFIELD2(
955621Seschrock 	    isup_op		:2,
965621Seschrock 	    __reserved2		:6);
975345Seschrock 	char		isup_passwd[20];
985345Seschrock } ipmi_set_user_password_t;
995345Seschrock 
1005345Seschrock #define	IPMI_PASSWORD_OP_DISABLE	0x0
1015345Seschrock #define	IPMI_PASSWORD_OP_ENABLE		0x1
1025345Seschrock #define	IPMI_PASSWORD_OP_SET		0x2
1035345Seschrock #define	IPMI_PASSWORD_OP_TEST		0x3
1045345Seschrock 
1055345Seschrock static ipmi_get_user_access_t *
ipmi_get_user_access(ipmi_handle_t * ihp,uint8_t channel,uint8_t uid)1065345Seschrock ipmi_get_user_access(ipmi_handle_t *ihp, uint8_t channel, uint8_t uid)
1075345Seschrock {
1085345Seschrock 	ipmi_cmd_t cmd, *resp;
1095345Seschrock 	ipmi_get_user_access_req_t req = { 0 };
1105345Seschrock 
1115345Seschrock 	req.igua_channel = channel;
1125345Seschrock 	req.igua_uid = uid;
1135345Seschrock 
1145345Seschrock 	cmd.ic_netfn = IPMI_NETFN_APP;
1155345Seschrock 	cmd.ic_cmd = IPMI_CMD_GET_USER_ACCESS;
1165345Seschrock 	cmd.ic_lun = 0;
1175345Seschrock 	cmd.ic_data = &req;
1185345Seschrock 	cmd.ic_dlen = sizeof (req);
1195345Seschrock 
1205345Seschrock 	if ((resp = ipmi_send(ihp, &cmd)) == NULL) {
1215345Seschrock 		/*
1225345Seschrock 		 * If sessions aren't supported on the current channel, some
1235345Seschrock 		 * service processors (notably Sun's ILOM) will return an
1245345Seschrock 		 * invalid request completion code (0xCC).  For these SPs, we
1255345Seschrock 		 * translate this to the more appropriate EIPMI_INVALID_COMMAND.
1265345Seschrock 		 */
1275345Seschrock 		if (ipmi_errno(ihp) == EIPMI_INVALID_REQUEST)
1285345Seschrock 			(void) ipmi_set_error(ihp, EIPMI_INVALID_COMMAND,
1295345Seschrock 			    NULL);
1305345Seschrock 		return (NULL);
1315345Seschrock 	}
1325345Seschrock 
1335345Seschrock 	if (resp->ic_dlen < sizeof (ipmi_get_user_access_t)) {
1345345Seschrock 		(void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL);
1355345Seschrock 		return (NULL);
1365345Seschrock 	}
1375345Seschrock 
1385345Seschrock 	return (resp->ic_data);
1395345Seschrock }
1405345Seschrock 
1415345Seschrock static const char *
ipmi_get_user_name(ipmi_handle_t * ihp,uint8_t uid)1425345Seschrock ipmi_get_user_name(ipmi_handle_t *ihp, uint8_t uid)
1435345Seschrock {
1445345Seschrock 	ipmi_cmd_t cmd, *resp;
1455345Seschrock 
1465345Seschrock 	cmd.ic_netfn = IPMI_NETFN_APP;
147*10516SEric.Schrock@Sun.COM 	cmd.ic_cmd = IPMI_CMD_GET_USER_NAME;
1485345Seschrock 	cmd.ic_lun = 0;
1495345Seschrock 	cmd.ic_data = &uid;
1505345Seschrock 	cmd.ic_dlen = sizeof (uid);
1515345Seschrock 
1525345Seschrock 	if ((resp = ipmi_send(ihp, &cmd)) == NULL)
1535345Seschrock 		return (NULL);
1545345Seschrock 
1555345Seschrock 	if (resp->ic_dlen < 16) {
1565345Seschrock 		(void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL);
1575345Seschrock 		return (NULL);
1585345Seschrock 	}
1595345Seschrock 
1605345Seschrock 	return (resp->ic_data);
1615345Seschrock }
1625345Seschrock 
1635345Seschrock void
ipmi_user_clear(ipmi_handle_t * ihp)1645345Seschrock ipmi_user_clear(ipmi_handle_t *ihp)
1655345Seschrock {
1666070Srobj 	ipmi_user_impl_t *uip;
1675345Seschrock 
1686070Srobj 	while ((uip = ipmi_list_next(&ihp->ih_users)) != NULL) {
1696070Srobj 		ipmi_list_delete(&ihp->ih_users, uip);
1706070Srobj 		ipmi_free(ihp, uip->iu_user.iu_name);
1716070Srobj 		ipmi_free(ihp, uip);
1725345Seschrock 	}
1735345Seschrock }
1745345Seschrock 
1755345Seschrock /*
1765345Seschrock  * Returns user information in a well-defined structure.
1775345Seschrock  */
1785345Seschrock int
ipmi_user_iter(ipmi_handle_t * ihp,int (* func)(ipmi_user_t *,void *),void * data)1795345Seschrock ipmi_user_iter(ipmi_handle_t *ihp, int (*func)(ipmi_user_t *, void *),
1805345Seschrock     void *data)
1815345Seschrock {
1825345Seschrock 	ipmi_get_user_access_t *resp;
183*10516SEric.Schrock@Sun.COM 	uint8_t i, uid_max;
1846070Srobj 	ipmi_user_impl_t *uip;
1855345Seschrock 	ipmi_user_t *up;
1865345Seschrock 	const char *name;
187*10516SEric.Schrock@Sun.COM 	uint8_t channel;
188*10516SEric.Schrock@Sun.COM 	ipmi_deviceid_t *devid;
1895345Seschrock 
1905345Seschrock 	ipmi_user_clear(ihp);
1915345Seschrock 
192*10516SEric.Schrock@Sun.COM 	channel = IPMI_USER_CHANNEL_CURRENT;
193*10516SEric.Schrock@Sun.COM 
1945345Seschrock 	/*
195*10516SEric.Schrock@Sun.COM 	 * Get the number of active users on the system by requesting the first
196*10516SEric.Schrock@Sun.COM 	 * user ID (1).
1975345Seschrock 	 */
198*10516SEric.Schrock@Sun.COM 	if ((resp = ipmi_get_user_access(ihp, channel, 1)) == NULL) {
199*10516SEric.Schrock@Sun.COM 		/*
200*10516SEric.Schrock@Sun.COM 		 * Some versions of the Sun ILOM have a bug which prevent the
201*10516SEric.Schrock@Sun.COM 		 * GET USER ACCESS command from succeeding over the default
202*10516SEric.Schrock@Sun.COM 		 * channel.  If this fails and we are on ILOM, then attempt to
203*10516SEric.Schrock@Sun.COM 		 * use the standard channel (1) instead.
204*10516SEric.Schrock@Sun.COM 		 */
205*10516SEric.Schrock@Sun.COM 		if ((devid = ipmi_get_deviceid(ihp)) == NULL)
206*10516SEric.Schrock@Sun.COM 			return (-1);
2075345Seschrock 
208*10516SEric.Schrock@Sun.COM 		if (!ipmi_is_sun_ilom(devid))
209*10516SEric.Schrock@Sun.COM 			return (-1);
210*10516SEric.Schrock@Sun.COM 
211*10516SEric.Schrock@Sun.COM 		channel = 1;
212*10516SEric.Schrock@Sun.COM 		if ((resp = ipmi_get_user_access(ihp, channel, 1)) == NULL)
213*10516SEric.Schrock@Sun.COM 			return (-1);
214*10516SEric.Schrock@Sun.COM 	}
215*10516SEric.Schrock@Sun.COM 
216*10516SEric.Schrock@Sun.COM 	uid_max = resp->igua_max_uid;
217*10516SEric.Schrock@Sun.COM 	for (i = 1; i <= uid_max; i++) {
218*10516SEric.Schrock@Sun.COM 		if (i != 1 && (resp = ipmi_get_user_access(ihp,
219*10516SEric.Schrock@Sun.COM 		    channel, i)) == NULL)
2205345Seschrock 			return (-1);
2215345Seschrock 
2226070Srobj 		if ((uip = ipmi_zalloc(ihp, sizeof (ipmi_user_impl_t))) == NULL)
2235345Seschrock 			return (-1);
2245345Seschrock 
2256070Srobj 		up = &uip->iu_user;
2266070Srobj 
2275345Seschrock 		up->iu_enabled = resp->igua_enabled_uid;
2285345Seschrock 		up->iu_uid = i;
2295345Seschrock 		up->iu_ipmi_msg_enable = resp->igua_ipmi_msg_enable;
2305345Seschrock 		up->iu_link_auth_enable = resp->igua_link_auth_enable;
2315345Seschrock 		up->iu_priv = resp->igua_privilege_level;
2326070Srobj 
2336070Srobj 		ipmi_list_append(&ihp->ih_users, uip);
2345345Seschrock 
235*10516SEric.Schrock@Sun.COM 		/*
236*10516SEric.Schrock@Sun.COM 		 * If we are requesting a username that doesn't have a
237*10516SEric.Schrock@Sun.COM 		 * supported username, we may get an INVALID REQUEST response.
238*10516SEric.Schrock@Sun.COM 		 * If this is the case, then continue as if there is no known
239*10516SEric.Schrock@Sun.COM 		 * username.
240*10516SEric.Schrock@Sun.COM 		 */
241*10516SEric.Schrock@Sun.COM 		if ((name = ipmi_get_user_name(ihp, i)) == NULL) {
242*10516SEric.Schrock@Sun.COM 			if (ipmi_errno(ihp) == EIPMI_INVALID_REQUEST)
243*10516SEric.Schrock@Sun.COM 				continue;
244*10516SEric.Schrock@Sun.COM 			else
245*10516SEric.Schrock@Sun.COM 				return (-1);
246*10516SEric.Schrock@Sun.COM 		}
2475345Seschrock 
248*10516SEric.Schrock@Sun.COM 		if (*name == '\0')
249*10516SEric.Schrock@Sun.COM 			continue;
250*10516SEric.Schrock@Sun.COM 
251*10516SEric.Schrock@Sun.COM 		if ((up->iu_name = ipmi_strdup(ihp, name)) == NULL)
2525345Seschrock 			return (-1);
2535345Seschrock 	}
2545345Seschrock 
2556070Srobj 	for (uip = ipmi_list_next(&ihp->ih_users); uip != NULL;
2566070Srobj 	    uip = ipmi_list_next(uip)) {
2576070Srobj 		if (func(&uip->iu_user, data) != 0)
2585345Seschrock 			return (-1);
2595345Seschrock 	}
2605345Seschrock 
2615345Seschrock 	return (0);
2625345Seschrock }
2635345Seschrock 
2645345Seschrock typedef struct ipmi_user_cb {
2655345Seschrock 	const char	*uic_name;
2665345Seschrock 	uint8_t		uic_uid;
2675345Seschrock 	ipmi_user_t	*uic_result;
2685345Seschrock } ipmi_user_cb_t;
2695345Seschrock 
2705345Seschrock static int
ipmi_user_callback(ipmi_user_t * up,void * data)2715345Seschrock ipmi_user_callback(ipmi_user_t *up, void *data)
2725345Seschrock {
2735345Seschrock 	ipmi_user_cb_t *cbp = data;
2745345Seschrock 
2755345Seschrock 	if (cbp->uic_result != NULL)
2765345Seschrock 		return (0);
2775345Seschrock 
2785345Seschrock 	if (up->iu_name) {
2795345Seschrock 		if (strcmp(up->iu_name, cbp->uic_name) == 0)
2805345Seschrock 			cbp->uic_result = up;
2815345Seschrock 	} else if (up->iu_uid == cbp->uic_uid) {
2825345Seschrock 		cbp->uic_result = up;
2835345Seschrock 	}
2845345Seschrock 
2855345Seschrock 	return (0);
2865345Seschrock }
2875345Seschrock 
2885345Seschrock ipmi_user_t *
ipmi_user_lookup_name(ipmi_handle_t * ihp,const char * name)2895345Seschrock ipmi_user_lookup_name(ipmi_handle_t *ihp, const char *name)
2905345Seschrock {
2915345Seschrock 	ipmi_user_cb_t cb = { 0 };
2925345Seschrock 
2935345Seschrock 	cb.uic_name = name;
2945345Seschrock 	cb.uic_result = NULL;
2955345Seschrock 
2965345Seschrock 	if (ipmi_user_iter(ihp, ipmi_user_callback, &cb) != 0)
2975345Seschrock 		return (NULL);
2985345Seschrock 
2995345Seschrock 	if (cb.uic_result == NULL)
3005345Seschrock 		(void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT,
3015345Seschrock 		    "no such user");
3025345Seschrock 
3035345Seschrock 	return (cb.uic_result);
3045345Seschrock }
3055345Seschrock 
3065345Seschrock ipmi_user_t *
ipmi_user_lookup_id(ipmi_handle_t * ihp,uint8_t uid)3075345Seschrock ipmi_user_lookup_id(ipmi_handle_t *ihp, uint8_t uid)
3085345Seschrock {
3095345Seschrock 	ipmi_user_cb_t cb = { 0 };
3105345Seschrock 
3115345Seschrock 	cb.uic_uid = uid;
3125345Seschrock 	cb.uic_result = NULL;
3135345Seschrock 
3145345Seschrock 	if (ipmi_user_iter(ihp, ipmi_user_callback, &cb) != 0)
3155345Seschrock 		return (NULL);
3165345Seschrock 
3175345Seschrock 	if (cb.uic_result == NULL)
3185345Seschrock 		(void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT,
3195345Seschrock 		    "no such user");
3205345Seschrock 
3215345Seschrock 	return (cb.uic_result);
3225345Seschrock }
3235345Seschrock 
3245345Seschrock int
ipmi_user_set_password(ipmi_handle_t * ihp,uint8_t uid,const char * passwd)3255345Seschrock ipmi_user_set_password(ipmi_handle_t *ihp, uint8_t uid, const char *passwd)
3265345Seschrock {
3275345Seschrock 	ipmi_set_user_password_t req = { 0 };
3285345Seschrock 	ipmi_cmd_t cmd;
3295345Seschrock 
3305345Seschrock 	req.isup_uid = uid;
3315345Seschrock 	req.isup_op = IPMI_PASSWORD_OP_SET;
3325345Seschrock 
3335345Seschrock 	if (strlen(passwd) > 19)
3345345Seschrock 		return (ipmi_set_error(ihp, EIPMI_INVALID_REQUEST,
3355345Seschrock 		    "password length must be less than 20 characters"));
3365345Seschrock 
3375345Seschrock 	if (strlen(passwd) > 15)
3385345Seschrock 		req.isup_len20 = 1;
3395345Seschrock 
3405345Seschrock 	(void) strcpy(req.isup_passwd, passwd);
3415345Seschrock 
3425345Seschrock 	cmd.ic_netfn = IPMI_NETFN_APP;
3435345Seschrock 	cmd.ic_cmd = IPMI_CMD_SET_USER_PASSWORD;
3445345Seschrock 	cmd.ic_lun = 0;
3455345Seschrock 	cmd.ic_data = &req;
3465345Seschrock 	if (req.isup_len20)
3475345Seschrock 		cmd.ic_dlen = sizeof (req);
3485345Seschrock 	else
3495345Seschrock 		cmd.ic_dlen = sizeof (req) - 4;
3505345Seschrock 
3515345Seschrock 	if (ipmi_send(ihp, &cmd) == NULL)
3525345Seschrock 		return (-1);
3535345Seschrock 
3545345Seschrock 	return (0);
3555345Seschrock }
356