Rework keylist_update() to fix both a buffer-size limitation and a
[u/mdw/putty] / windows / winpgnt.c
index 9d59327..e220d6b 100644 (file)
@@ -159,10 +159,8 @@ struct blob {
 };
 static int cmpkeys_ssh2_asymm(void *av, void *bv);
 
-#define PASSPHRASE_MAXLEN 512
-
 struct PassphraseProcStruct {
-    char *passphrase;
+    char **passphrase;
     char *comment;
 };
 
@@ -176,7 +174,7 @@ static void forget_passphrases(void)
 {
     while (count234(passphrases) > 0) {
        char *pp = index234(passphrases, 0);
-       memset(pp, 0, strlen(pp));
+       smemclr(pp, strlen(pp));
        delpos234(passphrases, 0);
        free(pp);
     }
@@ -247,7 +245,7 @@ static HWND passphrase_box;
 static int CALLBACK PassphraseProc(HWND hwnd, UINT msg,
                                   WPARAM wParam, LPARAM lParam)
 {
-    static char *passphrase = NULL;
+    static char **passphrase = NULL;
     struct PassphraseProcStruct *p;
 
     switch (msg) {
@@ -275,8 +273,9 @@ static int CALLBACK PassphraseProc(HWND hwnd, UINT msg,
        passphrase = p->passphrase;
        if (p->comment)
            SetDlgItemText(hwnd, 101, p->comment);
-       *passphrase = 0;
-       SetDlgItemText(hwnd, 102, passphrase);
+        burnstr(*passphrase);
+        *passphrase = dupstr("");
+       SetDlgItemText(hwnd, 102, *passphrase);
        return 0;
       case WM_COMMAND:
        switch (LOWORD(wParam)) {
@@ -291,9 +290,8 @@ static int CALLBACK PassphraseProc(HWND hwnd, UINT msg,
            return 0;
          case 102:                    /* edit box */
            if ((HIWORD(wParam) == EN_CHANGE) && passphrase) {
-               GetDlgItemText(hwnd, 102, passphrase,
-                              PASSPHRASE_MAXLEN - 1);
-               passphrase[PASSPHRASE_MAXLEN - 1] = '\0';
+                burnstr(*passphrase);
+                *passphrase = GetDlgItemText_alloc(hwnd, 102);
            }
            return 0;
        }
@@ -355,28 +353,27 @@ static void keylist_update(void)
                               0, (LPARAM) listentry);
        }
        for (i = 0; NULL != (skey = index234(ssh2keys, i)); i++) {
-           char listentry[512], *p;
-           int len;
+           char *listentry, *p;
+           int fp_len;
            /*
             * Replace two spaces in the fingerprint with tabs, for
             * nice alignment in the box.
             */
            p = skey->alg->fingerprint(skey->data);
-           strncpy(listentry, p, sizeof(listentry));
+            listentry = dupprintf("%s\t%s", p, skey->comment);
+            fp_len = strlen(listentry);
+            sfree(p);
+
            p = strchr(listentry, ' ');
-           if (p)
+           if (p && p < listentry + fp_len)
                *p = '\t';
            p = strchr(listentry, ' ');
-           if (p)
+           if (p && p < listentry + fp_len)
                *p = '\t';
-           len = strlen(listentry);
-           if (len < sizeof(listentry) - 2) {
-               listentry[len] = '\t';
-               strncpy(listentry + len + 1, skey->comment,
-                       sizeof(listentry) - len - 1);
-           }
+
            SendDlgItemMessage(keylist, 100, LB_ADDSTRING, 0,
                               (LPARAM) listentry);
+            sfree(listentry);
        }
        SendDlgItemMessage(keylist, 100, LB_SETCURSEL, (WPARAM) - 1, 0);
     }
@@ -387,7 +384,7 @@ static void keylist_update(void)
  */
 static void add_keyfile(Filename *filename)
 {
-    char passphrase[PASSPHRASE_MAXLEN];
+    char *passphrase;
     struct RSAKey *rkey = NULL;
     struct ssh2_userkey *skey = NULL;
     int needs_pass;
@@ -395,7 +392,6 @@ static void add_keyfile(Filename *filename)
     int attempts;
     char *comment;
     const char *error = NULL;
-    struct PassphraseProcStruct pps;
     int type;
     int original_pass;
        
@@ -453,7 +449,12 @@ static void add_keyfile(Filename *filename)
                           MB_OK | MB_ICONERROR);
                return;
            }
-           nkeys = GET_32BIT(keylist);
+           nkeys = toint(GET_32BIT(keylist));
+           if (nkeys < 0) {
+               MessageBox(NULL, "Received broken key list?!", APPNAME,
+                          MB_OK | MB_ICONERROR);
+               return;
+           }
            p = keylist + 4;
            keylistlen -= 4;
 
@@ -481,8 +482,8 @@ static void add_keyfile(Filename *filename)
                                   MB_OK | MB_ICONERROR);
                        return;
                    }
-                   n = 4 + GET_32BIT(p);
-                   if (keylistlen < n) {
+                   n = toint(4 + GET_32BIT(p));
+                   if (n < 0 || keylistlen < n) {
                        MessageBox(NULL, "Received broken key list?!", APPNAME,
                                   MB_OK | MB_ICONERROR);
                        return;
@@ -498,8 +499,8 @@ static void add_keyfile(Filename *filename)
                                   MB_OK | MB_ICONERROR);
                        return;
                    }
-                   n = 4 + GET_32BIT(p);
-                   if (keylistlen < n) {
+                   n = toint(4 + GET_32BIT(p));
+                   if (n < 0 || keylistlen < n) {
                        MessageBox(NULL, "Received broken key list?!", APPNAME,
                                   MB_OK | MB_ICONERROR);
                        return;
@@ -523,17 +524,24 @@ static void add_keyfile(Filename *filename)
     attempts = 0;
     if (type == SSH_KEYTYPE_SSH1)
        rkey = snew(struct RSAKey);
-    pps.passphrase = passphrase;
-    pps.comment = comment;
+    passphrase = NULL;
     original_pass = 0;
     do {
+        burnstr(passphrase);
+        passphrase = NULL;
+
        if (needs_pass) {
            /* try all the remembered passphrases first */
            char *pp = index234(passphrases, attempts);
            if(pp) {
-               strcpy(passphrase, pp);
+               passphrase = dupstr(pp);
            } else {
                int dlgret;
+                struct PassphraseProcStruct pps;
+
+                pps.passphrase = &passphrase;
+                pps.comment = comment;
+
                original_pass = 1;
                dlgret = DialogBoxParam(hinst, MAKEINTRESOURCE(210),
                                        NULL, PassphraseProc, (LPARAM) &pps);
@@ -545,9 +553,12 @@ static void add_keyfile(Filename *filename)
                        sfree(rkey);
                    return;                    /* operation cancelled */
                }
+
+                assert(passphrase != NULL);
            }
        } else
-           *passphrase = '\0';
+           passphrase = dupstr("");
+
        if (type == SSH_KEYTYPE_SSH1)
            ret = loadrsakey(filename, rkey, passphrase, &error);
        else {
@@ -562,11 +573,14 @@ static void add_keyfile(Filename *filename)
        attempts++;
     } while (ret == -1);
 
-    /* if they typed in an ok passphrase, remember it */
     if(original_pass && ret) {
-       char *pp = dupstr(passphrase);
-       addpos234(passphrases, pp, 0);
+        /* If they typed in an ok passphrase, remember it */
+       addpos234(passphrases, passphrase, 0);
+    } else {
+        /* Otherwise, destroy it */
+        burnstr(passphrase);
     }
+    passphrase = NULL;
 
     if (comment)
        sfree(comment);
@@ -958,7 +972,7 @@ static void answer_msg(void *msg)
            MD5Init(&md5c);
            MD5Update(&md5c, response_source, 48);
            MD5Final(response_md5, &md5c);
-           memset(response_source, 0, 48);     /* burn the evidence */
+           smemclr(response_source, 48);       /* burn the evidence */
            freebn(response);          /* and that evidence */
            freebn(challenge);         /* yes, and that evidence */
            freebn(reqkey.exponent);   /* and free some memory ... */
@@ -988,17 +1002,17 @@ static void answer_msg(void *msg)
 
            if (msgend < p+4)
                goto failure;
-           b.len = GET_32BIT(p);
+           b.len = toint(GET_32BIT(p));
+            if (b.len < 0 || b.len > msgend - (p+4))
+                goto failure;
            p += 4;
-           if (msgend < p+b.len)
-               goto failure;
            b.blob = p;
            p += b.len;
            if (msgend < p+4)
                goto failure;
-           datalen = GET_32BIT(p);
+           datalen = toint(GET_32BIT(p));
            p += 4;
-           if (msgend < p+datalen)
+           if (datalen < 0 || datalen > msgend - p)
                goto failure;
            data = p;
            key = find234(ssh2keys, &b, cmpkeys_ssh2_asymm);
@@ -1071,9 +1085,9 @@ static void answer_msg(void *msg)
                sfree(key);
                goto failure;
            }
-            commentlen = GET_32BIT(p);
+            commentlen = toint(GET_32BIT(p));
 
-           if (msgend < p+commentlen) {
+           if (commentlen < 0 || commentlen > msgend - p) {
                freersakey(key);
                sfree(key);
                goto failure;
@@ -1110,9 +1124,9 @@ static void answer_msg(void *msg)
 
            if (msgend < p+4)
                goto failure;
-           alglen = GET_32BIT(p);
+           alglen = toint(GET_32BIT(p));
            p += 4;
-           if (msgend < p+alglen)
+           if (alglen < 0 || alglen > msgend - p)
                goto failure;
            alg = p;
            p += alglen;
@@ -1146,10 +1160,10 @@ static void answer_msg(void *msg)
                sfree(key);
                goto failure;
            }
-           commlen = GET_32BIT(p);
+           commlen = toint(GET_32BIT(p));
            p += 4;
 
-           if (msgend < p+commlen) {
+           if (commlen < 0 || commlen > msgend - p) {
                key->alg->freekey(key->data);
                sfree(key);
                goto failure;
@@ -1213,10 +1227,10 @@ static void answer_msg(void *msg)
 
            if (msgend < p+4)
                goto failure;
-           b.len = GET_32BIT(p);
+           b.len = toint(GET_32BIT(p));
            p += 4;
 
-           if (msgend < p+b.len)
+           if (b.len < 0 || b.len > msgend - p)
                goto failure;
            b.blob = p;
            p += b.len;
@@ -1928,8 +1942,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                     }
 #endif
                    if (!EqualSid(mapowner, ourself) &&
-                        !EqualSid(mapowner, ourself2))
+                        !EqualSid(mapowner, ourself2)) {
+                        CloseHandle(filemap);
                        return 0;      /* security ID mismatch! */
+                    }
 #ifdef DEBUG_IPC
                    debug(("security stuff matched\n"));
 #endif