static int execute_commands(const unsigned char *dir, const unsigned char **cmds, unsigned char **p_log_txt) { FILE *fout = 0; char *fout_txt = 0; size_t fout_len = 0; int i; unsigned char *s; fout = open_memstream(&fout_txt, &fout_len); for (i = 0; cmds[i]; i++) { fprintf(fout, ">%s\n", cmds[i]); s = read_process_output(cmds[i], dir, 0, 1); fprintf(fout, "%s\n", s); xfree(s); } close_memstream(fout); fout = 0; if (p_log_txt) *p_log_txt = fout_txt; else xfree(fout_txt); return 1; }
/* * Export the function that handles a connection. */ int listener_newthread(SOCKET sock, int port, SOCKADDR_IN remoteaddr) { int len; char *nonce = NULL; doit_ctx *ctx = NULL; char *cmdline = NULL, *currdir = NULL; DWORD threadid; if (secret_reload) load_secret(); ctx = doit_init_ctx(secret, secretlen); if (!ctx) goto done; doit_perturb_nonce(ctx, "server", 6); doit_perturb_nonce(ctx, &remoteaddr, sizeof(remoteaddr)); threadid = GetCurrentThreadId(); doit_perturb_nonce(ctx, &threadid, sizeof(threadid)); nonce = doit_make_nonce(ctx, &len); if (do_send(sock, nonce, len) != len) goto done; free(nonce); nonce = NULL; while (1) { cmdline = do_fetch_line(sock, ctx); if (!cmdline) goto done; if (!strcmp(cmdline, "SetDirectory")) { /* * Read a second line and store it for use as the * default directory of a subsequent CreateProcess or * ShellExecute. */ free(cmdline); cmdline = NULL; cmdline = do_fetch_line(sock, ctx); if (!cmdline) goto done; currdir = cmdline; continue; } if (!strcmp(cmdline, "ShellExecute") || !strcmp(cmdline, "ShellExecuteArgs")) { int ret; int with_args; char *args; /* * Read a second line and feed it to ShellExecute(). Give * back either "+" (meaning OK) or "-" followed by an error * message (meaning not OK). * * ShellExecuteArgs is an alternative form in which we * also provide arguments to the process. */ if (!strcmp(cmdline, "ShellExecuteArgs")) with_args = TRUE; else with_args = FALSE; free(cmdline); cmdline = NULL; cmdline = do_fetch_line(sock, ctx); if (with_args) args = do_fetch_line(sock, ctx); else args = NULL; ret = (int)ShellExecute(listener_hwnd, "open", cmdline, args, currdir, SW_SHOWNORMAL); if (args) free(args); if (ret <= 32) { char *msg = "-ShellExecute failed: unknown error\n"; if (ret == 0) msg = "-ShellExecute failed: Out of memory or resources\n"; if (ret == ERROR_FILE_NOT_FOUND) msg = "-ShellExecute failed: File not found\n"; if (ret == ERROR_PATH_NOT_FOUND) msg = "-ShellExecute failed: Path not found\n"; if (ret == ERROR_BAD_FORMAT) msg = "-ShellExecute failed: Invalid .exe file\n"; if (ret == SE_ERR_ACCESSDENIED) msg = "-ShellExecute failed: Access denied\n"; if (ret == SE_ERR_ASSOCINCOMPLETE) msg = "-ShellExecute failed: File name association incomplete or invalid\n"; if (ret == SE_ERR_DDEBUSY) msg = "-ShellExecute failed: DDE busy\n"; if (ret == SE_ERR_DDEFAIL) msg = "-ShellExecute failed: DDE transaction failed\n"; if (ret == SE_ERR_DDETIMEOUT) msg = "-ShellExecute failed: DDE transaction timed out\n"; if (ret == SE_ERR_DLLNOTFOUND) msg = "-ShellExecute failed: DLL not found\n"; if (ret == SE_ERR_FNF) msg = "-ShellExecute failed: File not found\n"; if (ret == SE_ERR_NOASSOC) msg = "-ShellExecute failed: No application associated with this file type\n"; if (ret == SE_ERR_OOM) msg = "-ShellExecute failed: Out of memory\n"; if (ret == SE_ERR_PNF) msg = "-ShellExecute failed: Path not found\n"; if (ret == SE_ERR_SHARE) msg = "-ShellExecute failed: Sharing violation\n"; do_doit_send_str(sock, ctx, msg); } else { do_doit_send_str(sock, ctx, "+\n"); } free(cmdline); cmdline = NULL; goto done; } if (!strcmp(cmdline, "WriteClipboard")) { /* * Read data until the connection is closed, and write it * to the Windows clipboard. */ int len; char *msg; free(cmdline); cmdline = NULL; cmdline = do_fetch_all(sock, ctx, &len); if (cmdline) { msg = write_clip(cmdline, len); free(cmdline); cmdline = NULL; } else msg = "-error reading input\n"; do_doit_send_str(sock, ctx, msg); goto done; } if (!strcmp(cmdline, "ReadClipboard")) { /* * Read the Windows Clipboard. Give back a 4-byte * length followed by the text, and then send either * "+\n" or "-error message\n". */ int is_err; char *data = read_clip(&is_err); char length[4]; if (is_err) { /* data is an error message */ PUT_32BIT_MSB_FIRST(length, 0); do_doit_send(sock, ctx, length, 4); do_doit_send_str(sock, ctx, data); } else { int len = strlen(data); PUT_32BIT_MSB_FIRST(length, len); do_doit_send(sock, ctx, length, 4); do_doit_send(sock, ctx, data, len); do_doit_send_str(sock, ctx, "+\n"); GlobalUnlock(data); } goto done; } if (!strcmp(cmdline, "CreateProcessNoWait") || !strcmp(cmdline, "CreateProcessWait") || !strcmp(cmdline, "CreateProcessWithOutput")) { /* * Read a second line and feed it to CreateProcess. * Optionally, wait for it to finish, or even send output * back. * * If output is sent back, it is sent as a sequence of * Pascal-style length-prefixed strings (a single byte * followed by that many characters), and finally * terminated by a \0 length byte. After _that_ comes the * error indication, which may be "+number\n" for a * termination with exit code, or "-errmsg\n" if a system * call fails. */ int wait, output; struct process proc; if (!strcmp(cmdline, "CreateProcessNoWait")) wait = output = 0; if (!strcmp(cmdline, "CreateProcessWait")) wait = 1, output = 0; if (!strcmp(cmdline, "CreateProcessWithOutput")) wait = output = 1; free(cmdline); cmdline = NULL; cmdline = do_fetch_line(sock, ctx); proc = start_process(cmdline, wait, output, currdir); if (proc.error) { if (output) do_doit_send(sock, ctx, "\0", 1); do_doit_send_str(sock, ctx, proc.error); goto done; } if (wait) { int err; if (output) { char buf[256]; int len; while ((len = read_process_output(proc, buf+1, sizeof(buf)-1)) > 0) { buf[0] = len; do_doit_send(sock, ctx, buf, len+1); } do_doit_send(sock, ctx, "\0", 1); } err = process_exit_code(proc); if (err < 0) { do_doit_send_str(sock, ctx, "-GetExitCodeProcess failed\n"); } else { char buf[32]; sprintf(buf, "+%d\n", err); do_doit_send_str(sock, ctx, buf); } } else { do_doit_send_str(sock, ctx, "+\n"); } } /* * If we've reached here without `continue' or leaving the * loop, we must have an unrecognised command. */ do_doit_send_str(sock, ctx, "-unrecognised command \""); do_doit_send_str(sock, ctx, cmdline); do_doit_send_str(sock, ctx, "\"\n"); } done: if (nonce) free(nonce); if (cmdline) free(cmdline); if (currdir) free(currdir); if (ctx) doit_free_ctx(ctx); closesocket(sock); return 0; }
static void command_start(char * token, Channel * c) { int pid = 0; int err = 0; char dir[FILE_PATH_SIZE]; char exe[FILE_PATH_SIZE]; char ** args = NULL; char ** envp = NULL; int args_len = 0; int envp_len = 0; int attach = 0; int selfattach = 0; int pending = 0; ChildProcess * prs = NULL; Trap trap; if (set_trap(&trap)) { json_read_string(&c->inp, dir, sizeof(dir)); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); json_read_string(&c->inp, exe, sizeof(exe)); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); args = json_read_alloc_string_array(&c->inp, &args_len); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); envp = json_read_alloc_string_array(&c->inp, &envp_len); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); attach = json_read_boolean(&c->inp); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); if (dir[0] != 0 && chdir(dir) < 0) err = errno; if (err == 0 && start_process(c, envp, dir, exe, args, attach, &pid, &selfattach, &prs) < 0) err = errno; if (prs != NULL) { write_process_input(prs); prs->out_struct = read_process_output(prs, prs->out, prs->out_id, sizeof(prs->out_id)); if (prs->out != prs->err) prs->err_struct = read_process_output(prs, prs->err, prs->err_id, sizeof(prs->err_id)); strncpy(prs->name, exe, sizeof(prs->name) - 1); } if (!err) { if (attach) { AttachDoneArgs * data = loc_alloc_zero(sizeof *data); data->c = c; strcpy(data->token, token); pending = context_attach(pid, start_done, data, selfattach) == 0; if (pending) { stream_lock(c); } else { err = errno; loc_free(data); } } else { add_waitpid_process(pid); } } if (!pending) { write_stringz(&c->out, "R"); write_stringz(&c->out, token); write_errno(&c->out, err); if (err || pid == 0) { write_stringz(&c->out, "null"); } else { write_context(&c->out, pid); write_stream(&c->out, 0); } write_stream(&c->out, MARKER_EOM); } clear_trap(&trap); } loc_free(args); loc_free(envp); if (trap.error) exception(trap.error); }