1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 09:27:59 +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;
p->to_server = FALSE;
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);
assert(ret >= 0);
if (!ret) {
@ -845,8 +845,8 @@ int main(int argc, char **argv)
p->to_server = FALSE;
p->name = dupstr("New SSH key passphrase");
add_prompt(p, dupstr("Enter passphrase to save key: "), FALSE, 512);
add_prompt(p, dupstr("Re-enter passphrase to verify: "), FALSE, 512);
add_prompt(p, dupstr("Enter passphrase to save key: "), FALSE);
add_prompt(p, dupstr("Re-enter passphrase to verify: "), FALSE);
ret = console_get_userpass_input(p, NULL, 0);
assert(ret >= 0);
if (!ret) {

View File

@ -105,15 +105,12 @@ int cmdline_get_passwd_input(prompts_t *p, unsigned char *in, int inlen) {
if (tried_once)
return 0;
strncpy(p->prompts[0]->result, cmdline_password,
p->prompts[0]->result_len);
p->prompts[0]->result[p->prompts[0]->result_len-1] = '\0';
prompt_set_result(p->prompts[0], cmdline_password);
memset(cmdline_password, 0, strlen(cmdline_password));
sfree(cmdline_password);
cmdline_password = NULL;
tried_once = 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;
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);
char *result = snewn(len, char);
pr->prompt = promptstr;
pr->echo = echo;
pr->result = result;
pr->result_len = len;
pr->result = NULL;
pr->resultsize = 0;
p->n_prompts++;
p->prompts = sresize(p->prompts, p->n_prompts, prompt_t *);
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)
{
size_t i;
for (i=0; i < p->n_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->prompt);
sfree(pr);

19
putty.h
View File

@ -525,8 +525,19 @@ struct RSAKey; /* be a little careful of scope */
typedef struct {
char *prompt;
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;
typedef struct {
/*
@ -549,7 +560,9 @@ typedef struct {
* get_userpass_input(); initially NULL */
} prompts_t;
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.) */
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->to_server = TRUE;
rlogin->prompt->name = dupstr("Rlogin login name");
/* 512 is an arbitrary limit :-( */
add_prompt(rlogin->prompt, dupstr("rlogin username: "), TRUE, 512);
add_prompt(rlogin->prompt, dupstr("rlogin username: "), TRUE);
ret = get_userpass_input(rlogin->prompt, NULL, 0);
if (ret >= 0) {
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_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_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->to_server = TRUE;
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, 512);
add_prompt(s->cur_prompt, dupstr("login as: "), TRUE);
ret = get_userpass_input(s->cur_prompt, NULL, 0);
while (ret < 0) {
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");
add_prompt(s->cur_prompt,
dupprintf("Passphrase for key \"%.100s\": ",
s->publickey_comment),
FALSE, SSH_MAX_PASSWORD_LEN);
s->publickey_comment), FALSE);
ret = get_userpass_input(s->cur_prompt, NULL, 0);
while (ret < 0) {
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);
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);
}
}
@ -4019,7 +4014,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen,
(*instr_suf) ? "\n" : "",
instr_suf);
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);
}
}
@ -4032,7 +4027,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen,
s->cur_prompt->name = dupstr("SSH password");
add_prompt(s->cur_prompt, dupprintf("%s@%s's password: ",
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->to_server = TRUE;
s->cur_prompt->name = dupstr("SSH login name");
/* 512 is an arbitrary limit :-( */
add_prompt(s->cur_prompt, dupstr("login as: "), TRUE, 512);
add_prompt(s->cur_prompt, dupstr("login as: "), TRUE);
ret = get_userpass_input(s->cur_prompt, NULL, 0);
while (ret < 0) {
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,
dupprintf("Passphrase for key \"%.100s\": ",
s->publickey_comment),
FALSE, SSH_MAX_PASSWORD_LEN);
FALSE);
ret = get_userpass_input(s->cur_prompt, NULL, 0);
while (ret < 0) {
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,
dupprintf("%.*s", prompt_len, prompt),
echo, SSH_MAX_PASSWORD_LEN);
echo);
}
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: ",
ssh->username,
ssh->savedhost),
FALSE, SSH_MAX_PASSWORD_LEN);
FALSE);
ret = get_userpass_input(s->cur_prompt, NULL, 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,
dupstr("Current password (blank for previously entered password): "),
FALSE, SSH_MAX_PASSWORD_LEN);
FALSE);
add_prompt(s->cur_prompt, dupstr("Enter new password: "),
FALSE, SSH_MAX_PASSWORD_LEN);
FALSE);
add_prompt(s->cur_prompt, dupstr("Confirm new password: "),
FALSE, SSH_MAX_PASSWORD_LEN);
FALSE);
/*
* 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;
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 13:
term_data(term, 0, "\r\n", 2);
prompt_ensure_result_size(pr, s->pos + 1);
pr->result[s->pos] = '\0';
pr->result[pr->result_len - 1] = '\0';
/* go to next prompt, if any */
s->curr_prompt++;
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
* have control characters in their passwords.
*/
if ((!pr->echo ||
(c >= ' ' && c <= '~') ||
((unsigned char) c >= 160))
&& s->pos < pr->result_len - 1) {
if (!pr->echo || (c >= ' ' && c <= '~') ||
((unsigned char) c >= 160)) {
prompt_ensure_result_size(pr, s->pos + 1);
pr->result[s->pos++] = c;
if (pr->echo)
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;
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)
@ -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++) {
struct termios oldmode, newmode;
int i;
int len;
prompt_t *pr = p->prompts[curr_prompt];
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));
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);
if (i > 0 && pr->result[i-1] == '\n')
i--;
pr->result[i] = '\0';
if (!pr->echo)
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);

View File

@ -315,7 +315,7 @@ int console_get_userpass_input(prompts_t *p, unsigned char *in, int inlen)
{
int 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++) {
DWORD savemode, newmode, i = 0;
DWORD savemode, newmode;
int len;
prompt_t *pr = p->prompts[curr_prompt];
BOOL r;
GetConsoleMode(hin, &savemode);
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));
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);
if ((int) i > pr->result_len)
i = pr->result_len - 1;
else
i = i - 2;
pr->result[i] = '\0';
if (!pr->echo) {
DWORD dummy;
WriteFile(hout, "\r\n", 2, &dummy, NULL);
}
if (len < 0) {
return 0; /* failure due to read error */
}
pr->result[len] = '\0';
}
return 1; /* success */
}
void frontend_keypress(void *handle)