/* hdr parameter is received from dom0, so it is trusted */ void handle_server_exec_request(struct msg_header *hdr) { struct exec_params params; int buf_len = hdr->len-sizeof(params); char buf[buf_len]; pid_t child_agent; int client_fd; assert(hdr->len >= sizeof(params)); if (libvchan_recv(ctrl_vchan, ¶ms, sizeof(params)) < 0) handle_vchan_error("read exec params"); if (libvchan_recv(ctrl_vchan, buf, buf_len) < 0) handle_vchan_error("read exec cmd"); if ((hdr->type == MSG_EXEC_CMDLINE || hdr->type == MSG_JUST_EXEC) && !strstr(buf, ":nogui:")) { int child_socket = try_fork_server(hdr->type, params.connect_domain, params.connect_port, buf, buf_len); if (child_socket >= 0) { register_vchan_connection(-1, child_socket, params.connect_domain, params.connect_port); return; } } if (hdr->type == MSG_SERVICE_CONNECT && sscanf(buf, "SOCKET%d", &client_fd)) { /* FIXME: Maybe add some check if client_fd is really FD to some * qrexec-client-vm process; but this data comes from qrexec-daemon * (which sends back what it got from us earlier), so it isn't critical. */ if (write(client_fd, ¶ms, sizeof(params)) < 0) { /* ignore */ } /* No need to send request_id (buf) - the client don't need it, there * is only meaningless (for the client) socket FD */ /* Register connection even if there was an error sending params to * qrexec-client-vm. This way the mainloop will clean the things up * (close socket, send MSG_CONNECTION_TERMINATED) when qrexec-client-vm * will close the socket (terminate itself). */ register_vchan_connection(-1, client_fd, params.connect_domain, params.connect_port); return; } /* No fork server case */ child_agent = handle_new_process(hdr->type, params.connect_domain, params.connect_port, buf, buf_len); register_vchan_connection(child_agent, -1, params.connect_domain, params.connect_port); }
void handle_server_cmd() { struct msg_header s_hdr; if (libvchan_recv(ctrl_vchan, &s_hdr, sizeof(s_hdr)) < 0) handle_vchan_error("read s_hdr"); // fprintf(stderr, "got %x %x %x\n", s_hdr.type, s_hdr.client_id, // s_hdr.len); switch (s_hdr.type) { case MSG_EXEC_CMDLINE: case MSG_JUST_EXEC: case MSG_SERVICE_CONNECT: wake_meminfo_writer(); handle_server_exec_request(&s_hdr); break; case MSG_SERVICE_REFUSED: handle_service_refused(&s_hdr); break; default: fprintf(stderr, "msg type from daemon is %d ?\n", s_hdr.type); exit(1); } }
static void rec_packet(libvchan_t * con) { char done = 1; int data[4]; struct camera_data ca; libvchan_wait(con); int readSize = libvchan_recv(con, data, 4*sizeof(int)); assert(readSize == 4*sizeof(int)); DVM("received bounding box packet\n"); //here are your corners Lee! ca.bbox_l = data[0]; ca.bbox_r = data[1]; ca.bbox_t = data[2]; ca.bbox_b = data[3]; /* int xmid = ((r + l) / 2) - 160; */ /* int ymid = ((b + t) / 2) - 100; */ /* ymid = -1.0*ymid; //sign change (based on how the camera is oriented) */ /* //here are your angles Lee! */ /* ca.angle_x = ((float) xmid)*(0.00410666); */ /* ca.angle_y = ((float) ymid)*(0.00410666); */ if (camera_vm_Output_from_vm_0_write_camera_data(&ca)) { DVM("wrote bounding box\n"); } else { DVM("failed to write bouding box\n"); } DVM("camera_vm: sending ack\n"); libvchan_send(con, &done, sizeof(char)); }
int handle_agent_hello(libvchan_t *ctrl, const char *domain_name) { struct msg_header hdr; struct peer_info info; if (libvchan_recv(ctrl, &hdr, sizeof(hdr)) != sizeof(hdr)) { fprintf(stderr, "Failed to read agent HELLO hdr\n"); return -1; } if (hdr.type != MSG_HELLO || hdr.len != sizeof(info)) { fprintf(stderr, "Invalid HELLO packet received: type %d, len %d\n", hdr.type, hdr.len); return -1; } if (libvchan_recv(ctrl, &info, sizeof(info)) != sizeof(info)) { fprintf(stderr, "Failed to read agent HELLO body\n"); return -1; } if (info.version != QREXEC_PROTOCOL_VERSION) { fprintf(stderr, "Incompatible agent protocol version (remote %d, local %d)\n", info.version, QREXEC_PROTOCOL_VERSION); incompatible_protocol_error_message(domain_name, info.version); return -1; } /* send own HELLO */ /* those messages are the same as received from agent, but set it again for * readability */ hdr.type = MSG_HELLO; hdr.len = sizeof(info); info.version = QREXEC_PROTOCOL_VERSION; if (libvchan_send(ctrl, &hdr, sizeof(hdr)) != sizeof(hdr)) { fprintf(stderr, "Failed to send HELLO hdr to agent\n"); return -1; } if (libvchan_send(ctrl, &info, sizeof(info)) != sizeof(info)) { fprintf(stderr, "Failed to send HELLO hdr to agent\n"); return -1; } return 0; }
static void handle_execute_service(void) { int i; int policy_pending_slot; pid_t pid; struct trigger_service_params untrusted_params, params; char remote_domain_id_str[10]; if (libvchan_recv(vchan, &untrusted_params, sizeof(untrusted_params)) < 0) handle_vchan_error("recv params"); /* sanitize start */ ENSURE_NULL_TERMINATED(untrusted_params.service_name); ENSURE_NULL_TERMINATED(untrusted_params.target_domain); ENSURE_NULL_TERMINATED(untrusted_params.request_id.ident); sanitize_name(untrusted_params.service_name, "+"); sanitize_name(untrusted_params.target_domain, "@:"); sanitize_name(untrusted_params.request_id.ident, " "); params = untrusted_params; /* sanitize end */ policy_pending_slot = find_policy_pending_slot(); if (policy_pending_slot < 0) { fprintf(stderr, "Service request denied, too many pending requests\n"); send_service_refused(vchan, &untrusted_params.request_id); return; } switch (pid=fork()) { case -1: perror("fork"); exit(1); case 0: break; default: policy_pending[policy_pending_slot].pid = pid; policy_pending[policy_pending_slot].params = untrusted_params.request_id; return; } for (i = 3; i < MAX_FDS; i++) close(i); signal(SIGCHLD, SIG_DFL); signal(SIGPIPE, SIG_DFL); snprintf(remote_domain_id_str, sizeof(remote_domain_id_str), "%d", remote_domain_id); execl("/usr/bin/qrexec-policy", "qrexec-policy", "--", remote_domain_id_str, remote_domain_name, params.target_domain, params.service_name, params.request_id.ident, NULL); perror("execl"); _exit(1); }
void handle_service_refused(struct msg_header *hdr) { struct service_params params; int socket_fd; if (hdr->len != sizeof(params)) { fprintf(stderr, "Invalid msg 0x%x length (%d)\n", MSG_SERVICE_REFUSED, hdr->len); exit(1); } if (libvchan_recv(ctrl_vchan, ¶ms, sizeof(params)) < 0) handle_vchan_error("read exec params"); if (sscanf(params.ident, "SOCKET%d", &socket_fd)) close(socket_fd); else fprintf(stderr, "Received REFUSED for unknown service request '%s'\n", params.ident); }
static void handle_connection_terminated() { struct exec_params untrusted_params, params; if (libvchan_recv(vchan, &untrusted_params, sizeof(untrusted_params)) < 0) handle_vchan_error("recv params"); /* sanitize start */ if (untrusted_params.connect_port < VCHAN_BASE_DATA_PORT || untrusted_params.connect_port >= VCHAN_BASE_DATA_PORT+MAX_CLIENTS) { fprintf(stderr, "Invalid port in MSG_CONNECTION_TERMINATED (%d)\n", untrusted_params.connect_port); exit(1); } /* untrusted_params.connect_domain even if invalid will not harm - in worst * case the port will not be released */ params = untrusted_params; /* sanitize end */ release_vchan_port(params.connect_port, params.connect_domain); }
static void handle_message_from_agent(void) { struct msg_header hdr, untrusted_hdr; if (libvchan_recv(vchan, &untrusted_hdr, sizeof(untrusted_hdr)) < 0) handle_vchan_error("recv hdr"); /* sanitize start */ sanitize_message_from_agent(&untrusted_hdr); hdr = untrusted_hdr; /* sanitize end */ // fprintf(stderr, "got %x %x %x\n", hdr.type, hdr.client_id, // hdr.len); switch (hdr.type) { case MSG_TRIGGER_SERVICE: handle_execute_service(); return; case MSG_CONNECTION_TERMINATED: handle_connection_terminated(); return; } }
static int handle_vchan_data(libvchan_t *vchan, struct buffer *stdin_buf) { int status; struct msg_header hdr; char buf[MAX_DATA_CHUNK]; if (local_stdin_fd != -1) { switch(flush_client_data(local_stdin_fd, stdin_buf)) { case WRITE_STDIN_ERROR: perror("write stdin"); close(local_stdin_fd); local_stdin_fd = -1; break; case WRITE_STDIN_BUFFERED: return WRITE_STDIN_BUFFERED; case WRITE_STDIN_OK: break; } } if (libvchan_recv(vchan, &hdr, sizeof hdr) < 0) { perror("read vchan"); do_exit(1); } if (hdr.len > MAX_DATA_CHUNK) { fprintf(stderr, "client_header.len=%d\n", hdr.len); do_exit(1); } if (!read_vchan_all(vchan, buf, hdr.len)) { perror("read daemon"); do_exit(1); } switch (hdr.type) { /* both directions because we can serve as either end of service call */ case MSG_DATA_STDIN: case MSG_DATA_STDOUT: if (local_stdin_fd == -1) break; if (replace_esc_stdout) do_replace_esc(buf, hdr.len); if (hdr.len == 0) { /* restore flags, as we may have not the only copy of this file descriptor */ if (local_stdin_fd != -1) set_block(local_stdin_fd); close(local_stdin_fd); local_stdin_fd = -1; } else { switch (write_stdin(local_stdin_fd, buf, hdr.len, stdin_buf)) { case WRITE_STDIN_BUFFERED: return WRITE_STDIN_BUFFERED; case WRITE_STDIN_ERROR: if (errno == EPIPE) { // local process have closed its stdin, handle data in oposite // direction (if any) before exit close(local_stdin_fd); local_stdin_fd = -1; } else { perror("write local stdout"); do_exit(1); } break; case WRITE_STDIN_OK: break; } } break; case MSG_DATA_STDERR: if (replace_esc_stderr) do_replace_esc(buf, hdr.len); write_all(2, buf, hdr.len); break; case MSG_DATA_EXIT_CODE: libvchan_close(vchan); if (hdr.len < sizeof(status)) status = 255; else memcpy(&status, buf, sizeof(status)); flush_client_data(local_stdin_fd, stdin_buf); do_exit(status); break; default: fprintf(stderr, "unknown msg %d\n", hdr.type); do_exit(1); } /* intentionally do not distinguish between _ERROR and _OK, because in case * of write error, we simply eat the data - no way to report it to the * other side */ return WRITE_STDIN_OK; }