/*
 * Return 0 on success
 * Return -1 on fatal error
 */
static int
_console_write (ipmiconsole_ctx_t c)
{
  char buffer[IPMICONSOLE_PACKET_BUFLEN];
  ssize_t len;
  int n;

  assert (c);
  assert (c->magic == IPMICONSOLE_CTX_MAGIC);
  assert (!c->session.close_session_flag);

  /*
   * XXX: Shouldn't assume user will read data fast enough?  I could
   * overrun buffers?
   *
   * Deal with it later.
   */

  if ((n = scbuf_read (c->connection.console_bmc_to_remote_console, buffer, IPMICONSOLE_PACKET_BUFLEN)) < 0)
    {
      IPMICONSOLE_CTX_DEBUG (c, ("scbuf_read: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
      return (-1);
    }

  if ((len = write (c->connection.ipmiconsole_fd,
                    buffer,
                    n)) < 0)
    {
      IPMICONSOLE_CTX_DEBUG (c, ("write: %s", strerror (errno)));

      if (errno == EPIPE)
        {
          /* This error is ok since the user is allowed to close the
           * session
           */
          ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SUCCESS);
        }
      else
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR);
      return (-1);
    }

  if (len != n)
    {
      IPMICONSOLE_CTX_DEBUG (c, ("write: invalid bytes written; n=%d; len=%d", n, len));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
      return (-1);
    }

  /* scbuf should be empty now */
  if (!scbuf_is_empty (c->connection.console_bmc_to_remote_console))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("console_bmc_to_remote_console not empty"));
      /* Note: Not a fatal error, just return*/
      return (0);
    }

  return (0);
}
int
ipmiconsole_set_closeonexec (ipmiconsole_ctx_t c, int fd)
{
  int closeonexec;

  /* User need not pass in valid context for this function */

  if ((closeonexec = fcntl (fd, F_GETFD, 0)) < 0)
    {
      IPMICONSOLE_DEBUG (("fcntl: %s", strerror (errno)));
      if (c && c->magic == IPMICONSOLE_CTX_MAGIC)
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR);
      return (-1);
    }
  closeonexec |= FD_CLOEXEC;
  if (fcntl (fd, F_SETFD, closeonexec) < 0)
    {
      IPMICONSOLE_DEBUG (("fcntl: %s", strerror (errno)));
      if (c && c->magic == IPMICONSOLE_CTX_MAGIC)
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR);
      return (-1);
    }

  return (0);
}
/*
 * Return 0 on success
 * Return -1 on fatal error
 */
static int
_console_read (ipmiconsole_ctx_t c)
{
  char buffer[IPMICONSOLE_PACKET_BUFLEN];
  ssize_t len;
  int n, dropped = 0;
  int secure_malloc_flag;

  assert (c);
  assert (c->magic == IPMICONSOLE_CTX_MAGIC);
  assert (!c->session.close_session_flag);

  secure_malloc_flag = (c->config.engine_flags & IPMICONSOLE_ENGINE_LOCK_MEMORY) ? 1 : 0;

  if ((len = read (c->connection.ipmiconsole_fd,
                   buffer,
                   IPMICONSOLE_PACKET_BUFLEN)) < 0)
    {
      IPMICONSOLE_CTX_DEBUG (c, ("read: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR);
      return (-1);
    }

  if (!len)
    {
      /* Returning -1 closes the session, but really this error is ok
       * since the user is allowed to close the session
       */
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SUCCESS);
      return (-1);
    }

  if ((n = scbuf_write (c->connection.console_remote_console_to_bmc, buffer, len, &dropped, secure_malloc_flag)) < 0)
    {
      IPMICONSOLE_CTX_DEBUG (c, ("scbuf_write: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
      return (-1);
    }

  if (n != len)
    {
      IPMICONSOLE_CTX_DEBUG (c, ("scbuf_write: invalid bytes written; n=%d; len=%d", n, len));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
      return (-1);
    }

  if (dropped)
    {
      IPMICONSOLE_CTX_DEBUG (c, ("scbuf_write: dropped data: dropped=%d", dropped));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
      return (-1);
    }

  return (0);
}
int
ipmiconsole_check_open_session_response_privilege (ipmiconsole_ctx_t c, ipmiconsole_packet_type_t p)
{
    int rv;

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

    /* IPMI Workaround
     *
     * Intel IPMI 2.0 implementations don't support the highest level privilege.
     */
    if (c->config.workaround_flags & IPMICONSOLE_WORKAROUND_INTEL_2_0_SESSION)
    {
        uint8_t maximum_privilege_level;
        uint64_t val;

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

        rv = (maximum_privilege_level == c->config.privilege_level) ? 1 : 0;
    }
    else
    {
        if ((rv = ipmi_check_open_session_maximum_privilege (c->config.privilege_level,
                  c->connection.obj_open_session_response)) < 0)
        {
            IPMICONSOLE_CTX_DEBUG (c, ("ipmi_check_open_session_maximum_privilege: %s",
                                       strerror (errno)));
            ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
            return (-1);
        }
    }

    if (!rv)
        IPMICONSOLE_CTX_DEBUG (c, ("open session response privilege check failed; p = %d", p));

    return (rv);
}
int
ipmiconsole_check_network_function (ipmiconsole_ctx_t c, ipmiconsole_packet_type_t p)
{
    uint8_t netfn, expected_netfn;
    uint64_t val;

    assert (c);
    assert (c->magic == IPMICONSOLE_CTX_MAGIC);
    assert (IPMICONSOLE_PACKET_TYPE_RESPONSE (p));
    assert (p == IPMICONSOLE_PACKET_TYPE_GET_AUTHENTICATION_CAPABILITIES_RS
            || p == IPMICONSOLE_PACKET_TYPE_SET_SESSION_PRIVILEGE_LEVEL_RS
            || p == IPMICONSOLE_PACKET_TYPE_GET_CHANNEL_PAYLOAD_SUPPORT_RS
            || p == IPMICONSOLE_PACKET_TYPE_GET_PAYLOAD_ACTIVATION_STATUS_RS
            || p == IPMICONSOLE_PACKET_TYPE_ACTIVATE_PAYLOAD_RS
            || p == IPMICONSOLE_PACKET_TYPE_GET_CHANNEL_PAYLOAD_VERSION_RS
            || p == IPMICONSOLE_PACKET_TYPE_DEACTIVATE_PAYLOAD_RS
            || p == IPMICONSOLE_PACKET_TYPE_CLOSE_SESSION_RS);

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

    if (netfn != expected_netfn)
        IPMICONSOLE_CTX_DEBUG (c, ("network function check failed; p = %d; netfn = %Xh; expected_netfn = %Xh", p, netfn, expected_netfn));

    return ((netfn == expected_netfn) ? 1 : 0);
}
int
ipmiconsole_check_requester_sequence_number (ipmiconsole_ctx_t c, ipmiconsole_packet_type_t p)
{
    uint8_t req_seq, expected_req_seq;
    uint64_t val;

    assert (c);
    assert (c->magic == IPMICONSOLE_CTX_MAGIC);
    assert (IPMICONSOLE_PACKET_TYPE_RESPONSE (p));
    assert (p == IPMICONSOLE_PACKET_TYPE_GET_AUTHENTICATION_CAPABILITIES_RS
            || p == IPMICONSOLE_PACKET_TYPE_SET_SESSION_PRIVILEGE_LEVEL_RS
            || p == IPMICONSOLE_PACKET_TYPE_GET_CHANNEL_PAYLOAD_SUPPORT_RS
            || p == IPMICONSOLE_PACKET_TYPE_GET_PAYLOAD_ACTIVATION_STATUS_RS
            || p == IPMICONSOLE_PACKET_TYPE_ACTIVATE_PAYLOAD_RS
            || p == IPMICONSOLE_PACKET_TYPE_GET_CHANNEL_PAYLOAD_VERSION_RS
            || p == IPMICONSOLE_PACKET_TYPE_DEACTIVATE_PAYLOAD_RS
            || p == IPMICONSOLE_PACKET_TYPE_CLOSE_SESSION_RS);

    if (FIID_OBJ_GET (c->connection.obj_lan_msg_hdr_rs,
                      "rq_seq",
                      &val) < 0)
    {
        IPMICONSOLE_CTX_DEBUG (c, ("FIID_OBJ_GET: 'rq_seq': %s",
                                   fiid_obj_errormsg (c->connection.obj_lan_msg_hdr_rs)));
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
        return (-1);
    }
    req_seq = val;
    expected_req_seq = c->session.requester_sequence_number;

    if (req_seq != expected_req_seq)
        IPMICONSOLE_CTX_DEBUG (c, ("requester sequence number check failed; p = %d; req_seq = %Xh; expected_req_seq = %Xh", p, req_seq, expected_req_seq));

    return ((req_seq == expected_req_seq) ? 1 : 0);
}
int
ipmiconsole_check_message_tag (ipmiconsole_ctx_t c, ipmiconsole_packet_type_t p)
{
    uint8_t message_tag, expected_message_tag;
    fiid_obj_t obj_cmd;
    uint64_t val;

    assert (c);
    assert (c->magic == IPMICONSOLE_CTX_MAGIC);
    assert (IPMICONSOLE_PACKET_TYPE_RESPONSE (p));
    assert (p == IPMICONSOLE_PACKET_TYPE_OPEN_SESSION_RESPONSE
            || p == IPMICONSOLE_PACKET_TYPE_RAKP_MESSAGE_2
            || p == IPMICONSOLE_PACKET_TYPE_RAKP_MESSAGE_4);

    obj_cmd = ipmiconsole_packet_object (c, p);
    if (FIID_OBJ_GET (obj_cmd,
                      "message_tag",
                      &val) < 0)
    {
        IPMICONSOLE_CTX_DEBUG (c, ("FIID_OBJ_GET: 'message_tag': %s",
                                   fiid_obj_errormsg (obj_cmd)));
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
        return (-1);
    }
    message_tag = val;
    expected_message_tag = c->session.message_tag;

    if (message_tag != expected_message_tag)
        IPMICONSOLE_CTX_DEBUG (c, ("message tag check failed; p = %d", p));

    return ((message_tag == expected_message_tag) ? 1 : 0);
}
int
ipmiconsole_check_rmcpplus_status_code (ipmiconsole_ctx_t c, ipmiconsole_packet_type_t p)
{
    uint8_t rmcpplus_status_code;
    uint64_t val;
    fiid_obj_t obj_cmd;

    assert (c);
    assert (c->magic == IPMICONSOLE_CTX_MAGIC);
    assert (IPMICONSOLE_PACKET_TYPE_RESPONSE (p));
    assert (p == IPMICONSOLE_PACKET_TYPE_OPEN_SESSION_RESPONSE
            || p == IPMICONSOLE_PACKET_TYPE_RAKP_MESSAGE_2
            || p == IPMICONSOLE_PACKET_TYPE_RAKP_MESSAGE_4);

    obj_cmd = ipmiconsole_packet_object (c, p);
    if (FIID_OBJ_GET (obj_cmd,
                      "rmcpplus_status_code",
                      &val) < 0)
    {
        IPMICONSOLE_CTX_DEBUG (c, ("FIID_OBJ_GET: 'rmcpplus_status_code': %s",
                                   fiid_obj_errormsg (obj_cmd)));
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
        return (-1);
    }
    rmcpplus_status_code = val;

    if (rmcpplus_status_code != RMCPPLUS_STATUS_NO_ERRORS)
        IPMICONSOLE_CTX_DEBUG (c, ("rmcpplus status code check failed; p = %d", p));

    return ((rmcpplus_status_code == RMCPPLUS_STATUS_NO_ERRORS) ? 1 : 0);
}
Beispiel #9
0
int
ipmiconsole_ctx_debug_setup (ipmiconsole_ctx_t c)
{
  assert (c);
  assert (c->magic == IPMICONSOLE_CTX_MAGIC);

  if (c->config.debug_flags & IPMICONSOLE_DEBUG_FILE)
    {
      char filename[MAXPATHLEN];
      pid_t pid;

      pid = getpid();

      snprintf (filename,
                MAXPATHLEN,
                "%s.%s.%d",
                IPMICONSOLE_DEBUG_FILENAME,
                c->config.hostname,
		pid);

      if ((c->debug.debug_fd = open (filename,
                                     O_CREAT | O_APPEND | O_WRONLY | O_EXCL,
                                     0600)) < 0)
        {
          c->config.debug_flags &= ~IPMICONSOLE_DEBUG_FILE;
          IPMICONSOLE_CTX_DEBUG (c, ("open: %s", strerror (errno)));
          ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR);
          c->config.debug_flags = 0;
          return (-1);
        }
    }

  return (0);
}
Beispiel #10
0
int
ipmiconsole_check_payload_pad (ipmiconsole_ctx_t c, ipmiconsole_packet_type_t p)
{
    int rv;

    assert (c);
    assert (c->magic == IPMICONSOLE_CTX_MAGIC);
    assert (IPMICONSOLE_PACKET_TYPE_RESPONSE (p));
    assert (p == IPMICONSOLE_PACKET_TYPE_GET_CHANNEL_PAYLOAD_SUPPORT_RS
            || p == IPMICONSOLE_PACKET_TYPE_SET_SESSION_PRIVILEGE_LEVEL_RS
            || p == IPMICONSOLE_PACKET_TYPE_GET_PAYLOAD_ACTIVATION_STATUS_RS
            || p == IPMICONSOLE_PACKET_TYPE_ACTIVATE_PAYLOAD_RS
            || p == IPMICONSOLE_PACKET_TYPE_SOL_PAYLOAD_DATA_RS
            || p == IPMICONSOLE_PACKET_TYPE_GET_CHANNEL_PAYLOAD_VERSION_RS
            || p == IPMICONSOLE_PACKET_TYPE_DEACTIVATE_PAYLOAD_RS
            || p == IPMICONSOLE_PACKET_TYPE_CLOSE_SESSION_RS);

    if ((rv = ipmi_rmcpplus_check_payload_pad (c->config.confidentiality_algorithm,
              c->connection.obj_rmcpplus_payload_rs)) < 0)
    {
        IPMICONSOLE_CTX_DEBUG (c, ("ipmi_rmcpplus_check_payload_pad: p = %d; %s", p, strerror (errno)));
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
        return (-1);
    }

    if (!rv)
        IPMICONSOLE_CTX_DEBUG (c, ("payload pad check failed; p = %d", p));

    return (rv);
}
/*
 * Return 0 on success
 * Return -1 on fatal error
 */
static int
_asynccomm (ipmiconsole_ctx_t c)
{
  uint8_t tmpbyte;
  ssize_t len;

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

  if ((len = read (c->connection.asynccomm[0], (void *)&tmpbyte, 1)) < 0)
    {
      IPMICONSOLE_CTX_DEBUG (c, ("read: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR);
      return (-1);
    }

  if (!len)
    {
      IPMICONSOLE_CTX_DEBUG (c, ("asynccomm closed"));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
      return (-1);
    }

  /* User may have requested several break conditions in a
   * row quickly.  We assume it means just one
   */
  if (tmpbyte == IPMICONSOLE_PIPE_GENERATE_BREAK_CODE)
    {
      if (!(c->session.break_requested))
        {
          int bytes_before_break;

          c->session.break_requested++;

          if ((bytes_before_break = scbuf_used (c->connection.console_remote_console_to_bmc)) < 0)
            {
              IPMICONSOLE_CTX_DEBUG (c, ("scbuf_used: %s", strerror (errno)));
              ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
              return (-1);
            }
          c->session.console_remote_console_to_bmc_bytes_before_break = bytes_before_break;
        }
    }

  return (0);
}
Beispiel #12
0
int
ipmiconsole_check_outbound_sequence_number (ipmiconsole_ctx_t c, ipmiconsole_packet_type_t p)
{
    uint32_t session_sequence_number;
    uint64_t val;
    int rv = 0;

    assert (c);
    assert (c->magic == IPMICONSOLE_CTX_MAGIC);
    assert (IPMICONSOLE_PACKET_TYPE_RESPONSE (p));
    assert (p == IPMICONSOLE_PACKET_TYPE_SET_SESSION_PRIVILEGE_LEVEL_RS
            || p == IPMICONSOLE_PACKET_TYPE_GET_CHANNEL_PAYLOAD_SUPPORT_RS
            || p == IPMICONSOLE_PACKET_TYPE_GET_PAYLOAD_ACTIVATION_STATUS_RS
            || p == IPMICONSOLE_PACKET_TYPE_ACTIVATE_PAYLOAD_RS
            || p == IPMICONSOLE_PACKET_TYPE_SOL_PAYLOAD_DATA_RS
            || p == IPMICONSOLE_PACKET_TYPE_GET_CHANNEL_PAYLOAD_VERSION_RS
            || p == IPMICONSOLE_PACKET_TYPE_DEACTIVATE_PAYLOAD_RS
            || p == IPMICONSOLE_PACKET_TYPE_CLOSE_SESSION_RS);

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

    if ((rv = ipmi_check_session_sequence_number_2_0 (session_sequence_number,
              &(c->session.highest_received_sequence_number),
              &(c->session.previously_received_list),
              0)) < 0)
    {
        IPMICONSOLE_CTX_DEBUG (c, ("ipmi_check_session_sequence_number_2_0: 'session_sequence_number': %s",
                                   fiid_obj_errormsg (c->connection.obj_rmcpplus_session_hdr_rs)));
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
        return (-1);
    }

    if (!rv)
        IPMICONSOLE_CTX_DEBUG (c, ("session sequence number check failed; p = %d; session_sequence_number = %u; highest_received_sequence_number = %u", p, session_sequence_number, c->session.highest_received_sequence_number));

    return (rv);
}
Beispiel #13
0
int
ipmiconsole_check_payload_type (ipmiconsole_ctx_t c, ipmiconsole_packet_type_t p)
{
    uint8_t payload_type, expected_payload_type;
    uint64_t val;

    assert (c);
    assert (c->magic == IPMICONSOLE_CTX_MAGIC);
    assert (IPMICONSOLE_PACKET_TYPE_RESPONSE (p));
    assert (p == IPMICONSOLE_PACKET_TYPE_OPEN_SESSION_RESPONSE
            || p == IPMICONSOLE_PACKET_TYPE_RAKP_MESSAGE_2
            || p == IPMICONSOLE_PACKET_TYPE_RAKP_MESSAGE_4
            || p == IPMICONSOLE_PACKET_TYPE_SET_SESSION_PRIVILEGE_LEVEL_RS
            || p == IPMICONSOLE_PACKET_TYPE_GET_CHANNEL_PAYLOAD_SUPPORT_RS
            || p == IPMICONSOLE_PACKET_TYPE_GET_PAYLOAD_ACTIVATION_STATUS_RS
            || p == IPMICONSOLE_PACKET_TYPE_ACTIVATE_PAYLOAD_RS
            || p == IPMICONSOLE_PACKET_TYPE_SOL_PAYLOAD_DATA_RS
            || p == IPMICONSOLE_PACKET_TYPE_GET_CHANNEL_PAYLOAD_VERSION_RS
            || p == IPMICONSOLE_PACKET_TYPE_DEACTIVATE_PAYLOAD_RS
            || p == IPMICONSOLE_PACKET_TYPE_CLOSE_SESSION_RS);

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

    if (p == IPMICONSOLE_PACKET_TYPE_OPEN_SESSION_RESPONSE)
        expected_payload_type = IPMI_PAYLOAD_TYPE_RMCPPLUS_OPEN_SESSION_RESPONSE;
    else if (p == IPMICONSOLE_PACKET_TYPE_RAKP_MESSAGE_2)
        expected_payload_type = IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_2;
    else if (p == IPMICONSOLE_PACKET_TYPE_RAKP_MESSAGE_4)
        expected_payload_type = IPMI_PAYLOAD_TYPE_RAKP_MESSAGE_4;
    else if (p == IPMICONSOLE_PACKET_TYPE_SOL_PAYLOAD_DATA_RS)
        expected_payload_type = IPMI_PAYLOAD_TYPE_SOL;
    else
        expected_payload_type = IPMI_PAYLOAD_TYPE_IPMI;

    if (payload_type != expected_payload_type)
        IPMICONSOLE_CTX_DEBUG (c, ("payload type check failed; p = %d; payload_type = %Xh; expected_payload_type = %Xh", p, payload_type, expected_payload_type));

    return ((payload_type == expected_payload_type) ? 1 : 0);
}
Beispiel #14
0
void
ipmiconsole_ctx_cleanup (ipmiconsole_ctx_t c)
{
  assert (c);
  assert (c->magic == IPMICONSOLE_CTX_MAGIC);

  /* don't call ctx_set_errnum after the mutex_destroy */
  ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_CTX_INVALID);
  pthread_mutex_destroy (&(c->errnum_mutex));
  c->magic = ~IPMICONSOLE_CTX_MAGIC;
  c->api_magic = ~IPMICONSOLE_CTX_API_MAGIC;
  if (c->config.engine_flags & IPMICONSOLE_ENGINE_LOCK_MEMORY)
    secure_free (c, sizeof (struct ipmiconsole_ctx));
  else
    free (c);
}
Beispiel #15
0
int
ipmiconsole_check_authentication_code (ipmiconsole_ctx_t c,
                                       ipmiconsole_packet_type_t p,
                                       void *buf,
                                       unsigned int buflen)
{
    char *password;
    int rv;

    assert (c);
    assert (c->magic == IPMICONSOLE_CTX_MAGIC);
    assert (IPMICONSOLE_PACKET_TYPE_RESPONSE (p));
    assert (p == IPMICONSOLE_PACKET_TYPE_SET_SESSION_PRIVILEGE_LEVEL_RS
            || p == IPMICONSOLE_PACKET_TYPE_GET_CHANNEL_PAYLOAD_SUPPORT_RS
            || p == IPMICONSOLE_PACKET_TYPE_GET_PAYLOAD_ACTIVATION_STATUS_RS
            || p == IPMICONSOLE_PACKET_TYPE_ACTIVATE_PAYLOAD_RS
            || p == IPMICONSOLE_PACKET_TYPE_SOL_PAYLOAD_DATA_RS
            || p == IPMICONSOLE_PACKET_TYPE_GET_CHANNEL_PAYLOAD_VERSION_RS
            || p == IPMICONSOLE_PACKET_TYPE_DEACTIVATE_PAYLOAD_RS
            || p == IPMICONSOLE_PACKET_TYPE_CLOSE_SESSION_RS);
    assert (buf);
    assert (buflen);

    if (strlen (c->config.password))
        password = c->config.password;
    else
        password = NULL;

    if ((rv = ipmi_rmcpplus_check_packet_session_authentication_code (c->config.integrity_algorithm,
              buf,
              buflen,
              c->session.integrity_key_ptr,
              c->session.integrity_key_len,
              password,
              (password) ? strlen (password) : 0,
              c->connection.obj_rmcpplus_session_trlr_rs)) < 0)
    {
        IPMICONSOLE_CTX_DEBUG (c, ("ipmi_rmcpplus_check_packet_session_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, ("authentication code check failed; p = %d", p));

    return (rv);
}
Beispiel #16
0
int
ipmiconsole_check_checksum (ipmiconsole_ctx_t c, ipmiconsole_packet_type_t p)
{
    fiid_obj_t obj_cmd;
    int rv;

    assert (c);
    assert (c->magic == IPMICONSOLE_CTX_MAGIC);
    assert (IPMICONSOLE_PACKET_TYPE_RESPONSE (p));
    assert (p == IPMICONSOLE_PACKET_TYPE_GET_AUTHENTICATION_CAPABILITIES_RS
            || p == IPMICONSOLE_PACKET_TYPE_SET_SESSION_PRIVILEGE_LEVEL_RS
            || p == IPMICONSOLE_PACKET_TYPE_GET_CHANNEL_PAYLOAD_SUPPORT_RS
            || p == IPMICONSOLE_PACKET_TYPE_GET_PAYLOAD_ACTIVATION_STATUS_RS
            || p == IPMICONSOLE_PACKET_TYPE_ACTIVATE_PAYLOAD_RS
            || p == IPMICONSOLE_PACKET_TYPE_GET_CHANNEL_PAYLOAD_VERSION_RS
            || p == IPMICONSOLE_PACKET_TYPE_DEACTIVATE_PAYLOAD_RS
            || p == IPMICONSOLE_PACKET_TYPE_CLOSE_SESSION_RS);

    /* IPMI Workaround
     *
     * Discovered on Supermicro X9SCM-iiF, Supermicro X9DRi-F
     *
     * Checksums are computed incorrectly.
     */
    if (c->config.workaround_flags & IPMICONSOLE_WORKAROUND_NO_CHECKSUM_CHECK)
        return (1);

    obj_cmd = ipmiconsole_packet_object (c, p);
    if ((rv = ipmi_lan_check_checksum (c->connection.obj_lan_msg_hdr_rs,
                                       obj_cmd,
                                       c->connection.obj_lan_msg_trlr_rs)) < 0)
    {
        IPMICONSOLE_CTX_DEBUG (c, ("ipmi_lan_check_checksum: p = %d; %s", p, strerror (errno)));
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
        return (-1);
    }

    if (!rv)
        IPMICONSOLE_CTX_DEBUG (c, ("checksum check failed; p = %d", p));

    return (rv);
}
Beispiel #17
0
int
ipmiconsole_ctx_setup (ipmiconsole_ctx_t c)
{
  int perr;

  assert (c);

  /* magic may not be set yet, no assert */

  memset (c, '\0', sizeof (struct ipmiconsole_ctx));
  c->magic = IPMICONSOLE_CTX_MAGIC;
  c->api_magic = IPMICONSOLE_CTX_API_MAGIC;

  if ((perr = pthread_mutex_init (&(c->errnum_mutex), NULL)) != 0)
    {
      errno = perr;
      return (-1);
    }

  ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SUCCESS);

  return (0);
}
Beispiel #18
0
int
ipmiconsole_check_completion_code (ipmiconsole_ctx_t c, ipmiconsole_packet_type_t p)
{
    uint8_t comp_code;
    fiid_obj_t obj_cmd;
    uint64_t val;

    assert (c);
    assert (c->magic == IPMICONSOLE_CTX_MAGIC);
    assert (IPMICONSOLE_PACKET_TYPE_RESPONSE (p));
    assert (p == IPMICONSOLE_PACKET_TYPE_GET_AUTHENTICATION_CAPABILITIES_RS
            || p == IPMICONSOLE_PACKET_TYPE_SET_SESSION_PRIVILEGE_LEVEL_RS
            || p == IPMICONSOLE_PACKET_TYPE_GET_CHANNEL_PAYLOAD_SUPPORT_RS
            || p == IPMICONSOLE_PACKET_TYPE_GET_PAYLOAD_ACTIVATION_STATUS_RS
            || p == IPMICONSOLE_PACKET_TYPE_ACTIVATE_PAYLOAD_RS
            || p == IPMICONSOLE_PACKET_TYPE_GET_CHANNEL_PAYLOAD_VERSION_RS
            || p == IPMICONSOLE_PACKET_TYPE_DEACTIVATE_PAYLOAD_RS
            || p == IPMICONSOLE_PACKET_TYPE_CLOSE_SESSION_RS);

    obj_cmd = ipmiconsole_packet_object (c, p);
    if (FIID_OBJ_GET (obj_cmd,
                      "comp_code",
                      &val) < 0)
    {
        IPMICONSOLE_CTX_DEBUG (c, ("FIID_OBJ_GET: 'comp_code': %s",
                                   fiid_obj_errormsg (obj_cmd)));
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
        return (-1);
    }
    comp_code = val;

    if (comp_code != IPMI_COMP_CODE_COMMAND_SUCCESS)
        IPMICONSOLE_CTX_DEBUG (c, ("completion code check failed; p = %d; comp_code = %Xh", p, comp_code));

    return ((comp_code == IPMI_COMP_CODE_COMMAND_SUCCESS) ? 1 : 0);
}
Beispiel #19
0
int
ipmiconsole_check_session_id (ipmiconsole_ctx_t c, ipmiconsole_packet_type_t p)
{
    uint32_t session_id, expected_session_id;
    uint64_t val;

    assert (c);
    assert (c->magic == IPMICONSOLE_CTX_MAGIC);
    assert (IPMICONSOLE_PACKET_TYPE_RESPONSE (p));
    assert (p == IPMICONSOLE_PACKET_TYPE_OPEN_SESSION_RESPONSE
            || p == IPMICONSOLE_PACKET_TYPE_RAKP_MESSAGE_2
            || p == IPMICONSOLE_PACKET_TYPE_RAKP_MESSAGE_4
            || p == IPMICONSOLE_PACKET_TYPE_SET_SESSION_PRIVILEGE_LEVEL_RS
            || p == IPMICONSOLE_PACKET_TYPE_GET_CHANNEL_PAYLOAD_SUPPORT_RS
            || p == IPMICONSOLE_PACKET_TYPE_GET_PAYLOAD_ACTIVATION_STATUS_RS
            || p == IPMICONSOLE_PACKET_TYPE_ACTIVATE_PAYLOAD_RS
            || p == IPMICONSOLE_PACKET_TYPE_SOL_PAYLOAD_DATA_RS
            || p == IPMICONSOLE_PACKET_TYPE_GET_CHANNEL_PAYLOAD_VERSION_RS
            || p == IPMICONSOLE_PACKET_TYPE_DEACTIVATE_PAYLOAD_RS
            || p == IPMICONSOLE_PACKET_TYPE_CLOSE_SESSION_RS);

    if (p == IPMICONSOLE_PACKET_TYPE_OPEN_SESSION_RESPONSE
            || p == IPMICONSOLE_PACKET_TYPE_RAKP_MESSAGE_2
            || p == IPMICONSOLE_PACKET_TYPE_RAKP_MESSAGE_4)
    {
        fiid_obj_t obj_cmd;

        obj_cmd = ipmiconsole_packet_object (c, p);

        if (FIID_OBJ_GET (obj_cmd,
                          "remote_console_session_id",
                          &val) < 0)
        {
            IPMICONSOLE_CTX_DEBUG (c, ("FIID_OBJ_GET: 'remote_console_session_id': %s",
                                       fiid_obj_errormsg (obj_cmd)));
            ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
            return (-1);
        }
        session_id = val;
        expected_session_id = c->session.remote_console_session_id;
    }
    else
    {
        if (FIID_OBJ_GET (c->connection.obj_rmcpplus_session_hdr_rs,
                          "session_id",
                          &val) < 0)
        {
            IPMICONSOLE_CTX_DEBUG (c, ("FIID_OBJ_GET: 'session_id': %s",
                                       fiid_obj_errormsg (c->connection.obj_rmcpplus_session_hdr_rs)));
            ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
            return (-1);
        }
        session_id = val;
        expected_session_id = c->session.remote_console_session_id;
    }

    if (session_id != expected_session_id)
        IPMICONSOLE_CTX_DEBUG (c, ("session id check failed; p = %d; session_id = %Xh; expected_session_id = %Xh", p, session_id, expected_session_id));

    return ((session_id == expected_session_id) ? 1 : 0);
}
Beispiel #20
0
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);
}
Beispiel #21
0
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);
}
Beispiel #22
0
int
ipmiconsole_ctx_connection_setup (ipmiconsole_ctx_t c)
{
  struct sockaddr_in srcaddr;
  int sv[2];
  int secure_malloc_flag;

  assert (c);
  assert (c->magic == IPMICONSOLE_CTX_MAGIC);
  assert (!(c->session_submitted));

  _ipmiconsole_ctx_connection_init (c);

  /* File Descriptor User Interface */

  if (socketpair (AF_UNIX, SOCK_STREAM, 0, sv) < 0)
    {
      IPMICONSOLE_DEBUG (("socketpair: %s", strerror (errno)));
      if (errno == EMFILE)
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_TOO_MANY_OPEN_FILES);
      else
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR);
      goto cleanup;
    }
  c->connection.user_fd = sv[0];
  c->connection.ipmiconsole_fd = sv[1];

  if (ipmiconsole_set_closeonexec (c, c->connection.user_fd) < 0)
    {
      IPMICONSOLE_DEBUG (("closeonexec error"));
      goto cleanup;
    }
  if (ipmiconsole_set_closeonexec (c, c->connection.ipmiconsole_fd) < 0)
    {
      IPMICONSOLE_DEBUG (("closeonexec error"));
      goto cleanup;
    }

  /* Copy for API level */
  c->fds.user_fd = c->connection.user_fd;

  secure_malloc_flag = (c->config.engine_flags & IPMICONSOLE_ENGINE_LOCK_MEMORY) ? 1 : 0;

  if (!(c->connection.console_remote_console_to_bmc = scbuf_create (CONSOLE_REMOTE_CONSOLE_TO_BMC_BUF_MIN, CONSOLE_REMOTE_CONSOLE_TO_BMC_BUF_MAX, secure_malloc_flag)))
    {
      IPMICONSOLE_DEBUG (("scbuf_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }

  if (!(c->connection.console_bmc_to_remote_console = scbuf_create (CONSOLE_BMC_TO_REMOTE_CONSOLE_BUF_MIN, CONSOLE_BMC_TO_REMOTE_CONSOLE_BUF_MAX, secure_malloc_flag)))
    {
      IPMICONSOLE_DEBUG (("scbuf_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }

  /* Connection Data */

  if ((c->connection.ipmi_fd = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
    {
      IPMICONSOLE_DEBUG (("socket: %s", strerror (errno)));
      if (errno == EMFILE)
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_TOO_MANY_OPEN_FILES);
      else
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR);
      goto cleanup;
    }

  if (ipmiconsole_set_closeonexec (c, c->connection.ipmi_fd) < 0)
    {
      IPMICONSOLE_DEBUG (("closeonexec error"));
      goto cleanup;
    }

  memset (&srcaddr, '\0', sizeof (struct sockaddr_in));
  srcaddr.sin_family = AF_INET;
  srcaddr.sin_port = htons (0);
  srcaddr.sin_addr.s_addr = htonl (INADDR_ANY);

  if (bind (c->connection.ipmi_fd, (struct sockaddr *)&srcaddr, sizeof (struct sockaddr_in)) < 0)
    {
      IPMICONSOLE_DEBUG (("bind: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR);
      goto cleanup;
    }

  if (!(c->connection.ipmi_from_bmc = scbuf_create (IPMI_FROM_BMC_BUF_MIN, IPMI_FROM_BMC_BUF_MAX, secure_malloc_flag)))
    {
      IPMICONSOLE_DEBUG (("scbuf_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }

  if (!(c->connection.ipmi_to_bmc = scbuf_create (IPMI_TO_BMC_BUF_MIN, IPMI_TO_BMC_BUF_MAX, secure_malloc_flag)))
    {
      IPMICONSOLE_DEBUG (("scbuf_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }

  /* Pipe for non-fd communication */
  if (pipe (c->connection.asynccomm) < 0)
    {
      IPMICONSOLE_DEBUG (("pipe: %s", strerror (errno)));
      if (errno == EMFILE)
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_TOO_MANY_OPEN_FILES);
      else
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR);
      goto cleanup;
    }

  if (ipmiconsole_set_closeonexec (c, c->connection.asynccomm[0]) < 0)
    {
      IPMICONSOLE_DEBUG (("closeonexec error"));
      goto cleanup;
    }

  if (ipmiconsole_set_closeonexec (c, c->connection.asynccomm[1]) < 0)
    {
      IPMICONSOLE_DEBUG (("closeonexec error"));
      goto cleanup;
    }

  /* Copy for API level */
  c->fds.asynccomm[0] = c->connection.asynccomm[0];
  c->fds.asynccomm[1] = c->connection.asynccomm[1];

  /* Fiid Objects */

  if (!(c->connection.obj_rmcp_hdr_rq = fiid_obj_create (tmpl_rmcp_hdr)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_rmcp_hdr_rs = fiid_obj_create (tmpl_rmcp_hdr)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_lan_session_hdr_rq = fiid_obj_create (tmpl_lan_session_hdr)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_lan_session_hdr_rs = fiid_obj_create (tmpl_lan_session_hdr)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_lan_msg_hdr_rq = fiid_obj_create (tmpl_lan_msg_hdr_rq)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_lan_msg_hdr_rs = fiid_obj_create (tmpl_lan_msg_hdr_rs)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_lan_msg_trlr_rs = fiid_obj_create (tmpl_lan_msg_trlr)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_rmcpplus_session_hdr_rq = fiid_obj_create (tmpl_rmcpplus_session_hdr)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_rmcpplus_session_hdr_rs = fiid_obj_create (tmpl_rmcpplus_session_hdr)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_rmcpplus_payload_rs = fiid_obj_create (tmpl_rmcpplus_payload)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_rmcpplus_session_trlr_rq = fiid_obj_create (tmpl_rmcpplus_session_trlr)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_rmcpplus_session_trlr_rs = fiid_obj_create (tmpl_rmcpplus_session_trlr)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_authentication_capabilities_rq = fiid_obj_create (tmpl_cmd_get_channel_authentication_capabilities_rq)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_authentication_capabilities_rs = fiid_obj_create (tmpl_cmd_get_channel_authentication_capabilities_rs)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_open_session_request = fiid_obj_create (tmpl_rmcpplus_open_session_request)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_open_session_response = fiid_obj_create (tmpl_rmcpplus_open_session_response)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_rakp_message_1 = fiid_obj_create (tmpl_rmcpplus_rakp_message_1)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_rakp_message_2 = fiid_obj_create (tmpl_rmcpplus_rakp_message_2)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_rakp_message_3 = fiid_obj_create (tmpl_rmcpplus_rakp_message_3)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_rakp_message_4 = fiid_obj_create (tmpl_rmcpplus_rakp_message_4)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_set_session_privilege_level_rq = fiid_obj_create (tmpl_cmd_set_session_privilege_level_rq)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_set_session_privilege_level_rs = fiid_obj_create (tmpl_cmd_set_session_privilege_level_rs)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_get_channel_payload_support_rq = fiid_obj_create (tmpl_cmd_get_channel_payload_support_rq)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_get_channel_payload_support_rs = fiid_obj_create (tmpl_cmd_get_channel_payload_support_rs)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_get_payload_activation_status_rq = fiid_obj_create (tmpl_cmd_get_payload_activation_status_rq)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_get_payload_activation_status_rs = fiid_obj_create (tmpl_cmd_get_payload_activation_status_rs)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_activate_payload_rq = fiid_obj_create (tmpl_cmd_activate_payload_sol_rq)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_activate_payload_rs = fiid_obj_create (tmpl_cmd_activate_payload_sol_rs)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_sol_payload_data_rq = fiid_obj_create (tmpl_sol_payload_data_remote_console_to_bmc)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_sol_payload_data_rs = fiid_obj_create (tmpl_sol_payload_data_bmc_to_remote_console)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_get_channel_payload_version_rq = fiid_obj_create (tmpl_cmd_get_channel_payload_version_rq)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_get_channel_payload_version_rs = fiid_obj_create (tmpl_cmd_get_channel_payload_version_rs)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_deactivate_payload_rq = fiid_obj_create (tmpl_cmd_deactivate_payload_rq)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_deactivate_payload_rs = fiid_obj_create (tmpl_cmd_deactivate_payload_rs)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_close_session_rq = fiid_obj_create (tmpl_cmd_close_session_rq)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }
  if (!(c->connection.obj_close_session_rs = fiid_obj_create (tmpl_cmd_close_session_rs)))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_create: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_OUT_OF_MEMORY);
      goto cleanup;
    }

  return (0);

 cleanup:
  /* Previously called here, but this is now supposed to be handled in API land */
  /* ipmiconsole_ctx_connection_cleanup(c) */
  /* _ipmiconsole_ctx_fds_cleanup(c); */
  /* _ipmiconsole_ctx_fds_setup(c); */
  return (-1);
}
int
ipmiconsole_engine_submit_ctx (ipmiconsole_ctx_t c)
{
  void *ptr;
  unsigned int i;
  int perr, ret = -1;
  unsigned int min_submitted = UINT_MAX;
  int index = 0;

  assert (c);
  assert (c->magic == IPMICONSOLE_CTX_MAGIC);
  assert (!(c->session_submitted));
  assert (console_engine_is_setup);

  if ((perr = pthread_mutex_lock (&console_engine_thread_count_mutex)))
    {
      IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));
      return (-1);
    }

  for (i = 0; i < console_engine_thread_count; i++)
    {
      if ((perr = pthread_mutex_lock (&console_engine_ctxs_mutex[i])))
        {
          IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));
          ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
          goto cleanup_thread_count;
        }

      if (console_engine_ctxs_count[i] < min_submitted)
        {
          min_submitted = console_engine_ctxs_count[i];
          index = i;
        }

      if ((perr = pthread_mutex_unlock (&console_engine_ctxs_mutex[i])))
        {
          IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
          ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
          goto cleanup_thread_count;
        }
    }

  if ((perr = pthread_mutex_lock (&console_engine_ctxs_mutex[index])))
    {
      IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
      goto cleanup_thread_count;
    }

  if (!(ptr = list_append (console_engine_ctxs[index], c)))
    {
      /* Note: Don't do a CTX debug, this is more of a global debug */
      IPMICONSOLE_DEBUG (("list_append: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
      goto cleanup_ctxs;
    }

  if (ptr != (void *)c)
    {
      IPMICONSOLE_DEBUG (("list_append: invalid pointer: ptr=%p; c=%p", ptr, c));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
      goto cleanup_ctxs;
    }

  console_engine_ctxs_count[index]++;

  ret = 0;

  /* achu:
   *
   * Necessary to set this here b/c at this point in time, the context
   * is submitted, so the engine will be doing its own cleanup
   * (garbage collector, etc.).
   */
  c->session_submitted++;

  /* "Interrupt" the engine and tell it to get moving along w/ the new context */
  if (write (console_engine_ctxs_notifier[index][1], "1", 1) < 0)
    IPMICONSOLE_DEBUG (("write: %s", strerror (errno)));

 cleanup_ctxs:
  if ((perr = pthread_mutex_unlock (&console_engine_ctxs_mutex[index])))
    {
      IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
      goto cleanup_thread_count;
    }

 cleanup_thread_count:
  if ((perr = pthread_mutex_unlock (&console_engine_thread_count_mutex)))
    IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));

  return (ret);
}
/*
 * Return 0 on success
 * Return -1 on fatal error
 */
static int
_ipmi_recvfrom (ipmiconsole_ctx_t c)
{
  char buffer[IPMICONSOLE_PACKET_BUFLEN];
  struct sockaddr_in from;
  unsigned int fromlen = sizeof (struct sockaddr_in);
  ssize_t len;
  int n, dropped = 0;
  int secure_malloc_flag;

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

  secure_malloc_flag = (c->config.engine_flags & IPMICONSOLE_ENGINE_LOCK_MEMORY) ? 1 : 0;

  do
    {
      /* For receive side, ipmi_lan_recvfrom and
       * ipmi_rmcpplus_recvfrom are identical.  So we just use
       * ipmi_lan_recvfrom for both.
       *
       * In event of future change, should use util functions
       * ipmi_is_ipmi_1_5_packet or ipmi_is_ipmi_2_0_packet
       * appropriately.
       */
      len = ipmi_lan_recvfrom (c->connection.ipmi_fd,
                               buffer,
                               IPMICONSOLE_PACKET_BUFLEN,
                               0,
                               (struct sockaddr *)&from,
                               &fromlen);
    } while (len < 0 && errno == EINTR);

  /* achu & hliebig:
   *
   * Premise from ipmitool (http://ipmitool.sourceforge.net/)
   *
   * On some OSes (it seems Unixes), the behavior is to not return
   * port denied errors up to the client for UDP responses (i.e. you
   * need to timeout).  But on some OSes (it seems Windows), the
   * behavior is to return port denied errors up to the user for UDP
   * responses via ECONNRESET or ECONNREFUSED.
   *
   * If this were just the case, we could return or handle errors
   * properly and move on.  However, it's not the case.
   *
   * According to Ipmitool, on some motherboards, both the OS and the
   * BMC are capable of responding to an IPMI request.  That means you
   * can get an ECONNRESET or ECONNREFUSED, then later on, get your
   * real IPMI response.
   *
   * Our solution is copied from Ipmitool, we'll ignore some specific
   * errors and try to read again.
   *
   * If the ECONNREFUSED or ECONNRESET is from the OS, but we will get
   * an IPMI response later, the recvfrom later on gets the packet we
   * want.
   *
   * If the ECONNREFUSED or ECONNRESET is from the OS but there is no
   * BMC (or IPMI disabled, etc.), just do the recvfrom again to
   * eventually get a timeout, which is the behavior we'd like.
   */
  if (len < 0
      && (errno == ECONNRESET
          || errno == ECONNREFUSED))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("ipmi_lan_recvfrom: connection refused: %s", strerror (errno)));
      return (0);
    }

  if (len < 0)
    {
      IPMICONSOLE_CTX_DEBUG (c, ("ipmi_lan_recvfrom: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR);
      return (-1);
    }

  if (!len)
    {
      IPMICONSOLE_CTX_DEBUG (c, ("ipmi_lan_recvfrom: no data", strerror (errno)));
      /* Note: Not a fatal error, just return*/
      return (0);
    }

  /* Sanity Check */
  if (from.sin_family != AF_INET
      || from.sin_addr.s_addr != c->session.addr.sin_addr.s_addr)
    {
      IPMICONSOLE_CTX_DEBUG (c, ("received from invalid address"));
      /* Note: Not a fatal error, just return */
      return (0);
    }

  /* Empty the scbuf if it's not empty */
  if (!scbuf_is_empty (c->connection.ipmi_from_bmc))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("ipmi_from_bmc not empty, draining"));
      do {
        char tempbuf[IPMICONSOLE_PACKET_BUFLEN];
        if (scbuf_read (c->connection.ipmi_from_bmc, tempbuf, IPMICONSOLE_PACKET_BUFLEN) < 0)
          {
            IPMICONSOLE_CTX_DEBUG (c, ("scbuf_read: %s", strerror (errno)));
            break;
          }
      } while(!scbuf_is_empty (c->connection.ipmi_from_bmc));
    }

  if ((n = scbuf_write (c->connection.ipmi_from_bmc, buffer, len, &dropped, secure_malloc_flag)) < 0)
    {
      IPMICONSOLE_CTX_DEBUG (c, ("scbuf_write: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
      return (-1);
    }

  if (n != len)
    {
      IPMICONSOLE_CTX_DEBUG (c, ("scbuf_write: invalid bytes written; n=%d; len=%d", n, len));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
      return (-1);
    }

  if (dropped)
    {
      IPMICONSOLE_CTX_DEBUG (c, ("scbuf_write: dropped data: dropped=%d", dropped));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
      return (-1);
    }

  return (0);
}
/*
 * Return 0 on success
 * Return -1 on fatal error
 */
static int
_ipmi_sendto (ipmiconsole_ctx_t c)
{
  char buffer[IPMICONSOLE_PACKET_BUFLEN];
  ssize_t len;
  int n;

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

  if ((n = scbuf_read (c->connection.ipmi_to_bmc, buffer, IPMICONSOLE_PACKET_BUFLEN)) < 0)
    {
      IPMICONSOLE_CTX_DEBUG (c, ("scbuf_read: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
      return (-1);
    }

  if (ipmi_is_ipmi_1_5_packet (buffer, n))
    {
      do
	{
	  len = ipmi_lan_sendto (c->connection.ipmi_fd,
				 buffer,
				 n,
				 0,
				 (struct sockaddr *)&(c->session.addr),
				 sizeof (struct sockaddr_in));
	} while (len < 0 && errno == EINTR);
    }
  else
    {
      do
	{
	  len = ipmi_rmcpplus_sendto (c->connection.ipmi_fd,
				      buffer,
				      n,
				      0,
				      (struct sockaddr *)&(c->session.addr),
				      sizeof (struct sockaddr_in));
	} while (len < 0 && errno == EINTR);
    }

  if (len < 0)
    {
      IPMICONSOLE_CTX_DEBUG (c, ("ipmi_lan_sendto: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR);
      return (-1);
    }

#if 0
  /* don't check, let bad packet timeout */
  if (len != n)
    {
      IPMICONSOLE_CTX_DEBUG (c, ("ipmi_lan_sendto: invalid bytes written; n=%d; len=%d", n, len));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR);
      return (-1);
    }
#endif

  /* scbuf should be empty now */
  if (!scbuf_is_empty (c->connection.ipmi_to_bmc))
    {
      IPMICONSOLE_CTX_DEBUG (c, ("ipmi_to_bmc not empty"));
      /* Note: Not a fatal error, just return*/
      return (0);
    }

  return (0);
}
Beispiel #26
0
int
ipmiconsole_check_command (ipmiconsole_ctx_t c, ipmiconsole_packet_type_t p)
{
    uint8_t cmd, expected_cmd;
    fiid_obj_t obj_cmd;
    uint64_t val;

    assert (c);
    assert (c->magic == IPMICONSOLE_CTX_MAGIC);
    assert (IPMICONSOLE_PACKET_TYPE_RESPONSE (p));
    assert (p == IPMICONSOLE_PACKET_TYPE_GET_AUTHENTICATION_CAPABILITIES_RS
            || p == IPMICONSOLE_PACKET_TYPE_SET_SESSION_PRIVILEGE_LEVEL_RS
            || p == IPMICONSOLE_PACKET_TYPE_GET_CHANNEL_PAYLOAD_SUPPORT_RS
            || p == IPMICONSOLE_PACKET_TYPE_GET_PAYLOAD_ACTIVATION_STATUS_RS
            || p == IPMICONSOLE_PACKET_TYPE_ACTIVATE_PAYLOAD_RS
            || p == IPMICONSOLE_PACKET_TYPE_GET_CHANNEL_PAYLOAD_VERSION_RS
            || p == IPMICONSOLE_PACKET_TYPE_DEACTIVATE_PAYLOAD_RS
            || p == IPMICONSOLE_PACKET_TYPE_CLOSE_SESSION_RS);

    obj_cmd = ipmiconsole_packet_object (c, p);
    if (FIID_OBJ_GET (obj_cmd,
                      "cmd",
                      &val) < 0)
    {
        IPMICONSOLE_CTX_DEBUG (c, ("FIID_OBJ_GET: 'cmd': %s",
                                   fiid_obj_errormsg (obj_cmd)));
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
        return (-1);
    }
    cmd = val;

    switch (p)
    {
    case IPMICONSOLE_PACKET_TYPE_GET_AUTHENTICATION_CAPABILITIES_RS:
        expected_cmd = IPMI_CMD_GET_CHANNEL_AUTHENTICATION_CAPABILITIES;
        break;
    case IPMICONSOLE_PACKET_TYPE_SET_SESSION_PRIVILEGE_LEVEL_RS:
        expected_cmd = IPMI_CMD_SET_SESSION_PRIVILEGE_LEVEL;
        break;
    case IPMICONSOLE_PACKET_TYPE_GET_CHANNEL_PAYLOAD_SUPPORT_RS:
        expected_cmd = IPMI_CMD_GET_CHANNEL_PAYLOAD_SUPPORT;
        break;
    case IPMICONSOLE_PACKET_TYPE_GET_PAYLOAD_ACTIVATION_STATUS_RS:
        expected_cmd = IPMI_CMD_GET_PAYLOAD_ACTIVATION_STATUS;
        break;
    case IPMICONSOLE_PACKET_TYPE_ACTIVATE_PAYLOAD_RS:
        expected_cmd = IPMI_CMD_ACTIVATE_PAYLOAD;
        break;
    case IPMICONSOLE_PACKET_TYPE_GET_CHANNEL_PAYLOAD_VERSION_RS:
        expected_cmd = IPMI_CMD_GET_CHANNEL_PAYLOAD_VERSION;
        break;
    case IPMICONSOLE_PACKET_TYPE_DEACTIVATE_PAYLOAD_RS:
        expected_cmd = IPMI_CMD_DEACTIVATE_PAYLOAD;
        break;
    case IPMICONSOLE_PACKET_TYPE_CLOSE_SESSION_RS:
        expected_cmd = IPMI_CMD_CLOSE_SESSION;
        break;
    default:
        IPMICONSOLE_CTX_DEBUG (c, ("invalid packet type: p = %d", p));
        ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
        return (-1);
    }

    if (cmd != expected_cmd)
        IPMICONSOLE_CTX_DEBUG (c, ("command check failed; p = %d; cmd = %Xh; expected_cmd = %Xh", p, cmd, expected_cmd));

    return ((cmd == expected_cmd) ? 1 : 0);
}
static void *
_ipmiconsole_engine (void *arg)
{
  int perr, ctxs_count = 0;
  unsigned int index;
  unsigned int teardown_flag = 0;
  unsigned int teardown_initiated = 0;

  assert (arg);

  index = *((unsigned int *)arg);

  assert (index < IPMICONSOLE_THREAD_COUNT_MAX);

  free (arg);

  /* No need to exit on failure, probability is low we'll SIGPIPE anyways */
  if (signal (SIGPIPE, SIG_IGN) == SIG_ERR)
    IPMICONSOLE_DEBUG (("signal: %s", strerror (errno)));

  while (!teardown_flag || ctxs_count)
    {
      struct _ipmiconsole_poll_data poll_data;
      int count;
      unsigned int timeout_len;
      unsigned int i;
      int unlock_console_engine_ctxs_mutex_flag = 0;
      int spin_wait_flag = 0;
      char buf[IPMICONSOLE_PIPE_BUFLEN];

      memset (&poll_data, '\0', sizeof (struct _ipmiconsole_poll_data));

      if ((perr = pthread_mutex_lock (&console_engine_teardown_mutex)))
        {
          /* This is one of the only truly "fatal" conditions */
          IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));
          teardown_flag = 1;
        }

      if (console_engine_teardown_immediate)
        {
          if ((perr = pthread_mutex_unlock (&console_engine_teardown_mutex)))
            IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
          break;
        }

      if (console_engine_teardown)
        teardown_flag = 1;

      if ((perr = pthread_mutex_unlock (&console_engine_teardown_mutex)))
        {
          /* This is one of the only truly "fatal" conditions */
          IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
          teardown_flag = 1;
        }

      /* Notes:
       *
       * We must lock the list from here till all context data and pointers
       * are retrieved.
       */

      if ((perr = pthread_mutex_lock (&console_engine_ctxs_mutex[index])))
        {
          /* This is one of the only truly "fatal" conditions */
          IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));
          teardown_flag = 1;
        }

      /* Note: Set close_session_flag in the contexts before
       * ipmiconsole_process_ctxs(), so the initiation of the closing
       * down will begin now rather than the next iteration of the
       * loop.
       */
      if (teardown_flag && !teardown_initiated)
        {
          /* XXX: Umm, if this fails, we may not be able to teardown
           * cleanly.  Break out of the loop I guess.
           */
          if (list_for_each (console_engine_ctxs[index], _teardown_initiate, NULL) < 0)
            {
              IPMICONSOLE_DEBUG (("list_for_each: %s", strerror (errno)));
              break;
            }
          teardown_initiated++;
        }

      if ((ctxs_count = ipmiconsole_process_ctxs (console_engine_ctxs[index], &timeout_len)) < 0)
        goto continue_loop;

      if (!ctxs_count && teardown_flag)
        continue;

      if (!ctxs_count)
        {
          spin_wait_flag++;
          goto continue_loop;
        }
      poll_data.ctxs_len = ctxs_count;

      /* achu: I always wonder if this poll() loop could be done far
       * more elegantly and efficiently without all this crazy
       * indexing, perhaps through a callback/event mechanism.  It'd
       * probably be more efficient, since most callback/event based
       * models have min-heap like structures inside for determining
       * what things timed out. Overall though, I don't think the O(n)
       * (n being hosts/fds) processing is really that inefficient for
       * this particular application and is not worth going back and
       * changing.  By going to a callback/event mechanism, there will
       * still be some O(n) activities within the code, so I am only
       * going to create a more efficient O(n) poll loop.
       */

      /*
       * There are 3 pfds per ctx.  One for 'ipmi_fd', 'asynccomm[0]', and 'ipmiconsole_fd'.
       *
       * There is + 1 pfds for the "console_engine_ctxs_notifier".
       * This will be set up manually here, and not in _poll_setup().
       */
      if (!(poll_data.pfds = (struct pollfd *)malloc (((poll_data.ctxs_len * 3) + 1) * sizeof (struct pollfd))))
        {
          IPMICONSOLE_DEBUG (("malloc: %s", strerror (errno)));
          goto continue_loop;
        }

      if (!(poll_data.pfds_ctxs = (ipmiconsole_ctx_t *)malloc (poll_data.ctxs_len * sizeof (ipmiconsole_ctx_t))))
        {
          IPMICONSOLE_DEBUG (("malloc: %s", strerror (errno)));
          goto continue_loop;
        }

      if ((count = list_for_each (console_engine_ctxs[index], _poll_setup, &poll_data)) < 0)
        {
          IPMICONSOLE_DEBUG (("list_for_each: %s", strerror (errno)));
          goto continue_loop;
        }

      if ((perr = pthread_mutex_unlock (&console_engine_ctxs_mutex[index])))
        IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
      unlock_console_engine_ctxs_mutex_flag++;

      /* Setup notifier pipe as last remaining poll data */
      poll_data.pfds[(poll_data.ctxs_len * 3)].fd = console_engine_ctxs_notifier[index][0];
      poll_data.pfds[(poll_data.ctxs_len * 3)].events = POLLIN;
      poll_data.pfds[(poll_data.ctxs_len * 3)].revents = 0;

      if (count != ctxs_count)
        {
          IPMICONSOLE_DEBUG (("list_for_each: invalid length returned: %d", count));
          goto continue_loop;
        }

      if (poll_data.pfds_index != ctxs_count)
        {
          IPMICONSOLE_DEBUG (("invalid index set on returned: %d", poll_data.pfds_index));
          goto continue_loop;
        }

      if (_ipmiconsole_poll (poll_data.pfds, (poll_data.ctxs_len * 3) + 1, timeout_len) < 0)
        {
          IPMICONSOLE_DEBUG (("poll: %s", strerror (errno)));
          goto continue_loop;
        }

      for (i = 0; i < poll_data.ctxs_len; i++)
        {
          if (poll_data.pfds[i*3].revents & POLLERR)
            {
              IPMICONSOLE_CTX_DEBUG (poll_data.pfds_ctxs[i], ("POLLERR"));
              /* See comments in _ipmi_recvfrom() regarding ECONNRESET/ECONNREFUSED */
              if (_ipmi_recvfrom (poll_data.pfds_ctxs[i]) < 0)
                {
                  ipmiconsole_ctx_set_errnum (poll_data.pfds_ctxs[i], IPMICONSOLE_ERR_SYSTEM_ERROR);
                  poll_data.pfds_ctxs[i]->session.close_session_flag++;
                  continue;
                }
            }
          if (!poll_data.pfds_ctxs[i]->session.close_session_flag)
            {
              if (poll_data.pfds[i*3+1].revents & POLLNVAL)
                {
                  /* This indicates the user closed the asynccomm file descriptors
                   * which is ok.
                   */
                  IPMICONSOLE_CTX_DEBUG (poll_data.pfds_ctxs[i], ("POLLNVAL"));
                  ipmiconsole_ctx_set_errnum (poll_data.pfds_ctxs[i], IPMICONSOLE_ERR_SUCCESS);
                  poll_data.pfds_ctxs[i]->session.close_session_flag++;
                  continue;
                }
              if (poll_data.pfds[i*3+2].revents & POLLHUP)
                {
                  /* This indicates the user closed the other end of
                   * the socketpair so it's ok.
                   */
                  IPMICONSOLE_CTX_DEBUG (poll_data.pfds_ctxs[i], ("POLLHUP"));
                  ipmiconsole_ctx_set_errnum (poll_data.pfds_ctxs[i], IPMICONSOLE_ERR_SUCCESS);
                  poll_data.pfds_ctxs[i]->session.close_session_flag++;
                  continue;
                }
              if (poll_data.pfds[i*3+1].revents & POLLERR)
                {
                  IPMICONSOLE_CTX_DEBUG (poll_data.pfds_ctxs[i], ("POLLERR"));
                  ipmiconsole_ctx_set_errnum (poll_data.pfds_ctxs[i], IPMICONSOLE_ERR_INTERNAL_ERROR);
                  poll_data.pfds_ctxs[i]->session.close_session_flag++;
                  continue;
                }
              if (poll_data.pfds[i*3+2].revents & POLLERR)
                {
                  IPMICONSOLE_CTX_DEBUG (poll_data.pfds_ctxs[i], ("POLLERR"));
                  ipmiconsole_ctx_set_errnum (poll_data.pfds_ctxs[i], IPMICONSOLE_ERR_INTERNAL_ERROR);
                  poll_data.pfds_ctxs[i]->session.close_session_flag++;
                  continue;
                }
            }
          if (poll_data.pfds[i*3].revents & POLLIN)
            {
              if (_ipmi_recvfrom (poll_data.pfds_ctxs[i]) < 0)
                {
                  poll_data.pfds_ctxs[i]->session.close_session_flag++;
                  continue;
                }
            }
          if (poll_data.pfds[i*3].revents & POLLOUT)
            {
              if (_ipmi_sendto (poll_data.pfds_ctxs[i]) < 0)
                {
                  poll_data.pfds_ctxs[i]->session.close_session_flag++;
                  continue;
                }
            }
          if (poll_data.pfds[i*3 + 1].revents & POLLIN)
            {
              if (_asynccomm (poll_data.pfds_ctxs[i]) < 0)
                {
                  poll_data.pfds_ctxs[i]->session.close_session_flag++;
                  continue;
                }
            }
          if (!poll_data.pfds_ctxs[i]->session.close_session_flag)
            {
              if (poll_data.pfds[i*3+2].revents & POLLIN)
                {
                  if (_console_read (poll_data.pfds_ctxs[i]) < 0)
                    {
                      poll_data.pfds_ctxs[i]->session.close_session_flag++;
                      continue;
                    }
                }
              if (poll_data.pfds[i*3+2].revents & POLLOUT)
                {
                  if (_console_write (poll_data.pfds_ctxs[i]) < 0)
                    {
                      poll_data.pfds_ctxs[i]->session.close_session_flag++;
                      continue;
                    }
                }
            }
        }

      /* We don't care what's read, just get it off the fd */
      if (poll_data.pfds[(poll_data.ctxs_len * 3)].revents & POLLIN)
        {
          if (read (console_engine_ctxs_notifier[index][0], buf, IPMICONSOLE_PIPE_BUFLEN) < 0)
            IPMICONSOLE_DEBUG (("read: %s", strerror (errno)));
        }

    continue_loop:
      if (!unlock_console_engine_ctxs_mutex_flag)
        {
          if ((perr = pthread_mutex_unlock (&console_engine_ctxs_mutex[index])))
            {
              /* This is one of the only truly "fatal" conditions */
              IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));
              teardown_flag = 1;
            }
        }
      if (spin_wait_flag)
        {
          /* No contexts stored, either because they all died or none
           * have been submitted yet.  Sleep a little bit to kill some
           * time and avoid spinning.
           */
          /* XXX: Is this portable? */
          usleep (IPMICONSOLE_SPIN_WAIT_TIME);
        }
      free (poll_data.pfds);
      free (poll_data.pfds_ctxs);
    }

  /* No way to return error, so just continue on even if there is a failure */
  if ((perr = pthread_mutex_lock (&console_engine_thread_count_mutex)))
    IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr)));

  console_engine_thread_count--;

  if ((perr = pthread_mutex_unlock (&console_engine_thread_count_mutex)))
    IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr)));

  return (NULL);
}
Beispiel #28
0
int
ipmiconsole_ctx_session_setup (ipmiconsole_ctx_t c)
{
  struct hostent hent;
  int h_errnop;
  char buf[GETHOSTBYNAME_AUX_BUFLEN];
#if defined(HAVE_FUNC_GETHOSTBYNAME_R_6)
  struct hostent *hptr;
#elif defined(HAVE_FUNC_GETHOSTBYNAME_R_5)
#else /* !HAVE_FUNC_GETHOSTBYNAME_R */
  struct hostent *hptr;
#endif /* !HAVE_FUNC_GETHOSTBYNAME_R */

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

  c->session.console_port = c->config.port;

  memset (&(c->session.addr), '\0', sizeof (struct sockaddr_in));
  c->session.addr.sin_family = AF_INET;
  c->session.addr.sin_port = htons (c->session.console_port);

  timeval_clear (&(c->session.last_ipmi_packet_sent));

  /* Note:
   *
   * Initial last_ipmi_packet_received and last_sol_packet_received to
   * current time, so appropriate timeouts can be calculated in the
   * beginning if necessary.
   */

  if (gettimeofday (&(c->session.last_ipmi_packet_received), NULL) < 0)
    {
      IPMICONSOLE_DEBUG (("gettimeofday: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR);
      return (-1);
    }

  timeval_clear (&(c->session.last_keepalive_packet_sent));

  if (gettimeofday (&(c->session.last_sol_packet_received), NULL) < 0)
    {
      IPMICONSOLE_DEBUG (("gettimeofday: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR);
      return (-1);
    }

  memset (&hent, '\0', sizeof (struct hostent));
#if defined(HAVE_FUNC_GETHOSTBYNAME_R_6)
  if (gethostbyname_r (c->config.hostname,
                       &hent,
                       buf,
                       GETHOSTBYNAME_AUX_BUFLEN,
                       &hptr,
                       &h_errnop))
#elif defined(HAVE_FUNC_GETHOSTBYNAME_R_5)
  /* Jan Forch - Solaris gethostbyname_r returns ptr, not integer */
  if (!gethostbyname_r (c->config.hostname,
                        &hent,
                        buf,
                        GETHOSTBYNAME_AUX_BUFLEN,
                        &h_errnop))
#else /* !HAVE_FUNC_GETHOSTBYNAME_R */
  if (freeipmi_gethostbyname_r (c->config.hostname,
                                &hent,
                                buf,
                                GETHOSTBYNAME_AUX_BUFLEN,
                                &hptr,
                                &h_errnop))
#endif /* !HAVE_FUNC_GETHOSTBYNAME_R */
    {
      if (h_errnop == HOST_NOT_FOUND
          || h_errnop == NO_ADDRESS
          || h_errnop == NO_DATA)
        {
          ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_HOSTNAME_INVALID);
          return (-1);
        }
#if HAVE_HSTRERROR
      IPMICONSOLE_DEBUG (("gethostbyname_r: %s", hstrerror (h_errnop)));
#else /* !HAVE_HSTRERROR */
      IPMICONSOLE_DEBUG (("gethostbyname_r: h_errno = %d", h_errnop));
#endif /* !HAVE_HSTRERROR */
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_SYSTEM_ERROR);
      return (-1);
    }

#if defined(HAVE_FUNC_GETHOSTBYNAME_R_6)
  if (!hptr)
    {
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_HOSTNAME_INVALID);
      return (-1);
    }
#elif defined(HAVE_FUNC_GETHOSTBYNAME_R_5)
#else /* !HAVE_FUNC_GETHOSTBYNAME_R */
  if (!hptr)
    {
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_HOSTNAME_INVALID);
      return (-1);
    }
#endif /* !HAVE_FUNC_GETHOSTBYNAME_R */

  c->session.addr.sin_addr = *((struct in_addr *)hent.h_addr);

  c->session.protocol_state = IPMICONSOLE_PROTOCOL_STATE_START;
  c->session.close_session_flag = 0;
  c->session.try_new_port_flag = 0;
  c->session.deactivate_payload_instances = 0;
  c->session.deactivate_payload_instances_and_try_again_flag = 0;
  c->session.close_timeout_flag = 0;
  c->session.deactivate_only_succeeded_flag = 0;

  c->session.retransmission_count = 0;
  c->session.errors_count = 0;
  c->session.session_sequence_number_errors_count = 0;
  c->session.activate_payloads_count = 0;
  c->session.deactivate_active_payloads_count = 0;

  if (ipmi_check_session_sequence_number_2_0_init (&(c->session.highest_received_sequence_number),
                                                   &(c->session.previously_received_list)) < 0)
    {
      IPMICONSOLE_DEBUG (("ipmi_check_session_sequence_number_2_0_init: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
      return (-1);
    }

  if (ipmi_get_random (&(c->session.message_tag),
                       sizeof (c->session.message_tag)) < 0)
    {
      IPMICONSOLE_DEBUG (("ipmi_get_random: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
      return (-1);
    }
  if (ipmi_get_random (&(c->session.requester_sequence_number),
                       sizeof (c->session.requester_sequence_number)) < 0)
    {
      IPMICONSOLE_DEBUG (("ipmi_get_random: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
      return (-1);
    }
  c->session.requester_sequence_number %= (IPMI_LAN_REQUESTER_SEQUENCE_NUMBER_MAX + 1);

  c->session.session_sequence_number = 0; /* 0, so initial increment puts it at 1 */
  c->session.name_only_lookup = IPMI_NAME_ONLY_LOOKUP;

  /* In IPMI 2.0, session_ids of 0 are special */
  do
    {
      if (ipmi_get_random (&(c->session.remote_console_session_id),
                           sizeof (c->session.remote_console_session_id)) < 0)
        {
          IPMICONSOLE_DEBUG (("ipmi_get_random: %s", strerror (errno)));
          ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
          return (-1);
        }
    } while (!c->session.remote_console_session_id);

  if (ipmi_get_random (c->session.remote_console_random_number,
                       IPMI_REMOTE_CONSOLE_RANDOM_NUMBER_LENGTH) < 0)
    {
      IPMICONSOLE_DEBUG (("ipmi_get_random: %s", strerror (errno)));
      ipmiconsole_ctx_set_errnum (c, IPMICONSOLE_ERR_INTERNAL_ERROR);
      return (-1);
    }

  /* Keys and ptrs will be calculated during session setup.  We just
   * memet/clear here.
   */
  memset (c->session.sik_key, '\0', IPMI_MAX_SIK_KEY_LENGTH);
  c->session.sik_key_ptr = c->session.sik_key;
  c->session.sik_key_len = IPMI_MAX_SIK_KEY_LENGTH;
  memset (c->session.integrity_key, '\0', IPMI_MAX_INTEGRITY_KEY_LENGTH);
  c->session.integrity_key_ptr = c->session.integrity_key;
  c->session.integrity_key_len = IPMI_MAX_INTEGRITY_KEY_LENGTH;
  memset (c->session.confidentiality_key, '\0', IPMI_MAX_CONFIDENTIALITY_KEY_LENGTH);
  c->session.confidentiality_key_ptr = c->session.confidentiality_key;
  c->session.confidentiality_key_len = IPMI_MAX_CONFIDENTIALITY_KEY_LENGTH;

  /* Following 3 will be calculated during session setup.  We only
   * memset/clear it here
   */
  c->session.sol_instance_capacity = 0;
  memset (c->session.sol_instances_activated, '\0', IPMI_INSTANCES_ACTIVATED_LENGTH);
  c->session.sol_instances_activated_count = 0;
  /* this is used just to index the number of instances deactivated */
  c->session.sol_instances_deactivated_count = 0;

  /* Calculated during the session setup. */
  c->session.max_sol_character_send_size = 0;

  /* Serial Break Maintenance */
  c->session.break_requested = 0;
  c->session.console_remote_console_to_bmc_bytes_before_break = 0;

  /* SOL Input (remote console to BMC) */
  c->session.sol_input_waiting_for_ack = 0;
  c->session.sol_input_waiting_for_break_ack = 0;
  timeval_clear (&(c->session.last_sol_input_packet_sent));
  c->session.sol_input_packet_sequence_number = 0; /* 0, so initial increment puts it at 1 */
  memset (c->session.sol_input_character_data, '\0', IPMICONSOLE_MAX_CHARACTER_DATA+1);
  c->session.sol_input_character_data_len = 0;

  /* SOL Output (BMC to remote console) */
  c->session.last_sol_output_packet_sequence_number = 0;
  c->session.last_sol_output_accepted_character_count = 0;

  return (0);
}