/* * 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_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); }
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_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 _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_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); }
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_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); }
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); }
/* * 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); }
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); }
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); }
int ipmiconsole_check_packet (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)); obj_cmd = ipmiconsole_packet_object (c, p); if ((rv = fiid_obj_packet_valid (obj_cmd)) < 0) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_packet_valid: %s", fiid_obj_errormsg (obj_cmd))); return (-1); } if (!rv) IPMICONSOLE_CTX_DEBUG (c, ("invalid packet received; p = %d", p)); return (rv); }
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); }
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); }
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 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 void __ipmiconsole_ctx_connection_cleanup (ipmiconsole_ctx_t c, int session_submitted) { int blocking_requested = 0; int status_initial = 0; int secure_malloc_flag; int perr; assert (c); assert (c->magic == IPMICONSOLE_CTX_MAGIC); secure_malloc_flag = (c->config.engine_flags & IPMICONSOLE_ENGINE_LOCK_MEMORY) ? 1 : 0; /* We have to cleanup, so in general continue on even if locking fails */ if ((perr = pthread_mutex_lock (&(c->signal.status_mutex))) != 0) IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr))); /* Don't change status if it's already been set before */ if (c->signal.status != IPMICONSOLE_CTX_STATUS_SOL_ESTABLISHED) { c->signal.status = IPMICONSOLE_CTX_STATUS_SOL_ERROR; status_initial++; } if ((perr = pthread_mutex_unlock (&(c->signal.status_mutex))) != 0) IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr))); if ((perr = pthread_mutex_lock (&(c->blocking.blocking_mutex))) != 0) IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr))); if (c->blocking.blocking_submit_requested && !c->blocking.sol_session_established) { uint8_t tmpbyte; blocking_requested++; if (c->config.behavior_flags & IPMICONSOLE_BEHAVIOR_DEACTIVATE_ONLY && c->session.deactivate_only_succeeded_flag) tmpbyte = IPMICONSOLE_BLOCKING_NOTIFICATION_SOL_SESSION_DEACTIVATED; else tmpbyte = IPMICONSOLE_BLOCKING_NOTIFICATION_SOL_SESSION_ERROR; if (write (c->blocking.blocking_notification[1], &tmpbyte, 1) < 0) IPMICONSOLE_CTX_DEBUG (c, ("write: %s", strerror (errno))); } if ((perr = pthread_mutex_unlock (&(c->blocking.blocking_mutex))) != 0) IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr))); /* only call the callback if it's an initial SOL error and blocking * was not requested and the session was submitted. We do not want * to call the callback if an error happened in API land and we are * calling in via * ipmiconsole_ctx_connection_cleanup_session_not_submitted(). */ if (status_initial && !blocking_requested && session_submitted && c->non_blocking.callback) (*(c->non_blocking.callback))(c->non_blocking.callback_arg); /* Under default circumstances, close only the ipmiconsole_fd so * that an error will be detected by the user via a EOF on a read() * or EPIPE on a write() when reading/writing on their file * descriptor. * * On error situations (i.e. ipmiconsole_engine_submit() doesn't * return to the user w/ success), it is the responsibility of other * code to call _ipmiconsole_ctx_api_managed_session_data_cleanup(). * * The exception to this is when the user specifies the * IPMICONSOLE_ENGINE_CLOSE_FD flag. Then we close it here */ if (c->config.engine_flags & IPMICONSOLE_ENGINE_CLOSE_FD) { /* ignore potential error, cleanup path */ if (c->connection.user_fd >= 0) close (c->connection.user_fd); } /* ignore potential error, cleanup path */ if (c->connection.ipmiconsole_fd >= 0) close (c->connection.ipmiconsole_fd); if (c->connection.console_remote_console_to_bmc) scbuf_destroy (c->connection.console_remote_console_to_bmc, secure_malloc_flag); if (c->connection.console_bmc_to_remote_console) scbuf_destroy (c->connection.console_bmc_to_remote_console, secure_malloc_flag); /* ignore potential error, cleanup path */ if (c->connection.ipmi_fd >= 0) close (c->connection.ipmi_fd); if (c->connection.ipmi_from_bmc) scbuf_destroy (c->connection.ipmi_from_bmc, secure_malloc_flag); if (c->connection.ipmi_to_bmc) scbuf_destroy (c->connection.ipmi_to_bmc, secure_malloc_flag); /* Similarly to the user_fd above, it is the responsibility of other * code to close asynccomm[0] and asynccomm[1], which is replicated * in the context. */ if (c->connection.obj_rmcp_hdr_rq) fiid_obj_destroy (c->connection.obj_rmcp_hdr_rq); if (c->connection.obj_rmcp_hdr_rs) fiid_obj_destroy (c->connection.obj_rmcp_hdr_rs); if (c->connection.obj_lan_session_hdr_rq) fiid_obj_destroy (c->connection.obj_lan_session_hdr_rq); if (c->connection.obj_lan_session_hdr_rs) fiid_obj_destroy (c->connection.obj_lan_session_hdr_rs); if (c->connection.obj_lan_msg_hdr_rq) fiid_obj_destroy (c->connection.obj_lan_msg_hdr_rq); if (c->connection.obj_lan_msg_hdr_rs) fiid_obj_destroy (c->connection.obj_lan_msg_hdr_rs); if (c->connection.obj_lan_msg_trlr_rs) fiid_obj_destroy (c->connection.obj_lan_msg_trlr_rs); if (c->connection.obj_rmcpplus_session_hdr_rq) fiid_obj_destroy (c->connection.obj_rmcpplus_session_hdr_rq); if (c->connection.obj_rmcpplus_session_hdr_rs) fiid_obj_destroy (c->connection.obj_rmcpplus_session_hdr_rs); if (c->connection.obj_rmcpplus_payload_rs) fiid_obj_destroy (c->connection.obj_rmcpplus_payload_rs); if (c->connection.obj_rmcpplus_session_trlr_rq) fiid_obj_destroy (c->connection.obj_rmcpplus_session_trlr_rq); if (c->connection.obj_rmcpplus_session_trlr_rs) fiid_obj_destroy (c->connection.obj_rmcpplus_session_trlr_rs); if (c->connection.obj_authentication_capabilities_rq) fiid_obj_destroy (c->connection.obj_authentication_capabilities_rq); if (c->connection.obj_authentication_capabilities_rs) fiid_obj_destroy (c->connection.obj_authentication_capabilities_rs); if (c->connection.obj_open_session_request) fiid_obj_destroy (c->connection.obj_open_session_request); if (c->connection.obj_open_session_response) fiid_obj_destroy (c->connection.obj_open_session_response); if (c->connection.obj_rakp_message_1) fiid_obj_destroy (c->connection.obj_rakp_message_1); if (c->connection.obj_rakp_message_2) fiid_obj_destroy (c->connection.obj_rakp_message_2); if (c->connection.obj_rakp_message_3) fiid_obj_destroy (c->connection.obj_rakp_message_3); if (c->connection.obj_rakp_message_4) fiid_obj_destroy (c->connection.obj_rakp_message_4); if (c->connection.obj_set_session_privilege_level_rq) fiid_obj_destroy (c->connection.obj_set_session_privilege_level_rq); if (c->connection.obj_set_session_privilege_level_rs) fiid_obj_destroy (c->connection.obj_set_session_privilege_level_rs); if (c->connection.obj_get_channel_payload_support_rq) fiid_obj_destroy (c->connection.obj_get_channel_payload_support_rq); if (c->connection.obj_get_channel_payload_support_rs) fiid_obj_destroy (c->connection.obj_get_channel_payload_support_rs); if (c->connection.obj_get_payload_activation_status_rq) fiid_obj_destroy (c->connection.obj_get_payload_activation_status_rq); if (c->connection.obj_get_payload_activation_status_rs) fiid_obj_destroy (c->connection.obj_get_payload_activation_status_rs); if (c->connection.obj_activate_payload_rq) fiid_obj_destroy (c->connection.obj_activate_payload_rq); if (c->connection.obj_activate_payload_rs) fiid_obj_destroy (c->connection.obj_activate_payload_rs); if (c->connection.obj_sol_payload_data_rq) fiid_obj_destroy (c->connection.obj_sol_payload_data_rq); if (c->connection.obj_sol_payload_data_rs) fiid_obj_destroy (c->connection.obj_sol_payload_data_rs); if (c->connection.obj_get_channel_payload_version_rq) fiid_obj_destroy (c->connection.obj_get_channel_payload_version_rq); if (c->connection.obj_get_channel_payload_version_rs) fiid_obj_destroy (c->connection.obj_get_channel_payload_version_rs); if (c->connection.obj_deactivate_payload_rq) fiid_obj_destroy (c->connection.obj_deactivate_payload_rq); if (c->connection.obj_deactivate_payload_rs) fiid_obj_destroy (c->connection.obj_deactivate_payload_rs); if (c->connection.obj_close_session_rq) fiid_obj_destroy (c->connection.obj_close_session_rq); if (c->connection.obj_close_session_rs) fiid_obj_destroy (c->connection.obj_close_session_rs); _ipmiconsole_ctx_connection_init (c); /* If the session was never submitted (i.e. error in API land), don't * move this around. */ /* achu: See note in ipmiconsole_defs.h about the * c->session_submitted flag. That flag is only used in API land * for the user to know if a session was submitted or not. The * session_submitted flag passed into this function is the "real" * one that is known by the engine, and is not dependent on any race * conditions with the API level. */ if (!session_submitted) return; /* Be careful, if the user requested to destroy the context, we can * destroy it here. But if we destroy it, there is no mutex to * unlock. */ /* Note: the code in __ipmiconsole_ctx_connection_cleanup() and * ipmiconsole_garbage_collector() may look like it may race and * could deadlock. (ABBA and BAAB deadlock situation). However, * the context mutex c->signal.destroyed_mutex is accessed in * __ipmiconsole_ctx_connection_cleanup() when trying to add this item * to the console_engine_ctxs_to_destroy list. It is accessed in * ipmiconsole_garbage_collector() only on the items already in the * console_engine_ctxs_to_destroy list. So the * c->signal.destroyed_mutex can never be raced against in these two * functions. */ if ((perr = pthread_mutex_lock (&(c->signal.destroyed_mutex))) != 0) IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr))); if (c->signal.user_has_destroyed) { ipmiconsole_ctx_debug_cleanup (c); ipmiconsole_ctx_signal_cleanup (c); ipmiconsole_ctx_blocking_cleanup (c); ipmiconsole_ctx_cleanup (c); } else { if (!c->signal.moved_to_destroyed) { void *ptr; c->signal.moved_to_destroyed++; /* I suppose if we fail here, we mem-leak?? Log for now ... */ if ((perr = pthread_mutex_lock (&(console_engine_ctxs_to_destroy_mutex))) != 0) IPMICONSOLE_DEBUG (("pthread_mutex_lock: %s", strerror (perr))); if (!(ptr = list_append (console_engine_ctxs_to_destroy, c))) IPMICONSOLE_DEBUG (("list_append: %s", strerror (errno))); if (ptr != (void *)c) IPMICONSOLE_DEBUG (("list_append: invalid pointer: ptr=%p; c=%p", ptr, c)); if ((perr = pthread_mutex_unlock (&(console_engine_ctxs_to_destroy_mutex))) != 0) IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr))); } if ((perr = pthread_mutex_unlock (&(c->signal.destroyed_mutex))) != 0) IPMICONSOLE_DEBUG (("pthread_mutex_unlock: %s", strerror (perr))); } }
/* * 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); }
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); }
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_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); }