int32_t 
Fiid_obj_get_data(fiid_obj_t obj, char *field, uint8_t *data, uint32_t data_len)
{
  int32_t rv;

  assert(fiid_obj_valid(obj) && field && data && data_len);

  if ((rv = fiid_obj_get_data(obj, field, data, data_len)) < 0)
    ierr_exit("Fiid_obj_get_data: field=%s: %s", field, fiid_strerror(fiid_obj_errnum(obj)));

  return rv;
}
int
ipmi_oem_get_system_info_string (ipmi_oem_state_data_t *state_data,
				 uint8_t parameter_selector,
				 uint8_t set_selector,
				 uint8_t block_selector,
				 char *string,
				 unsigned int string_len,
				 unsigned int *string_len_ret)
{
  fiid_obj_t obj_cmd_rs = NULL;
  uint8_t configuration_parameter_data[IPMI_OEM_MAX_BYTES];
  int len;
  int rv = -1;

  assert (state_data);
  assert (string);
  assert (string_len);

  if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_get_system_info_parameters_rs)))
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "fiid_obj_create: %s\n",
                       strerror (errno));
      goto cleanup;
    }

  if (ipmi_cmd_get_system_info_parameters (state_data->ipmi_ctx,
                                           IPMI_GET_SYSTEM_INFO_PARAMETER,
                                           parameter_selector,
					   set_selector,
					   block_selector,
                                           obj_cmd_rs) < 0)
    {
      if ((ipmi_ctx_errnum (state_data->ipmi_ctx) == IPMI_ERR_BAD_COMPLETION_CODE
	   && ipmi_check_completion_code (obj_cmd_rs,
					  IPMI_COMP_CODE_GET_SYSTEM_INFO_PARAMETERS_PARAMETER_NOT_SUPPORTED) == 1)
	  || (ipmi_ctx_errnum (state_data->ipmi_ctx) == IPMI_ERR_COMMAND_INVALID_OR_UNSUPPORTED
	      && ipmi_check_completion_code (obj_cmd_rs,
					     IPMI_COMP_CODE_INVALID_DATA_FIELD_IN_REQUEST) == 1))
	{
	  pstdout_fprintf (state_data->pstate,
			   stderr,
			   "%s:%s '%s' option not supported on this system\n",
			   state_data->prog_data->args->oem_id,
			   state_data->prog_data->args->oem_command,
			   state_data->prog_data->args->oem_options[0]);
	  goto cleanup;
	}
      
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "ipmi_cmd_get_system_info_parameters: %s\n",
                       ipmi_ctx_errormsg (state_data->ipmi_ctx));
      goto cleanup;
    }

  if ((len = fiid_obj_get_data (obj_cmd_rs,
                                "configuration_parameter_data",
                                configuration_parameter_data,
                                IPMI_OEM_MAX_BYTES)) < 0)
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "fiid_obj_get_data: 'configuration_parameter_data': %s\n",
                       fiid_obj_errormsg (obj_cmd_rs));
      goto cleanup;
    }

  if (len > string_len)
    {
      pstdout_fprintf (state_data->pstate,
		       stderr,
		       "buffer overflow\n");
      goto cleanup;
    }
  
  memcpy (string,
	  &(configuration_parameter_data[0]),
	  len);

  if (string_len_ret)
    (*string_len_ret) = len;

  rv = 0;
 cleanup:
  fiid_obj_destroy (obj_cmd_rs);
  return (rv);
}
static config_err_t
community_string_checkout (const char *section_name,
                           struct config_keyvalue *kv,
                           void *arg)
{
  ipmi_pef_config_state_data_t *state_data;
  char community_string[IPMI_MAX_COMMUNITY_STRING_LENGTH+1] = { 0, };
  fiid_obj_t obj_cmd_rs = NULL;
  config_err_t rv = CONFIG_ERR_FATAL_ERROR;
  config_err_t ret;
  uint8_t channel_number;

  assert (section_name);
  assert (kv);
  assert (arg);
  
  state_data = (ipmi_pef_config_state_data_t *)arg;

  if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_get_lan_configuration_parameters_community_string_rs)))
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "fiid_obj_create: %s\n",
                       strerror (errno));
      goto cleanup;
    }

  if ((ret = get_lan_channel_number (state_data, section_name, &channel_number)) != CONFIG_ERR_SUCCESS)
    {
      rv = ret;
      goto cleanup;
    }

  if (ipmi_cmd_get_lan_configuration_parameters_community_string (state_data->ipmi_ctx,
                                                                  channel_number,
                                                                  IPMI_GET_LAN_PARAMETER,
                                                                  IPMI_PEF_CONFIGURATION_PARAMETERS_NO_SET_SELECTOR,
                                                                  IPMI_PEF_CONFIGURATION_PARAMETERS_NO_BLOCK_SELECTOR,
                                                                  obj_cmd_rs) < 0)
    {
      if (state_data->prog_data->args->config_args.common_args.debug)
        pstdout_fprintf (state_data->pstate,
                         stderr,
                         "ipmi_cmd_get_lan_configuration_parameters_community_string: %s\n",
                         ipmi_ctx_errormsg (state_data->ipmi_ctx));

      if (config_is_config_param_non_fatal_error (state_data->ipmi_ctx,
                                                  obj_cmd_rs,
                                                  &ret))
        rv = ret;

      goto cleanup;
    }

  memset (community_string,'\0', IPMI_MAX_COMMUNITY_STRING_LENGTH+1);
  if (fiid_obj_get_data (obj_cmd_rs,
                         "community_string",
                         community_string,
                         IPMI_MAX_COMMUNITY_STRING_LENGTH+1) < 0)
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "fiid_obj_get_data: 'obj_cmd_rs': %s\n",
                       fiid_obj_errormsg (obj_cmd_rs));
      goto cleanup;
    }

  if (config_section_update_keyvalue_output (state_data->pstate,
                                             kv,
                                             community_string) < 0)
    return (CONFIG_ERR_FATAL_ERROR);

  rv = CONFIG_ERR_SUCCESS;
 cleanup:
  fiid_obj_destroy (obj_cmd_rs);
  return (rv);
}
int
ipmiconsole_check_rakp_4_integrity_check_value (ipmiconsole_ctx_t c, ipmiconsole_packet_type_t p)
{
    uint8_t managed_system_guid[IPMI_MANAGED_SYSTEM_GUID_LENGTH];
    int managed_system_guid_len;
    uint32_t managed_system_session_id;
    uint8_t authentication_algorithm = 0;
    uint64_t val;
    int rv;

    assert (c);
    assert (c->magic == IPMICONSOLE_CTX_MAGIC);
    assert (p == IPMICONSOLE_PACKET_TYPE_RAKP_MESSAGE_4);

    /* IPMI Workaround
     *
     * Intel IPMI 2.0 implementations respond with the integrity check
     * value based on the integrity algorithm rather than the
     * authentication algorithm.
     */
    if (c->config.workaround_flags & IPMICONSOLE_WORKAROUND_INTEL_2_0_SESSION)
    {
        if (c->config.integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_NONE)
            authentication_algorithm = IPMI_AUTHENTICATION_ALGORITHM_RAKP_NONE;
        else if (c->config.integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_HMAC_SHA1_96)
            authentication_algorithm = IPMI_AUTHENTICATION_ALGORITHM_RAKP_HMAC_SHA1;
        else if (c->config.integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_HMAC_MD5_128)
            authentication_algorithm = IPMI_AUTHENTICATION_ALGORITHM_RAKP_HMAC_MD5;
        else if (c->config.integrity_algorithm == IPMI_INTEGRITY_ALGORITHM_MD5_128)
        {
            /* achu: I have thus far been unable to reverse engineer this
             * corner case.  Since we cannot provide a reasonable two
             * part authentication, we're going to error out.
             */
            IPMICONSOLE_CTX_DEBUG (c, ("Intel Non-Compliance: Cannot Reverse Engineer"));
            ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_BMC_ERROR);
            return (0);
        }
    }
    else
        authentication_algorithm = c->config.authentication_algorithm;

    if (FIID_OBJ_GET (c->connection.obj_open_session_response,
                      "managed_system_session_id",
                      &val) < 0)
    {
        IPMICONSOLE_CTX_DEBUG (c, ("FIID_OBJ_GET: 'managed_system_session_id': %s",
                                   fiid_obj_errormsg (c->connection.obj_open_session_response)));
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
        return (-1);
    }
    managed_system_session_id = val;

    if ((managed_system_guid_len = fiid_obj_get_data (c->connection.obj_rakp_message_2,
                                   "managed_system_guid",
                                   managed_system_guid,
                                   IPMI_MANAGED_SYSTEM_RANDOM_NUMBER_LENGTH)) < 0)
    {
        IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_get_data: 'managed_system_guid': %s",
                                   fiid_obj_errormsg (c->connection.obj_rakp_message_2)));
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
        return (-1);
    }

    if (managed_system_guid_len != IPMI_MANAGED_SYSTEM_GUID_LENGTH)
    {
        IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_get_data: invalid managed system guid length: %d",
                                   managed_system_guid_len));
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
        return (-1);
    }

    /* IPMI Workaround (achu)
     *
     * Discovered on Supermicro X8DTG, Supermicro X8DTU, Intel
     * S5500WBV/Penguin Relion 700
     *
     * For whatever reason, with cipher suite 0, the RAKP 4 response
     * returns with an Integrity Check Value when it should be empty.
     */

    if (c->config.workaround_flags & IPMICONSOLE_WORKAROUND_NON_EMPTY_INTEGRITY_CHECK_VALUE
            && !c->config.cipher_suite_id)
    {
        if (fiid_obj_clear_field (c->connection.obj_rakp_message_4,
                                  "integrity_check_value") < 0)
        {
            IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_clear_field: 'integrity_check_value': %s",
                                       fiid_obj_errormsg (c->connection.obj_rakp_message_4)));
            ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
            return (-1);
        }
    }

    if ((rv = ipmi_rmcpplus_check_rakp_4_integrity_check_value (authentication_algorithm,
              c->session.sik_key_ptr,
              c->session.sik_key_len,
              c->session.remote_console_random_number,
              IPMI_REMOTE_CONSOLE_RANDOM_NUMBER_LENGTH,
              managed_system_session_id,
              managed_system_guid,
              managed_system_guid_len,
              c->connection.obj_rakp_message_4)) < 0)
    {
        IPMICONSOLE_CTX_DEBUG (c, ("ipmi_rmcpplus_check_rakp_4_integrity_check_value: p = %d; %s", p, strerror (errno)));
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
        return (-1);
    }

    if (!rv)
        IPMICONSOLE_CTX_DEBUG (c, ("rakp 4 integrity check value check failed; p = %d", p));

    return (rv);
}
int
assemble_ipmi_lan_pkt (fiid_obj_t obj_rmcp_hdr,
                       fiid_obj_t obj_lan_session_hdr,
                       fiid_obj_t obj_lan_msg_hdr,
                       fiid_obj_t obj_cmd,
                       const void *authentication_code_data,
                       unsigned int authentication_code_data_len,
                       void *pkt,
                       unsigned int pkt_len,
		       unsigned int flags)
{
  uint8_t authentication_type;
  uint64_t val;
  unsigned int indx = 0;
  int required_len;
  void *authentication_code_field_ptr = NULL;
  void *checksum_data_ptr = NULL;
  void *msg_data_ptr = NULL;
  void *ipmi_msg_len_ptr = NULL;
  unsigned int msg_data_count = 0;
  unsigned int checksum_data_count = 0;
  uint8_t ipmi_msg_len;
  fiid_obj_t obj_lan_msg_trlr = NULL;
  uint8_t pwbuf[IPMI_1_5_MAX_PASSWORD_LENGTH];
  uint8_t checksum;
  int len, rv = -1;
  unsigned int flags_mask = 0;

  if (!fiid_obj_valid (obj_rmcp_hdr)
      || !fiid_obj_valid (obj_lan_session_hdr)
      || !fiid_obj_valid (obj_lan_msg_hdr)
      || !fiid_obj_valid (obj_cmd)
      || (authentication_code_data && authentication_code_data_len > IPMI_1_5_MAX_PASSWORD_LENGTH)
      || !pkt
      || (flags & ~flags_mask))
    {
      SET_ERRNO (EINVAL);
      return (-1);
    }

  if (FIID_OBJ_TEMPLATE_COMPARE (obj_rmcp_hdr, tmpl_rmcp_hdr) < 0)
    {
      ERRNO_TRACE (errno);
      return (-1);
    }
  if (FIID_OBJ_TEMPLATE_COMPARE (obj_lan_session_hdr, tmpl_lan_session_hdr) < 0)
    {
      ERRNO_TRACE (errno);
      return (-1);
    }
  if (FIID_OBJ_TEMPLATE_COMPARE (obj_lan_msg_hdr, tmpl_lan_msg_hdr_rq) < 0)
    {
      ERRNO_TRACE (errno);
      return (-1);
    }

  if (FIID_OBJ_PACKET_VALID (obj_rmcp_hdr) < 0)
    {
      FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcp_hdr);
      return (-1);
    }

  /*
   * ipmi_msg_len is calculated in this function, so we can't use
   * fiid_obj_packet_valid() on obj_lan_session_hdr b/c ipmi_msg_len
   * is probably not set yet.
   */

  if (FIID_OBJ_PACKET_VALID (obj_lan_msg_hdr) < 0)
    {
      FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_hdr);
      return (-1);
    }
  if (FIID_OBJ_PACKET_VALID (obj_cmd) < 0)
    {
      FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
      return (-1);
    }

  if (FIID_OBJ_GET (obj_lan_session_hdr,
                    "authentication_type",
                    &val) < 0)
    {
      ERRNO_TRACE (errno);
      return (-1);
    }
  authentication_type = val;

  if (authentication_type != IPMI_AUTHENTICATION_TYPE_NONE
      && authentication_type != IPMI_AUTHENTICATION_TYPE_MD2
      && authentication_type != IPMI_AUTHENTICATION_TYPE_MD5
      && authentication_type != IPMI_AUTHENTICATION_TYPE_STRAIGHT_PASSWORD_KEY)
    {
      SET_ERRNO (EINVAL);
      return (-1);
    }

  /* no need for overflow checks, handled w/ _ipmi_lan_pkt_rq_min_size check */

  required_len = _ipmi_lan_pkt_rq_min_size (authentication_type, obj_cmd);
  if (pkt_len < required_len)
    {
      SET_ERRNO (EMSGSIZE);
      return (-1);
    }

  memset (pkt, 0, pkt_len);

  if ((len = fiid_obj_get_all (obj_rmcp_hdr, pkt + indx, pkt_len - indx)) < 0)
    {
      FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcp_hdr);
      goto cleanup;
    }
  indx += len;

  if ((len = fiid_obj_get_block (obj_lan_session_hdr,
                                 "authentication_type",
                                 "session_id",
                                 pkt + indx,
                                 pkt_len - indx)) < 0)
    {
      FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_session_hdr);
      goto cleanup;
    }

  indx += len;

  /* authentication_code generated last.  Save pointers for later calculation */
  if (authentication_type != IPMI_AUTHENTICATION_TYPE_NONE)
    {
      authentication_code_field_ptr = (pkt + indx);
      indx += IPMI_1_5_MAX_PASSWORD_LENGTH;
    }

  ipmi_msg_len_ptr = (pkt + indx);
  if ((len = fiid_template_field_len_bytes (tmpl_lan_session_hdr, "ipmi_msg_len")) < 0)
    {
      ERRNO_TRACE (errno);
      goto cleanup;
    }
  if (len != 1)
    {
      SET_ERRNO (EINVAL);
      goto cleanup;
    }
  indx += len;

  msg_data_ptr = (pkt + indx);

  if ((len = fiid_obj_get_block (obj_lan_msg_hdr,
                                 "rs_addr",
                                 "checksum1",
                                 pkt + indx,
                                 pkt_len - indx)) < 0)
    {
      FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_hdr);
      goto cleanup;
    }
  indx += len;
  msg_data_count += len;

  checksum_data_ptr = (pkt + indx);

  if ((len = fiid_obj_get_block (obj_lan_msg_hdr,
                                 "rq_addr",
                                 "rq_seq",
                                 pkt + indx,
                                 pkt_len - indx)) < 0)
    {
      FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_hdr);
      goto cleanup;
    }
  indx += len;
  msg_data_count += len;
  checksum_data_count += len;

  if ((len = fiid_obj_get_all (obj_cmd, pkt + indx, pkt_len - indx)) < 0)
    {
      FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
      goto cleanup;
    }
  indx += len;
  msg_data_count += len;
  checksum_data_count += len;

  if (!(obj_lan_msg_trlr = fiid_obj_create (tmpl_lan_msg_trlr)))
    {
      ERRNO_TRACE (errno);
      goto cleanup;
    }

  checksum = ipmi_checksum (checksum_data_ptr, checksum_data_count);

  if (fiid_obj_set_all (obj_lan_msg_trlr, &checksum, sizeof (checksum)) < 0)
    {
      FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_trlr);
      goto cleanup;
    }

  if ((len = fiid_obj_get_all (obj_lan_msg_trlr, pkt + indx, pkt_len - indx)) < 0)
    {
      FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_trlr);
      goto cleanup;
    }
  indx += len;
  msg_data_count += len;

  /* ipmi_msg_len done after message length is computed */
  ipmi_msg_len = msg_data_count;
  memcpy (ipmi_msg_len_ptr,
          &ipmi_msg_len,
          sizeof (ipmi_msg_len));

  /* Auth code must be done last, some authentication like md2 and md5
   * require all fields, including checksums, to be calculated
   * beforehand
   */
  if (authentication_type != IPMI_AUTHENTICATION_TYPE_NONE)
    {
      int authentication_len;

      memset (pwbuf, '\0', IPMI_1_5_MAX_PASSWORD_LENGTH);

      if ((authentication_len = fiid_obj_field_len_bytes (obj_lan_session_hdr,
                                                          "authentication_code")) < 0)
        {
          FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_session_hdr);
          goto cleanup;
        }

      if (authentication_len)
        {
          if (fiid_obj_get_data (obj_lan_session_hdr,
                                 "authentication_code",
                                 pwbuf,
                                 IPMI_1_5_MAX_PASSWORD_LENGTH) < 0)
            {
              FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_session_hdr);
              goto cleanup;
            }

          memcpy (authentication_code_field_ptr,
                  pwbuf,
                  IPMI_1_5_MAX_PASSWORD_LENGTH);
        }
      else
        {
          if (authentication_code_data)
            memcpy (pwbuf,
                    authentication_code_data,
                    authentication_code_data_len);

          if (authentication_type == IPMI_AUTHENTICATION_TYPE_STRAIGHT_PASSWORD_KEY)
            {
              memcpy (authentication_code_field_ptr,
                      pwbuf,
                      IPMI_1_5_MAX_PASSWORD_LENGTH);
            }
          else /* IPMI_AUTHENTICATION_TYPE_MD2 || IPMI_AUTHENTICATION_TYPE_MD5 */
            {
              uint8_t session_id_buf[1024];
              uint8_t session_sequence_number_buf[1024];
              int session_id_len, session_sequence_number_len;

              if ((session_id_len = fiid_obj_get_data (obj_lan_session_hdr,
                                                       "session_id",
                                                       session_id_buf,
                                                       1024)) < 0)
                {
                  FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_session_hdr);
                  goto cleanup;
                }

              if ((session_sequence_number_len = fiid_obj_get_data (obj_lan_session_hdr,
                                                                    "session_sequence_number",
                                                                    session_sequence_number_buf,
                                                                    1024)) < 0)
                {
                  FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_session_hdr);
                  goto cleanup;
                }

              if (authentication_type == IPMI_AUTHENTICATION_TYPE_MD2)
                {
                  md2_t ctx;
                  uint8_t digest[MD2_DIGEST_LENGTH];

                  assert (IPMI_1_5_MAX_PASSWORD_LENGTH == MD2_DIGEST_LENGTH);

                  md2_init (&ctx);
                  md2_update_data (&ctx, pwbuf, IPMI_1_5_MAX_PASSWORD_LENGTH);
                  md2_update_data (&ctx, session_id_buf, session_id_len);
                  md2_update_data (&ctx, msg_data_ptr, msg_data_count);
                  md2_update_data (&ctx, session_sequence_number_buf, session_sequence_number_len);
                  md2_update_data (&ctx, pwbuf, IPMI_1_5_MAX_PASSWORD_LENGTH);
                  md2_finish (&ctx, digest, MD2_DIGEST_LENGTH);
                  md2_init (&ctx);

                  memcpy (authentication_code_field_ptr, digest, IPMI_1_5_MAX_PASSWORD_LENGTH);
                  secure_memset (digest, '\0', MD2_DIGEST_LENGTH);
                }
              else if (authentication_type == IPMI_AUTHENTICATION_TYPE_MD5)
                {
                  md5_t ctx;
                  uint8_t digest[MD5_DIGEST_LENGTH];

                  assert (IPMI_1_5_MAX_PASSWORD_LENGTH == MD5_DIGEST_LENGTH);

                  md5_init (&ctx);
                  md5_update_data (&ctx, pwbuf, IPMI_1_5_MAX_PASSWORD_LENGTH);
                  md5_update_data (&ctx, session_id_buf, session_id_len);
                  md5_update_data (&ctx, msg_data_ptr, msg_data_count);
                  md5_update_data (&ctx, session_sequence_number_buf, session_sequence_number_len);
                  md5_update_data (&ctx, pwbuf, IPMI_1_5_MAX_PASSWORD_LENGTH);
                  md5_finish (&ctx, digest, MD5_DIGEST_LENGTH);
                  md5_init (&ctx);

                  memcpy (authentication_code_field_ptr, digest, IPMI_1_5_MAX_PASSWORD_LENGTH);
                  secure_memset (digest, '\0', MD5_DIGEST_LENGTH);
                }
            }
        }
    }

  if (indx > INT_MAX)
    {
      SET_ERRNO (EMSGSIZE);
      goto cleanup;
    }

  rv = indx;
 cleanup:
  if (rv < 0)
    secure_memset (pkt, '\0', pkt_len);
  fiid_obj_destroy (obj_lan_msg_trlr);
  secure_memset (pwbuf, '\0', IPMI_1_5_MAX_PASSWORD_LENGTH);
  return (rv);
}
int
ipmiconsole_check_rakp_2_key_exchange_authentication_code (ipmiconsole_ctx_t c, ipmiconsole_packet_type_t p)
{
    uint8_t managed_system_random_number[IPMI_MANAGED_SYSTEM_RANDOM_NUMBER_LENGTH];
    int managed_system_random_number_len;
    uint8_t managed_system_guid[IPMI_MANAGED_SYSTEM_GUID_LENGTH];
    int managed_system_guid_len;
    char username_buf[IPMI_MAX_USER_NAME_LENGTH+1];
    char *username;
    unsigned int username_len;
    char *password;
    unsigned int password_len;
    uint32_t managed_system_session_id;
    uint64_t val;
    int rv;

    assert (c);
    assert (c->magic == IPMICONSOLE_CTX_MAGIC);
    assert (p == IPMICONSOLE_PACKET_TYPE_RAKP_MESSAGE_2);

    /* IPMI Workaround
     *
     * Intel IPMI 2.0 implementations pad their usernames.
     */
    if (c->config.workaround_flags & IPMICONSOLE_WORKAROUND_INTEL_2_0_SESSION)
    {
        memset (username_buf, '\0', IPMI_MAX_USER_NAME_LENGTH+1);
        if (strlen (c->config.username))
            strcpy (username_buf, c->config.username);
        username = username_buf;
        username_len = IPMI_MAX_USER_NAME_LENGTH;
    }
    else
    {
        if (strlen (c->config.username))
            username = c->config.username;
        else
            username = NULL;
        username_len = (username) ? strlen (username) : 0;
    }

    /* IPMI Workaround
     *
     * Supermicro IPMI 2.0 implementations may have invalid payload lengths
     * on the RAKP response packet.
     */
    if (c->config.workaround_flags & IPMICONSOLE_WORKAROUND_SUPERMICRO_2_0_SESSION)
    {
        uint8_t keybuf[IPMICONSOLE_PACKET_BUFLEN];
        int keybuf_len;

        if ((keybuf_len = fiid_obj_get_data (c->connection.obj_rakp_message_2,
                                             "key_exchange_authentication_code",
                                             keybuf,
                                             IPMICONSOLE_PACKET_BUFLEN)) < 0)
        {
            IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_get_data: 'key_exchange_authentication_code': %s",
                                       fiid_obj_errormsg (c->connection.obj_rakp_message_2)));
            ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
            return (-1);
        }

        if (c->config.authentication_algorithm == IPMI_AUTHENTICATION_ALGORITHM_RAKP_NONE
                && keybuf_len == 1)
        {
            if (fiid_obj_clear_field (c->connection.obj_rakp_message_2,
                                      "key_exchange_authentication_code") < 0)
            {
                IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_clear_field: 'key_exchange_authentication_code': %s",
                                           fiid_obj_errormsg (c->connection.obj_rakp_message_2)));
                ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
                return (-1);
            }
        }
        else if (c->config.authentication_algorithm == IPMI_AUTHENTICATION_ALGORITHM_RAKP_HMAC_SHA1
                 && keybuf_len == (IPMI_HMAC_SHA1_DIGEST_LENGTH + 1))
        {
            if (fiid_obj_set_data (c->connection.obj_rakp_message_2,
                                   "key_exchange_authentication_code",
                                   keybuf,
                                   IPMI_HMAC_SHA1_DIGEST_LENGTH) < 0)
            {
                IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_set_data: 'key_exchange_authentication_code': %s",
                                           fiid_obj_errormsg (c->connection.obj_rakp_message_2)));
                ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
                return (-1);
            }
        }
        else if (c->config.authentication_algorithm == IPMI_AUTHENTICATION_ALGORITHM_RAKP_HMAC_MD5
                 && keybuf_len == (IPMI_HMAC_MD5_DIGEST_LENGTH + 1))
        {
            if (fiid_obj_set_data (c->connection.obj_rakp_message_2,
                                   "key_exchange_authentication_code",
                                   keybuf,
                                   IPMI_HMAC_MD5_DIGEST_LENGTH) < 0)
            {
                IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_set_data: 'key_exchange_authentication_code': %s",
                                           fiid_obj_errormsg (c->connection.obj_rakp_message_2)));
                ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
                return (-1);
            }
        }
    }

    if (strlen (c->config.password))
        password = c->config.password;
    else
        password = NULL;
    password_len = (password) ? strlen (password) : 0;

    /* IPMI Workaround
     *
     * Intel IPMI 2.0 implementations improperly calculate HMAC-MD5-128 hashes
     * when the passwords are > 16 bytes long.  The BMCs probably assume
     * all keys are <= 16 bytes in length.  So we have to adjust.
     */
    if (c->config.workaround_flags & IPMICONSOLE_WORKAROUND_INTEL_2_0_SESSION
            && c->config.authentication_algorithm == IPMI_AUTHENTICATION_ALGORITHM_RAKP_HMAC_MD5
            && password_len > IPMI_1_5_MAX_PASSWORD_LENGTH)
        password_len = IPMI_1_5_MAX_PASSWORD_LENGTH;

    /* IPMI Workaround
     *
     * Discovered on Sun Fire 4100.
     *
     * The key exchange authentication code is the wrong length.  We
     * need to shorten it.
     */
    if (c->config.workaround_flags & IPMICONSOLE_WORKAROUND_SUN_2_0_SESSION
            && c->config.authentication_algorithm == IPMI_AUTHENTICATION_ALGORITHM_RAKP_HMAC_SHA1)
    {
        uint8_t buf[IPMI_MAX_KEY_EXCHANGE_AUTHENTICATION_CODE_LENGTH];
        int buf_len;

        /* trace, but do not return potential error */

        if ((buf_len = fiid_obj_get_data (c->connection.obj_rakp_message_2,
                                          "key_exchange_authentication_code",
                                          buf,
                                          IPMI_MAX_KEY_EXCHANGE_AUTHENTICATION_CODE_LENGTH)) < 0)
            IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_get_data: 'key_exchange_authentication_code': %s",
                                       fiid_obj_errormsg (c->connection.obj_rakp_message_2)));

        if (buf_len == (IPMI_HMAC_SHA1_DIGEST_LENGTH + 1))
        {
            /* trace, but do not return potential error */

            if (fiid_obj_clear_field (c->connection.obj_rakp_message_2,
                                      "key_exchange_authentication_code") < 0)
                IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_clear_field: 'key_exchange_authentication_code': %s",
                                           fiid_obj_errormsg (c->connection.obj_rakp_message_2)));

            if (fiid_obj_set_data (c->connection.obj_rakp_message_2,
                                   "key_exchange_authentication_code",
                                   buf,
                                   IPMI_HMAC_SHA1_DIGEST_LENGTH) < 0)
                IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_set_data: 'key_exchange_authentication_code': %s",
                                           fiid_obj_errormsg (c->connection.obj_rakp_message_2)));
        }
    }


    if (FIID_OBJ_GET (c->connection.obj_open_session_response,
                      "managed_system_session_id",
                      &val) < 0)
    {
        IPMICONSOLE_CTX_DEBUG (c, ("FIID_OBJ_GET: 'managed_system_session_id': %s",
                                   fiid_obj_errormsg (c->connection.obj_open_session_response)));
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
        return (-1);
    }
    managed_system_session_id = val;

    if ((managed_system_random_number_len = fiid_obj_get_data (c->connection.obj_rakp_message_2,
                                            "managed_system_random_number",
                                            managed_system_random_number,
                                            IPMI_MANAGED_SYSTEM_RANDOM_NUMBER_LENGTH)) < 0)
    {
        IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_get_data: 'managed_system_random_number': %s",
                                   fiid_obj_errormsg (c->connection.obj_rakp_message_2)));
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
        return (-1);
    }

    if (managed_system_random_number_len != IPMI_MANAGED_SYSTEM_RANDOM_NUMBER_LENGTH)
    {
        IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_get_data: invalid managed system random number length: %d",
                                   managed_system_random_number_len));
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
        return (-1);
    }

    if ((managed_system_guid_len = fiid_obj_get_data (c->connection.obj_rakp_message_2,
                                   "managed_system_guid",
                                   managed_system_guid,
                                   IPMI_MANAGED_SYSTEM_GUID_LENGTH)) < 0)
    {
        IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_get_data: 'managed_system_guid': %s",
                                   fiid_obj_errormsg (c->connection.obj_rakp_message_2)));
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
        return (-1);
    }

    if (managed_system_guid_len != IPMI_MANAGED_SYSTEM_GUID_LENGTH)
    {
        IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_get_data: invalid managed system guid length: %d",
                                   managed_system_guid_len));
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
        return (-1);
    }

    if ((rv = ipmi_rmcpplus_check_rakp_2_key_exchange_authentication_code (c->config.authentication_algorithm,
              password,
              password_len,
              c->session.remote_console_session_id,
              managed_system_session_id,
              c->session.remote_console_random_number,
              IPMI_REMOTE_CONSOLE_RANDOM_NUMBER_LENGTH,
              managed_system_random_number,
              managed_system_random_number_len,
              managed_system_guid,
              managed_system_guid_len,
              c->session.name_only_lookup,
              c->config.privilege_level,
              username,
              username_len,
              c->connection.obj_rakp_message_2)) < 0)
    {
        IPMICONSOLE_CTX_DEBUG (c, ("ipmi_rmcpplus_check_rakp_2_key_exchange_authentication_code: p = %d; %s", p, strerror (errno)));
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
        return (-1);
    }

    if (!rv)
        IPMICONSOLE_CTX_DEBUG (c, ("rakp 2 key exchanged authentication code check failed; p = %d", p));

    return (rv);
}
static int
_sdr_cache_get_record (ipmi_sdr_ctx_t ctx,
                       ipmi_ctx_t ipmi_ctx,
                       uint16_t record_id,
                       void *record_buf,
                       unsigned int record_buf_len,
                       uint16_t *reservation_id,
                       uint16_t *next_record_id)
{
    fiid_obj_t obj_cmd_rs = NULL;
    fiid_obj_t obj_sdr_record_header = NULL;
    int sdr_record_header_length = 0;
    int sdr_record_len = 0;
    unsigned int record_length = 0;
    int rv = -1;
    unsigned int bytes_to_read = IPMI_SDR_CACHE_BYTES_TO_READ_START;
    unsigned int offset_into_record = 0;
    unsigned int reservation_id_retry_count = 0;
    uint8_t temp_record_buf[IPMI_SDR_MAX_RECORD_LENGTH];
    uint64_t val;

    assert (ctx);
    assert (ctx->magic == IPMI_SDR_CTX_MAGIC);
    assert (ipmi_ctx);
    assert (record_buf);
    assert (record_buf_len);
    assert (reservation_id);
    assert (next_record_id);

    if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_get_sdr_rs)))
    {
        SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
        goto cleanup;
    }

    if (!(obj_sdr_record_header = fiid_obj_create (tmpl_sdr_record_header)))
    {
        SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
        goto cleanup;
    }

    if ((sdr_record_header_length = fiid_template_len_bytes (tmpl_sdr_record_header)) < 0)
    {
        SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
        goto cleanup;
    }

    /* achu:
     *
     * Many motherboards now allow you to read the full SDR record, try
     * that first.  If it fails for any reason, bail and try to read via
     * partial reads.
     */

    reservation_id_retry_count = 0;
    while (!offset_into_record)
    {
        if (ipmi_cmd_get_sdr (ipmi_ctx,
                              *reservation_id,
                              record_id,
                              0,
                              IPMI_SDR_READ_ENTIRE_RECORD_BYTES_TO_READ,
                              obj_cmd_rs) < 0)
        {
            if (ipmi_ctx_errnum (ipmi_ctx) == IPMI_ERR_BAD_COMPLETION_CODE)
            {
                uint8_t comp_code;

                if (FIID_OBJ_GET (obj_cmd_rs,
                                  "comp_code",
                                  &val) < 0)
                {
                    SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_cmd_rs);
                    goto cleanup;
                }
                comp_code = val;

                if (comp_code == IPMI_COMP_CODE_RESERVATION_CANCELLED
                        && (reservation_id_retry_count < IPMI_SDR_CACHE_MAX_RESERVATION_ID_RETRY))
                {
                    if (_sdr_cache_reservation_id (ctx,
                                                   ipmi_ctx,
                                                   reservation_id) < 0)
                        goto cleanup;
                    reservation_id_retry_count++;
                    continue;
                }
            }

            goto partial_read;
        }

        if ((sdr_record_len = fiid_obj_get_data (obj_cmd_rs,
                              "record_data",
                              temp_record_buf,
                              IPMI_SDR_MAX_RECORD_LENGTH)) < 0)
        {
            SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_cmd_rs);
            goto cleanup;
        }

        /* Assume this is an "IPMI Error", fall through to partial reads */
        if (sdr_record_len < sdr_record_header_length)
            goto partial_read;

        /*
         * IPMI Workaround (achu)
         *
         * Discovered on Xyratex HB-F8-SRAY
         *
         * For some reason reading the entire SDR record (with
         * IPMI_SDR_READ_ENTIRE_RECORD_BYTES_TO_READ) the response
         * returns fewer bytes than the actual length of the record.
         * However, when reading with partial reads things ultimately
         * succeed.  If we notice the length is off, we fall out and do
         * a partial read.
         */
        if ((((uint8_t)temp_record_buf[IPMI_SDR_RECORD_LENGTH_INDEX]) + IPMI_SDR_RECORD_HEADER_LENGTH) > sdr_record_len)
            goto partial_read;

        if (sdr_record_len > record_buf_len)
        {
            SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_INTERNAL_ERROR);
            goto cleanup;
        }

        if (FIID_OBJ_GET (obj_cmd_rs,
                          "next_record_id",
                          &val) < 0)
        {
            SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_cmd_rs);
            goto cleanup;
        }
        *next_record_id = val;

        memcpy (record_buf, temp_record_buf, sdr_record_len);
        offset_into_record += sdr_record_len;
        goto out;
    }

partial_read:

    reservation_id_retry_count = 0;
    while (!record_length)
    {
        uint8_t record_header_buf[IPMI_SDR_MAX_RECORD_LENGTH];
        int sdr_record_header_len;

        if (ipmi_cmd_get_sdr (ipmi_ctx,
                              *reservation_id,
                              record_id,
                              0,
                              sdr_record_header_length,
                              obj_cmd_rs) < 0)
        {
            if (ipmi_ctx_errnum (ipmi_ctx) != IPMI_ERR_BAD_COMPLETION_CODE)
            {
                SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_IPMI_ERROR);
                goto cleanup;
            }
            else
            {
                uint8_t comp_code;

                if (FIID_OBJ_GET (obj_cmd_rs,
                                  "comp_code",
                                  &val) < 0)
                {
                    SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_cmd_rs);
                    goto cleanup;
                }
                comp_code = val;

                if (comp_code == IPMI_COMP_CODE_RESERVATION_CANCELLED
                        && (reservation_id_retry_count < IPMI_SDR_CACHE_MAX_RESERVATION_ID_RETRY))
                {
                    if (_sdr_cache_reservation_id (ctx,
                                                   ipmi_ctx,
                                                   reservation_id) < 0)
                        goto cleanup;
                    reservation_id_retry_count++;
                    continue;
                }

                SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_IPMI_ERROR);
                goto cleanup;
            }
        }

        if ((sdr_record_header_len = fiid_obj_get_data (obj_cmd_rs,
                                     "record_data",
                                     record_header_buf,
                                     IPMI_SDR_MAX_RECORD_LENGTH)) < 0)
        {
            SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_cmd_rs);
            goto cleanup;
        }

        if (sdr_record_header_len < sdr_record_header_length)
        {
            SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_IPMI_ERROR);
            goto cleanup;
        }

        if (fiid_obj_set_all (obj_sdr_record_header,
                              record_header_buf,
                              sdr_record_header_len) < 0)
        {
            SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_sdr_record_header);
            goto cleanup;
        }

        if (FIID_OBJ_GET (obj_sdr_record_header,
                          "record_length",
                          &val) < 0)
        {
            SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_sdr_record_header);
            goto cleanup;
        }

        if (sdr_record_header_len > record_buf_len)
        {
            SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_INTERNAL_ERROR);
            goto cleanup;
        }

        /* copy header into buf */
        memcpy (record_buf, record_header_buf, sdr_record_header_len);
        offset_into_record += sdr_record_header_len;
        record_length = val + sdr_record_header_length;
    }

    if (record_length > record_buf_len)
    {
        SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_INTERNAL_ERROR);
        goto cleanup;
    }

    if (FIID_OBJ_GET (obj_cmd_rs,
                      "next_record_id",
                      &val) < 0)
    {
        SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_cmd_rs);
        goto cleanup;
    }
    *next_record_id = val;

    reservation_id_retry_count = 0;
    while (offset_into_record < record_length)
    {
        int record_data_len;

        if ((record_length - offset_into_record) < bytes_to_read)
            bytes_to_read = record_length - offset_into_record;

        if (ipmi_cmd_get_sdr (ipmi_ctx,
                              *reservation_id,
                              record_id,
                              offset_into_record,
                              bytes_to_read,
                              obj_cmd_rs) < 0)
        {
            if (ipmi_ctx_errnum (ipmi_ctx) != IPMI_ERR_BAD_COMPLETION_CODE)
            {
                SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_IPMI_ERROR);
                goto cleanup;
            }
            else
            {
                uint8_t comp_code;

                if (FIID_OBJ_GET (obj_cmd_rs,
                                  "comp_code",
                                  &val) < 0)
                {
                    SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_cmd_rs);
                    goto cleanup;
                }
                comp_code = val;

                if (comp_code == IPMI_COMP_CODE_RESERVATION_CANCELLED
                        && (reservation_id_retry_count < IPMI_SDR_CACHE_MAX_RESERVATION_ID_RETRY))
                {
                    if (_sdr_cache_reservation_id (ctx,
                                                   ipmi_ctx,
                                                   reservation_id) < 0)
                        goto cleanup;
                    reservation_id_retry_count++;
                    continue;
                }
                else if  ((comp_code == IPMI_COMP_CODE_CANNOT_RETURN_REQUESTED_NUMBER_OF_BYTES
                           || comp_code == IPMI_COMP_CODE_UNSPECIFIED_ERROR)
                          && bytes_to_read > sdr_record_header_length)
                {
                    bytes_to_read -= IPMI_SDR_CACHE_BYTES_TO_READ_DECREMENT;
                    if (bytes_to_read < sdr_record_header_length)
                        bytes_to_read = sdr_record_header_length;
                    continue;
                }

                SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_IPMI_ERROR);
                goto cleanup;
            }
        }

        if ((record_data_len = fiid_obj_get_data (obj_cmd_rs,
                               "record_data",
                               record_buf + offset_into_record,
                               record_buf_len - offset_into_record)) < 0)
        {
            SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_cmd_rs);
            goto cleanup;
        }

        offset_into_record += record_data_len;
    }

out:
    rv = offset_into_record;
cleanup:
    fiid_obj_destroy (obj_cmd_rs);
    fiid_obj_destroy (obj_sdr_record_header);
    return (rv);
}
static int
_api_ssif_ipmb_recv (ipmi_ctx_t ctx,
		     fiid_obj_t obj_ipmb_msg_hdr_rs,
		     fiid_obj_t obj_ipmb_msg_trlr,
		     fiid_obj_t obj_cmd_rs)
{
  struct ipmi_ctx_target target_save;
  uint8_t buf[IPMI_MAX_PKT_LEN];
  fiid_obj_t obj_ipmb_msg_rs = NULL;
  fiid_obj_t obj_get_cmd_rs = NULL;
  int len, ret, rv = -1;
  unsigned int intf_flags = IPMI_INTERFACE_FLAGS_DEFAULT;

  assert (ctx
          && ctx->magic == IPMI_CTX_MAGIC
          && ctx->type == IPMI_DEVICE_SSIF
          && fiid_obj_valid (obj_ipmb_msg_hdr_rs)
          && fiid_obj_valid (obj_ipmb_msg_trlr)
          && fiid_obj_valid (obj_cmd_rs));

  if (ctx->flags & IPMI_FLAGS_NO_LEGAL_CHECK)
    intf_flags |= IPMI_INTERFACE_FLAGS_NO_LEGAL_CHECK;

  if (!(obj_ipmb_msg_rs = fiid_obj_create (tmpl_ipmb_msg)))
    {
      API_ERRNO_TO_API_ERRNUM (ctx, errno);
      goto cleanup;
    }
  if (!(obj_get_cmd_rs = fiid_obj_create (tmpl_cmd_get_message_rs)))
    {
      API_ERRNO_TO_API_ERRNUM (ctx, errno);
      goto cleanup;
    }
  
  /* get_message will send to the BMC, so clear out target information */
  memcpy (&target_save, &ctx->target, sizeof (target_save));
  ctx->target.channel_number_is_set = 0;
  ctx->target.rs_addr_is_set = 0;
  
  ret = ipmi_cmd_get_message (ctx, obj_get_cmd_rs);

  /* restore target info */
  memcpy (&ctx->target, &target_save, sizeof (target_save));

  if (ret < 0)
    {
      if (ipmi_check_completion_code (obj_get_cmd_rs, IPMI_COMP_CODE_GET_MESSAGE_DATA_NOT_AVAILABLE) == 1)
        API_SET_ERRNUM (ctx, IPMI_ERR_MESSAGE_TIMEOUT);
      else
        API_BAD_RESPONSE_TO_API_ERRNUM (ctx, obj_get_cmd_rs);
      goto cleanup;
    }

  if ((len = fiid_obj_get_data (obj_get_cmd_rs,
                                "message_data",
                                buf,
                                IPMI_MAX_PKT_LEN)) < 0)
    {
      API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_get_cmd_rs);
      goto cleanup;
    }

  if (fiid_obj_set_all (obj_ipmb_msg_rs,
                        buf,
                        len) < 0)
    {
      API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_ipmb_msg_rs);
      goto cleanup;
    }

  if (unassemble_ipmi_ipmb_msg (obj_ipmb_msg_rs,
                                obj_ipmb_msg_hdr_rs,
                                obj_cmd_rs,
                                obj_ipmb_msg_trlr,
				intf_flags) < 0)
    {
      API_ERRNO_TO_API_ERRNUM (ctx, errno);
      goto cleanup;
    }

  rv = 0;
 cleanup:
  fiid_obj_destroy (obj_ipmb_msg_rs);
  fiid_obj_destroy (obj_get_cmd_rs);
  return (rv);
}
static ipmi_config_err_t
_get_key (ipmi_config_state_data_t *state_data,
          const char *section_name,
          uint8_t key_type,
          void *key,
          unsigned int key_len)
{
  fiid_obj_t obj_cmd_rs = NULL;
  uint8_t buf[IPMI_CONFIG_PARSE_BUFLEN];
  int buf_len;
  ipmi_config_err_t rv = IPMI_CONFIG_ERR_FATAL_ERROR;
  ipmi_config_err_t ret;
  uint8_t channel_number;

  assert (state_data);
  assert (section_name);
  assert (key_type == IPMI_CHANNEL_SECURITY_KEYS_KEY_ID_K_R
          || key_type == IPMI_CHANNEL_SECURITY_KEYS_KEY_ID_K_G);
  assert (key);
  assert (key_len);

  if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_set_channel_security_keys_rs)))
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "fiid_obj_create: %s\n",
                       strerror (errno));
      goto cleanup;
    }

  if ((ret = get_lan_channel_number (state_data, section_name, &channel_number)) != IPMI_CONFIG_ERR_SUCCESS)
    {
      rv = ret;
      goto cleanup;
    }

  if (ipmi_cmd_set_channel_security_keys (state_data->ipmi_ctx,
                                          channel_number,
                                          IPMI_CHANNEL_SECURITY_KEYS_OPERATION_READ_KEY,
                                          key_type,
                                          NULL,
                                          0,
                                          obj_cmd_rs) < 0)
    {
      if (!IPMI_CTX_ERRNUM_IS_FATAL_ERROR (state_data->ipmi_ctx))
        rv = IPMI_CONFIG_ERR_NON_FATAL_ERROR;

      if (rv == IPMI_CONFIG_ERR_FATAL_ERROR
	  || state_data->prog_data->args->common_args.debug)
        pstdout_fprintf (state_data->pstate,
                         stderr,
                         "ipmi_cmd_set_channel_security_keys: %s\n",
                         ipmi_ctx_errormsg (state_data->ipmi_ctx));

      goto cleanup;
    }

  if ((buf_len = fiid_obj_get_data (obj_cmd_rs,
                                    "key_value",
                                    buf,
                                    IPMI_CONFIG_PARSE_BUFLEN)) < 0)
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "fiid_obj_get_data: 'key_value': %s\n",
                       fiid_obj_errormsg (obj_cmd_rs));
      goto cleanup;
    }

  if (key_len < buf_len)
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "ipmi_cmd_set_channel_security_keys: short buffer\n");
      goto cleanup;
    }
  memcpy (key, buf, buf_len);

  rv = IPMI_CONFIG_ERR_SUCCESS;
 cleanup:
  fiid_obj_destroy (obj_cmd_rs);
  return (rv);
}
static ipmi_config_err_t
asset_tag_checkout (ipmi_config_state_data_t *state_data,
                    const char *section_name,
                    struct ipmi_config_keyvalue *kv)
{
  fiid_obj_t obj_cmd_rs = NULL;
  char asset_tag_data[IPMI_DCMI_MAX_ASSET_TAG_LENGTH + 1];
  int data_len;
  unsigned int offset = 0;
  uint8_t total_asset_tag_length = 0;
  uint8_t bytes_to_read = IPMI_DCMI_ASSET_TAG_NUMBER_OF_BYTES_TO_READ_MAX;
  ipmi_config_err_t rv = IPMI_CONFIG_ERR_FATAL_ERROR;
  ipmi_config_err_t ret;

  assert (state_data);
  assert (section_name);
  assert (kv);

  if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_dcmi_get_asset_tag_rs)))
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "fiid_obj_create: %s\n",
                       strerror (errno));
      goto cleanup;
    }

  memset (asset_tag_data, '\0', IPMI_DCMI_MAX_ASSET_TAG_LENGTH + 1);

  while (1)
    {
      uint64_t val;

      if (!offset
          || ((total_asset_tag_length - offset) >= IPMI_DCMI_ASSET_TAG_NUMBER_OF_BYTES_TO_READ_MAX))
        bytes_to_read = IPMI_DCMI_ASSET_TAG_NUMBER_OF_BYTES_TO_READ_MAX;
      else 
        bytes_to_read = total_asset_tag_length - offset;
      
      if (ipmi_cmd_dcmi_get_asset_tag (state_data->ipmi_ctx,
                                       offset,
                                       bytes_to_read,
                                       obj_cmd_rs) < 0)
        {
          if (ipmi_config_param_errnum_is_non_fatal (state_data,
                                                     obj_cmd_rs,
                                                     &ret))
            rv = ret;

          if (rv == IPMI_CONFIG_ERR_FATAL_ERROR
              || state_data->prog_data->args->common_args.debug)
            pstdout_fprintf (state_data->pstate,
                             stderr,
                             "ipmi_cmd_dcmi_get_asset_tag: %s\n",
                             ipmi_ctx_errormsg (state_data->ipmi_ctx));
          
          goto cleanup;
        }

      if (FIID_OBJ_GET (obj_cmd_rs,
                        "total_asset_tag_length",
                        &val) < 0)
        {
          pstdout_fprintf (state_data->pstate,
                           stderr,
                           "fiid_obj_get: 'total_asset_tag_length': %s\n",
                           fiid_obj_errormsg (obj_cmd_rs));
          goto cleanup;
        }
      total_asset_tag_length = val;

      if (!total_asset_tag_length)
        break;

      if ((data_len = fiid_obj_get_data (obj_cmd_rs,
                                         "data",
                                         asset_tag_data + offset,
                                         IPMI_DCMI_MAX_ASSET_TAG_LENGTH - offset)) < 0)
        {
          pstdout_fprintf (state_data->pstate,
                           stderr,
                           "fiid_obj_get_data: 'data': %s\n",
                           fiid_obj_errormsg (obj_cmd_rs));
          goto cleanup;
        }
      offset += data_len;

      if (offset >= total_asset_tag_length)
        break;
    }

  /* Handle special case UTF-8 encoding w/ BOM prefix */
  if (asset_tag_data[0] == IPMI_DCMI_ASSET_TAG_UTF8_BOM_BYTE0
      && asset_tag_data[1] == IPMI_DCMI_ASSET_TAG_UTF8_BOM_BYTE1
      && asset_tag_data[2] == IPMI_DCMI_ASSET_TAG_UTF8_BOM_BYTE2)
    {
      /* achu: I think this is right for UTF-8 in libc and is
       * portable, but I would bet some systems won't like this.
       */
      if (ipmi_config_section_update_keyvalue_output (state_data,
                                                      kv,
                                                      &asset_tag_data[3]) < 0)
        return (IPMI_CONFIG_ERR_FATAL_ERROR);
    }
  else
    {
      if (ipmi_config_section_update_keyvalue_output (state_data,
                                                      kv,
                                                      asset_tag_data) < 0)
        return (IPMI_CONFIG_ERR_FATAL_ERROR);
    }

  rv = IPMI_CONFIG_ERR_SUCCESS;
 cleanup:
  fiid_obj_destroy (obj_cmd_rs);
  return (rv);
}
static ipmi_config_err_t
management_controller_identifier_string_checkout (ipmi_config_state_data_t *state_data,
                                                  const char *section_name,
                                                  struct ipmi_config_keyvalue *kv)
{
  fiid_obj_t obj_cmd_rs = NULL;
  char management_controller_identifier_string_data[IPMI_DCMI_MAX_MANAGEMENT_CONTROLLER_IDENTIFIER_STRING_LENGTH + 1];
  int data_len;
  unsigned int offset = 0;
  uint8_t total_length = 0;
  uint8_t bytes_to_read = IPMI_DCMI_MANAGEMENT_CONTROLLER_IDENTIFIER_STRING_NUMBER_OF_BYTES_TO_READ_MAX;
  ipmi_config_err_t rv = IPMI_CONFIG_ERR_FATAL_ERROR;
  ipmi_config_err_t ret;

  assert (state_data);
  assert (section_name);
  assert (kv);

  if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_dcmi_get_management_controller_identifier_string_rs)))
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "fiid_obj_create: %s\n",
                       strerror (errno));
      goto cleanup;
    }

  memset (management_controller_identifier_string_data, '\0', IPMI_DCMI_MAX_MANAGEMENT_CONTROLLER_IDENTIFIER_STRING_LENGTH + 1);

  while (1)
    {
      uint64_t val;

      if (!offset
          || ((total_length - offset) >= IPMI_DCMI_MANAGEMENT_CONTROLLER_IDENTIFIER_STRING_NUMBER_OF_BYTES_TO_READ_MAX))
        bytes_to_read = IPMI_DCMI_MANAGEMENT_CONTROLLER_IDENTIFIER_STRING_NUMBER_OF_BYTES_TO_READ_MAX;
      else 
        bytes_to_read = total_length - offset;
      
      if (ipmi_cmd_dcmi_get_management_controller_identifier_string (state_data->ipmi_ctx,
                                                                     offset,
                                                                     bytes_to_read,
                                                                     obj_cmd_rs) < 0)
        {
          if (ipmi_config_param_errnum_is_non_fatal (state_data,
                                                     obj_cmd_rs,
                                                     &ret))
            rv = ret;
          
          if (rv == IPMI_CONFIG_ERR_FATAL_ERROR
              || state_data->prog_data->args->common_args.debug)
            pstdout_fprintf (state_data->pstate,
                             stderr,
                             "ipmi_cmd_dcmi_get_management_controller_identifier_string: %s\n",
                             ipmi_ctx_errormsg (state_data->ipmi_ctx));

          goto cleanup;
        }
      
      if (FIID_OBJ_GET (obj_cmd_rs,
                        "total_length",
                        &val) < 0)
        {
          pstdout_fprintf (state_data->pstate,
                           stderr,
                           "fiid_obj_get: 'total_length': %s\n",
                           fiid_obj_errormsg (obj_cmd_rs));
          goto cleanup;
        }
      total_length = val;

      if (!total_length)
        break;

      if ((data_len = fiid_obj_get_data (obj_cmd_rs,
                                         "data",
                                         management_controller_identifier_string_data + offset,
                                         IPMI_DCMI_MAX_MANAGEMENT_CONTROLLER_IDENTIFIER_STRING_LENGTH - offset)) < 0)
        {
          pstdout_fprintf (state_data->pstate,
                           stderr,
                           "fiid_obj_get_data: 'data': %s\n",
                           fiid_obj_errormsg (obj_cmd_rs));
          goto cleanup;
        }
      offset += data_len;
      
      if (offset >= total_length)
        break;
    }
  
  if (ipmi_config_section_update_keyvalue_output (state_data,
                                                  kv,
                                                  management_controller_identifier_string_data) < 0)
        return (IPMI_CONFIG_ERR_FATAL_ERROR);

  rv = IPMI_CONFIG_ERR_SUCCESS;
 cleanup:
  fiid_obj_destroy (obj_cmd_rs);
  return (rv);
}