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