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