dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libipmi / common / ipmi_user.c
blob7d12c6d76d746a6f6f09e158c5ea58963c9b9b5a
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <libipmi.h>
27 #include <string.h>
29 #include "ipmi_impl.h"
31 typedef struct ipmi_user_impl {
32 ipmi_list_t iu_list;
33 ipmi_user_t iu_user;
34 } ipmi_user_impl_t;
37 * Get User Access. See section 22.27.
39 * See libipmi.h for a complete description of IPMI reference material.
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;
51 #define IPMI_CMD_GET_USER_ACCESS 0x44
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;
71 #define IPMI_USER_ENABLE_UNSPECIFIED 0x00
72 #define IPMI_USER_ENABLE_SETPASSWD 0x01
73 #define IPMI_USER_DISABLE_SETPASSWD 0x02
75 #define IPMI_USER_CHANNEL_CURRENT 0xe
78 * Get User Name. See section 22.29
81 #define IPMI_CMD_GET_USER_NAME 0x46
84 * Set User Password. See section 22.30
87 #define IPMI_CMD_SET_USER_PASSWORD 0x47
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;
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
105 static ipmi_get_user_access_t *
106 ipmi_get_user_access(ipmi_handle_t *ihp, uint8_t channel, uint8_t uid)
108 ipmi_cmd_t cmd, *resp;
109 ipmi_get_user_access_req_t req = { 0 };
111 req.igua_channel = channel;
112 req.igua_uid = uid;
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);
120 if ((resp = ipmi_send(ihp, &cmd)) == NULL) {
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.
127 if (ipmi_errno(ihp) == EIPMI_INVALID_REQUEST)
128 (void) ipmi_set_error(ihp, EIPMI_INVALID_COMMAND,
129 NULL);
130 return (NULL);
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);
138 return (resp->ic_data);
141 static const char *
142 ipmi_get_user_name(ipmi_handle_t *ihp, uint8_t uid)
144 ipmi_cmd_t cmd, *resp;
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);
152 if ((resp = ipmi_send(ihp, &cmd)) == NULL)
153 return (NULL);
155 if (resp->ic_dlen < 16) {
156 (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL);
157 return (NULL);
160 return (resp->ic_data);
163 void
164 ipmi_user_clear(ipmi_handle_t *ihp)
166 ipmi_user_impl_t *uip;
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);
176 * Returns user information in a well-defined structure.
179 ipmi_user_iter(ipmi_handle_t *ihp, int (*func)(ipmi_user_t *, void *),
180 void *data)
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;
190 ipmi_user_clear(ihp);
192 channel = IPMI_USER_CHANNEL_CURRENT;
195 * Get the number of active users on the system by requesting the first
196 * user ID (1).
198 if ((resp = ipmi_get_user_access(ihp, channel, 1)) == NULL) {
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.
205 if ((devid = ipmi_get_deviceid(ihp)) == NULL)
206 return (-1);
208 if (!ipmi_is_sun_ilom(devid))
209 return (-1);
211 channel = 1;
212 if ((resp = ipmi_get_user_access(ihp, channel, 1)) == NULL)
213 return (-1);
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);
222 if ((uip = ipmi_zalloc(ihp, sizeof (ipmi_user_impl_t))) == NULL)
223 return (-1);
225 up = &uip->iu_user;
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;
233 ipmi_list_append(&ihp->ih_users, uip);
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.
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);
248 if (*name == '\0')
249 continue;
251 if ((up->iu_name = ipmi_strdup(ihp, name)) == NULL)
252 return (-1);
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);
261 return (0);
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;
270 static int
271 ipmi_user_callback(ipmi_user_t *up, void *data)
273 ipmi_user_cb_t *cbp = data;
275 if (cbp->uic_result != NULL)
276 return (0);
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;
285 return (0);
288 ipmi_user_t *
289 ipmi_user_lookup_name(ipmi_handle_t *ihp, const char *name)
291 ipmi_user_cb_t cb = { 0 };
293 cb.uic_name = name;
294 cb.uic_result = NULL;
296 if (ipmi_user_iter(ihp, ipmi_user_callback, &cb) != 0)
297 return (NULL);
299 if (cb.uic_result == NULL)
300 (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT,
301 "no such user");
303 return (cb.uic_result);
306 ipmi_user_t *
307 ipmi_user_lookup_id(ipmi_handle_t *ihp, uint8_t uid)
309 ipmi_user_cb_t cb = { 0 };
311 cb.uic_uid = uid;
312 cb.uic_result = NULL;
314 if (ipmi_user_iter(ihp, ipmi_user_callback, &cb) != 0)
315 return (NULL);
317 if (cb.uic_result == NULL)
318 (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT,
319 "no such user");
321 return (cb.uic_result);
325 ipmi_user_set_password(ipmi_handle_t *ihp, uint8_t uid, const char *passwd)
327 ipmi_set_user_password_t req = { 0 };
328 ipmi_cmd_t cmd;
330 req.isup_uid = uid;
331 req.isup_op = IPMI_PASSWORD_OP_SET;
333 if (strlen(passwd) > 19)
334 return (ipmi_set_error(ihp, EIPMI_INVALID_REQUEST,
335 "password length must be less than 20 characters"));
337 if (strlen(passwd) > 15)
338 req.isup_len20 = 1;
340 (void) strcpy(req.isup_passwd, passwd);
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;
351 if (ipmi_send(ihp, &cmd) == NULL)
352 return (-1);
354 return (0);