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*6070Srobj  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
235345Seschrock  * Use is subject to license terms.
245345Seschrock  */
255345Seschrock 
265345Seschrock #pragma ident	"%Z%%M%	%I%	%E% SMI"
275345Seschrock 
285345Seschrock #include <libipmi.h>
295345Seschrock #include <string.h>
305345Seschrock 
315345Seschrock #include "ipmi_impl.h"
325345Seschrock 
33*6070Srobj typedef struct ipmi_user_impl {
34*6070Srobj 	ipmi_list_t	iu_list;
35*6070Srobj 	ipmi_user_t	iu_user;
36*6070Srobj } ipmi_user_impl_t;
37*6070Srobj 
385345Seschrock /*
395345Seschrock  * Get User Access.  See section 22.27.
405345Seschrock  *
415345Seschrock  * See libipmi.h for a complete description of IPMI reference material.
425345Seschrock  */
435345Seschrock 
445345Seschrock typedef struct ipmi_get_user_access_req {
455621Seschrock 	DECL_BITFIELD2(
465621Seschrock 	    igua_channel		:4,
475621Seschrock 	    __reserved1			:4);
485621Seschrock 	DECL_BITFIELD2(
495621Seschrock 	    igua_uid			:2,
505621Seschrock 	    __reserved2			:6);
515345Seschrock } ipmi_get_user_access_req_t;
525345Seschrock 
535345Seschrock #define	IPMI_CMD_GET_USER_ACCESS	0x44
545345Seschrock 
555345Seschrock typedef struct ipmi_get_user_access {
565621Seschrock 	DECL_BITFIELD2(
575621Seschrock 	    igua_max_uid		:4,
585621Seschrock 	    __reserved1			:4);
595621Seschrock 	DECL_BITFIELD2(
605621Seschrock 	    igua_enable_status		:4,
615621Seschrock 	    igua_enabled_uid		:4);
625621Seschrock 	DECL_BITFIELD2(
635621Seschrock 	    __reserved2			:4,
645621Seschrock 	    igua_fixed_uid		:4);
655621Seschrock 	DECL_BITFIELD5(
665621Seschrock 	    __reserved3			:1,
675621Seschrock 	    igua_only_callback		:1,
685621Seschrock 	    igua_link_auth_enable	:1,
695621Seschrock 	    igua_ipmi_msg_enable	:1,
705621Seschrock 	    igua_privilege_level	:4);
715345Seschrock } ipmi_get_user_access_t;
725345Seschrock 
735345Seschrock #define	IPMI_USER_ENABLE_UNSPECIFIED	0x00
745345Seschrock #define	IPMI_USER_ENABLE_SETPASSWD	0x01
755345Seschrock #define	IPMI_USER_DISABLE_SETPASSWD	0x02
765345Seschrock 
775345Seschrock #define	IPMI_USER_CHANNEL_CURRENT	0xe
785345Seschrock 
795345Seschrock /*
805345Seschrock  * Get User Name.  See section 22.29
815345Seschrock  */
825345Seschrock 
835345Seschrock #define	IPMI_CMD_GET_USER_NAME		0x46
845345Seschrock 
855345Seschrock /*
865345Seschrock  * Set User Password.  See section 22.30
875345Seschrock  */
885345Seschrock 
895345Seschrock #define	IPMI_CMD_SET_USER_PASSWORD	0x47
905345Seschrock 
915345Seschrock typedef struct ipmi_set_user_password {
925621Seschrock 	DECL_BITFIELD3(
935621Seschrock 	    isup_uid		:6,
945621Seschrock 	    __reserved1		:1,
955621Seschrock 	    isup_len20		:1);
965621Seschrock 	DECL_BITFIELD2(
975621Seschrock 	    isup_op		:2,
985621Seschrock 	    __reserved2		:6);
995345Seschrock 	char		isup_passwd[20];
1005345Seschrock } ipmi_set_user_password_t;
1015345Seschrock 
1025345Seschrock #define	IPMI_PASSWORD_OP_DISABLE	0x0
1035345Seschrock #define	IPMI_PASSWORD_OP_ENABLE		0x1
1045345Seschrock #define	IPMI_PASSWORD_OP_SET		0x2
1055345Seschrock #define	IPMI_PASSWORD_OP_TEST		0x3
1065345Seschrock 
1075345Seschrock static ipmi_get_user_access_t *
1085345Seschrock ipmi_get_user_access(ipmi_handle_t *ihp, uint8_t channel, uint8_t uid)
1095345Seschrock {
1105345Seschrock 	ipmi_cmd_t cmd, *resp;
1115345Seschrock 	ipmi_get_user_access_req_t req = { 0 };
1125345Seschrock 
1135345Seschrock 	req.igua_channel = channel;
1145345Seschrock 	req.igua_uid = uid;
1155345Seschrock 
1165345Seschrock 	cmd.ic_netfn = IPMI_NETFN_APP;
1175345Seschrock 	cmd.ic_cmd = IPMI_CMD_GET_USER_ACCESS;
1185345Seschrock 	cmd.ic_lun = 0;
1195345Seschrock 	cmd.ic_data = &req;
1205345Seschrock 	cmd.ic_dlen = sizeof (req);
1215345Seschrock 
1225345Seschrock 	if ((resp = ipmi_send(ihp, &cmd)) == NULL) {
1235345Seschrock 		/*
1245345Seschrock 		 * If sessions aren't supported on the current channel, some
1255345Seschrock 		 * service processors (notably Sun's ILOM) will return an
1265345Seschrock 		 * invalid request completion code (0xCC).  For these SPs, we
1275345Seschrock 		 * translate this to the more appropriate EIPMI_INVALID_COMMAND.
1285345Seschrock 		 */
1295345Seschrock 		if (ipmi_errno(ihp) == EIPMI_INVALID_REQUEST)
1305345Seschrock 			(void) ipmi_set_error(ihp, EIPMI_INVALID_COMMAND,
1315345Seschrock 			    NULL);
1325345Seschrock 		return (NULL);
1335345Seschrock 	}
1345345Seschrock 
1355345Seschrock 	if (resp->ic_dlen < sizeof (ipmi_get_user_access_t)) {
1365345Seschrock 		(void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL);
1375345Seschrock 		return (NULL);
1385345Seschrock 	}
1395345Seschrock 
1405345Seschrock 	return (resp->ic_data);
1415345Seschrock }
1425345Seschrock 
1435345Seschrock static const char *
1445345Seschrock ipmi_get_user_name(ipmi_handle_t *ihp, uint8_t uid)
1455345Seschrock {
1465345Seschrock 	ipmi_cmd_t cmd, *resp;
1475345Seschrock 
1485345Seschrock 	cmd.ic_netfn = IPMI_NETFN_APP;
1495345Seschrock 	cmd.ic_cmd = IPMI_CMD_GET_USER_ACCESS;
1505345Seschrock 	cmd.ic_lun = 0;
1515345Seschrock 	cmd.ic_data = &uid;
1525345Seschrock 	cmd.ic_dlen = sizeof (uid);
1535345Seschrock 
1545345Seschrock 	if ((resp = ipmi_send(ihp, &cmd)) == NULL)
1555345Seschrock 		return (NULL);
1565345Seschrock 
1575345Seschrock 	if (resp->ic_dlen < 16) {
1585345Seschrock 		(void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL);
1595345Seschrock 		return (NULL);
1605345Seschrock 	}
1615345Seschrock 
1625345Seschrock 	return (resp->ic_data);
1635345Seschrock }
1645345Seschrock 
1655345Seschrock void
1665345Seschrock ipmi_user_clear(ipmi_handle_t *ihp)
1675345Seschrock {
168*6070Srobj 	ipmi_user_impl_t *uip;
1695345Seschrock 
170*6070Srobj 	while ((uip = ipmi_list_next(&ihp->ih_users)) != NULL) {
171*6070Srobj 		ipmi_list_delete(&ihp->ih_users, uip);
172*6070Srobj 		ipmi_free(ihp, uip->iu_user.iu_name);
173*6070Srobj 		ipmi_free(ihp, uip);
1745345Seschrock 	}
1755345Seschrock }
1765345Seschrock 
1775345Seschrock /*
1785345Seschrock  * Returns user information in a well-defined structure.
1795345Seschrock  */
1805345Seschrock int
1815345Seschrock ipmi_user_iter(ipmi_handle_t *ihp, int (*func)(ipmi_user_t *, void *),
1825345Seschrock     void *data)
1835345Seschrock {
1845345Seschrock 	ipmi_get_user_access_t *resp;
1855345Seschrock 	uint8_t i;
186*6070Srobj 	ipmi_user_impl_t *uip;
1875345Seschrock 	ipmi_user_t *up;
1885345Seschrock 	const char *name;
1895345Seschrock 
1905345Seschrock 	ipmi_user_clear(ihp);
1915345Seschrock 
1925345Seschrock 	/*
1935345Seschrock 	 * First get the number of active users on the system by requesting the
1945345Seschrock 	 * reserved user ID (0).
1955345Seschrock 	 */
1965345Seschrock 	if ((resp = ipmi_get_user_access(ihp,
1975345Seschrock 	    IPMI_USER_CHANNEL_CURRENT, 0)) == NULL)
1985345Seschrock 		return (-1);
1995345Seschrock 
2005345Seschrock 	for (i = 1; i <= resp->igua_max_uid; i++) {
2015345Seschrock 		if ((resp = ipmi_get_user_access(ihp,
2025345Seschrock 		    IPMI_USER_CHANNEL_CURRENT, i)) == NULL)
2035345Seschrock 			return (-1);
2045345Seschrock 
205*6070Srobj 		if ((uip = ipmi_zalloc(ihp, sizeof (ipmi_user_impl_t))) == NULL)
2065345Seschrock 			return (-1);
2075345Seschrock 
208*6070Srobj 		up = &uip->iu_user;
209*6070Srobj 
2105345Seschrock 		up->iu_enabled = resp->igua_enabled_uid;
2115345Seschrock 		up->iu_uid = i;
2125345Seschrock 		up->iu_ipmi_msg_enable = resp->igua_ipmi_msg_enable;
2135345Seschrock 		up->iu_link_auth_enable = resp->igua_link_auth_enable;
2145345Seschrock 		up->iu_priv = resp->igua_privilege_level;
215*6070Srobj 
216*6070Srobj 		ipmi_list_append(&ihp->ih_users, uip);
2175345Seschrock 
2185345Seschrock 		if ((name = ipmi_get_user_name(ihp, i)) == NULL)
2195345Seschrock 			return (-1);
2205345Seschrock 
2215345Seschrock 		if (*name != '\0' &&
2225345Seschrock 		    (up->iu_name = ipmi_strdup(ihp, name)) == NULL)
2235345Seschrock 			return (-1);
2245345Seschrock 	}
2255345Seschrock 
226*6070Srobj 	for (uip = ipmi_list_next(&ihp->ih_users); uip != NULL;
227*6070Srobj 	    uip = ipmi_list_next(uip)) {
228*6070Srobj 		if (func(&uip->iu_user, data) != 0)
2295345Seschrock 			return (-1);
2305345Seschrock 	}
2315345Seschrock 
2325345Seschrock 	return (0);
2335345Seschrock }
2345345Seschrock 
2355345Seschrock typedef struct ipmi_user_cb {
2365345Seschrock 	const char	*uic_name;
2375345Seschrock 	uint8_t		uic_uid;
2385345Seschrock 	ipmi_user_t	*uic_result;
2395345Seschrock } ipmi_user_cb_t;
2405345Seschrock 
2415345Seschrock static int
2425345Seschrock ipmi_user_callback(ipmi_user_t *up, void *data)
2435345Seschrock {
2445345Seschrock 	ipmi_user_cb_t *cbp = data;
2455345Seschrock 
2465345Seschrock 	if (cbp->uic_result != NULL)
2475345Seschrock 		return (0);
2485345Seschrock 
2495345Seschrock 	if (up->iu_name) {
2505345Seschrock 		if (strcmp(up->iu_name, cbp->uic_name) == 0)
2515345Seschrock 			cbp->uic_result = up;
2525345Seschrock 	} else if (up->iu_uid == cbp->uic_uid) {
2535345Seschrock 		cbp->uic_result = up;
2545345Seschrock 	}
2555345Seschrock 
2565345Seschrock 	return (0);
2575345Seschrock }
2585345Seschrock 
2595345Seschrock ipmi_user_t *
2605345Seschrock ipmi_user_lookup_name(ipmi_handle_t *ihp, const char *name)
2615345Seschrock {
2625345Seschrock 	ipmi_user_cb_t cb = { 0 };
2635345Seschrock 
2645345Seschrock 	cb.uic_name = name;
2655345Seschrock 	cb.uic_result = NULL;
2665345Seschrock 
2675345Seschrock 	if (ipmi_user_iter(ihp, ipmi_user_callback, &cb) != 0)
2685345Seschrock 		return (NULL);
2695345Seschrock 
2705345Seschrock 	if (cb.uic_result == NULL)
2715345Seschrock 		(void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT,
2725345Seschrock 		    "no such user");
2735345Seschrock 
2745345Seschrock 	return (cb.uic_result);
2755345Seschrock }
2765345Seschrock 
2775345Seschrock ipmi_user_t *
2785345Seschrock ipmi_user_lookup_id(ipmi_handle_t *ihp, uint8_t uid)
2795345Seschrock {
2805345Seschrock 	ipmi_user_cb_t cb = { 0 };
2815345Seschrock 
2825345Seschrock 	cb.uic_uid = uid;
2835345Seschrock 	cb.uic_result = NULL;
2845345Seschrock 
2855345Seschrock 	if (ipmi_user_iter(ihp, ipmi_user_callback, &cb) != 0)
2865345Seschrock 		return (NULL);
2875345Seschrock 
2885345Seschrock 	if (cb.uic_result == NULL)
2895345Seschrock 		(void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT,
2905345Seschrock 		    "no such user");
2915345Seschrock 
2925345Seschrock 	return (cb.uic_result);
2935345Seschrock }
2945345Seschrock 
2955345Seschrock int
2965345Seschrock ipmi_user_set_password(ipmi_handle_t *ihp, uint8_t uid, const char *passwd)
2975345Seschrock {
2985345Seschrock 	ipmi_set_user_password_t req = { 0 };
2995345Seschrock 	ipmi_cmd_t cmd;
3005345Seschrock 
3015345Seschrock 	req.isup_uid = uid;
3025345Seschrock 	req.isup_op = IPMI_PASSWORD_OP_SET;
3035345Seschrock 
3045345Seschrock 	if (strlen(passwd) > 19)
3055345Seschrock 		return (ipmi_set_error(ihp, EIPMI_INVALID_REQUEST,
3065345Seschrock 		    "password length must be less than 20 characters"));
3075345Seschrock 
3085345Seschrock 	if (strlen(passwd) > 15)
3095345Seschrock 		req.isup_len20 = 1;
3105345Seschrock 
3115345Seschrock 	(void) strcpy(req.isup_passwd, passwd);
3125345Seschrock 
3135345Seschrock 	cmd.ic_netfn = IPMI_NETFN_APP;
3145345Seschrock 	cmd.ic_cmd = IPMI_CMD_SET_USER_PASSWORD;
3155345Seschrock 	cmd.ic_lun = 0;
3165345Seschrock 	cmd.ic_data = &req;
3175345Seschrock 	if (req.isup_len20)
3185345Seschrock 		cmd.ic_dlen = sizeof (req);
3195345Seschrock 	else
3205345Seschrock 		cmd.ic_dlen = sizeof (req) - 4;
3215345Seschrock 
3225345Seschrock 	if (ipmi_send(ihp, &cmd) == NULL)
3235345Seschrock 		return (-1);
3245345Seschrock 
3255345Seschrock 	return (0);
3265345Seschrock }
327