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