123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795 |
- /*
- * Implement the "session" channel type for the SSH server.
- */
- #include <assert.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <ctype.h>
- #include "putty.h"
- #include "ssh.h"
- #include "channel.h"
- #include "server.h"
- #include "sftp.h"
- struct agentfwd {
- ConnectionLayer *cl;
- Socket *socket;
- Plug plug;
- };
- typedef struct sesschan {
- SshChannel *c;
- LogContext *parent_logctx, *child_logctx;
- Conf *conf;
- const SftpServerVtable *sftpserver_vt;
- LogPolicy logpolicy;
- Seat seat;
- bool want_pty;
- struct ssh_ttymodes ttymodes;
- int wc, hc, wp, hp;
- strbuf *termtype;
- bool ignoring_input;
- bool seen_eof, seen_exit;
- Plug xfwd_plug;
- int n_x11_sockets;
- Socket *x11_sockets[MAX_X11_SOCKETS];
- agentfwd *agent;
- Backend *backend;
- bufchain subsys_input;
- SftpServer *sftpsrv;
- ScpServer *scpsrv;
- const SshServerConfig *ssc;
- Channel chan;
- } sesschan;
- static void sesschan_free(Channel *chan);
- static size_t sesschan_send(
- Channel *chan, bool is_stderr, const void *, size_t);
- static void sesschan_send_eof(Channel *chan);
- static char *sesschan_log_close_msg(Channel *chan);
- static bool sesschan_want_close(Channel *, bool, bool);
- static void sesschan_set_input_wanted(Channel *chan, bool wanted);
- static bool sesschan_run_shell(Channel *chan);
- static bool sesschan_run_command(Channel *chan, ptrlen command);
- static bool sesschan_run_subsystem(Channel *chan, ptrlen subsys);
- static bool sesschan_enable_x11_forwarding(
- Channel *chan, bool oneshot, ptrlen authproto, ptrlen authdata,
- unsigned screen_number);
- static bool sesschan_enable_agent_forwarding(Channel *chan);
- static bool sesschan_allocate_pty(
- Channel *chan, ptrlen termtype, unsigned width, unsigned height,
- unsigned pixwidth, unsigned pixheight, struct ssh_ttymodes modes);
- static bool sesschan_set_env(Channel *chan, ptrlen var, ptrlen value);
- static bool sesschan_send_break(Channel *chan, unsigned length);
- static bool sesschan_send_signal(Channel *chan, ptrlen signame);
- static bool sesschan_change_window_size(
- Channel *chan, unsigned width, unsigned height,
- unsigned pixwidth, unsigned pixheight);
- static const ChannelVtable sesschan_channelvt = {
- .free = sesschan_free,
- .open_confirmation = chan_remotely_opened_confirmation,
- .open_failed = chan_remotely_opened_failure,
- .send = sesschan_send,
- .send_eof = sesschan_send_eof,
- .set_input_wanted = sesschan_set_input_wanted,
- .log_close_msg = sesschan_log_close_msg,
- .want_close = sesschan_want_close,
- .rcvd_exit_status = chan_no_exit_status,
- .rcvd_exit_signal = chan_no_exit_signal,
- .rcvd_exit_signal_numeric = chan_no_exit_signal_numeric,
- .run_shell = sesschan_run_shell,
- .run_command = sesschan_run_command,
- .run_subsystem = sesschan_run_subsystem,
- .enable_x11_forwarding = sesschan_enable_x11_forwarding,
- .enable_agent_forwarding = sesschan_enable_agent_forwarding,
- .allocate_pty = sesschan_allocate_pty,
- .set_env = sesschan_set_env,
- .send_break = sesschan_send_break,
- .send_signal = sesschan_send_signal,
- .change_window_size = sesschan_change_window_size,
- .request_response = chan_no_request_response,
- };
- static size_t sftp_chan_send(
- Channel *chan, bool is_stderr, const void *, size_t);
- static void sftp_chan_send_eof(Channel *chan);
- static char *sftp_log_close_msg(Channel *chan);
- static const ChannelVtable sftp_channelvt = {
- .free = sesschan_free,
- .open_confirmation = chan_remotely_opened_confirmation,
- .open_failed = chan_remotely_opened_failure,
- .send = sftp_chan_send,
- .send_eof = sftp_chan_send_eof,
- .set_input_wanted = sesschan_set_input_wanted,
- .log_close_msg = sftp_log_close_msg,
- .want_close = chan_default_want_close,
- .rcvd_exit_status = chan_no_exit_status,
- .rcvd_exit_signal = chan_no_exit_signal,
- .rcvd_exit_signal_numeric = chan_no_exit_signal_numeric,
- .run_shell = chan_no_run_shell,
- .run_command = chan_no_run_command,
- .run_subsystem = chan_no_run_subsystem,
- .enable_x11_forwarding = chan_no_enable_x11_forwarding,
- .enable_agent_forwarding = chan_no_enable_agent_forwarding,
- .allocate_pty = chan_no_allocate_pty,
- .set_env = chan_no_set_env,
- .send_break = chan_no_send_break,
- .send_signal = chan_no_send_signal,
- .change_window_size = chan_no_change_window_size,
- .request_response = chan_no_request_response,
- };
- static size_t scp_chan_send(
- Channel *chan, bool is_stderr, const void *, size_t);
- static void scp_chan_send_eof(Channel *chan);
- static void scp_set_input_wanted(Channel *chan, bool wanted);
- static char *scp_log_close_msg(Channel *chan);
- static const ChannelVtable scp_channelvt = {
- .free = sesschan_free,
- .open_confirmation = chan_remotely_opened_confirmation,
- .open_failed = chan_remotely_opened_failure,
- .send = scp_chan_send,
- .send_eof = scp_chan_send_eof,
- .set_input_wanted = scp_set_input_wanted,
- .log_close_msg = scp_log_close_msg,
- .want_close = chan_default_want_close,
- .rcvd_exit_status = chan_no_exit_status,
- .rcvd_exit_signal = chan_no_exit_signal,
- .rcvd_exit_signal_numeric = chan_no_exit_signal_numeric,
- .run_shell = chan_no_run_shell,
- .run_command = chan_no_run_command,
- .run_subsystem = chan_no_run_subsystem,
- .enable_x11_forwarding = chan_no_enable_x11_forwarding,
- .enable_agent_forwarding = chan_no_enable_agent_forwarding,
- .allocate_pty = chan_no_allocate_pty,
- .set_env = chan_no_set_env,
- .send_break = chan_no_send_break,
- .send_signal = chan_no_send_signal,
- .change_window_size = chan_no_change_window_size,
- .request_response = chan_no_request_response,
- };
- static void sesschan_eventlog(LogPolicy *lp, const char *event) {}
- static void sesschan_logging_error(LogPolicy *lp, const char *event) {}
- static int sesschan_askappend(
- LogPolicy *lp, Filename *filename,
- void (*callback)(void *ctx, int result), void *ctx) { return 2; }
- static const LogPolicyVtable sesschan_logpolicy_vt = {
- .eventlog = sesschan_eventlog,
- .askappend = sesschan_askappend,
- .logging_error = sesschan_logging_error,
- .verbose = null_lp_verbose_no,
- };
- static size_t sesschan_seat_output(
- Seat *, SeatOutputType type, const void *, size_t);
- static bool sesschan_seat_eof(Seat *);
- static void sesschan_notify_remote_exit(Seat *seat);
- static void sesschan_connection_fatal(Seat *seat, const char *message);
- static bool sesschan_get_window_pixel_size(Seat *seat, int *w, int *h);
- static const SeatVtable sesschan_seat_vt = {
- .output = sesschan_seat_output,
- .eof = sesschan_seat_eof,
- .sent = nullseat_sent,
- .banner = nullseat_banner,
- .get_userpass_input = nullseat_get_userpass_input,
- .notify_session_started = nullseat_notify_session_started,
- .notify_remote_exit = sesschan_notify_remote_exit,
- .notify_remote_disconnect = nullseat_notify_remote_disconnect,
- .connection_fatal = sesschan_connection_fatal,
- .nonfatal = nullseat_nonfatal,
- .update_specials_menu = nullseat_update_specials_menu,
- .get_ttymode = nullseat_get_ttymode,
- .set_busy_status = nullseat_set_busy_status,
- .confirm_ssh_host_key = nullseat_confirm_ssh_host_key,
- .confirm_weak_crypto_primitive = nullseat_confirm_weak_crypto_primitive,
- .confirm_weak_cached_hostkey = nullseat_confirm_weak_cached_hostkey,
- .prompt_descriptions = nullseat_prompt_descriptions,
- .is_utf8 = nullseat_is_never_utf8,
- .echoedit_update = nullseat_echoedit_update,
- .get_x_display = nullseat_get_x_display,
- .get_windowid = nullseat_get_windowid,
- .get_window_pixel_size = sesschan_get_window_pixel_size,
- .stripctrl_new = nullseat_stripctrl_new,
- .set_trust_status = nullseat_set_trust_status,
- .can_set_trust_status = nullseat_can_set_trust_status_no,
- .has_mixed_input_stream = nullseat_has_mixed_input_stream_no,
- .verbose = nullseat_verbose_no,
- .interactive = nullseat_interactive_no,
- .get_cursor_position = nullseat_get_cursor_position,
- };
- Channel *sesschan_new(SshChannel *c, LogContext *logctx,
- const SftpServerVtable *sftpserver_vt,
- const SshServerConfig *ssc)
- {
- sesschan *sess = snew(sesschan);
- memset(sess, 0, sizeof(sesschan));
- sess->c = c;
- sess->chan.vt = &sesschan_channelvt;
- sess->chan.initial_fixed_window_size = 0;
- sess->parent_logctx = logctx;
- sess->ssc = ssc;
- /* Start with a completely default Conf */
- sess->conf = conf_new();
- load_open_settings(NULL, sess->conf);
- /* Set close-on-exit = true to suppress pty.c's "[pterm: process
- * terminated with status x]" message */
- conf_set_int(sess->conf, CONF_close_on_exit, FORCE_ON);
- sess->seat.vt = &sesschan_seat_vt;
- sess->logpolicy.vt = &sesschan_logpolicy_vt;
- sess->child_logctx = log_init(&sess->logpolicy, sess->conf);
- sess->sftpserver_vt = sftpserver_vt;
- bufchain_init(&sess->subsys_input);
- return &sess->chan;
- }
- static void sesschan_free(Channel *chan)
- {
- sesschan *sess = container_of(chan, sesschan, chan);
- int i;
- delete_callbacks_for_context(sess);
- conf_free(sess->conf);
- if (sess->backend)
- backend_free(sess->backend);
- bufchain_clear(&sess->subsys_input);
- if (sess->sftpsrv)
- sftpsrv_free(sess->sftpsrv);
- for (i = 0; i < sess->n_x11_sockets; i++)
- sk_close(sess->x11_sockets[i]);
- if (sess->agent)
- agentfwd_free(sess->agent);
- sfree(sess);
- }
- static size_t sesschan_send(Channel *chan, bool is_stderr,
- const void *data, size_t length)
- {
- sesschan *sess = container_of(chan, sesschan, chan);
- if (!sess->backend || sess->ignoring_input)
- return 0;
- backend_send(sess->backend, data, length);
- return backend_sendbuffer(sess->backend);
- }
- static void sesschan_send_eof(Channel *chan)
- {
- sesschan *sess = container_of(chan, sesschan, chan);
- if (sess->backend)
- backend_special(sess->backend, SS_EOF, 0);
- }
- static char *sesschan_log_close_msg(Channel *chan)
- {
- return dupstr("Session channel closed");
- }
- static void sesschan_set_input_wanted(Channel *chan, bool wanted)
- {
- sesschan *sess = container_of(chan, sesschan, chan);
- /* Request the back end to resume sending input, if it had become
- * throttled by the channel window shortening */
- if (wanted && sess->backend)
- backend_unthrottle(sess->backend, 0);
- }
- static void sesschan_start_backend(sesschan *sess, const char *cmd)
- {
- /*
- * List of environment variables that we should not pass through
- * from the login session Uppity was run in (which, it being a
- * test server, there will usually be one of). These variables
- * will be set as part of X or agent forwarding, and shouldn't be
- * confusingly set in the absence of that.
- *
- * (DISPLAY must also be cleared, but pty.c will do that anyway
- * when our get_x_display method returns NULL.)
- */
- static const char *const env_to_unset[] = {
- "XAUTHORITY", "SSH_AUTH_SOCK", "SSH_AGENT_PID",
- NULL /* terminator */
- };
- sess->backend = pty_backend_create(
- &sess->seat, sess->child_logctx, sess->conf, NULL, cmd,
- sess->ttymodes, !sess->want_pty, sess->ssc->session_starting_dir,
- env_to_unset);
- backend_size(sess->backend, sess->wc, sess->hc);
- }
- bool sesschan_run_shell(Channel *chan)
- {
- sesschan *sess = container_of(chan, sesschan, chan);
- if (sess->backend)
- return false;
- sesschan_start_backend(sess, NULL);
- return true;
- }
- bool sesschan_run_command(Channel *chan, ptrlen command)
- {
- sesschan *sess = container_of(chan, sesschan, chan);
- if (sess->backend)
- return false;
- /* FIXME: make this possible to configure off */
- if ((sess->scpsrv = scp_recognise_exec(sess->c, sess->sftpserver_vt,
- command)) != NULL) {
- sess->chan.vt = &scp_channelvt;
- logevent(sess->parent_logctx, "Starting built-in SCP server");
- return true;
- }
- char *command_str = mkstr(command);
- sesschan_start_backend(sess, command_str);
- sfree(command_str);
- return true;
- }
- bool sesschan_run_subsystem(Channel *chan, ptrlen subsys)
- {
- sesschan *sess = container_of(chan, sesschan, chan);
- if (ptrlen_eq_string(subsys, "sftp") && sess->sftpserver_vt) {
- sess->sftpsrv = sftpsrv_new(sess->sftpserver_vt);
- sess->chan.vt = &sftp_channelvt;
- logevent(sess->parent_logctx, "Starting built-in SFTP subsystem");
- return true;
- }
- return false;
- }
- static int xfwd_accepting(Plug *p, accept_fn_t constructor, accept_ctx_t ctx)
- {
- sesschan *sess = container_of(p, sesschan, xfwd_plug);
- Plug *plug;
- Channel *chan;
- Socket *s;
- SocketEndpointInfo *pi;
- const char *err;
- chan = portfwd_raw_new(sess->c->cl, &plug, false);
- s = constructor(ctx, plug);
- if ((err = sk_socket_error(s)) != NULL) {
- portfwd_raw_free(chan);
- return 1;
- }
- pi = sk_peer_info(s);
- portfwd_raw_setup(chan, s, ssh_serverside_x11_open(sess->c->cl, chan, pi));
- sk_free_endpoint_info(pi);
- return 0;
- }
- static const PlugVtable xfwd_plugvt = {
- .log = nullplug_log,
- .closing = nullplug_closing,
- .accepting = xfwd_accepting,
- };
- bool sesschan_enable_x11_forwarding(
- Channel *chan, bool oneshot, ptrlen authproto, ptrlen authdata_hex,
- unsigned screen_number)
- {
- sesschan *sess = container_of(chan, sesschan, chan);
- strbuf *authdata_bin;
- size_t i;
- if (oneshot)
- return false; /* not supported */
- /*
- * Decode the authorisation data from ASCII hex into binary.
- */
- if (authdata_hex.len % 2)
- return false; /* expected an even number of digits */
- authdata_bin = strbuf_new_nm();
- for (i = 0; i < authdata_hex.len; i += 2) {
- const unsigned char *hex = authdata_hex.ptr;
- char hexbuf[3];
- if (!isxdigit((unsigned char)hex[i]) ||
- !isxdigit((unsigned char)hex[i+1])) {
- strbuf_free(authdata_bin);
- return false; /* not hex */
- }
- hexbuf[0] = hex[i];
- hexbuf[1] = hex[i+1];
- hexbuf[2] = '\0';
- put_byte(authdata_bin, strtoul(hexbuf, NULL, 16));
- }
- sess->xfwd_plug.vt = &xfwd_plugvt;
- char *screensuffix = dupprintf(".%u", screen_number);
- sess->n_x11_sockets = platform_make_x11_server(
- &sess->xfwd_plug, appname, 10, screensuffix,
- authproto, ptrlen_from_strbuf(authdata_bin),
- sess->x11_sockets, sess->conf);
- sfree(screensuffix);
- strbuf_free(authdata_bin);
- return sess->n_x11_sockets != 0;
- }
- static int agentfwd_accepting(
- Plug *p, accept_fn_t constructor, accept_ctx_t ctx)
- {
- agentfwd *agent = container_of(p, agentfwd, plug);
- Plug *plug;
- Channel *chan;
- Socket *s;
- const char *err;
- chan = portfwd_raw_new(agent->cl, &plug, false);
- s = constructor(ctx, plug);
- if ((err = sk_socket_error(s)) != NULL) {
- portfwd_raw_free(chan);
- return 1;
- }
- portfwd_raw_setup(chan, s, ssh_serverside_agent_open(agent->cl, chan));
- return 0;
- }
- static const PlugVtable agentfwd_plugvt = {
- .log = nullplug_log,
- .closing = nullplug_closing,
- .accepting = agentfwd_accepting,
- };
- agentfwd *agentfwd_new(ConnectionLayer *cl, char **socketname_out)
- {
- agentfwd *agent = snew(agentfwd);
- agent->cl = cl;
- agent->plug.vt = &agentfwd_plugvt;
- char *dir_prefix = dupprintf("/tmp/%s-agentfwd", appname);
- char *error = NULL, *socketname = NULL;
- agent->socket = platform_make_agent_socket(
- &agent->plug, dir_prefix, &error, &socketname);
- sfree(dir_prefix);
- sfree(error);
- if (!agent->socket) {
- sfree(agent);
- sfree(socketname);
- return NULL;
- }
- *socketname_out = socketname;
- return agent;
- }
- void agentfwd_free(agentfwd *agent)
- {
- if (agent->socket)
- sk_close(agent->socket);
- sfree(agent);
- }
- bool sesschan_enable_agent_forwarding(Channel *chan)
- {
- sesschan *sess = container_of(chan, sesschan, chan);
- char *socketname;
- assert(!sess->agent);
- sess->agent = agentfwd_new(sess->c->cl, &socketname);
- if (!sess->agent)
- return false;
- conf_set_str_str(sess->conf, CONF_environmt, "SSH_AUTH_SOCK", socketname);
- sfree(socketname);
- return true;
- }
- bool sesschan_allocate_pty(
- Channel *chan, ptrlen termtype, unsigned width, unsigned height,
- unsigned pixwidth, unsigned pixheight, struct ssh_ttymodes modes)
- {
- sesschan *sess = container_of(chan, sesschan, chan);
- char *s;
- if (sess->want_pty)
- return false;
- s = mkstr(termtype);
- conf_set_str(sess->conf, CONF_termtype, s);
- sfree(s);
- sess->want_pty = true;
- sess->ttymodes = modes;
- sess->wc = width;
- sess->hc = height;
- sess->wp = pixwidth;
- sess->hp = pixheight;
- return true;
- }
- bool sesschan_set_env(Channel *chan, ptrlen var, ptrlen value)
- {
- sesschan *sess = container_of(chan, sesschan, chan);
- char *svar = mkstr(var), *svalue = mkstr(value);
- conf_set_str_str(sess->conf, CONF_environmt, svar, svalue);
- sfree(svar);
- sfree(svalue);
- return true;
- }
- bool sesschan_send_break(Channel *chan, unsigned length)
- {
- sesschan *sess = container_of(chan, sesschan, chan);
- if (sess->backend) {
- /* We ignore the break length. We could pass it through as the
- * 'arg' parameter, and have pty.c collect it and pass it on
- * to tcsendbreak, but since tcsendbreak in turn assigns
- * implementation-defined semantics to _its_ duration
- * parameter, this all just sounds too difficult. */
- backend_special(sess->backend, SS_BRK, 0);
- return true;
- }
- return false;
- }
- bool sesschan_send_signal(Channel *chan, ptrlen signame)
- {
- sesschan *sess = container_of(chan, sesschan, chan);
- /* Start with a code that definitely isn't a signal (or indeed a
- * special command at all), to indicate 'nothing matched'. */
- SessionSpecialCode code = SS_EXITMENU;
- #define SIGNAL_SUB(name) \
- if (ptrlen_eq_string(signame, #name)) code = SS_SIG ## name;
- #define SIGNAL_MAIN(name, text) SIGNAL_SUB(name)
- #include "signal-list.h"
- #undef SIGNAL_MAIN
- #undef SIGNAL_SUB
- if (code == SS_EXITMENU)
- return false;
- backend_special(sess->backend, code, 0);
- return true;
- }
- bool sesschan_change_window_size(
- Channel *chan, unsigned width, unsigned height,
- unsigned pixwidth, unsigned pixheight)
- {
- sesschan *sess = container_of(chan, sesschan, chan);
- if (!sess->want_pty)
- return false;
- sess->wc = width;
- sess->hc = height;
- sess->wp = pixwidth;
- sess->hp = pixheight;
- if (sess->backend)
- backend_size(sess->backend, sess->wc, sess->hc);
- return true;
- }
- static size_t sesschan_seat_output(
- Seat *seat, SeatOutputType type, const void *data, size_t len)
- {
- sesschan *sess = container_of(seat, sesschan, seat);
- return sshfwd_write_ext(sess->c, type == SEAT_OUTPUT_STDERR, data, len);
- }
- static void sesschan_check_close_callback(void *vctx)
- {
- sesschan *sess = (sesschan *)vctx;
- /*
- * Once we've seen incoming EOF from the backend (aka EIO from the
- * pty master) and also passed on the process's exit status, we
- * should proactively initiate closure of the session channel.
- */
- if (sess->seen_eof && sess->seen_exit)
- sshfwd_initiate_close(sess->c, NULL);
- }
- static bool sesschan_want_close(Channel *chan, bool seen_eof, bool rcvd_eof)
- {
- sesschan *sess = container_of(chan, sesschan, chan);
- /*
- * Similarly to above, we don't want to initiate channel closure
- * until we've sent the process's exit status, _even_ if EOF of
- * the actual data stream has happened in both directions.
- */
- return (sess->seen_eof && sess->seen_exit);
- }
- static bool sesschan_seat_eof(Seat *seat)
- {
- sesschan *sess = container_of(seat, sesschan, seat);
- sshfwd_write_eof(sess->c);
- sess->seen_eof = true;
- queue_toplevel_callback(sesschan_check_close_callback, sess);
- return true;
- }
- static void sesschan_notify_remote_exit(Seat *seat)
- {
- sesschan *sess = container_of(seat, sesschan, seat);
- if (!sess->backend)
- return;
- bool got_signal = false;
- if (!sess->ssc->exit_signal_numeric) {
- char *sigmsg;
- ptrlen signame = pty_backend_exit_signame(sess->backend, &sigmsg);
- if (signame.len) {
- if (!sigmsg)
- sigmsg = dupstr("");
- sshfwd_send_exit_signal(
- sess->c, signame, false, ptrlen_from_asciz(sigmsg));
- got_signal = true;
- }
- sfree(sigmsg);
- } else {
- int signum = pty_backend_exit_signum(sess->backend);
- if (signum >= 0) {
- sshfwd_send_exit_signal_numeric(sess->c, signum, false,
- PTRLEN_LITERAL(""));
- got_signal = true;
- }
- }
- if (!got_signal)
- sshfwd_send_exit_status(sess->c, backend_exitcode(sess->backend));
- sess->seen_exit = true;
- queue_toplevel_callback(sesschan_check_close_callback, sess);
- }
- static void sesschan_connection_fatal(Seat *seat, const char *message)
- {
- sesschan *sess = container_of(seat, sesschan, seat);
- /* Closest translation I can think of */
- sshfwd_send_exit_signal(
- sess->c, PTRLEN_LITERAL("HUP"), false, ptrlen_from_asciz(message));
- sess->ignoring_input = true;
- }
- static bool sesschan_get_window_pixel_size(Seat *seat, int *width, int *height)
- {
- sesschan *sess = container_of(seat, sesschan, seat);
- *width = sess->wp;
- *height = sess->hp;
- return true;
- }
- /* ----------------------------------------------------------------------
- * Built-in SFTP subsystem.
- */
- static size_t sftp_chan_send(Channel *chan, bool is_stderr,
- const void *data, size_t length)
- {
- sesschan *sess = container_of(chan, sesschan, chan);
- bufchain_add(&sess->subsys_input, data, length);
- while (bufchain_size(&sess->subsys_input) >= 4) {
- char lenbuf[4];
- unsigned pktlen;
- struct sftp_packet *pkt, *reply;
- bufchain_fetch(&sess->subsys_input, lenbuf, 4);
- pktlen = GET_32BIT_MSB_FIRST(lenbuf);
- if (bufchain_size(&sess->subsys_input) - 4 < pktlen)
- break; /* wait for more data */
- bufchain_consume(&sess->subsys_input, 4);
- pkt = sftp_recv_prepare(pktlen);
- bufchain_fetch_consume(&sess->subsys_input, pkt->data, pktlen);
- sftp_recv_finish(pkt);
- reply = sftp_handle_request(sess->sftpsrv, pkt);
- sftp_pkt_free(pkt);
- sftp_send_prepare(reply);
- sshfwd_write(sess->c, reply->data, reply->length);
- sftp_pkt_free(reply);
- }
- return 0;
- }
- static void sftp_chan_send_eof(Channel *chan)
- {
- sesschan *sess = container_of(chan, sesschan, chan);
- sshfwd_write_eof(sess->c);
- }
- static char *sftp_log_close_msg(Channel *chan)
- {
- return dupstr("Session channel (SFTP) closed");
- }
- /* ----------------------------------------------------------------------
- * Built-in SCP subsystem.
- */
- static size_t scp_chan_send(Channel *chan, bool is_stderr,
- const void *data, size_t length)
- {
- sesschan *sess = container_of(chan, sesschan, chan);
- return scp_send(sess->scpsrv, data, length);
- }
- static void scp_chan_send_eof(Channel *chan)
- {
- sesschan *sess = container_of(chan, sesschan, chan);
- scp_eof(sess->scpsrv);
- }
- static char *scp_log_close_msg(Channel *chan)
- {
- return dupstr("Session channel (SCP) closed");
- }
- static void scp_set_input_wanted(Channel *chan, bool wanted)
- {
- sesschan *sess = container_of(chan, sesschan, chan);
- scp_throttle(sess->scpsrv, !wanted);
- }
|