static int rakp_hmac_c4(rakp_info_t *info, unsigned char *data, unsigned int data_len) { unsigned char idata[36]; unsigned int ilen; unsigned char integ_data[20]; rakp_hmac_key_t *rinfo = info->key_data; const unsigned char *p; unsigned int plen; if (data_len < 8+rinfo->integ_len) return E2BIG; p = ipmi_rmcpp_auth_get_my_rand(info->ainfo, &plen); memcpy(idata+0, p, 16); ipmi_set_uint32(idata+16, ipmi_rmcpp_auth_get_mgsys_session_id(info->ainfo)); p = ipmi_rmcpp_auth_get_mgsys_guid(info->ainfo, &plen); if (plen < 16) return EINVAL; memcpy(idata+20, p, 16); p = ipmi_rmcpp_auth_get_sik(info->ainfo, &plen); HMAC(rinfo->evp_md, p, rinfo->key_len, idata, 36, integ_data, &ilen); if (memcmp(data+8, integ_data, rinfo->integ_len) != 0) return EINVAL; return 0; }
static void handle_picmg_cmd_get_shelf_manager_ip_addresses(lmc_data_t *mc, msg_t *msg, unsigned char *rdata, unsigned int *rdata_len, void *cb_data) { emu_data_t *emu = mc->emu; unsigned int addr; unsigned int count; emu_addr_t *ap = NULL; int i; if (check_msg_length(msg, 2, rdata, rdata_len)) return; addr = msg->data[1]; for (count=0, i=0; i<MAX_EMU_ADDR; i++) { if (emu->addr[i].valid) { if (count == addr) ap = &(emu->addr[i]); count++; } } if (addr >= count) { rdata[0] = IPMI_PARAMETER_OUT_OF_RANGE_CC; *rdata_len = 1; return; } rdata[0] = 0; ipmi_set_uint32(rdata+1, emu->last_addr_change_time.tv_sec); rdata[5] = count; rdata[6] = 0x03; rdata[7] = addr - 1; rdata[8] = 20; rdata[9] = ap->addr_type; if (addr == 0) rdata[9] |= 0x80; memcpy(rdata+10, ap->addr_data, ap->addr_len); *rdata_len = 10 + ap->addr_len; }
static int send_rakp3(ipmi_con_t *ipmi, rakp_info_t *info, ipmi_msgi_t *rspi, int addr_num, int err) { int rv; unsigned char data[64]; ipmi_msg_t msg; ipmi_rmcpp_addr_t addr; memset(data, 0, sizeof(data)); data[0] = info->msg_tag; data[1] = err; ipmi_set_uint32(data+4, ipmi_rmcpp_auth_get_mgsys_session_id(info->ainfo)); msg.netfn = IPMI_RMCPP_DUMMY_NETFN; msg.cmd = 0; msg.data = data; msg.data_len = 8; addr.addr_type = IPMI_RMCPP_ADDR_START + IPMI_RMCPP_PAYLOAD_TYPE_RAKP_3; rspi->data1 = info; if (info->set3) { unsigned int len; len = msg.data_len; rv = info->set3(info, data, &len, sizeof(data)); if (rv) return rv; msg.data_len = len; } if (err) /* Don't handle the responst (if one comes back) on an error. */ rv = ipmi_lan_send_command_forceip(ipmi, addr_num, (ipmi_addr_t *) &addr, sizeof(addr), &msg, NULL, rspi); else rv = ipmi_lan_send_command_forceip(ipmi, addr_num, (ipmi_addr_t *) &addr, sizeof(addr), &msg, handle_rakp4, rspi); return rv; }
static int send_rakp1(ipmi_con_t *ipmi, rakp_info_t *info, ipmi_msgi_t *rspi, int addr_num) { int rv; unsigned char data[44]; ipmi_msg_t msg; ipmi_rmcpp_addr_t addr; const unsigned char *p; unsigned int plen; memset(data, 0, sizeof(data)); data[0] = info->msg_tag; ipmi_set_uint32(data+4, ipmi_rmcpp_auth_get_mgsys_session_id(info->ainfo)); p = ipmi_rmcpp_auth_get_my_rand(info->ainfo, &plen); if (plen < 16) return EINVAL; memcpy(data+8, p, 16); data[24] = ipmi_rmcpp_auth_get_role(info->ainfo); data[27] = ipmi_rmcpp_auth_get_username_len(info->ainfo); p = ipmi_rmcpp_auth_get_username(info->ainfo, &plen); if (plen < 16) return EINVAL; memcpy(data+28, p, data[27]); msg.netfn = IPMI_RMCPP_DUMMY_NETFN; msg.cmd = 0; msg.data = data; msg.data_len = 28 + data[27]; addr.addr_type = IPMI_RMCPP_ADDR_START + IPMI_RMCPP_PAYLOAD_TYPE_RAKP_1; rspi->data1 = info; rv = ipmi_lan_send_command_forceip(ipmi, addr_num, (ipmi_addr_t *) &addr, sizeof(addr), &msg, handle_rakp2, rspi); return rv; }
static int rakp_hmac_s3(rakp_info_t *info, unsigned char *data, unsigned int *data_len, unsigned int total_len) { unsigned char idata[38]; unsigned int ilen; rakp_hmac_key_t *rinfo = info->key_data; const unsigned char *p; unsigned int plen; if (((*data_len)+rinfo->key_len) > total_len) return E2BIG; p = ipmi_rmcpp_auth_get_mgsys_rand(info->ainfo, &plen); memcpy(idata+0, p, 16); ipmi_set_uint32(idata+16, ipmi_rmcpp_auth_get_my_session_id(info->ainfo)); idata[20] = ipmi_rmcpp_auth_get_role(info->ainfo); if (info->hacks & IPMI_CONN_HACK_RAKP3_WRONG_ROLEM) /* For the RAKP3 message, the Intel BMC only uses the bottom 4 nibbles. */ idata[20] &= 0xf; idata[21] = ipmi_rmcpp_auth_get_username_len(info->ainfo); if (idata[21] > 16) return EINVAL; p = ipmi_rmcpp_auth_get_username(info->ainfo, &plen); memcpy(idata+22, p, idata[21]); p = ipmi_rmcpp_auth_get_password(info->ainfo, &plen); if (plen < rinfo->key_len) return EINVAL; HMAC(rinfo->evp_md, p, rinfo->key_len, idata, 22+idata[21], data+*data_len, &ilen); *data_len += rinfo->key_len; return 0; }
void ipmi_sol_activate(lmc_data_t *mc, channel_t *channel, msg_t *msg, unsigned char *rdata, unsigned int *rdata_len) { ipmi_sol_t *sol = ipmi_mc_get_sol(mc); soldata_t *sd = sol->soldata; uint16_t port; int rv; msg_t *dmsg; unsigned int instance; if (!sol->solparm.enabled) { rdata[0] = 0x81; /* Payload is disabled. */ *rdata_len = 1; return; } /* * FIXME - we are currently ignoring all the payload encryption and * authentication bits in the message. */ instance = msg->data[1] & 0xf; if (instance == 1) { if (sol->active) { *rdata = 0x80; /* Payload already active */ *rdata_len = 1; return; } dmsg = &sd->dummy_send_msg; } else if (instance == 2 && sol->history_size) { if (sol->history_active) { *rdata = 0x80; /* Payload already active */ *rdata_len = 1; return; } dmsg = &sd->history_dummy_send_msg; } else { rdata[0] = IPMI_INVALID_DATA_FIELD_CC; *rdata_len = 1; return; } dmsg->src_addr = sd->sys->alloc(sd->sys, msg->src_len); if (!dmsg->src_addr) { rdata[0] = IPMI_OUT_OF_SPACE_CC; *rdata_len = 1; return; } memcpy(dmsg->src_addr, msg->src_addr, msg->src_len); dmsg->src_len = msg->src_len; dmsg->rmcpp.payload = IPMI_RMCPP_PAYLOAD_TYPE_SOL; rv = channel->set_associated_mc(channel, msg->sid, msg->data[0] & 0xf, mc, &port, sol_session_closed, sol); if (rv == EBUSY) { sd->sys->free(sd->sys, dmsg->src_addr); dmsg->src_addr = NULL; rdata[0] = IPMI_NODE_BUSY_CC; *rdata_len = 1; return; } else if (rv) { sd->sys->free(sd->sys, dmsg->src_addr); dmsg->src_addr = NULL; rdata[0] = IPMI_UNKNOWN_ERR_CC; *rdata_len = 1; return; } dmsg->sid = msg->sid; if (instance == 1) { rv = sd->activate(sol, msg); if (rv) { sd->sys->free(sd->sys, dmsg->src_addr); dmsg->src_addr = NULL; rdata[0] = IPMI_UNKNOWN_ERR_CC; *rdata_len = 1; return; } sol->active = 1; sol->session_id = msg->sid; sd->channel = channel; sd->outlen = 0; ipmi_set_uint16(rdata + 5, sizeof(sd->inbuf)); ipmi_set_uint16(rdata + 7, sizeof(sd->outbuf)); } else if (instance == 2 && sol->history_size) { struct timeval tv; sd->history_copy = copy_history_buffer(sol, &sd->history_copy_size); if (!sd->history_copy) { rdata[0] = IPMI_OUT_OF_SPACE_CC; *rdata_len = 1; return; } sd->history_pos = 0; sol->history_active = 1; sol->history_session_id = msg->sid; sd->history_channel = channel; ipmi_set_uint16(rdata + 5, MAX_HISTORY_SEND); ipmi_set_uint16(rdata + 7, MAX_HISTORY_SEND); tv.tv_sec = 0; tv.tv_usec = 0; /* Send immediately */ sd->history_num_sends = 0; sd->sys->start_timer(sd->history_timer, &tv); } rdata[0] = 0; ipmi_set_uint32(rdata + 1, 0); ipmi_set_uint16(rdata + 9, port); ipmi_set_uint16(rdata + 11, 0xffff); *rdata_len = 13; }
static void handle_picmg_cmd_fru_inventory_device_lock_control(lmc_data_t *mc, msg_t *msg, unsigned char *rdata, unsigned int *rdata_len, void *cb_data) { emu_data_t *emu = mc->emu; uint16_t lock_id; fru_data_t *fru; if (mc->ipmb != 0x20) { handle_invalid_cmd(mc, rdata, rdata_len); return; } if (check_msg_length(msg, 5, rdata, rdata_len)) return; if (msg->data[1] != 254) { rdata[0] = IPMI_DESTINATION_UNAVAILABLE_CC; *rdata_len = 1; return; } rdata[0] = 0; rdata[1] = IPMI_PICMG_GRP_EXT; switch (msg->data[2]) { case 0: rdata[2] = 0; rdata[3] = 0; ipmi_set_uint32(rdata+4, emu->atca_fru_inv_curr_timestamp); *rdata_len = 8; break; case 1: if (emu->atca_fru_inv_locked) { rdata[0] = 0x81; *rdata_len = 1; break; } fru = find_fru(mc, 254); if (!fru || fru->length == 0) { rdata[0] = IPMI_NOT_SUPPORTED_IN_PRESENT_STATE_CC; *rdata_len = 1; break; } emu->temp_fru_inv_data = malloc(fru->length); if (!emu->temp_fru_inv_data) { rdata[0] = IPMI_OUT_OF_SPACE_CC; *rdata_len = 1; break; } emu->temp_fru_inv_data_len = fru->length; memcpy(emu->temp_fru_inv_data, fru->data, emu->temp_fru_inv_data_len); emu->atca_fru_inv_locked = 1; emu->atca_fru_inv_curr_lock_id++; ipmi_set_uint16(rdata+2, emu->atca_fru_inv_curr_lock_id); ipmi_set_uint32(rdata+4, emu->atca_fru_inv_curr_timestamp); *rdata_len = 8; emu->atca_fru_inv_lock_timeout = 20; break; case 2: lock_id = ipmi_get_uint16(msg->data+3); if (!emu->atca_fru_inv_locked || (lock_id != emu->atca_fru_inv_curr_lock_id)) { rdata[0] = 0x81; *rdata_len = 1; break; } emu->atca_fru_inv_locked = 0; rdata[2] = 0; rdata[3] = 0; ipmi_set_uint32(rdata+4, emu->atca_fru_inv_curr_timestamp); *rdata_len = 8; free(emu->temp_fru_inv_data); emu->temp_fru_inv_data = NULL; break; case 3: lock_id = ipmi_get_uint16(msg->data+3); if (!emu->atca_fru_inv_locked || (lock_id != emu->atca_fru_inv_curr_lock_id)) { rdata[0] = 0x81; *rdata_len = 1; break; } emu->atca_fru_inv_locked = 0; rdata[2] = 0; rdata[3] = 0; ipmi_set_uint32(rdata+4, emu->atca_fru_inv_curr_timestamp); *rdata_len = 8; emu->atca_fru_inv_curr_timestamp++; /* FIXME - validate data. */ fru = find_fru(mc, 254); if (!fru || fru->length == 0) { rdata[0] = IPMI_NOT_SUPPORTED_IN_PRESENT_STATE_CC; *rdata_len = 1; break; } memcpy(fru->data, emu->temp_fru_inv_data, emu->temp_fru_inv_data_len); free(emu->temp_fru_inv_data); emu->temp_fru_inv_data = NULL; break; default: rdata[0] = IPMI_INVALID_DATA_FIELD_CC; *rdata_len = 1; break; } }
static int rakp_hmac_c2(rakp_info_t *info, unsigned char *data, unsigned int data_len) { unsigned char idata[74]; unsigned int ilen; unsigned char integ_data[20]; rakp_hmac_key_t *rinfo = info->key_data; const unsigned char *p; unsigned char *s; unsigned char *k; unsigned int plen; if (data_len < 40+rinfo->key_len) return E2BIG; ipmi_set_uint32(idata+0, ipmi_rmcpp_auth_get_my_session_id(info->ainfo)); ipmi_set_uint32(idata+4, ipmi_rmcpp_auth_get_mgsys_session_id(info->ainfo)); p = ipmi_rmcpp_auth_get_my_rand(info->ainfo, &plen); memcpy(idata+8, p, 16); p = ipmi_rmcpp_auth_get_mgsys_rand(info->ainfo, &plen); memcpy(idata+24, p, 16); p = ipmi_rmcpp_auth_get_mgsys_guid(info->ainfo, &plen); memcpy(idata+40, p, 16); idata[56] = ipmi_rmcpp_auth_get_role(info->ainfo); idata[57] = ipmi_rmcpp_auth_get_username_len(info->ainfo); if (idata[57] > 16) return EINVAL; p = ipmi_rmcpp_auth_get_username(info->ainfo, &plen); memcpy(idata+58, p, idata[57]); p = ipmi_rmcpp_auth_get_password(info->ainfo, &plen); if (plen < rinfo->key_len) return EINVAL; HMAC(rinfo->evp_md, p, rinfo->key_len, idata, 58+idata[57], integ_data, &ilen); if (memcmp(data+40, integ_data, rinfo->key_len) != 0) return EINVAL; /* Now generate the SIK */ p = ipmi_rmcpp_auth_get_my_rand(info->ainfo, &plen); memcpy(idata+0, p, 16); p = ipmi_rmcpp_auth_get_mgsys_rand(info->ainfo, &plen); memcpy(idata+16, p, 16); idata[32] = ipmi_rmcpp_auth_get_role(info->ainfo); idata[33] = ipmi_rmcpp_auth_get_username_len(info->ainfo); p = ipmi_rmcpp_auth_get_username(info->ainfo, &plen); memcpy(idata+34, p, idata[33]); p = ipmi_rmcpp_auth_get_bmc_key(info->ainfo, &plen); if (plen < rinfo->key_len) return EINVAL; s = ipmi_rmcpp_auth_get_sik(info->ainfo, &plen); if (plen < rinfo->key_len) return EINVAL; HMAC(rinfo->evp_md, p, rinfo->key_len, idata, 34+idata[33], s, &ilen); ipmi_rmcpp_auth_set_sik_len(info->ainfo, rinfo->key_len); /* Now generate k1 and k2. */ k = ipmi_rmcpp_auth_get_k1(info->ainfo, &plen); if (plen < rinfo->key_len) return EINVAL; memset(idata, 1, rinfo->key_len); HMAC(rinfo->evp_md, s, rinfo->key_len, idata, rinfo->key_len, k, &ilen); ipmi_rmcpp_auth_set_k2_len(info->ainfo, rinfo->key_len); k = ipmi_rmcpp_auth_get_k2(info->ainfo, &plen); if (plen < rinfo->key_len) return EINVAL; memset(idata, 2, rinfo->key_len); HMAC(rinfo->evp_md, s, rinfo->key_len, idata, rinfo->key_len, k, &ilen); ipmi_rmcpp_auth_set_k2_len(info->ainfo, rinfo->key_len); return 0; }