static void meta_command(struct sockaddr_in *from, char *command) { Server *s; char *cmd, *name, *dummy; parse_connect(command, &cmd, &name, &dummy); s = serv_name2server(name); if (!strcmp(cmd + 1, "connect")) { char buf[128]; Server *local; if (!s) { s = promiscuous_connect(from, name); if (!s) { return; } } else if (verify_servers && !verify_server(s, from)) { return; } s->connected = 1; s->last_msgid = -1; writelog(); fprintf(stderr, "Server %s (%s %d) connected\n", s->name, s->hostname, s->port); local = serv_id2server(0); sprintf(buf, "*connectok %s\n", local->name); sendto(yo_sock, buf, strlen(buf), 0, (struct sockaddr *) from, sizeof(*from)); connect_server(s->id); } else if (!strcmp(cmd + 1, "connectok")) { if (!s) { s = promiscuous_connect(from, name); if (!s) { return; } } else if (verify_servers && !verify_server(s, from)) { return; } s->connected = 1; s->last_msgid = -1; writelog(); fprintf(stderr, "Server %s (%s %d) connected ok\n", s->name, s->hostname, s->port); connect_server(s->id); } else if (!strcmp(cmd + 1, "disconnect")) { if (!s) { return; } s->connected = 0; writelog(); fprintf(stderr, "Server %s (%s %d) disconnected\n", s->name, s->hostname, s->port); disconnect_server(s->id); } else { if (!s) { return; } writelog(); fprintf(stderr, "Unknown metacommand \"%s\" from server %s\n", command, s->name); } }
int main(int argc, char **argv) { int opt; char *domname = NULL; libvchan_t *data_vchan = NULL; int data_port; int data_domain; int msg_type; int s; int just_exec = 0; int connect_existing = 0; char *local_cmdline = NULL; char *remote_cmdline = NULL; char *request_id; char *src_domain_name = NULL; int src_domain_id = 0; /* if not -c given, the process is run in dom0 */ struct service_params svc_params; while ((opt = getopt(argc, argv, "d:l:ec:tT")) != -1) { switch (opt) { case 'd': domname = strdup(optarg); break; case 'l': local_cmdline = strdup(optarg); break; case 'e': just_exec = 1; break; case 'c': parse_connect(optarg, &request_id, &src_domain_name, &src_domain_id); connect_existing = 1; is_service = 1; break; case 't': replace_esc_stdout = 1; break; case 'T': replace_esc_stderr = 1; break; default: usage(argv[0]); } } if (optind >= argc || !domname) usage(argv[0]); remote_cmdline = argv[optind]; register_exec_func(&do_exec); if (just_exec + connect_existing + (local_cmdline != 0) > 1) { fprintf(stderr, "ERROR: only one of -e, -l, -c can be specified\n"); usage(argv[0]); } if (strcmp(domname, "dom0") == 0 && !connect_existing) { fprintf(stderr, "ERROR: when target domain is 'dom0', -c must be specified\n"); usage(argv[0]); } if (strcmp(domname, "dom0") == 0) { if (connect_existing) { msg_type = MSG_SERVICE_CONNECT; strncpy(svc_params.ident, request_id, sizeof(svc_params.ident)); } else if (just_exec) msg_type = MSG_JUST_EXEC; else msg_type = MSG_EXEC_CMDLINE; assert(src_domain_name); setenv("QREXEC_REMOTE_DOMAIN", src_domain_name, 1); s = connect_unix_socket(src_domain_name); negotiate_connection_params(s, 0, /* dom0 */ msg_type, connect_existing ? (void*)&svc_params : (void*)remote_cmdline, connect_existing ? sizeof(svc_params) : strlen(remote_cmdline) + 1, &data_domain, &data_port); prepare_local_fds(remote_cmdline); if (connect_existing) data_vchan = libvchan_client_init(data_domain, data_port); else { data_vchan = libvchan_server_init(data_domain, data_port, VCHAN_BUFFER_SIZE, VCHAN_BUFFER_SIZE); while (data_vchan && libvchan_is_open(data_vchan) == VCHAN_WAITING) libvchan_wait(data_vchan); } if (!data_vchan || !libvchan_is_open(data_vchan)) { fprintf(stderr, "Failed to open data vchan connection\n"); do_exit(1); } if (handle_agent_handshake(data_vchan, connect_existing) < 0) do_exit(1); select_loop(data_vchan); } else { if (just_exec) msg_type = MSG_JUST_EXEC; else msg_type = MSG_EXEC_CMDLINE; s = connect_unix_socket(domname); negotiate_connection_params(s, src_domain_id, msg_type, remote_cmdline, strlen(remote_cmdline) + 1, &data_domain, &data_port); close(s); setenv("QREXEC_REMOTE_DOMAIN", domname, 1); prepare_local_fds(local_cmdline); if (connect_existing) { s = connect_unix_socket(src_domain_name); send_service_connect(s, request_id, data_domain, data_port); close(s); } else { data_vchan = libvchan_server_init(data_domain, data_port, VCHAN_BUFFER_SIZE, VCHAN_BUFFER_SIZE); if (!data_vchan) { fprintf(stderr, "Failed to start data vchan server\n"); do_exit(1); } while (libvchan_is_open(data_vchan) == VCHAN_WAITING) libvchan_wait(data_vchan); if (!libvchan_is_open(data_vchan)) { fprintf(stderr, "Failed to open data vchan connection\n"); do_exit(1); } if (handle_agent_handshake(data_vchan, 0) < 0) do_exit(1); select_loop(data_vchan); } } return 0; }