diff --git a/pscp.c b/pscp.c index 7717d8d6..07546dd4 100644 --- a/pscp.c +++ b/pscp.c @@ -60,7 +60,7 @@ const char *const appname = "PSCP"; void ldisc_echoedit_update(Ldisc *ldisc) { } void ldisc_check_sendok(Ldisc *ldisc) { } -static size_t pscp_output(Seat *, bool is_stderr, const void *, size_t); +static size_t pscp_output(Seat *, SeatOutputType type, const void *, size_t); static bool pscp_eof(Seat *); static const SeatVtable pscp_seat_vt = { @@ -146,13 +146,14 @@ static PRINTF_LIKE(2, 3) void tell_user(FILE *stream, const char *fmt, ...) static bufchain received_data; static BinarySink *stderr_bs; static size_t pscp_output( - Seat *seat, bool is_stderr, const void *data, size_t len) + Seat *seat, SeatOutputType type, const void *data, size_t len) { /* - * stderr data is just spouted to local stderr (optionally via a - * sanitiser) and otherwise ignored. + * Non-stdout data (both stderr and SSH auth banners) is just + * spouted to local stderr (optionally via a sanitiser) and + * otherwise ignored. */ - if (is_stderr) { + if (type != SEAT_OUTPUT_STDOUT) { put_data(stderr_bs, data, len); return 0; } diff --git a/psftp.c b/psftp.c index a09837c7..993a3e35 100644 --- a/psftp.c +++ b/psftp.c @@ -41,7 +41,7 @@ static bool sent_eof = false; * Seat vtable. */ -static size_t psftp_output(Seat *, bool is_stderr, const void *, size_t); +static size_t psftp_output(Seat *, SeatOutputType type, const void *, size_t); static bool psftp_eof(Seat *); static const SeatVtable psftp_seat_vt = { @@ -2461,13 +2461,14 @@ void ldisc_check_sendok(Ldisc *ldisc) { } static bufchain received_data; static BinarySink *stderr_bs; static size_t psftp_output( - Seat *seat, bool is_stderr, const void *data, size_t len) + Seat *seat, SeatOutputType type, const void *data, size_t len) { /* - * stderr data is just spouted to local stderr (optionally via a - * sanitiser) and otherwise ignored. + * Non-stdout data (both stderr and SSH auth banners) is just + * spouted to local stderr (optionally via a sanitiser) and + * otherwise ignored. */ - if (is_stderr) { + if (type != SEAT_OUTPUT_STDOUT) { put_data(stderr_bs, data, len); return 0; } diff --git a/putty.h b/putty.h index dba26335..5a765771 100644 --- a/putty.h +++ b/putty.h @@ -889,6 +889,10 @@ typedef enum SeatInteractionContext { SIC_BANNER, SIC_KI_PROMPTS } SeatInteractionContext; +typedef enum SeatOutputType { + SEAT_OUTPUT_STDOUT, SEAT_OUTPUT_STDERR, SEAT_OUTPUT_AUTH_BANNER +} SeatOutputType; + /* * Data type 'Seat', which is an API intended to contain essentially * everything that a back end might need to talk to its client for: @@ -901,14 +905,17 @@ struct Seat { }; struct SeatVtable { /* - * Provide output from the remote session. 'is_stderr' indicates - * that the output should be sent to a separate error message - * channel, if the seat has one. But combining both channels into - * one is OK too; that's what terminal-window based seats do. + * Provide output from the remote session. 'type' indicates the + * type of the output (stdout, stderr or SSH auth banner), which + * can be used to split the output into separate message channels, + * if the seat wants to handle them differently. But combining the + * channels into one is OK too; that's what terminal-window based + * seats do. * * The return value is the current size of the output backlog. */ - size_t (*output)(Seat *seat, bool is_stderr, const void *data, size_t len); + size_t (*output)(Seat *seat, SeatOutputType type, + const void *data, size_t len); /* * Called when the back end wants to indicate that EOF has arrived @@ -1167,8 +1174,8 @@ struct SeatVtable { }; static inline size_t seat_output( - Seat *seat, bool err, const void *data, size_t len) -{ return seat->vt->output(seat, err, data, len); } + Seat *seat, SeatOutputType type, const void *data, size_t len) +{ return seat->vt->output(seat, type, data, len); } static inline bool seat_eof(Seat *seat) { return seat->vt->eof(seat); } static inline void seat_sent(Seat *seat, size_t bufsize) @@ -1231,13 +1238,17 @@ void seat_connection_fatal(Seat *seat, const char *fmt, ...) PRINTF_LIKE(2, 3); /* Handy aliases for seat_output which set is_stderr to a fixed value. */ static inline size_t seat_stdout(Seat *seat, const void *data, size_t len) -{ return seat_output(seat, false, data, len); } +{ return seat_output(seat, SEAT_OUTPUT_STDOUT, data, len); } static inline size_t seat_stdout_pl(Seat *seat, ptrlen data) -{ return seat_output(seat, false, data.ptr, data.len); } +{ return seat_output(seat, SEAT_OUTPUT_STDOUT, data.ptr, data.len); } static inline size_t seat_stderr(Seat *seat, const void *data, size_t len) -{ return seat_output(seat, true, data, len); } +{ return seat_output(seat, SEAT_OUTPUT_STDERR, data, len); } static inline size_t seat_stderr_pl(Seat *seat, ptrlen data) -{ return seat_output(seat, true, data.ptr, data.len); } +{ return seat_output(seat, SEAT_OUTPUT_STDERR, data.ptr, data.len); } +static inline size_t seat_banner(Seat *seat, const void *data, size_t len) +{ return seat_output(seat, SEAT_OUTPUT_AUTH_BANNER, data, len); } +static inline size_t seat_banner_pl(Seat *seat, ptrlen data) +{ return seat_output(seat, SEAT_OUTPUT_AUTH_BANNER, data.ptr, data.len); } /* * Stub methods for seat implementations that want to use the obvious @@ -1247,7 +1258,7 @@ static inline size_t seat_stderr_pl(Seat *seat, ptrlen data) * plausibly want to return either fixed answer 'no' or 'yes'. */ size_t nullseat_output( - Seat *seat, bool is_stderr, const void *data, size_t len); + Seat *seat, SeatOutputType type, const void *data, size_t len); bool nullseat_eof(Seat *seat); void nullseat_sent(Seat *seat, size_t bufsize); int nullseat_get_userpass_input(Seat *seat, prompts_t *p); diff --git a/ssh/sesschan.c b/ssh/sesschan.c index 527b7603..1ef55dde 100644 --- a/ssh/sesschan.c +++ b/ssh/sesschan.c @@ -177,7 +177,7 @@ static const LogPolicyVtable sesschan_logpolicy_vt = { }; static size_t sesschan_seat_output( - Seat *, bool is_stderr, const void *, size_t); + 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); @@ -612,10 +612,15 @@ bool sesschan_change_window_size( } static size_t sesschan_seat_output( - Seat *seat, bool is_stderr, const void *data, size_t len) + Seat *seat, SeatOutputType type, const void *data, size_t len) { sesschan *sess = container_of(seat, sesschan, seat); - return sshfwd_write_ext(sess->c, is_stderr, data, len); + + /* We don't expect anything but stdout and stderr to come here, + * because the pty backend doesn't generate auth banners */ + assert(type != SEAT_OUTPUT_AUTH_BANNER); + + return sshfwd_write_ext(sess->c, type == SEAT_OUTPUT_STDERR, data, len); } static void sesschan_check_close_callback(void *vctx) diff --git a/ssh/userauth2-client.c b/ssh/userauth2-client.c index f1e2f319..4c908048 100644 --- a/ssh/userauth2-client.c +++ b/ssh/userauth2-client.c @@ -530,7 +530,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) bool mid_line = false; while (bufchain_size(&s->banner) > 0) { ptrlen data = bufchain_prefix(&s->banner); - seat_stderr_pl(s->ppl.seat, data); + seat_banner_pl(s->ppl.seat, data); mid_line = (((const char *)data.ptr)[data.len-1] != '\n'); bufchain_consume(&s->banner, data.len); @@ -538,7 +538,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl) bufchain_clear(&s->banner); if (mid_line) - seat_stderr_pl(s->ppl.seat, PTRLEN_LITERAL("\r\n")); + seat_banner_pl(s->ppl.seat, PTRLEN_LITERAL("\r\n")); if (s->banner_scc) { seat_set_trust_status(s->ppl.seat, true); @@ -1919,6 +1919,6 @@ static void ssh2_userauth_antispoof_msg( put_byte(sb, '-'); } put_datapl(sb, PTRLEN_LITERAL("\r\n")); - seat_stderr_pl(s->ppl.seat, ptrlen_from_strbuf(sb)); + seat_banner_pl(s->ppl.seat, ptrlen_from_strbuf(sb)); strbuf_free(sb); } diff --git a/sshproxy.c b/sshproxy.c index 96667212..c5fed894 100644 --- a/sshproxy.c +++ b/sshproxy.c @@ -254,7 +254,7 @@ static void sshproxy_notify_session_started(Seat *seat) plug_log(sp->plug, PLUGLOG_CONNECT_SUCCESS, sp->addr, sp->port, NULL, 0); } -static size_t sshproxy_output(Seat *seat, bool is_stderr, +static size_t sshproxy_output(Seat *seat, SeatOutputType type, const void *data, size_t len) { SshProxy *sp = container_of(seat, SshProxy, seat); diff --git a/unix/plink.c b/unix/plink.c index 46f2da85..74e772b4 100644 --- a/unix/plink.c +++ b/unix/plink.c @@ -352,8 +352,9 @@ size_t try_output(bool is_stderr) } static size_t plink_output( - Seat *seat, bool is_stderr, const void *data, size_t len) + Seat *seat, SeatOutputType type, const void *data, size_t len) { + bool is_stderr = type != SEAT_OUTPUT_STDOUT; assert(is_stderr || outgoingeof == EOF_NO); BinarySink *bs = is_stderr ? stderr_bs : stdout_bs; diff --git a/unix/window.c b/unix/window.c index b3f98827..69c35eb3 100644 --- a/unix/window.c +++ b/unix/window.c @@ -318,7 +318,7 @@ static char *gtk_seat_get_ttymode(Seat *seat, const char *mode) return term_get_ttymode(inst->term, mode); } -static size_t gtk_seat_output(Seat *seat, bool is_stderr, +static size_t gtk_seat_output(Seat *seat, SeatOutputType type, const void *data, size_t len) { GtkFrontend *inst = container_of(seat, GtkFrontend, seat); diff --git a/utils/nullseat.c b/utils/nullseat.c index 564225e5..43c478e0 100644 --- a/utils/nullseat.c +++ b/utils/nullseat.c @@ -5,7 +5,7 @@ #include "putty.h" size_t nullseat_output( - Seat *seat, bool is_stderr, const void *data, size_t len) { return 0; } + Seat *seat, SeatOutputType type, const void *data, size_t len) {return 0;} bool nullseat_eof(Seat *seat) { return true; } void nullseat_sent(Seat *seat, size_t bufsize) {} int nullseat_get_userpass_input(Seat *seat, prompts_t *p) { return 0; } diff --git a/utils/tempseat.c b/utils/tempseat.c index aa3fbe5a..56006f61 100644 --- a/utils/tempseat.c +++ b/utils/tempseat.c @@ -17,7 +17,7 @@ typedef struct TempSeat TempSeat; struct TempSeat { Seat *realseat; - bufchain outputs[2]; /* stdout, stderr */ + bufchain outputs[3]; /* stdout, stderr, auth banner (just in case) */ bool seen_session_started; bool seen_remote_exit; bool seen_remote_disconnect; @@ -33,12 +33,19 @@ struct TempSeat { * real Seat in tempseat_flush(). */ -static size_t tempseat_output(Seat *seat, bool is_stderr, const void *data, - size_t len) +static size_t tempseat_output(Seat *seat, SeatOutputType type, + const void *data, size_t len) { TempSeat *ts = container_of(seat, TempSeat, seat); - bufchain_add(&ts->outputs[is_stderr], data, len); - return bufchain_size(&ts->outputs[0]) + bufchain_size(&ts->outputs[1]); + + size_t index = (size_t)type; + assert(index < lenof(ts->outputs)); + bufchain_add(&ts->outputs[index], data, len); + + size_t total_size = 0; + for (size_t i = 0; i < lenof(ts->outputs); i++) + total_size += bufchain_size(&ts->outputs[i]); + return total_size; } static void tempseat_notify_session_started(Seat *seat) @@ -295,7 +302,7 @@ Seat *tempseat_new(Seat *realseat) ts->seat.vt = &tempseat_vt; ts->realseat = realseat; - for (unsigned i = 0; i < 2; i++) + for (size_t i = 0; i < lenof(ts->outputs); i++) bufchain_init(&ts->outputs[i]); return &ts->seat; @@ -327,8 +334,8 @@ void tempseat_flush(Seat *seat) assert(seat->vt == &tempseat_vt); TempSeat *ts = container_of(seat, TempSeat, seat); - /* Empty the stdout/stderr bufchains into the real seat */ - for (unsigned i = 0; i < 2; i++) { + /* Empty the output bufchains into the real seat */ + for (size_t i = 0; i < lenof(ts->outputs); i++) { while (bufchain_size(&ts->outputs[i])) { ptrlen pl = bufchain_prefix(&ts->outputs[i]); seat_output(ts->realseat, i, pl.ptr, pl.len); diff --git a/windows/plink.c b/windows/plink.c index bbed994d..1c1872dc 100644 --- a/windows/plink.c +++ b/windows/plink.c @@ -50,8 +50,9 @@ static void plink_echoedit_update(Seat *seat, bool echo, bool edit) } static size_t plink_output( - Seat *seat, bool is_stderr, const void *data, size_t len) + Seat *seat, SeatOutputType type, const void *data, size_t len) { + bool is_stderr = type != SEAT_OUTPUT_STDOUT; BinarySink *bs = is_stderr ? stderr_bs : stdout_bs; put_data(bs, data, len); diff --git a/windows/window.c b/windows/window.c index ec398c0f..8fbbbd27 100644 --- a/windows/window.c +++ b/windows/window.c @@ -315,7 +315,7 @@ static StripCtrlChars *win_seat_stripctrl_new( } static size_t win_seat_output( - Seat *seat, bool is_stderr, const void *, size_t); + Seat *seat, SeatOutputType type, const void *, size_t); static bool win_seat_eof(Seat *seat); static int win_seat_get_userpass_input(Seat *seat, prompts_t *p); static void win_seat_notify_remote_exit(Seat *seat); @@ -5734,7 +5734,7 @@ static void flip_full_screen() } } -static size_t win_seat_output(Seat *seat, bool is_stderr, +static size_t win_seat_output(Seat *seat, SeatOutputType type, const void *data, size_t len) { return term_data(term, data, len);