mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
Move sanitisation of k-i prompts into the SSH code.
Now, instead of each seat's prompt-handling function doing the control-char sanitisation of prompt text, the SSH code does it. This means we can do it differently depending on the prompt. In particular, prompts _we_ generate (e.g. a genuine request for your private key's passphrase) are not sanitised; but prompts coming from the server (in keyboard-interactive mode, or its more restricted SSH-1 analogues, TIS and CryptoCard) are not only sanitised but also line-length limited and surrounded by uncounterfeitable headers, like I've just done to the authentication banners. This should mean that if a malicious server tries to fake the local passphrase prompt (perhaps because it's somehow already got a copy of your _encrypted_ private key), you can tell the difference.
This commit is contained in:
parent
767a9c6e45
commit
e21afff605
90
ssh1login.c
90
ssh1login.c
@ -57,6 +57,9 @@ struct ssh1_login_state {
|
||||
RSAKey servkey, hostkey;
|
||||
bool want_user_input;
|
||||
|
||||
StripCtrlChars *tis_scc;
|
||||
bool tis_scc_initialised;
|
||||
|
||||
PacketProtocolLayer ppl;
|
||||
};
|
||||
|
||||
@ -135,6 +138,8 @@ static PktIn *ssh1_login_pop(struct ssh1_login_state *s)
|
||||
return pq_pop(s->ppl.in_pq);
|
||||
}
|
||||
|
||||
static void ssh1_login_setup_tis_scc(struct ssh1_login_state *s);
|
||||
|
||||
static void ssh1_login_process_queue(PacketProtocolLayer *ppl)
|
||||
{
|
||||
struct ssh1_login_state *s =
|
||||
@ -784,6 +789,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl)
|
||||
if (conf_get_bool(s->conf, CONF_try_tis_auth) &&
|
||||
(s->supported_auths_mask & (1 << SSH1_AUTH_TIS)) &&
|
||||
!s->tis_auth_refused) {
|
||||
ssh1_login_setup_tis_scc(s);
|
||||
s->pwpkt_type = SSH1_CMSG_AUTH_TIS_RESPONSE;
|
||||
ppl_logevent("Requested TIS authentication");
|
||||
pkt = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_AUTH_TIS);
|
||||
@ -796,10 +802,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl)
|
||||
s->tis_auth_refused = true;
|
||||
continue;
|
||||
} else if (pktin->type == SSH1_SMSG_AUTH_TIS_CHALLENGE) {
|
||||
ptrlen challenge;
|
||||
char *instr_suf, *prompt;
|
||||
|
||||
challenge = get_string(pktin);
|
||||
ptrlen challenge = get_string(pktin);
|
||||
if (get_err(pktin)) {
|
||||
ssh_proto_error(s->ppl.ssh, "TIS challenge packet was "
|
||||
"badly formed");
|
||||
@ -809,21 +812,28 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl)
|
||||
s->cur_prompt->to_server = true;
|
||||
s->cur_prompt->from_server = true;
|
||||
s->cur_prompt->name = dupstr("SSH TIS authentication");
|
||||
/* Prompt heuristic comes from OpenSSH */
|
||||
if (!memchr(challenge.ptr, '\n', challenge.len)) {
|
||||
instr_suf = dupstr("");
|
||||
prompt = mkstr(challenge);
|
||||
|
||||
strbuf *sb = strbuf_new();
|
||||
put_datapl(sb, PTRLEN_LITERAL("\
|
||||
-- TIS authentication challenge from server: ---------------------------------\
|
||||
\r\n"));
|
||||
if (s->tis_scc) {
|
||||
stripctrl_retarget(s->tis_scc, BinarySink_UPCAST(sb));
|
||||
put_datapl(s->tis_scc, challenge);
|
||||
stripctrl_retarget(s->tis_scc, NULL);
|
||||
} else {
|
||||
instr_suf = mkstr(challenge);
|
||||
prompt = dupstr("Response: ");
|
||||
put_datapl(sb, challenge);
|
||||
}
|
||||
s->cur_prompt->instruction =
|
||||
dupprintf("Using TIS authentication.%s%s",
|
||||
(*instr_suf) ? "\n" : "",
|
||||
instr_suf);
|
||||
if (!ptrlen_endswith(challenge, PTRLEN_LITERAL("\n"), NULL))
|
||||
put_datapl(sb, PTRLEN_LITERAL("\r\n"));
|
||||
put_datapl(sb, PTRLEN_LITERAL("\
|
||||
-- End of TIS authentication challenge from server: --------------------------\
|
||||
\r\n"));
|
||||
|
||||
s->cur_prompt->instruction = strbuf_to_str(sb);
|
||||
s->cur_prompt->instr_reqd = true;
|
||||
add_prompt(s->cur_prompt, prompt, false);
|
||||
sfree(instr_suf);
|
||||
add_prompt(s->cur_prompt, dupstr(
|
||||
"TIS authentication response: "), false);
|
||||
} else {
|
||||
ssh_proto_error(s->ppl.ssh, "Received unexpected packet"
|
||||
" in response to TIS authentication, "
|
||||
@ -834,6 +844,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl)
|
||||
} else if (conf_get_bool(s->conf, CONF_try_tis_auth) &&
|
||||
(s->supported_auths_mask & (1 << SSH1_AUTH_CCARD)) &&
|
||||
!s->ccard_auth_refused) {
|
||||
ssh1_login_setup_tis_scc(s);
|
||||
s->pwpkt_type = SSH1_CMSG_AUTH_CCARD_RESPONSE;
|
||||
ppl_logevent("Requested CryptoCard authentication");
|
||||
pkt = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_AUTH_CCARD);
|
||||
@ -845,10 +856,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl)
|
||||
s->ccard_auth_refused = true;
|
||||
continue;
|
||||
} else if (pktin->type == SSH1_SMSG_AUTH_CCARD_CHALLENGE) {
|
||||
ptrlen challenge;
|
||||
char *instr_suf, *prompt;
|
||||
|
||||
challenge = get_string(pktin);
|
||||
ptrlen challenge = get_string(pktin);
|
||||
if (get_err(pktin)) {
|
||||
ssh_proto_error(s->ppl.ssh, "CryptoCard challenge packet "
|
||||
"was badly formed");
|
||||
@ -858,22 +866,28 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl)
|
||||
s->cur_prompt->to_server = true;
|
||||
s->cur_prompt->from_server = true;
|
||||
s->cur_prompt->name = dupstr("SSH CryptoCard authentication");
|
||||
s->cur_prompt->name_reqd = false;
|
||||
/* Prompt heuristic comes from OpenSSH */
|
||||
if (!memchr(challenge.ptr, '\n', challenge.len)) {
|
||||
instr_suf = dupstr("");
|
||||
prompt = mkstr(challenge);
|
||||
|
||||
strbuf *sb = strbuf_new();
|
||||
put_datapl(sb, PTRLEN_LITERAL("\
|
||||
-- CryptoCard authentication challenge from server: --------------------------\
|
||||
\r\n"));
|
||||
if (s->tis_scc) {
|
||||
stripctrl_retarget(s->tis_scc, BinarySink_UPCAST(sb));
|
||||
put_datapl(s->tis_scc, challenge);
|
||||
stripctrl_retarget(s->tis_scc, NULL);
|
||||
} else {
|
||||
instr_suf = mkstr(challenge);
|
||||
prompt = dupstr("Response: ");
|
||||
put_datapl(sb, challenge);
|
||||
}
|
||||
s->cur_prompt->instruction =
|
||||
dupprintf("Using CryptoCard authentication.%s%s",
|
||||
(*instr_suf) ? "\n" : "",
|
||||
instr_suf);
|
||||
if (!ptrlen_endswith(challenge, PTRLEN_LITERAL("\n"), NULL))
|
||||
put_datapl(sb, PTRLEN_LITERAL("\r\n"));
|
||||
put_datapl(sb, PTRLEN_LITERAL("\
|
||||
-- End of CryptoCard authentication challenge from server: -------------------\
|
||||
\r\n"));
|
||||
|
||||
s->cur_prompt->instruction = strbuf_to_str(sb);
|
||||
s->cur_prompt->instr_reqd = true;
|
||||
add_prompt(s->cur_prompt, prompt, false);
|
||||
sfree(instr_suf);
|
||||
add_prompt(s->cur_prompt, dupstr(
|
||||
"CryptoCard authentication response: "), false);
|
||||
} else {
|
||||
ssh_proto_error(s->ppl.ssh, "Received unexpected packet"
|
||||
" in response to TIS authentication, "
|
||||
@ -1085,6 +1099,16 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl)
|
||||
crFinishV;
|
||||
}
|
||||
|
||||
static void ssh1_login_setup_tis_scc(struct ssh1_login_state *s)
|
||||
{
|
||||
if (s->tis_scc_initialised)
|
||||
return;
|
||||
s->tis_scc = seat_stripctrl_new(s->ppl.seat, NULL, SIC_KI_PROMPTS);
|
||||
if (s->tis_scc)
|
||||
stripctrl_enable_line_limiting(s->tis_scc);
|
||||
s->tis_scc_initialised = true;
|
||||
}
|
||||
|
||||
static void ssh1_login_dialog_callback(void *loginv, int ret)
|
||||
{
|
||||
struct ssh1_login_state *s = (struct ssh1_login_state *)loginv;
|
||||
|
110
ssh2userauth.c
110
ssh2userauth.c
@ -81,6 +81,10 @@ struct ssh2_userauth_state {
|
||||
StripCtrlChars *banner_scc;
|
||||
bool banner_scc_initialised;
|
||||
|
||||
StripCtrlChars *ki_scc;
|
||||
bool ki_scc_initialised;
|
||||
bool ki_printed_header;
|
||||
|
||||
PacketProtocolLayer ppl;
|
||||
};
|
||||
|
||||
@ -176,6 +180,8 @@ static void ssh2_userauth_free(PacketProtocolLayer *ppl)
|
||||
strbuf_free(s->last_methods_string);
|
||||
if (s->banner_scc)
|
||||
stripctrl_free(s->banner_scc);
|
||||
if (s->ki_scc)
|
||||
stripctrl_free(s->ki_scc);
|
||||
sfree(s);
|
||||
}
|
||||
|
||||
@ -1174,6 +1180,14 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
|
||||
|
||||
ppl_logevent("Attempting keyboard-interactive authentication");
|
||||
|
||||
if (!s->ki_scc_initialised) {
|
||||
s->ki_scc = seat_stripctrl_new(
|
||||
s->ppl.seat, NULL, SIC_KI_PROMPTS);
|
||||
if (s->ki_scc)
|
||||
stripctrl_enable_line_limiting(s->ki_scc);
|
||||
s->ki_scc_initialised = true;
|
||||
}
|
||||
|
||||
crMaybeWaitUntilV((pktin = ssh2_userauth_pop(s)) != NULL);
|
||||
if (pktin->type != SSH2_MSG_USERAUTH_INFO_REQUEST) {
|
||||
/* Server is not willing to do keyboard-interactive
|
||||
@ -1186,12 +1200,15 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
|
||||
continue;
|
||||
}
|
||||
|
||||
s->ki_printed_header = false;
|
||||
|
||||
/*
|
||||
* Loop while the server continues to send INFO_REQUESTs.
|
||||
*/
|
||||
while (pktin->type == SSH2_MSG_USERAUTH_INFO_REQUEST) {
|
||||
|
||||
ptrlen name, inst;
|
||||
strbuf *sb;
|
||||
int i;
|
||||
|
||||
/*
|
||||
@ -1210,52 +1227,78 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
|
||||
*/
|
||||
s->num_prompts = get_uint32(pktin);
|
||||
for (i = 0; i < s->num_prompts; i++) {
|
||||
ptrlen prompt;
|
||||
bool echo;
|
||||
static char noprompt[] =
|
||||
"<server failed to send prompt>: ";
|
||||
ptrlen prompt = get_string(pktin);
|
||||
bool echo = get_bool(pktin);
|
||||
|
||||
prompt = get_string(pktin);
|
||||
echo = get_bool(pktin);
|
||||
sb = strbuf_new();
|
||||
if (!prompt.len) {
|
||||
prompt.ptr = noprompt;
|
||||
prompt.len = lenof(noprompt)-1;
|
||||
put_datapl(sb, PTRLEN_LITERAL(
|
||||
"<server failed to send prompt>: "));
|
||||
} else if (s->ki_scc) {
|
||||
stripctrl_retarget(
|
||||
s->ki_scc, BinarySink_UPCAST(sb));
|
||||
put_datapl(s->ki_scc, prompt);
|
||||
stripctrl_retarget(s->ki_scc, NULL);
|
||||
} else {
|
||||
put_datapl(sb, prompt);
|
||||
}
|
||||
add_prompt(s->cur_prompt, mkstr(prompt), echo);
|
||||
add_prompt(s->cur_prompt, strbuf_to_str(sb), echo);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make the header strings. This includes the
|
||||
* 'name' (optional dialog-box title) and
|
||||
* 'instruction' from the server.
|
||||
*
|
||||
* First, display our disambiguating header line
|
||||
* if this is the first time round the loop -
|
||||
* _unless_ the server has sent a completely empty
|
||||
* k-i packet with no prompts _or_ text, which
|
||||
* apparently some do. In that situation there's
|
||||
* no need to alert the user that the following
|
||||
* text is server- supplied, because, well, _what_
|
||||
* text?
|
||||
*
|
||||
* We also only do this if we got a stripctrl,
|
||||
* because if we didn't, that suggests this is all
|
||||
* being done via dialog boxes anyway.
|
||||
*/
|
||||
if (!s->ki_printed_header && s->ki_scc &&
|
||||
(s->num_prompts || name.len || inst.len)) {
|
||||
ssh2_userauth_antispoof_msg(
|
||||
s, "Keyboard-interactive authentication "
|
||||
"prompts from server:");
|
||||
s->ki_printed_header = true;
|
||||
}
|
||||
|
||||
sb = strbuf_new();
|
||||
if (name.len) {
|
||||
/* FIXME: better prefix to distinguish from
|
||||
* local prompts? */
|
||||
s->cur_prompt->name =
|
||||
dupprintf("SSH server: %.*s", PTRLEN_PRINTF(name));
|
||||
stripctrl_retarget(s->ki_scc, BinarySink_UPCAST(sb));
|
||||
put_datapl(s->ki_scc, name);
|
||||
stripctrl_retarget(s->ki_scc, NULL);
|
||||
|
||||
s->cur_prompt->name_reqd = true;
|
||||
} else {
|
||||
s->cur_prompt->name =
|
||||
dupstr("SSH server authentication");
|
||||
put_datapl(sb, PTRLEN_LITERAL(
|
||||
"SSH server authentication"));
|
||||
s->cur_prompt->name_reqd = false;
|
||||
}
|
||||
/* We add a prefix to try to make it clear that a prompt
|
||||
* has come from the server.
|
||||
* FIXME: ugly to print "Using..." in prompt _every_
|
||||
* time round. Can this be done more subtly? */
|
||||
/* Special case: for reasons best known to themselves,
|
||||
* some servers send k-i requests with no prompts and
|
||||
* nothing to display. Keep quiet in this case. */
|
||||
if (s->num_prompts || name.len || inst.len) {
|
||||
s->cur_prompt->instruction =
|
||||
dupprintf("Using keyboard-interactive "
|
||||
"authentication.%s%.*s",
|
||||
inst.len ? "\n" : "",
|
||||
PTRLEN_PRINTF(inst));
|
||||
s->cur_prompt->name = strbuf_to_str(sb);
|
||||
|
||||
sb = strbuf_new();
|
||||
if (inst.len) {
|
||||
stripctrl_retarget(s->ki_scc, BinarySink_UPCAST(sb));
|
||||
put_datapl(s->ki_scc, inst);
|
||||
stripctrl_retarget(s->ki_scc, NULL);
|
||||
|
||||
s->cur_prompt->instr_reqd = true;
|
||||
} else {
|
||||
s->cur_prompt->instr_reqd = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Display any instructions, and get the user's
|
||||
* response(s).
|
||||
* Our prompts_t is fully constructed now. Get the
|
||||
* user's response(s).
|
||||
*/
|
||||
s->userpass_ret = seat_get_userpass_input(
|
||||
s->ppl.seat, s->cur_prompt, NULL);
|
||||
@ -1313,6 +1356,13 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Print our trailer line, if we printed a header.
|
||||
*/
|
||||
if (s->ki_printed_header)
|
||||
ssh2_userauth_antispoof_msg(
|
||||
s, "End of keyboard-interactive prompts from server");
|
||||
|
||||
/*
|
||||
* We should have SUCCESS or FAILURE now.
|
||||
*/
|
||||
|
44
terminal.c
44
terminal.c
@ -1682,9 +1682,6 @@ Terminal *term_init(Conf *myconf, struct unicode_data *ucsdata, TermWin *win)
|
||||
term->paste_buffer = NULL;
|
||||
term->paste_len = 0;
|
||||
bufchain_init(&term->inbuf);
|
||||
bufchain_sink_init(&term->inbuf_bs, &term->inbuf);
|
||||
term->inbuf_scc = stripctrl_new_term(
|
||||
BinarySink_UPCAST(&term->inbuf_bs), false, 0, term);
|
||||
bufchain_init(&term->printer_buf);
|
||||
term->printing = term->only_printing = false;
|
||||
term->print_job = NULL;
|
||||
@ -1779,7 +1776,6 @@ void term_free(Terminal *term)
|
||||
term->beephead = beep->next;
|
||||
sfree(beep);
|
||||
}
|
||||
stripctrl_free(term->inbuf_scc);
|
||||
bufchain_clear(&term->inbuf);
|
||||
if(term->print_job)
|
||||
printer_finish_job(term->print_job);
|
||||
@ -6837,12 +6833,6 @@ size_t term_data(Terminal *term, bool is_stderr, const void *data, size_t len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void term_data_untrusted(Terminal *term, const void *data, size_t len)
|
||||
{
|
||||
put_data(term->inbuf_scc, data, len);
|
||||
term_added_data(term);
|
||||
}
|
||||
|
||||
void term_provide_logctx(Terminal *term, LogContext *logctx)
|
||||
{
|
||||
term->logctx = logctx;
|
||||
@ -6877,6 +6867,12 @@ struct term_userpass_state {
|
||||
size_t pos; /* cursor position */
|
||||
};
|
||||
|
||||
/* Tiny wrapper to make it easier to write lots of little strings */
|
||||
static inline void term_write(Terminal *term, ptrlen data)
|
||||
{
|
||||
term_data(term, false, data.ptr, data.len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process some terminal data in the course of username/password
|
||||
* input.
|
||||
@ -6893,17 +6889,17 @@ int term_get_userpass_input(Terminal *term, prompts_t *p, bufchain *input)
|
||||
s->done_prompt = false;
|
||||
/* We only print the `name' caption if we have to... */
|
||||
if (p->name_reqd && p->name) {
|
||||
size_t l = strlen(p->name);
|
||||
term_data_untrusted(term, p->name, l);
|
||||
if (p->name[l-1] != '\n')
|
||||
term_data_untrusted(term, "\n", 1);
|
||||
ptrlen plname = ptrlen_from_asciz(p->name);
|
||||
term_write(term, plname);
|
||||
if (!ptrlen_endswith(plname, PTRLEN_LITERAL("\n"), NULL))
|
||||
term_write(term, PTRLEN_LITERAL("\r\n"));
|
||||
}
|
||||
/* ...but we always print any `instruction'. */
|
||||
if (p->instruction) {
|
||||
size_t l = strlen(p->instruction);
|
||||
term_data_untrusted(term, p->instruction, l);
|
||||
if (p->instruction[l-1] != '\n')
|
||||
term_data_untrusted(term, "\n", 1);
|
||||
ptrlen plinst = ptrlen_from_asciz(p->instruction);
|
||||
term_write(term, plinst);
|
||||
if (!ptrlen_endswith(plinst, PTRLEN_LITERAL("\n"), NULL))
|
||||
term_write(term, PTRLEN_LITERAL("\r\n"));
|
||||
}
|
||||
/*
|
||||
* Zero all the results, in case we abort half-way through.
|
||||
@ -6921,7 +6917,7 @@ int term_get_userpass_input(Terminal *term, prompts_t *p, bufchain *input)
|
||||
bool finished_prompt = false;
|
||||
|
||||
if (!s->done_prompt) {
|
||||
term_data_untrusted(term, pr->prompt, strlen(pr->prompt));
|
||||
term_write(term, ptrlen_from_asciz(pr->prompt));
|
||||
s->done_prompt = true;
|
||||
s->pos = 0;
|
||||
}
|
||||
@ -6937,7 +6933,7 @@ int term_get_userpass_input(Terminal *term, prompts_t *p, bufchain *input)
|
||||
switch (c) {
|
||||
case 10:
|
||||
case 13:
|
||||
term_data(term, false, "\r\n", 2);
|
||||
term_write(term, PTRLEN_LITERAL("\r\n"));
|
||||
prompt_ensure_result_size(pr, s->pos + 1);
|
||||
pr->result[s->pos] = '\0';
|
||||
/* go to next prompt, if any */
|
||||
@ -6949,7 +6945,7 @@ int term_get_userpass_input(Terminal *term, prompts_t *p, bufchain *input)
|
||||
case 127:
|
||||
if (s->pos > 0) {
|
||||
if (pr->echo)
|
||||
term_data(term, false, "\b \b", 3);
|
||||
term_write(term, PTRLEN_LITERAL("\b \b"));
|
||||
s->pos--;
|
||||
}
|
||||
break;
|
||||
@ -6957,14 +6953,14 @@ int term_get_userpass_input(Terminal *term, prompts_t *p, bufchain *input)
|
||||
case 27:
|
||||
while (s->pos > 0) {
|
||||
if (pr->echo)
|
||||
term_data(term, false, "\b \b", 3);
|
||||
term_write(term, PTRLEN_LITERAL("\b \b"));
|
||||
s->pos--;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
/* Immediate abort. */
|
||||
term_data(term, false, "\r\n", 2);
|
||||
term_write(term, PTRLEN_LITERAL("\r\n"));
|
||||
sfree(s);
|
||||
p->data = NULL;
|
||||
return 0; /* user abort */
|
||||
@ -6979,7 +6975,7 @@ int term_get_userpass_input(Terminal *term, prompts_t *p, bufchain *input)
|
||||
prompt_ensure_result_size(pr, s->pos + 1);
|
||||
pr->result[s->pos++] = c;
|
||||
if (pr->echo)
|
||||
term_data(term, false, &c, 1);
|
||||
term_write(term, make_ptrlen(&c, 1));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -100,8 +100,6 @@ struct terminal_tag {
|
||||
termchar basic_erase_char, erase_char;
|
||||
|
||||
bufchain inbuf; /* terminal input buffer */
|
||||
bufchain_sink inbuf_bs;
|
||||
StripCtrlChars *inbuf_scc;
|
||||
|
||||
pos curs; /* cursor */
|
||||
pos savecurs; /* saved cursor position */
|
||||
|
@ -494,22 +494,9 @@ static void console_close(FILE *outfp, int infd)
|
||||
fclose(outfp); /* will automatically close infd too */
|
||||
}
|
||||
|
||||
static void console_prompt_text(FILE *outfp, const char *data, size_t len)
|
||||
static void console_write(FILE *outfp, ptrlen data)
|
||||
{
|
||||
bufchain sanitised;
|
||||
bufchain_sink bs;
|
||||
|
||||
bufchain_init(&sanitised);
|
||||
bufchain_sink_init(&bs, &sanitised);
|
||||
StripCtrlChars *scc = stripctrl_new(BinarySink_UPCAST(&bs), false, 0);
|
||||
put_data(scc, data, len);
|
||||
stripctrl_free(scc);
|
||||
|
||||
while (bufchain_size(&sanitised) > 0) {
|
||||
ptrlen sdata = bufchain_prefix(&sanitised);
|
||||
fwrite(sdata.ptr, 1, sdata.len, outfp);
|
||||
bufchain_consume(&sanitised, sdata.len);
|
||||
}
|
||||
fwrite(data.ptr, 1, data.len, outfp);
|
||||
fflush(outfp);
|
||||
}
|
||||
|
||||
@ -538,17 +525,17 @@ int console_get_userpass_input(prompts_t *p)
|
||||
*/
|
||||
/* We only print the `name' caption if we have to... */
|
||||
if (p->name_reqd && p->name) {
|
||||
size_t l = strlen(p->name);
|
||||
console_prompt_text(outfp, p->name, l);
|
||||
if (p->name[l-1] != '\n')
|
||||
console_prompt_text(outfp, "\n", 1);
|
||||
ptrlen plname = ptrlen_from_asciz(p->name);
|
||||
console_write(outfp, plname);
|
||||
if (!ptrlen_endswith(plname, PTRLEN_LITERAL("\n"), NULL))
|
||||
console_write(outfp, PTRLEN_LITERAL("\n"));
|
||||
}
|
||||
/* ...but we always print any `instruction'. */
|
||||
if (p->instruction) {
|
||||
size_t l = strlen(p->instruction);
|
||||
console_prompt_text(outfp, p->instruction, l);
|
||||
if (p->instruction[l-1] != '\n')
|
||||
console_prompt_text(outfp, "\n", 1);
|
||||
ptrlen plinst = ptrlen_from_asciz(p->instruction);
|
||||
console_write(outfp, plinst);
|
||||
if (!ptrlen_endswith(plinst, PTRLEN_LITERAL("\n"), NULL))
|
||||
console_write(outfp, PTRLEN_LITERAL("\n"));
|
||||
}
|
||||
|
||||
for (curr_prompt = 0; curr_prompt < p->n_prompts; curr_prompt++) {
|
||||
@ -566,7 +553,7 @@ int console_get_userpass_input(prompts_t *p)
|
||||
newmode.c_lflag |= ECHO;
|
||||
tcsetattr(infd, TCSANOW, &newmode);
|
||||
|
||||
console_prompt_text(outfp, pr->prompt, strlen(pr->prompt));
|
||||
console_write(outfp, ptrlen_from_asciz(pr->prompt));
|
||||
|
||||
len = 0;
|
||||
while (1) {
|
||||
@ -588,7 +575,7 @@ int console_get_userpass_input(prompts_t *p)
|
||||
tcsetattr(infd, TCSANOW, &oldmode);
|
||||
|
||||
if (!pr->echo)
|
||||
console_prompt_text(outfp, "\n", 1);
|
||||
console_write(outfp, PTRLEN_LITERAL("\n"));
|
||||
|
||||
if (len < 0) {
|
||||
console_close(outfp, infd);
|
||||
|
@ -394,23 +394,10 @@ StripCtrlChars *console_stripctrl_new(
|
||||
return stripctrl_new(bs_out, false, 0);
|
||||
}
|
||||
|
||||
static void console_data_untrusted(HANDLE hout, const char *data, size_t len)
|
||||
static void console_write(HANDLE hout, ptrlen data)
|
||||
{
|
||||
DWORD dummy;
|
||||
bufchain sanitised;
|
||||
bufchain_sink bs;
|
||||
|
||||
bufchain_init(&sanitised);
|
||||
bufchain_sink_init(&bs, &sanitised);
|
||||
StripCtrlChars *scc = stripctrl_new(BinarySink_UPCAST(&bs), false, 0);
|
||||
put_data(scc, data, len);
|
||||
stripctrl_free(scc);
|
||||
|
||||
while (bufchain_size(&sanitised) > 0) {
|
||||
ptrlen sdata = bufchain_prefix(&sanitised);
|
||||
WriteFile(hout, sdata.ptr, sdata.len, &dummy, NULL);
|
||||
bufchain_consume(&sanitised, sdata.len);
|
||||
}
|
||||
WriteFile(hout, data.ptr, data.len, &dummy, NULL);
|
||||
}
|
||||
|
||||
int console_get_userpass_input(prompts_t *p)
|
||||
@ -459,17 +446,17 @@ int console_get_userpass_input(prompts_t *p)
|
||||
*/
|
||||
/* We only print the `name' caption if we have to... */
|
||||
if (p->name_reqd && p->name) {
|
||||
size_t l = strlen(p->name);
|
||||
console_data_untrusted(hout, p->name, l);
|
||||
if (p->name[l-1] != '\n')
|
||||
console_data_untrusted(hout, "\n", 1);
|
||||
ptrlen plname = ptrlen_from_asciz(p->name);
|
||||
console_write(hout, plname);
|
||||
if (!ptrlen_endswith(plname, PTRLEN_LITERAL("\n"), NULL))
|
||||
console_write(hout, PTRLEN_LITERAL("\n"));
|
||||
}
|
||||
/* ...but we always print any `instruction'. */
|
||||
if (p->instruction) {
|
||||
size_t l = strlen(p->instruction);
|
||||
console_data_untrusted(hout, p->instruction, l);
|
||||
if (p->instruction[l-1] != '\n')
|
||||
console_data_untrusted(hout, "\n", 1);
|
||||
ptrlen plinst = ptrlen_from_asciz(p->instruction);
|
||||
console_write(hout, plinst);
|
||||
if (!ptrlen_endswith(plinst, PTRLEN_LITERAL("\n"), NULL))
|
||||
console_write(hout, PTRLEN_LITERAL("\n"));
|
||||
}
|
||||
|
||||
for (curr_prompt = 0; curr_prompt < p->n_prompts; curr_prompt++) {
|
||||
@ -486,7 +473,7 @@ int console_get_userpass_input(prompts_t *p)
|
||||
newmode |= ENABLE_ECHO_INPUT;
|
||||
SetConsoleMode(hin, newmode);
|
||||
|
||||
console_data_untrusted(hout, pr->prompt, strlen(pr->prompt));
|
||||
console_write(hout, ptrlen_from_asciz(pr->prompt));
|
||||
|
||||
len = 0;
|
||||
while (1) {
|
||||
@ -510,10 +497,8 @@ int console_get_userpass_input(prompts_t *p)
|
||||
|
||||
SetConsoleMode(hin, savemode);
|
||||
|
||||
if (!pr->echo) {
|
||||
DWORD dummy;
|
||||
WriteFile(hout, "\r\n", 2, &dummy, NULL);
|
||||
}
|
||||
if (!pr->echo)
|
||||
console_write(hout, PTRLEN_LITERAL("\r\n"));
|
||||
|
||||
if (len == (size_t)-1) {
|
||||
return 0; /* failure due to read error */
|
||||
|
Loading…
Reference in New Issue
Block a user