15345Seschrock /*
25345Seschrock * CDDL HEADER START
35345Seschrock *
45345Seschrock * The contents of this file are subject to the terms of the
55345Seschrock * Common Development and Distribution License (the "License").
65345Seschrock * You may not use this file except in compliance with the License.
75345Seschrock *
85345Seschrock * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95345Seschrock * or http://www.opensolaris.org/os/licensing.
105345Seschrock * See the License for the specific language governing permissions
115345Seschrock * and limitations under the License.
125345Seschrock *
135345Seschrock * When distributing Covered Code, include this CDDL HEADER in each
145345Seschrock * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155345Seschrock * If applicable, add the following below this CDDL HEADER, with the
165345Seschrock * fields enclosed by brackets "[]" replaced with your own identifying
175345Seschrock * information: Portions Copyright [yyyy] [name of copyright owner]
185345Seschrock *
195345Seschrock * CDDL HEADER END
205345Seschrock */
215345Seschrock /*
22*10516SEric.Schrock@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
235345Seschrock * Use is subject to license terms.
245345Seschrock */
255345Seschrock
265345Seschrock #include <libipmi.h>
275345Seschrock #include <string.h>
285345Seschrock
295345Seschrock #include "ipmi_impl.h"
305345Seschrock
316070Srobj typedef struct ipmi_user_impl {
326070Srobj ipmi_list_t iu_list;
336070Srobj ipmi_user_t iu_user;
346070Srobj } ipmi_user_impl_t;
356070Srobj
365345Seschrock /*
375345Seschrock * Get User Access. See section 22.27.
385345Seschrock *
395345Seschrock * See libipmi.h for a complete description of IPMI reference material.
405345Seschrock */
415345Seschrock
425345Seschrock typedef struct ipmi_get_user_access_req {
435621Seschrock DECL_BITFIELD2(
445621Seschrock igua_channel :4,
455621Seschrock __reserved1 :4);
465621Seschrock DECL_BITFIELD2(
475621Seschrock igua_uid :2,
485621Seschrock __reserved2 :6);
495345Seschrock } ipmi_get_user_access_req_t;
505345Seschrock
515345Seschrock #define IPMI_CMD_GET_USER_ACCESS 0x44
525345Seschrock
535345Seschrock typedef struct ipmi_get_user_access {
545621Seschrock DECL_BITFIELD2(
555621Seschrock igua_max_uid :4,
565621Seschrock __reserved1 :4);
575621Seschrock DECL_BITFIELD2(
585621Seschrock igua_enable_status :4,
595621Seschrock igua_enabled_uid :4);
605621Seschrock DECL_BITFIELD2(
615621Seschrock __reserved2 :4,
625621Seschrock igua_fixed_uid :4);
635621Seschrock DECL_BITFIELD5(
645621Seschrock __reserved3 :1,
655621Seschrock igua_only_callback :1,
665621Seschrock igua_link_auth_enable :1,
675621Seschrock igua_ipmi_msg_enable :1,
685621Seschrock igua_privilege_level :4);
695345Seschrock } ipmi_get_user_access_t;
705345Seschrock
715345Seschrock #define IPMI_USER_ENABLE_UNSPECIFIED 0x00
725345Seschrock #define IPMI_USER_ENABLE_SETPASSWD 0x01
735345Seschrock #define IPMI_USER_DISABLE_SETPASSWD 0x02
745345Seschrock
755345Seschrock #define IPMI_USER_CHANNEL_CURRENT 0xe
765345Seschrock
775345Seschrock /*
785345Seschrock * Get User Name. See section 22.29
795345Seschrock */
805345Seschrock
815345Seschrock #define IPMI_CMD_GET_USER_NAME 0x46
825345Seschrock
835345Seschrock /*
845345Seschrock * Set User Password. See section 22.30
855345Seschrock */
865345Seschrock
875345Seschrock #define IPMI_CMD_SET_USER_PASSWORD 0x47
885345Seschrock
895345Seschrock typedef struct ipmi_set_user_password {
905621Seschrock DECL_BITFIELD3(
915621Seschrock isup_uid :6,
925621Seschrock __reserved1 :1,
935621Seschrock isup_len20 :1);
945621Seschrock DECL_BITFIELD2(
955621Seschrock isup_op :2,
965621Seschrock __reserved2 :6);
975345Seschrock char isup_passwd[20];
985345Seschrock } ipmi_set_user_password_t;
995345Seschrock
1005345Seschrock #define IPMI_PASSWORD_OP_DISABLE 0x0
1015345Seschrock #define IPMI_PASSWORD_OP_ENABLE 0x1
1025345Seschrock #define IPMI_PASSWORD_OP_SET 0x2
1035345Seschrock #define IPMI_PASSWORD_OP_TEST 0x3
1045345Seschrock
1055345Seschrock static ipmi_get_user_access_t *
ipmi_get_user_access(ipmi_handle_t * ihp,uint8_t channel,uint8_t uid)1065345Seschrock ipmi_get_user_access(ipmi_handle_t *ihp, uint8_t channel, uint8_t uid)
1075345Seschrock {
1085345Seschrock ipmi_cmd_t cmd, *resp;
1095345Seschrock ipmi_get_user_access_req_t req = { 0 };
1105345Seschrock
1115345Seschrock req.igua_channel = channel;
1125345Seschrock req.igua_uid = uid;
1135345Seschrock
1145345Seschrock cmd.ic_netfn = IPMI_NETFN_APP;
1155345Seschrock cmd.ic_cmd = IPMI_CMD_GET_USER_ACCESS;
1165345Seschrock cmd.ic_lun = 0;
1175345Seschrock cmd.ic_data = &req;
1185345Seschrock cmd.ic_dlen = sizeof (req);
1195345Seschrock
1205345Seschrock if ((resp = ipmi_send(ihp, &cmd)) == NULL) {
1215345Seschrock /*
1225345Seschrock * If sessions aren't supported on the current channel, some
1235345Seschrock * service processors (notably Sun's ILOM) will return an
1245345Seschrock * invalid request completion code (0xCC). For these SPs, we
1255345Seschrock * translate this to the more appropriate EIPMI_INVALID_COMMAND.
1265345Seschrock */
1275345Seschrock if (ipmi_errno(ihp) == EIPMI_INVALID_REQUEST)
1285345Seschrock (void) ipmi_set_error(ihp, EIPMI_INVALID_COMMAND,
1295345Seschrock NULL);
1305345Seschrock return (NULL);
1315345Seschrock }
1325345Seschrock
1335345Seschrock if (resp->ic_dlen < sizeof (ipmi_get_user_access_t)) {
1345345Seschrock (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL);
1355345Seschrock return (NULL);
1365345Seschrock }
1375345Seschrock
1385345Seschrock return (resp->ic_data);
1395345Seschrock }
1405345Seschrock
1415345Seschrock static const char *
ipmi_get_user_name(ipmi_handle_t * ihp,uint8_t uid)1425345Seschrock ipmi_get_user_name(ipmi_handle_t *ihp, uint8_t uid)
1435345Seschrock {
1445345Seschrock ipmi_cmd_t cmd, *resp;
1455345Seschrock
1465345Seschrock cmd.ic_netfn = IPMI_NETFN_APP;
147*10516SEric.Schrock@Sun.COM cmd.ic_cmd = IPMI_CMD_GET_USER_NAME;
1485345Seschrock cmd.ic_lun = 0;
1495345Seschrock cmd.ic_data = &uid;
1505345Seschrock cmd.ic_dlen = sizeof (uid);
1515345Seschrock
1525345Seschrock if ((resp = ipmi_send(ihp, &cmd)) == NULL)
1535345Seschrock return (NULL);
1545345Seschrock
1555345Seschrock if (resp->ic_dlen < 16) {
1565345Seschrock (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL);
1575345Seschrock return (NULL);
1585345Seschrock }
1595345Seschrock
1605345Seschrock return (resp->ic_data);
1615345Seschrock }
1625345Seschrock
1635345Seschrock void
ipmi_user_clear(ipmi_handle_t * ihp)1645345Seschrock ipmi_user_clear(ipmi_handle_t *ihp)
1655345Seschrock {
1666070Srobj ipmi_user_impl_t *uip;
1675345Seschrock
1686070Srobj while ((uip = ipmi_list_next(&ihp->ih_users)) != NULL) {
1696070Srobj ipmi_list_delete(&ihp->ih_users, uip);
1706070Srobj ipmi_free(ihp, uip->iu_user.iu_name);
1716070Srobj ipmi_free(ihp, uip);
1725345Seschrock }
1735345Seschrock }
1745345Seschrock
1755345Seschrock /*
1765345Seschrock * Returns user information in a well-defined structure.
1775345Seschrock */
1785345Seschrock int
ipmi_user_iter(ipmi_handle_t * ihp,int (* func)(ipmi_user_t *,void *),void * data)1795345Seschrock ipmi_user_iter(ipmi_handle_t *ihp, int (*func)(ipmi_user_t *, void *),
1805345Seschrock void *data)
1815345Seschrock {
1825345Seschrock ipmi_get_user_access_t *resp;
183*10516SEric.Schrock@Sun.COM uint8_t i, uid_max;
1846070Srobj ipmi_user_impl_t *uip;
1855345Seschrock ipmi_user_t *up;
1865345Seschrock const char *name;
187*10516SEric.Schrock@Sun.COM uint8_t channel;
188*10516SEric.Schrock@Sun.COM ipmi_deviceid_t *devid;
1895345Seschrock
1905345Seschrock ipmi_user_clear(ihp);
1915345Seschrock
192*10516SEric.Schrock@Sun.COM channel = IPMI_USER_CHANNEL_CURRENT;
193*10516SEric.Schrock@Sun.COM
1945345Seschrock /*
195*10516SEric.Schrock@Sun.COM * Get the number of active users on the system by requesting the first
196*10516SEric.Schrock@Sun.COM * user ID (1).
1975345Seschrock */
198*10516SEric.Schrock@Sun.COM if ((resp = ipmi_get_user_access(ihp, channel, 1)) == NULL) {
199*10516SEric.Schrock@Sun.COM /*
200*10516SEric.Schrock@Sun.COM * Some versions of the Sun ILOM have a bug which prevent the
201*10516SEric.Schrock@Sun.COM * GET USER ACCESS command from succeeding over the default
202*10516SEric.Schrock@Sun.COM * channel. If this fails and we are on ILOM, then attempt to
203*10516SEric.Schrock@Sun.COM * use the standard channel (1) instead.
204*10516SEric.Schrock@Sun.COM */
205*10516SEric.Schrock@Sun.COM if ((devid = ipmi_get_deviceid(ihp)) == NULL)
206*10516SEric.Schrock@Sun.COM return (-1);
2075345Seschrock
208*10516SEric.Schrock@Sun.COM if (!ipmi_is_sun_ilom(devid))
209*10516SEric.Schrock@Sun.COM return (-1);
210*10516SEric.Schrock@Sun.COM
211*10516SEric.Schrock@Sun.COM channel = 1;
212*10516SEric.Schrock@Sun.COM if ((resp = ipmi_get_user_access(ihp, channel, 1)) == NULL)
213*10516SEric.Schrock@Sun.COM return (-1);
214*10516SEric.Schrock@Sun.COM }
215*10516SEric.Schrock@Sun.COM
216*10516SEric.Schrock@Sun.COM uid_max = resp->igua_max_uid;
217*10516SEric.Schrock@Sun.COM for (i = 1; i <= uid_max; i++) {
218*10516SEric.Schrock@Sun.COM if (i != 1 && (resp = ipmi_get_user_access(ihp,
219*10516SEric.Schrock@Sun.COM channel, i)) == NULL)
2205345Seschrock return (-1);
2215345Seschrock
2226070Srobj if ((uip = ipmi_zalloc(ihp, sizeof (ipmi_user_impl_t))) == NULL)
2235345Seschrock return (-1);
2245345Seschrock
2256070Srobj up = &uip->iu_user;
2266070Srobj
2275345Seschrock up->iu_enabled = resp->igua_enabled_uid;
2285345Seschrock up->iu_uid = i;
2295345Seschrock up->iu_ipmi_msg_enable = resp->igua_ipmi_msg_enable;
2305345Seschrock up->iu_link_auth_enable = resp->igua_link_auth_enable;
2315345Seschrock up->iu_priv = resp->igua_privilege_level;
2326070Srobj
2336070Srobj ipmi_list_append(&ihp->ih_users, uip);
2345345Seschrock
235*10516SEric.Schrock@Sun.COM /*
236*10516SEric.Schrock@Sun.COM * If we are requesting a username that doesn't have a
237*10516SEric.Schrock@Sun.COM * supported username, we may get an INVALID REQUEST response.
238*10516SEric.Schrock@Sun.COM * If this is the case, then continue as if there is no known
239*10516SEric.Schrock@Sun.COM * username.
240*10516SEric.Schrock@Sun.COM */
241*10516SEric.Schrock@Sun.COM if ((name = ipmi_get_user_name(ihp, i)) == NULL) {
242*10516SEric.Schrock@Sun.COM if (ipmi_errno(ihp) == EIPMI_INVALID_REQUEST)
243*10516SEric.Schrock@Sun.COM continue;
244*10516SEric.Schrock@Sun.COM else
245*10516SEric.Schrock@Sun.COM return (-1);
246*10516SEric.Schrock@Sun.COM }
2475345Seschrock
248*10516SEric.Schrock@Sun.COM if (*name == '\0')
249*10516SEric.Schrock@Sun.COM continue;
250*10516SEric.Schrock@Sun.COM
251*10516SEric.Schrock@Sun.COM if ((up->iu_name = ipmi_strdup(ihp, name)) == NULL)
2525345Seschrock return (-1);
2535345Seschrock }
2545345Seschrock
2556070Srobj for (uip = ipmi_list_next(&ihp->ih_users); uip != NULL;
2566070Srobj uip = ipmi_list_next(uip)) {
2576070Srobj if (func(&uip->iu_user, data) != 0)
2585345Seschrock return (-1);
2595345Seschrock }
2605345Seschrock
2615345Seschrock return (0);
2625345Seschrock }
2635345Seschrock
2645345Seschrock typedef struct ipmi_user_cb {
2655345Seschrock const char *uic_name;
2665345Seschrock uint8_t uic_uid;
2675345Seschrock ipmi_user_t *uic_result;
2685345Seschrock } ipmi_user_cb_t;
2695345Seschrock
2705345Seschrock static int
ipmi_user_callback(ipmi_user_t * up,void * data)2715345Seschrock ipmi_user_callback(ipmi_user_t *up, void *data)
2725345Seschrock {
2735345Seschrock ipmi_user_cb_t *cbp = data;
2745345Seschrock
2755345Seschrock if (cbp->uic_result != NULL)
2765345Seschrock return (0);
2775345Seschrock
2785345Seschrock if (up->iu_name) {
2795345Seschrock if (strcmp(up->iu_name, cbp->uic_name) == 0)
2805345Seschrock cbp->uic_result = up;
2815345Seschrock } else if (up->iu_uid == cbp->uic_uid) {
2825345Seschrock cbp->uic_result = up;
2835345Seschrock }
2845345Seschrock
2855345Seschrock return (0);
2865345Seschrock }
2875345Seschrock
2885345Seschrock ipmi_user_t *
ipmi_user_lookup_name(ipmi_handle_t * ihp,const char * name)2895345Seschrock ipmi_user_lookup_name(ipmi_handle_t *ihp, const char *name)
2905345Seschrock {
2915345Seschrock ipmi_user_cb_t cb = { 0 };
2925345Seschrock
2935345Seschrock cb.uic_name = name;
2945345Seschrock cb.uic_result = NULL;
2955345Seschrock
2965345Seschrock if (ipmi_user_iter(ihp, ipmi_user_callback, &cb) != 0)
2975345Seschrock return (NULL);
2985345Seschrock
2995345Seschrock if (cb.uic_result == NULL)
3005345Seschrock (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT,
3015345Seschrock "no such user");
3025345Seschrock
3035345Seschrock return (cb.uic_result);
3045345Seschrock }
3055345Seschrock
3065345Seschrock ipmi_user_t *
ipmi_user_lookup_id(ipmi_handle_t * ihp,uint8_t uid)3075345Seschrock ipmi_user_lookup_id(ipmi_handle_t *ihp, uint8_t uid)
3085345Seschrock {
3095345Seschrock ipmi_user_cb_t cb = { 0 };
3105345Seschrock
3115345Seschrock cb.uic_uid = uid;
3125345Seschrock cb.uic_result = NULL;
3135345Seschrock
3145345Seschrock if (ipmi_user_iter(ihp, ipmi_user_callback, &cb) != 0)
3155345Seschrock return (NULL);
3165345Seschrock
3175345Seschrock if (cb.uic_result == NULL)
3185345Seschrock (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT,
3195345Seschrock "no such user");
3205345Seschrock
3215345Seschrock return (cb.uic_result);
3225345Seschrock }
3235345Seschrock
3245345Seschrock int
ipmi_user_set_password(ipmi_handle_t * ihp,uint8_t uid,const char * passwd)3255345Seschrock ipmi_user_set_password(ipmi_handle_t *ihp, uint8_t uid, const char *passwd)
3265345Seschrock {
3275345Seschrock ipmi_set_user_password_t req = { 0 };
3285345Seschrock ipmi_cmd_t cmd;
3295345Seschrock
3305345Seschrock req.isup_uid = uid;
3315345Seschrock req.isup_op = IPMI_PASSWORD_OP_SET;
3325345Seschrock
3335345Seschrock if (strlen(passwd) > 19)
3345345Seschrock return (ipmi_set_error(ihp, EIPMI_INVALID_REQUEST,
3355345Seschrock "password length must be less than 20 characters"));
3365345Seschrock
3375345Seschrock if (strlen(passwd) > 15)
3385345Seschrock req.isup_len20 = 1;
3395345Seschrock
3405345Seschrock (void) strcpy(req.isup_passwd, passwd);
3415345Seschrock
3425345Seschrock cmd.ic_netfn = IPMI_NETFN_APP;
3435345Seschrock cmd.ic_cmd = IPMI_CMD_SET_USER_PASSWORD;
3445345Seschrock cmd.ic_lun = 0;
3455345Seschrock cmd.ic_data = &req;
3465345Seschrock if (req.isup_len20)
3475345Seschrock cmd.ic_dlen = sizeof (req);
3485345Seschrock else
3495345Seschrock cmd.ic_dlen = sizeof (req) - 4;
3505345Seschrock
3515345Seschrock if (ipmi_send(ihp, &cmd) == NULL)
3525345Seschrock return (-1);
3535345Seschrock
3545345Seschrock return (0);
3555345Seschrock }
356