1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-09 00:00:04 +01:00

sshd: support async exec or shell close

This commit is contained in:
Andy Green 2017-12-23 11:26:45 +08:00
parent f3c6fac3cb
commit b94091130b
6 changed files with 81 additions and 22 deletions

View file

@ -631,7 +631,7 @@ lws_tls_acme_sni_csr_create(struct lws_context *context, const char *elements[],
/* subject must be formatted like "C=TW,O=warmcat,CN=myserver" */
for (n = 0; n < ARRAY_SIZE(x5); n++) {
for (n = 0; n < (int)ARRAY_SIZE(x5); n++) {
if (p != subject)
*p++ = ',';
if (elements[n])

View file

@ -319,7 +319,7 @@ bail_p1:
}
static int
ssh_ops_shell(void *_priv, struct lws *wsi)
ssh_ops_shell(void *_priv, struct lws *wsi, lws_ssh_finish_exec finish, void *finish_handle)
{
struct sshd_instance_priv *priv = _priv;
@ -372,7 +372,7 @@ static const struct lws_ssh_ops ssh_ops = {
.banner = ssh_ops_banner,
.disconnect_reason = ssh_ops_disconnect_reason,
.server_string = "SSH-2.0-Libwebsockets",
.api_version = 1,
.api_version = 2,
};
static int

View file

@ -24,7 +24,7 @@
#define LWS_CALLBACK_SSH_UART_SET_RXFLOW (LWS_CALLBACK_USER + 800)
#define LWS_SSH_OPS_VERSION 1
#define LWS_SSH_OPS_VERSION 2
struct lws_ssh_pty {
char term[16];
@ -127,6 +127,8 @@ struct lws_ssh_pty {
*/
///@{
typedef void (*lws_ssh_finish_exec)(void *handle, int retcode);
struct lws_ssh_ops {
/**
* channel_create() - Channel created
@ -243,21 +245,25 @@ struct lws_ssh_ops {
* \param priv: void * you set when this channel was created
* \param wsi: the struct lws the connection belongs to
* \param command: string containing path to app and arguments
* \param finish: function to call to indicate the exec finished
* \param finish_handle: opaque handle identifying this exec for use with \p finish
*
* Client requested to exec something. Return nonzero to fail.
*/
int (*exec)(void *priv, struct lws *wsi, const char *command);
int (*exec)(void *priv, struct lws *wsi, const char *command, lws_ssh_finish_exec finish, void *finish_handle);
/**
* shell() - Spawn shell that is appropriate for user
*
* \param priv: void * you set when this channel was created
* \param wsi: the struct lws the connection belongs to
* \param finish: function to call to indicate the exec finished
* \param finish_handle: opaque handle identifying this exec for use with \p finish
*
* Spawn the appropriate shell for this user. Return 0 for OK
* or nonzero to fail.
*/
int (*shell)(void *priv, struct lws *wsi);
int (*shell)(void *priv, struct lws *wsi, lws_ssh_finish_exec finish, void *finish_handle);
/**
* pty_req() - Create a Pseudo-TTY as described in pty

View file

@ -194,6 +194,7 @@ enum {
SSH_WT_CH_CLOSE,
SSH_WT_CH_EOF,
SSH_WT_WINDOW_ADJUST,
SSH_WT_EXIT_STATUS,
/* RX parser states */
@ -426,8 +427,13 @@ typedef union {
struct lws_subprotocol_scp scp;
} lws_subprotocol;
struct per_session_data__sshd;
struct lws_ssh_channel {
struct lws_ssh_channel *next;
struct per_session_data__sshd *pss;
lws_subprotocol *sub; /* NULL, or allocated subprotocol state */
void *priv; /* owned by user code */
int type;
@ -438,8 +444,9 @@ struct lws_ssh_channel {
uint32_t max_pkt;
uint32_t spawn_pid;
int retcode;
uint8_t had_eof:1;
uint8_t scheduled_close:1;
uint8_t sent_close:1;
uint8_t received_close:1;
};
@ -514,8 +521,8 @@ struct per_session_data__sshd {
uint8_t msg_id;
uint8_t msg_padding;
uint8_t write_task[4];
struct lws_ssh_channel *write_channel[4];
uint8_t write_task[8];
struct lws_ssh_channel *write_channel[8];
uint8_t wt_head, wt_tail;
};

View file

@ -114,10 +114,21 @@ write_task(struct per_session_data__sshd *pss, struct lws_ssh_channel *ch,
{
pss->write_task[pss->wt_head] = task;
pss->write_channel[pss->wt_head] = ch;
pss->wt_head = (pss->wt_head + 1) & 3;
pss->wt_head = (pss->wt_head + 1) & 7;
lws_callback_on_writable(pss->wsi);
}
void
write_task_insert(struct per_session_data__sshd *pss, struct lws_ssh_channel *ch,
int task)
{
pss->wt_tail = (pss->wt_tail - 1) & 7;
pss->write_task[pss->wt_tail] = task;
pss->write_channel[pss->wt_tail] = ch;
lws_callback_on_writable(pss->wsi);
}
void
lws_pad_set_length(struct per_session_data__sshd *pss, void *start, uint8_t **p,
struct lws_ssh_keys *keys)
@ -520,6 +531,17 @@ ssh_destroy_channel(struct per_session_data__sshd *pss,
lwsl_notice("Failed to delete ch\n");
}
static void
lws_ssh_exec_finish(void *finish_handle, int retcode)
{
struct lws_ssh_channel *ch = (struct lws_ssh_channel *)finish_handle;
struct per_session_data__sshd *pss = ch->pss;
ch->retcode = retcode;
write_task(pss, ch, SSH_WT_EXIT_STATUS);
ch->scheduled_close = 1;
write_task(pss, ch, SSH_WT_CH_CLOSE);
}
static int
lws_ssh_parse_plaintext(struct per_session_data__sshd *pss, uint8_t *p, size_t len)
@ -1359,6 +1381,7 @@ again:
return -1;
pss->ch_temp->type = SSH_CH_TYPE_SESSION;
pss->ch_temp->pss = pss;
state_get_u32(pss, SSHS_NVC_CHOPEN_SENDER_CH);
break;
@ -1425,9 +1448,11 @@ again:
pss->channel_doing_spawn = pss->ch_temp->server_ch;
if (pss->vhd->ops && pss->vhd->ops->shell &&
!pss->vhd->ops->shell(pss->ch_temp->priv,
pss->wsi)) {
pss->wsi,
lws_ssh_exec_finish, pss->ch_temp)) {
if (pss->rq_want_reply)
write_task(pss, pss->ch_temp,
write_task_insert(pss, pss->ch_temp,
SSH_WT_CHRQ_SUCC);
pss->parser_state = SSHS_MSG_EAT_PADDING;
break;
@ -1544,10 +1569,11 @@ again:
if (pss->vhd->ops && pss->vhd->ops->exec &&
!pss->vhd->ops->exec(pss->ch_temp->priv, pss->wsi,
(const char *)pss->last_alloc)) {
(const char *)pss->last_alloc,
lws_ssh_exec_finish, pss->ch_temp)) {
ssh_free(pss->last_alloc);
if (pss->rq_want_reply)
write_task(pss, pss->ch_temp,
write_task_insert(pss, pss->ch_temp,
SSH_WT_CHRQ_SUCC);
pss->parser_state = SSHS_MSG_EAT_PADDING;
@ -1737,11 +1763,14 @@ again:
*/
lwsl_notice("SSH_MSG_CHANNEL_EOF: %d\n", pss->ch_recip);
ch = ssh_get_server_ch(pss, pss->ch_recip);
if (!ch)
if (!ch) {
lwsl_notice("unknown ch %d\n", pss->ch_recip);
return -1;
}
if (!ch->had_eof) {
ch->had_eof = 1;
if (!ch->scheduled_close) {
lwsl_notice("scheduling CLOSE\n");
ch->scheduled_close = 1;
write_task(pss, ch, SSH_WT_CH_CLOSE);
}
pss->parser_state = SSHS_MSG_EAT_PADDING;
@ -1781,6 +1810,7 @@ again:
}
ch->received_close = 1;
ch->scheduled_close = 1;
write_task(pss, ch, SSH_WT_CH_CLOSE);
break;
@ -2015,7 +2045,7 @@ lws_callback_raw_sshd(struct lws *wsi, enum lws_callback_reasons reason,
* The user code ops api_version has to be current
*/
if (vhd->ops->api_version != LWS_SSH_OPS_VERSION) {
lwsl_err("FATAL ops is api_version v%d but code is v%d",
lwsl_err("FATAL ops is api_version v%d but code is v%d\n",
vhd->ops->api_version, LWS_SSH_OPS_VERSION);
return 1;
}
@ -2318,6 +2348,21 @@ lws_callback_raw_sshd(struct lws *wsi, enum lws_callback_reasons reason,
lwsl_info("send SSH_MSG_CHANNEL_WINDOW_ADJUST\n");
goto pac;
case SSH_WT_EXIT_STATUS:
pp = ps + 5;
*pp++ = SSH_MSG_CHANNEL_REQUEST;
lws_p32(pp, ch->sender_ch);
pp += 4;
lws_p32(pp, 11);
pp += 4;
strcpy((char *)pp, "exit-status");
pp += 11;
*pp++ = 0;
lws_p32(pp, ch->retcode);
pp += 4;
lwsl_info("send SSH_MSG_CHANNEL_EXIT_STATUS\n");
goto pac;
case SSH_WT_NONE:
default:
/* sending payload */
@ -2432,7 +2477,7 @@ bail:
if (o != SSH_WT_NONE)
pss->wt_tail =
(pss->wt_tail + 1) & 3;
(pss->wt_tail + 1) & 7;
} else
if (o == SSH_WT_UA_PK_OK) /* free it either way */
free(ps);
@ -2498,6 +2543,7 @@ bail:
if (ch->spawn_pid == len) {
lwsl_notice("starting close of ch with PID %d\n",
(int)len);
ch->scheduled_close = 1;
write_task(pss, ch, SSH_WT_CH_CLOSE);
break;
}

View file

@ -545,7 +545,7 @@ ssh_ops_child_process_terminated(void *priv, struct lws *wsi)
}
static int
ssh_ops_exec(void *_priv, struct lws *wsi, const char *command)
ssh_ops_exec(void *_priv, struct lws *wsi, const char *command, lws_ssh_finish_exec finish, void *finish_handle)
{
lwsl_notice("%s: EXEC %s\n", __func__, command);
@ -554,7 +554,7 @@ ssh_ops_exec(void *_priv, struct lws *wsi, const char *command)
}
static int
ssh_ops_shell(void *_priv, struct lws *wsi)
ssh_ops_shell(void *_priv, struct lws *wsi, lws_ssh_finish_exec finish, void *finish_handle)
{
struct sshd_instance_priv *priv = _priv;
const char *cmd[] = {
@ -614,7 +614,7 @@ static const struct lws_ssh_ops ssh_ops = {
.banner = ssh_ops_banner,
.disconnect_reason = ssh_ops_disconnect_reason,
.server_string = "SSH-2.0-Libwebsockets",
.api_version = 1,
.api_version = 2,
};
/*