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:
parent
f3c6fac3cb
commit
b94091130b
6 changed files with 81 additions and 22 deletions
|
@ -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])
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
Loading…
Add table
Reference in a new issue