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