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:
parent
62cbc7dc0b
commit
da66c0656a
6
cmdgen.c
6
cmdgen.c
@ -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) {
|
||||
|
@ -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
34
misc.c
@ -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
19
putty.h
@ -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);
|
||||
|
||||
|
3
rlogin.c
3
rlogin.c
@ -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
30
ssh.c
@ -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
|
||||
|
11
terminal.c
11
terminal.c
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user