1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-25 01:02:24 +00:00

While I'm crusading against arbitrary limits, here's a redesign of

prompt_t to arrange that the buffer in which each prompt is stored can
be reallocated larger during the input process.

[originally from svn r9317]
This commit is contained in:
Simon Tatham 2011-10-02 11:50:45 +00:00
parent 62cbc7dc0b
commit da66c0656a
9 changed files with 121 additions and 59 deletions

View File

@ -720,7 +720,7 @@ int main(int argc, char **argv)
int ret; int ret;
p->to_server = FALSE; p->to_server = FALSE;
p->name = dupstr("SSH key passphrase"); p->name = dupstr("SSH key passphrase");
add_prompt(p, dupstr("Enter passphrase to load key: "), FALSE, 512); add_prompt(p, dupstr("Enter passphrase to load key: "), FALSE);
ret = console_get_userpass_input(p, NULL, 0); ret = console_get_userpass_input(p, NULL, 0);
assert(ret >= 0); assert(ret >= 0);
if (!ret) { if (!ret) {
@ -845,8 +845,8 @@ int main(int argc, char **argv)
p->to_server = FALSE; p->to_server = FALSE;
p->name = dupstr("New SSH key passphrase"); p->name = dupstr("New SSH key passphrase");
add_prompt(p, dupstr("Enter passphrase to save key: "), FALSE, 512); add_prompt(p, dupstr("Enter passphrase to save key: "), FALSE);
add_prompt(p, dupstr("Re-enter passphrase to verify: "), FALSE, 512); add_prompt(p, dupstr("Re-enter passphrase to verify: "), FALSE);
ret = console_get_userpass_input(p, NULL, 0); ret = console_get_userpass_input(p, NULL, 0);
assert(ret >= 0); assert(ret >= 0);
if (!ret) { if (!ret) {

View File

@ -105,15 +105,12 @@ int cmdline_get_passwd_input(prompts_t *p, unsigned char *in, int inlen) {
if (tried_once) if (tried_once)
return 0; return 0;
strncpy(p->prompts[0]->result, cmdline_password, prompt_set_result(p->prompts[0], cmdline_password);
p->prompts[0]->result_len);
p->prompts[0]->result[p->prompts[0]->result_len-1] = '\0';
memset(cmdline_password, 0, strlen(cmdline_password)); memset(cmdline_password, 0, strlen(cmdline_password));
sfree(cmdline_password); sfree(cmdline_password);
cmdline_password = NULL; cmdline_password = NULL;
tried_once = 1; tried_once = 1;
return 1; return 1;
} }
/* /*

34
misc.c
View File

@ -99,24 +99,48 @@ prompts_t *new_prompts(void *frontend)
p->name_reqd = p->instr_reqd = FALSE; p->name_reqd = p->instr_reqd = FALSE;
return p; return p;
} }
void add_prompt(prompts_t *p, char *promptstr, int echo, size_t len) void add_prompt(prompts_t *p, char *promptstr, int echo)
{ {
prompt_t *pr = snew(prompt_t); prompt_t *pr = snew(prompt_t);
char *result = snewn(len, char);
pr->prompt = promptstr; pr->prompt = promptstr;
pr->echo = echo; pr->echo = echo;
pr->result = result; pr->result = NULL;
pr->result_len = len; pr->resultsize = 0;
p->n_prompts++; p->n_prompts++;
p->prompts = sresize(p->prompts, p->n_prompts, prompt_t *); p->prompts = sresize(p->prompts, p->n_prompts, prompt_t *);
p->prompts[p->n_prompts-1] = pr; p->prompts[p->n_prompts-1] = pr;
} }
void prompt_ensure_result_size(prompt_t *pr, int newlen)
{
if ((int)pr->resultsize < newlen) {
char *newbuf;
newlen = newlen * 5 / 4 + 512; /* avoid too many small allocs */
/*
* We don't use sresize / realloc here, because we will be
* storing sensitive stuff like passwords in here, and we want
* to make sure that the data doesn't get copied around in
* memory without the old copy being destroyed.
*/
newbuf = snewn(newlen, char);
memcpy(newbuf, pr->result, pr->resultsize);
memset(pr->result, '\0', pr->resultsize);
sfree(pr->result);
pr->result = newbuf;
pr->resultsize = newlen;
}
}
void prompt_set_result(prompt_t *pr, const char *newstr)
{
prompt_ensure_result_size(pr, strlen(newstr) + 1);
strcpy(pr->result, newstr);
}
void free_prompts(prompts_t *p) void free_prompts(prompts_t *p)
{ {
size_t i; size_t i;
for (i=0; i < p->n_prompts; i++) { for (i=0; i < p->n_prompts; i++) {
prompt_t *pr = p->prompts[i]; prompt_t *pr = p->prompts[i];
memset(pr->result, 0, pr->result_len); /* burn the evidence */ memset(pr->result, 0, pr->resultsize); /* burn the evidence */
sfree(pr->result); sfree(pr->result);
sfree(pr->prompt); sfree(pr->prompt);
sfree(pr); sfree(pr);

19
putty.h
View File

@ -525,8 +525,19 @@ struct RSAKey; /* be a little careful of scope */
typedef struct { typedef struct {
char *prompt; char *prompt;
int echo; int echo;
char *result; /* allocated/freed by caller */ /*
size_t result_len; * 'result' must be a dynamically allocated array of exactly
* 'resultsize' chars. The code for actually reading input may
* realloc it bigger (and adjust resultsize accordingly) if it has
* to. The caller should free it again when finished with it.
*
* If resultsize==0, then result may be NULL. When setting up a
* prompt_t, it's therefore easiest to initialise them this way,
* which means all actual allocation is done by the callee. This
* is what add_prompt does.
*/
char *result;
size_t resultsize;
} prompt_t; } prompt_t;
typedef struct { typedef struct {
/* /*
@ -549,7 +560,9 @@ typedef struct {
* get_userpass_input(); initially NULL */ * get_userpass_input(); initially NULL */
} prompts_t; } prompts_t;
prompts_t *new_prompts(void *frontend); prompts_t *new_prompts(void *frontend);
void add_prompt(prompts_t *p, char *promptstr, int echo, size_t len); void add_prompt(prompts_t *p, char *promptstr, int echo);
void prompt_set_result(prompt_t *pr, const char *newstr);
void prompt_ensure_result_size(prompt_t *pr, int len);
/* Burn the evidence. (Assumes _all_ strings want free()ing.) */ /* Burn the evidence. (Assumes _all_ strings want free()ing.) */
void free_prompts(prompts_t *p); void free_prompts(prompts_t *p);

View File

@ -246,8 +246,7 @@ static const char *rlogin_init(void *frontend_handle, void **backend_handle,
rlogin->prompt = new_prompts(rlogin->frontend); rlogin->prompt = new_prompts(rlogin->frontend);
rlogin->prompt->to_server = TRUE; rlogin->prompt->to_server = TRUE;
rlogin->prompt->name = dupstr("Rlogin login name"); rlogin->prompt->name = dupstr("Rlogin login name");
/* 512 is an arbitrary limit :-( */ add_prompt(rlogin->prompt, dupstr("rlogin username: "), TRUE);
add_prompt(rlogin->prompt, dupstr("rlogin username: "), TRUE, 512);
ret = get_userpass_input(rlogin->prompt, NULL, 0); ret = get_userpass_input(rlogin->prompt, NULL, 0);
if (ret >= 0) { if (ret >= 0) {
rlogin_startup(rlogin, rlogin->prompt->prompts[0]->result); rlogin_startup(rlogin, rlogin->prompt->prompts[0]->result);

30
ssh.c
View File

@ -517,9 +517,6 @@ static void ssh_channel_destroy(struct ssh_channel *c);
#define OUR_V2_MAXPKT 0x4000UL #define OUR_V2_MAXPKT 0x4000UL
#define OUR_V2_PACKETLIMIT 0x9000UL #define OUR_V2_PACKETLIMIT 0x9000UL
/* Maximum length of passwords/passphrases (arbitrary) */
#define SSH_MAX_PASSWORD_LEN 100
const static struct ssh_signkey *hostkey_algs[] = { &ssh_rsa, &ssh_dss }; const static struct ssh_signkey *hostkey_algs[] = { &ssh_rsa, &ssh_dss };
const static struct ssh_mac *macs[] = { const static struct ssh_mac *macs[] = {
@ -3526,8 +3523,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen,
s->cur_prompt = new_prompts(ssh->frontend); s->cur_prompt = new_prompts(ssh->frontend);
s->cur_prompt->to_server = TRUE; s->cur_prompt->to_server = TRUE;
s->cur_prompt->name = dupstr("SSH login name"); s->cur_prompt->name = dupstr("SSH login name");
/* 512 is an arbitrary upper limit on username size */ add_prompt(s->cur_prompt, dupstr("login as: "), TRUE);
add_prompt(s->cur_prompt, dupstr("login as: "), TRUE, 512);
ret = get_userpass_input(s->cur_prompt, NULL, 0); ret = get_userpass_input(s->cur_prompt, NULL, 0);
while (ret < 0) { while (ret < 0) {
ssh->send_ok = 1; ssh->send_ok = 1;
@ -3820,8 +3816,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen,
s->cur_prompt->name = dupstr("SSH key passphrase"); s->cur_prompt->name = dupstr("SSH key passphrase");
add_prompt(s->cur_prompt, add_prompt(s->cur_prompt,
dupprintf("Passphrase for key \"%.100s\": ", dupprintf("Passphrase for key \"%.100s\": ",
s->publickey_comment), s->publickey_comment), FALSE);
FALSE, SSH_MAX_PASSWORD_LEN);
ret = get_userpass_input(s->cur_prompt, NULL, 0); ret = get_userpass_input(s->cur_prompt, NULL, 0);
while (ret < 0) { while (ret < 0) {
ssh->send_ok = 1; ssh->send_ok = 1;
@ -3976,7 +3971,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen,
(*instr_suf) ? "\n" : "", (*instr_suf) ? "\n" : "",
instr_suf); instr_suf);
s->cur_prompt->instr_reqd = TRUE; s->cur_prompt->instr_reqd = TRUE;
add_prompt(s->cur_prompt, prompt, FALSE, SSH_MAX_PASSWORD_LEN); add_prompt(s->cur_prompt, prompt, FALSE);
sfree(instr_suf); sfree(instr_suf);
} }
} }
@ -4019,7 +4014,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen,
(*instr_suf) ? "\n" : "", (*instr_suf) ? "\n" : "",
instr_suf); instr_suf);
s->cur_prompt->instr_reqd = TRUE; s->cur_prompt->instr_reqd = TRUE;
add_prompt(s->cur_prompt, prompt, FALSE, SSH_MAX_PASSWORD_LEN); add_prompt(s->cur_prompt, prompt, FALSE);
sfree(instr_suf); sfree(instr_suf);
} }
} }
@ -4032,7 +4027,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen,
s->cur_prompt->name = dupstr("SSH password"); s->cur_prompt->name = dupstr("SSH password");
add_prompt(s->cur_prompt, dupprintf("%s@%s's password: ", add_prompt(s->cur_prompt, dupprintf("%s@%s's password: ",
ssh->username, ssh->savedhost), ssh->username, ssh->savedhost),
FALSE, SSH_MAX_PASSWORD_LEN); FALSE);
} }
/* /*
@ -7675,8 +7670,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
s->cur_prompt = new_prompts(ssh->frontend); s->cur_prompt = new_prompts(ssh->frontend);
s->cur_prompt->to_server = TRUE; s->cur_prompt->to_server = TRUE;
s->cur_prompt->name = dupstr("SSH login name"); s->cur_prompt->name = dupstr("SSH login name");
/* 512 is an arbitrary limit :-( */ add_prompt(s->cur_prompt, dupstr("login as: "), TRUE);
add_prompt(s->cur_prompt, dupstr("login as: "), TRUE, 512);
ret = get_userpass_input(s->cur_prompt, NULL, 0); ret = get_userpass_input(s->cur_prompt, NULL, 0);
while (ret < 0) { while (ret < 0) {
ssh->send_ok = 1; ssh->send_ok = 1;
@ -8082,7 +8076,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
add_prompt(s->cur_prompt, add_prompt(s->cur_prompt,
dupprintf("Passphrase for key \"%.100s\": ", dupprintf("Passphrase for key \"%.100s\": ",
s->publickey_comment), s->publickey_comment),
FALSE, SSH_MAX_PASSWORD_LEN); FALSE);
ret = get_userpass_input(s->cur_prompt, NULL, 0); ret = get_userpass_input(s->cur_prompt, NULL, 0);
while (ret < 0) { while (ret < 0) {
ssh->send_ok = 1; ssh->send_ok = 1;
@ -8462,7 +8456,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
} }
add_prompt(s->cur_prompt, add_prompt(s->cur_prompt,
dupprintf("%.*s", prompt_len, prompt), dupprintf("%.*s", prompt_len, prompt),
echo, SSH_MAX_PASSWORD_LEN); echo);
} }
if (name_len) { if (name_len) {
@ -8559,7 +8553,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
add_prompt(s->cur_prompt, dupprintf("%s@%s's password: ", add_prompt(s->cur_prompt, dupprintf("%s@%s's password: ",
ssh->username, ssh->username,
ssh->savedhost), ssh->savedhost),
FALSE, SSH_MAX_PASSWORD_LEN); FALSE);
ret = get_userpass_input(s->cur_prompt, NULL, 0); ret = get_userpass_input(s->cur_prompt, NULL, 0);
while (ret < 0) { while (ret < 0) {
@ -8661,11 +8655,11 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
*/ */
add_prompt(s->cur_prompt, add_prompt(s->cur_prompt,
dupstr("Current password (blank for previously entered password): "), dupstr("Current password (blank for previously entered password): "),
FALSE, SSH_MAX_PASSWORD_LEN); FALSE);
add_prompt(s->cur_prompt, dupstr("Enter new password: "), add_prompt(s->cur_prompt, dupstr("Enter new password: "),
FALSE, SSH_MAX_PASSWORD_LEN); FALSE);
add_prompt(s->cur_prompt, dupstr("Confirm new password: "), add_prompt(s->cur_prompt, dupstr("Confirm new password: "),
FALSE, SSH_MAX_PASSWORD_LEN); FALSE);
/* /*
* Loop until the user manages to enter the same * Loop until the user manages to enter the same

View File

@ -6604,7 +6604,7 @@ int term_get_userpass_input(Terminal *term, prompts_t *p,
{ {
int i; int i;
for (i = 0; i < (int)p->n_prompts; i++) for (i = 0; i < (int)p->n_prompts; i++)
memset(p->prompts[i]->result, 0, p->prompts[i]->result_len); prompt_set_result(p->prompts[i], "");
} }
} }
@ -6631,8 +6631,8 @@ int term_get_userpass_input(Terminal *term, prompts_t *p,
case 10: case 10:
case 13: case 13:
term_data(term, 0, "\r\n", 2); term_data(term, 0, "\r\n", 2);
prompt_ensure_result_size(pr, s->pos + 1);
pr->result[s->pos] = '\0'; pr->result[s->pos] = '\0';
pr->result[pr->result_len - 1] = '\0';
/* go to next prompt, if any */ /* go to next prompt, if any */
s->curr_prompt++; s->curr_prompt++;
s->done_prompt = 0; s->done_prompt = 0;
@ -6667,10 +6667,9 @@ int term_get_userpass_input(Terminal *term, prompts_t *p,
* when we're doing password input, because some people * when we're doing password input, because some people
* have control characters in their passwords. * have control characters in their passwords.
*/ */
if ((!pr->echo || if (!pr->echo || (c >= ' ' && c <= '~') ||
(c >= ' ' && c <= '~') || ((unsigned char) c >= 160)) {
((unsigned char) c >= 160)) prompt_ensure_result_size(pr, s->pos + 1);
&& s->pos < pr->result_len - 1) {
pr->result[s->pos++] = c; pr->result[s->pos++] = c;
if (pr->echo) if (pr->echo)
term_data(term, 0, &c, 1); term_data(term, 0, &c, 1);

View File

@ -374,7 +374,7 @@ int console_get_userpass_input(prompts_t *p, unsigned char *in, int inlen)
{ {
int i; int i;
for (i = 0; i < p->n_prompts; i++) for (i = 0; i < p->n_prompts; i++)
memset(p->prompts[i]->result, 0, p->prompts[i]->result_len); prompt_set_result(p->prompts[i], "");
} }
if (p->n_prompts && console_batch_mode) if (p->n_prompts && console_batch_mode)
@ -403,7 +403,7 @@ int console_get_userpass_input(prompts_t *p, unsigned char *in, int inlen)
for (curr_prompt = 0; curr_prompt < p->n_prompts; curr_prompt++) { for (curr_prompt = 0; curr_prompt < p->n_prompts; curr_prompt++) {
struct termios oldmode, newmode; struct termios oldmode, newmode;
int i; int len;
prompt_t *pr = p->prompts[curr_prompt]; prompt_t *pr = p->prompts[curr_prompt];
tcgetattr(infd, &oldmode); tcgetattr(infd, &oldmode);
@ -417,17 +417,34 @@ int console_get_userpass_input(prompts_t *p, unsigned char *in, int inlen)
console_prompt_text(outfp, pr->prompt, strlen(pr->prompt)); console_prompt_text(outfp, pr->prompt, strlen(pr->prompt));
i = read(infd, pr->result, pr->result_len - 1); len = 0;
while (1) {
int ret;
prompt_ensure_result_size(pr, len * 5 / 4 + 512);
ret = read(infd, pr->result + len, pr->resultsize - len - 1);
if (ret <= 0) {
len = -1;
break;
}
len += ret;
if (pr->result[len - 1] == '\n') {
len--;
break;
}
}
tcsetattr(infd, TCSANOW, &oldmode); tcsetattr(infd, TCSANOW, &oldmode);
if (i > 0 && pr->result[i-1] == '\n')
i--;
pr->result[i] = '\0';
if (!pr->echo) if (!pr->echo)
console_prompt_text(outfp, "\n", 1); console_prompt_text(outfp, "\n", 1);
if (len < 0) {
console_close(outfp, infd);
return 0; /* failure due to read error */
}
pr->result[len] = '\0';
} }
console_close(outfp, infd); console_close(outfp, infd);

View File

@ -315,7 +315,7 @@ int console_get_userpass_input(prompts_t *p, unsigned char *in, int inlen)
{ {
int i; int i;
for (i = 0; i < (int)p->n_prompts; i++) for (i = 0; i < (int)p->n_prompts; i++)
memset(p->prompts[i]->result, 0, p->prompts[i]->result_len); prompt_set_result(p->prompts[i], "");
} }
/* /*
@ -365,9 +365,9 @@ int console_get_userpass_input(prompts_t *p, unsigned char *in, int inlen)
for (curr_prompt = 0; curr_prompt < p->n_prompts; curr_prompt++) { for (curr_prompt = 0; curr_prompt < p->n_prompts; curr_prompt++) {
DWORD savemode, newmode, i = 0; DWORD savemode, newmode;
int len;
prompt_t *pr = p->prompts[curr_prompt]; prompt_t *pr = p->prompts[curr_prompt];
BOOL r;
GetConsoleMode(hin, &savemode); GetConsoleMode(hin, &savemode);
newmode = savemode | ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT; newmode = savemode | ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT;
@ -379,25 +379,44 @@ int console_get_userpass_input(prompts_t *p, unsigned char *in, int inlen)
console_data_untrusted(hout, pr->prompt, strlen(pr->prompt)); console_data_untrusted(hout, pr->prompt, strlen(pr->prompt));
r = ReadFile(hin, pr->result, pr->result_len - 1, &i, NULL); len = 0;
while (1) {
DWORD ret = 0;
BOOL r;
prompt_ensure_result_size(pr, len * 5 / 4 + 512);
r = ReadFile(hin, pr->result + len, pr->resultsize - len - 1,
&ret, NULL);
if (!r || ret == 0) {
len = -1;
break;
}
len += ret;
if (pr->result[len - 1] == '\n') {
len--;
if (pr->result[len - 1] == '\r')
len--;
break;
}
}
SetConsoleMode(hin, savemode); SetConsoleMode(hin, savemode);
if ((int) i > pr->result_len)
i = pr->result_len - 1;
else
i = i - 2;
pr->result[i] = '\0';
if (!pr->echo) { if (!pr->echo) {
DWORD dummy; DWORD dummy;
WriteFile(hout, "\r\n", 2, &dummy, NULL); WriteFile(hout, "\r\n", 2, &dummy, NULL);
} }
if (len < 0) {
return 0; /* failure due to read error */
}
pr->result[len] = '\0';
} }
return 1; /* success */ return 1; /* success */
} }
void frontend_keypress(void *handle) void frontend_keypress(void *handle)