While I'm crusading against arbitrary limits, here's a redesign of
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Sun, 2 Oct 2011 11:50:45 +0000 (11:50 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Sun, 2 Oct 2011 11:50:45 +0000 (11:50 +0000)
prompt_t to arrange that the buffer in which each prompt is stored can
be reallocated larger during the input process.

git-svn-id: svn://svn.tartarus.org/sgt/putty@9317 cda61777-01e9-0310-a592-d414129be87e

cmdgen.c
cmdline.c
misc.c
putty.h
rlogin.c
ssh.c
terminal.c
unix/uxcons.c
windows/wincons.c

index 9cd5b52..3abc245 100644 (file)
--- a/cmdgen.c
+++ b/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) {
index 9c87350..2c3b7ce 100644 (file)
--- a/cmdline.c
+++ b/cmdline.c
@@ -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;
-
 }
 
 /*
diff --git a/misc.c b/misc.c
index cf97c04..8a9c7b1 100644 (file)
--- a/misc.c
+++ b/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);
diff --git a/putty.h b/putty.h
index e4d3e77..4c338b4 100644 (file)
--- a/putty.h
+++ b/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);
 
index a79576e..aa6b1d7 100644 (file)
--- a/rlogin.c
+++ b/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);
diff --git a/ssh.c b/ssh.c
index b17a57d..aabbcc4 100644 (file)
--- a/ssh.c
+++ b/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
index 08ce42e..abb06e2 100644 (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);
index 9ceed0d..ce1a492 100644 (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);
index da5bac5..9824a5a 100644 (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)