static int serve_request_main(sec_mod_st *sec, int fd, uint8_t *buffer, unsigned buffer_size) { int ret, e; uint8_t cmd; size_t length; void *pool = buffer; /* read request */ ret = recv_msg_headers(fd, &cmd, MAIN_SEC_MOD_TIMEOUT); if (ret < 0) { seclog(sec, LOG_ERR, "error receiving msg head from main"); ret = ERR_BAD_COMMAND; goto leave; } length = ret; seclog(sec, LOG_DEBUG, "received request %s", cmd_request_to_str(cmd)); if (cmd <= MIN_SECM_CMD || cmd >= MAX_SECM_CMD) { seclog(sec, LOG_ERR, "received invalid message from main of %u bytes (cmd: %u)\n", (unsigned)length, (unsigned)cmd); return ERR_BAD_COMMAND; } if (length > buffer_size) { seclog(sec, LOG_ERR, "received too big message (%d)", (int)length); ret = ERR_BAD_COMMAND; goto leave; } /* read the body */ ret = force_read_timeout(fd, buffer, length, MAIN_SEC_MOD_TIMEOUT); if (ret < 0) { e = errno; seclog(sec, LOG_ERR, "error receiving msg body of cmd %u with length %u: %s", cmd, (unsigned)length, strerror(e)); ret = ERR_BAD_COMMAND; goto leave; } ret = process_packet_from_main(pool, fd, sec, cmd, buffer, ret); if (ret < 0) { seclog(sec, LOG_ERR, "error processing data for '%s' command (%d)", cmd_request_to_str(cmd), ret); } leave: return ret; }
static int serve_request_worker(sec_mod_st *sec, int cfd, pid_t pid, uint8_t *buffer, unsigned buffer_size) { int ret, e; uint8_t cmd; size_t length; void *pool = buffer; /* read request */ ret = recv_msg_headers(cfd, &cmd, MAX_WAIT_SECS); if (ret < 0) { seclog(sec, LOG_DEBUG, "error receiving msg head from worker"); goto leave; } length = ret; if (length > buffer_size) { seclog(sec, LOG_INFO, "too big message (%d)", (int)length); ret = -1; goto leave; } /* read the body */ ret = force_read_timeout(cfd, buffer, length, MAX_WAIT_SECS); if (ret < 0) { e = errno; seclog(sec, LOG_INFO, "error receiving msg body: %s", strerror(e)); ret = -1; goto leave; } ret = process_worker_packet(pool, cfd, pid, sec, cmd, buffer, ret); if (ret < 0) { seclog(sec, LOG_INFO, "error processing data for '%s' command (%d)", cmd_request_to_str(cmd), ret); } leave: return ret; }
int handle_commands_from_main(struct worker_st *ws) { uint8_t cmd; size_t length; uint8_t cmd_data[1536]; UdpFdMsg *tmsg = NULL; int ret; int fd = -1; /*int cmd_data_len;*/ memset(&cmd_data, 0, sizeof(cmd_data)); ret = recv_msg_data(ws->cmd_fd, &cmd, cmd_data, sizeof(cmd_data), &fd); if (ret < 0) { oclog(ws, LOG_DEBUG, "cannot obtain data from command socket"); exit_worker_reason(ws, REASON_SERVER_DISCONNECT); } if (ret == 0) { oclog(ws, LOG_ERR, "parent terminated"); return ERR_NO_CMD_FD; } length = ret; oclog(ws, LOG_DEBUG, "worker received message %s of %u bytes\n", cmd_request_to_str(cmd), (unsigned)length); /*cmd_data_len = ret - 1;*/ switch(cmd) { case CMD_TERMINATE: exit_worker_reason(ws, REASON_SERVER_DISCONNECT); case CMD_UDP_FD: { unsigned has_hello = 1; if (ws->udp_state != UP_WAIT_FD) { oclog(ws, LOG_DEBUG, "received another a UDP fd!"); } tmsg = udp_fd_msg__unpack(NULL, length, cmd_data); if (tmsg) { has_hello = tmsg->hello; } if (fd == -1) { oclog(ws, LOG_ERR, "received UDP fd message of wrong type"); goto udp_fd_fail; } set_non_block(fd); if (has_hello == 0) { /* check if the first packet received is a valid one - * if not discard the new fd */ if (!recv_from_new_fd(ws, fd, tmsg)) { oclog(ws, LOG_INFO, "received UDP fd message but its session has invalid data!"); if (tmsg) udp_fd_msg__free_unpacked(tmsg, NULL); close(fd); return 0; } RESET_DTLS_MTU(ws); } else { /* received client hello */ ws->udp_state = UP_SETUP; } if (ws->dtls_tptr.fd != -1) close(ws->dtls_tptr.fd); if (ws->dtls_tptr.msg != NULL) udp_fd_msg__free_unpacked(ws->dtls_tptr.msg, NULL); ws->dtls_tptr.msg = tmsg; ws->dtls_tptr.fd = fd; oclog(ws, LOG_DEBUG, "received new UDP fd and connected to peer"); return 0; } break; default: oclog(ws, LOG_ERR, "unknown CMD 0x%x", (unsigned)cmd); exit_worker_reason(ws, REASON_ERROR); } return 0; udp_fd_fail: if (tmsg) udp_fd_msg__free_unpacked(tmsg, NULL); if (ws->dtls_tptr.fd == -1) ws->udp_state = UP_DISABLED; return -1; }
static int process_packet_from_main(void *pool, int fd, sec_mod_st * sec, cmd_request_t cmd, uint8_t * buffer, size_t buffer_size) { gnutls_datum_t data; int ret; PROTOBUF_ALLOCATOR(pa, pool); seclog(sec, LOG_DEBUG, "cmd [size=%d] %s\n", (int)buffer_size, cmd_request_to_str(cmd)); data.data = buffer; data.size = buffer_size; switch (cmd) { case CMD_SECM_LIST_COOKIES: handle_secm_list_cookies_reply(pool, fd, sec); return 0; case CMD_SECM_BAN_IP_REPLY:{ BanIpReplyMsg *msg = NULL; msg = ban_ip_reply_msg__unpack(&pa, data.size, data.data); if (msg == NULL) { seclog(sec, LOG_INFO, "error unpacking auth ban ip reply\n"); return ERR_BAD_COMMAND; } handle_sec_auth_ban_ip_reply(sec, msg); ban_ip_reply_msg__free_unpacked(msg, &pa); return 0; } case CMD_SECM_SESSION_OPEN:{ SecmSessionOpenMsg *msg; msg = secm_session_open_msg__unpack(&pa, data.size, data.data); if (msg == NULL) { seclog(sec, LOG_INFO, "error unpacking session open\n"); return ERR_BAD_COMMAND; } ret = handle_secm_session_open_cmd(sec, fd, msg); secm_session_open_msg__free_unpacked(msg, &pa); return ret; } case CMD_SECM_SESSION_CLOSE:{ SecmSessionCloseMsg *msg; msg = secm_session_close_msg__unpack(&pa, data.size, data.data); if (msg == NULL) { seclog(sec, LOG_INFO, "error unpacking session close\n"); return ERR_BAD_COMMAND; } ret = handle_secm_session_close_cmd(sec, fd, msg); secm_session_close_msg__free_unpacked(msg, &pa); return ret; } default: seclog(sec, LOG_WARNING, "unknown type 0x%.2x", cmd); return ERR_BAD_COMMAND; } return 0; }
static int process_worker_packet(void *pool, int cfd, pid_t pid, sec_mod_st * sec, cmd_request_t cmd, uint8_t * buffer, size_t buffer_size) { unsigned i; gnutls_datum_t data, out; int ret; SecOpMsg *op; PROTOBUF_ALLOCATOR(pa, pool); seclog(sec, LOG_DEBUG, "cmd [size=%d] %s\n", (int)buffer_size, cmd_request_to_str(cmd)); data.data = buffer; data.size = buffer_size; switch (cmd) { case CMD_SEC_SIGN: case CMD_SEC_DECRYPT: op = sec_op_msg__unpack(&pa, data.size, data.data); if (op == NULL) { seclog(sec, LOG_INFO, "error unpacking sec op\n"); return -1; } i = op->key_idx; if (op->has_key_idx == 0 || i >= sec->key_size) { seclog(sec, LOG_INFO, "received out-of-bounds key index (%d)", i); return -1; } data.data = op->data.data; data.size = op->data.len; if (cmd == CMD_SEC_DECRYPT) { ret = gnutls_privkey_decrypt_data(sec->key[i], 0, &data, &out); } else { #if GNUTLS_VERSION_NUMBER >= 0x030200 ret = gnutls_privkey_sign_hash(sec->key[i], 0, GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA, &data, &out); #else ret = gnutls_privkey_sign_raw_data(sec->key[i], 0, &data, &out); #endif } sec_op_msg__free_unpacked(op, &pa); if (ret < 0) { seclog(sec, LOG_INFO, "error in crypto operation: %s", gnutls_strerror(ret)); return -1; } ret = handle_op(pool, cfd, sec, cmd, out.data, out.size); gnutls_free(out.data); return ret; case CMD_SEC_CLI_STATS:{ CliStatsMsg *tmsg; tmsg = cli_stats_msg__unpack(&pa, data.size, data.data); if (tmsg == NULL) { seclog(sec, LOG_ERR, "error unpacking data"); return -1; } ret = handle_sec_auth_stats_cmd(sec, tmsg, pid); cli_stats_msg__free_unpacked(tmsg, &pa); return ret; } break; case CMD_SEC_AUTH_INIT:{ SecAuthInitMsg *auth_init; auth_init = sec_auth_init_msg__unpack(&pa, data.size, data.data); if (auth_init == NULL) { seclog(sec, LOG_INFO, "error unpacking auth init\n"); return -1; } ret = handle_sec_auth_init(cfd, sec, auth_init, pid); sec_auth_init_msg__free_unpacked(auth_init, &pa); return ret; } case CMD_SEC_AUTH_CONT:{ SecAuthContMsg *auth_cont; auth_cont = sec_auth_cont_msg__unpack(&pa, data.size, data.data); if (auth_cont == NULL) { seclog(sec, LOG_INFO, "error unpacking auth cont\n"); return -1; } ret = handle_sec_auth_cont(cfd, sec, auth_cont); sec_auth_cont_msg__free_unpacked(auth_cont, &pa); return ret; } case RESUME_STORE_REQ:{ SessionResumeStoreReqMsg *smsg; smsg = session_resume_store_req_msg__unpack(&pa, buffer_size, buffer); if (smsg == NULL) { seclog(sec, LOG_ERR, "error unpacking data"); return ERR_BAD_COMMAND; } ret = handle_resume_store_req(sec, smsg); /* zeroize the data */ safe_memset(buffer, 0, buffer_size); safe_memset(smsg->session_data.data, 0, smsg->session_data.len); session_resume_store_req_msg__free_unpacked(smsg, &pa); if (ret < 0) { seclog(sec, LOG_DEBUG, "could not store resumption data"); } } break; case RESUME_DELETE_REQ:{ SessionResumeFetchMsg *fmsg; fmsg = session_resume_fetch_msg__unpack(&pa, buffer_size, buffer); if (fmsg == NULL) { seclog(sec, LOG_ERR, "error unpacking data"); return ERR_BAD_COMMAND; } ret = handle_resume_delete_req(sec, fmsg); session_resume_fetch_msg__free_unpacked(fmsg, &pa); if (ret < 0) { seclog(sec, LOG_DEBUG, "could not delete resumption data."); } } break; case RESUME_FETCH_REQ:{ SessionResumeReplyMsg msg = SESSION_RESUME_REPLY_MSG__INIT; SessionResumeFetchMsg *fmsg; /* FIXME: rate limit that */ fmsg = session_resume_fetch_msg__unpack(&pa, buffer_size, buffer); if (fmsg == NULL) { seclog(sec, LOG_ERR, "error unpacking data"); return ERR_BAD_COMMAND; } ret = handle_resume_fetch_req(sec, fmsg, &msg); session_resume_fetch_msg__free_unpacked(fmsg, &pa); if (ret < 0) { msg.reply = SESSION_RESUME_REPLY_MSG__RESUME__REP__FAILED; seclog(sec, LOG_DEBUG, "could not fetch resumption data."); } else { msg.reply = SESSION_RESUME_REPLY_MSG__RESUME__REP__OK; } ret = send_msg(pool, cfd, RESUME_FETCH_REP, &msg, (pack_size_func) session_resume_reply_msg__get_packed_size, (pack_func) session_resume_reply_msg__pack); if (ret < 0) { seclog(sec, LOG_ERR, "could not send reply cmd %d.", (unsigned)cmd); return ERR_BAD_COMMAND; } } break; default: seclog(sec, LOG_WARNING, "unknown type 0x%.2x", cmd); return -1; } return 0; }