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