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) {
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) {
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;
-
}
/*
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);
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 {
/*
* 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);
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);
#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[] = {
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;
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;
(*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);
}
}
(*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);
}
}
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);
}
/*
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;
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;
}
add_prompt(s->cur_prompt,
dupprintf("%.*s", prompt_len, prompt),
- echo, SSH_MAX_PASSWORD_LEN);
+ echo);
}
if (name_len) {
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) {
*/
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
{
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], "");
}
}
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;
* 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);
{
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)
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);
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);
{
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], "");
}
/*
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;
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)