INCOMPATIBLE CHANGE to the SSH2 private key file format. There is
[u/mdw/putty] / pageant.c
index 0605b4b..0114804 100644 (file)
--- a/pageant.c
+++ b/pageant.c
@@ -65,7 +65,7 @@ int agent_exists(void);
  * pads its data with random bytes. Since we only use rsadecrypt()
  * and the signing functions, which are deterministic, this should
  * never be called.
- * 
+ *
  * If it _is_ called, there is a _serious_ problem, because it
  * won't generate true random numbers. So we must scream, panic,
  * and exit immediately if that should happen.
@@ -74,6 +74,8 @@ int random_byte(void)
 {
     MessageBox(hwnd, "Internal Error", APPNAME, MB_OK | MB_ICONERROR);
     exit(0);
+    /* this line can't be reached but it placates MSVC's warnings :-) */
+    return 0;
 }
 
 /*
@@ -168,6 +170,8 @@ static int CALLBACK AboutProc(HWND hwnd, UINT msg,
     return 0;
 }
 
+static HWND passphrase_box;
+
 /*
  * Dialog-box function for the passphrase box.
  */
@@ -179,6 +183,7 @@ static int CALLBACK PassphraseProc(HWND hwnd, UINT msg,
 
     switch (msg) {
       case WM_INITDIALOG:
+       passphrase_box = hwnd;
        /*
         * Centre the window.
         */
@@ -232,6 +237,26 @@ static int CALLBACK PassphraseProc(HWND hwnd, UINT msg,
 }
 
 /*
+ * Warn about the obsolescent key file format.
+ */
+void old_keyfile_warning(void)
+{
+    static const char mbtitle[] = "PuTTY Key File Warning";
+    static const char message[] =
+       "You are loading an SSH 2 private key which has an\n"
+       "old version of the file format. This means your key\n"
+       "file is not fully tamperproof. Future versions of\n"
+       "PuTTY may stop supporting this private key format,\n"
+       "so we recommend you convert your key to the new\n"
+       "format.\n"
+       "\n"
+       "You can perform this conversion by loading the key\n"
+       "into PuTTYgen and then saving it again.";
+
+    MessageBox(NULL, message, mbtitle, MB_OK);
+}
+
+/*
  * Update the visible key list.
  */
 static void keylist_update(void)
@@ -294,8 +319,8 @@ static void keylist_update(void)
 static void add_keyfile(char *filename)
 {
     char passphrase[PASSPHRASE_MAXLEN];
-    struct RSAKey *rkey;
-    struct ssh2_userkey *skey;
+    struct RSAKey *rkey = NULL;
+    struct ssh2_userkey *skey = NULL;
     int needs_pass;
     int ret;
     int attempts;
@@ -324,6 +349,7 @@ static void add_keyfile(char *filename)
            int dlgret;
            dlgret = DialogBoxParam(instance, MAKEINTRESOURCE(210),
                                    NULL, PassphraseProc, (LPARAM) & pps);
+           passphrase_box = NULL;
            if (!dlgret) {
                if (comment)
                    sfree(comment);
@@ -358,6 +384,7 @@ static void add_keyfile(char *filename)
     if (ver == 1) {
        if (already_running) {
            unsigned char *request, *response;
+           void *vresponse;
            int reqlen, clen, resplen;
 
            clen = strlen(rkey->comment);
@@ -391,7 +418,8 @@ static void add_keyfile(char *filename)
            reqlen += 4 + clen;
            PUT_32BIT(request, reqlen - 4);
 
-           agent_query(request, reqlen, &response, &resplen);
+           agent_query(request, reqlen, &vresponse, &resplen);
+           response = vresponse;
            if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS)
                MessageBox(NULL, "The already running Pageant "
                           "refused to add the key.", APPNAME,
@@ -403,6 +431,7 @@ static void add_keyfile(char *filename)
     } else {
        if (already_running) {
            unsigned char *request, *response;
+           void *vresponse;
            int reqlen, alglen, clen, keybloblen, resplen;
            alglen = strlen(skey->alg->name);
            clen = strlen(skey->comment);
@@ -431,7 +460,8 @@ static void add_keyfile(char *filename)
            PUT_32BIT(request, reqlen - 4);
            reqlen += clen + 4;
 
-           agent_query(request, reqlen, &response, &resplen);
+           agent_query(request, reqlen, &vresponse, &resplen);
+           response = vresponse;
            if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS)
                MessageBox(NULL, "The already running Pageant"
                           "refused to add the key.", APPNAME,
@@ -603,7 +633,7 @@ static void answer_msg(void *msg)
        break;
       case SSH2_AGENTC_SIGN_REQUEST:
        /*
-        * Reply with either SSH2_AGENT_RSA_RESPONSE or
+        * Reply with either SSH2_AGENT_SIGN_RESPONSE or
         * SSH_AGENT_FAILURE, depending on whether we have that key
         * or not.
         */
@@ -640,16 +670,19 @@ static void answer_msg(void *msg)
        {
            struct RSAKey *key;
            char *comment;
+            int commentlen;
            key = smalloc(sizeof(struct RSAKey));
-           memset(key, 0, sizeof(key));
+           memset(key, 0, sizeof(struct RSAKey));
            p += makekey(p, key, NULL, 1);
            p += makeprivate(p, key);
-           p += ssh1_read_bignum(p, key->iqmp);        /* p^-1 mod q */
-           p += ssh1_read_bignum(p, key->p);   /* p */
-           p += ssh1_read_bignum(p, key->q);   /* q */
-           comment = smalloc(GET_32BIT(p));
+           p += ssh1_read_bignum(p, &key->iqmp);       /* p^-1 mod q */
+           p += ssh1_read_bignum(p, &key->p);  /* p */
+           p += ssh1_read_bignum(p, &key->q);  /* q */
+            commentlen = GET_32BIT(p);
+           comment = smalloc(commentlen+1);
            if (comment) {
-               memcpy(comment, p + 4, GET_32BIT(p));
+               memcpy(comment, p + 4, commentlen);
+                comment[commentlen] = '\0';
                key->comment = comment;
            }
            PUT_32BIT(ret, 1);
@@ -683,6 +716,8 @@ static void answer_msg(void *msg)
            /* Add further algorithm names here. */
            if (alglen == 7 && !memcmp(alg, "ssh-rsa", 7))
                key->alg = &ssh_rsa;
+           else if (alglen == 7 && !memcmp(alg, "ssh-dss", 7))
+               key->alg = &ssh_dss;
            else {
                sfree(key);
                goto failure;
@@ -938,11 +973,6 @@ static int cmpkeys_ssh2_asymm(void *av, void *bv)
     return c;
 }
 
-static void error(char *s)
-{
-    MessageBox(hwnd, s, APPNAME, MB_OK | MB_ICONERROR);
-}
-
 /*
  * Prompt for a key file to add, and add it.
  */
@@ -1018,6 +1048,11 @@ static int CALLBACK KeyListProc(HWND hwnd, UINT msg,
          case 101:                    /* add key */
            if (HIWORD(wParam) == BN_CLICKED ||
                HIWORD(wParam) == BN_DOUBLECLICKED) {
+               if (passphrase_box) {
+                   MessageBeep(MB_ICONERROR);
+                   SetForegroundWindow(passphrase_box);
+                   break;
+               }
                prompt_add_keyfile();
            }
            return 0;
@@ -1060,13 +1095,54 @@ static int CALLBACK KeyListProc(HWND hwnd, UINT msg,
     return 0;
 }
 
+/* Set up a system tray icon */
+static BOOL AddTrayIcon(HWND hwnd)
+{
+    BOOL res;
+    NOTIFYICONDATA tnid;
+    HICON hicon;
+
+#ifdef NIM_SETVERSION
+    tnid.uVersion = 0;
+    res = Shell_NotifyIcon(NIM_SETVERSION, &tnid);
+#endif
+
+    tnid.cbSize = sizeof(NOTIFYICONDATA);
+    tnid.hWnd = hwnd;
+    tnid.uID = 1;             /* unique within this systray use */
+    tnid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
+    tnid.uCallbackMessage = WM_SYSTRAY;
+    tnid.hIcon = hicon = LoadIcon(instance, MAKEINTRESOURCE(201));
+    strcpy(tnid.szTip, "Pageant (PuTTY authentication agent)");
+
+    res = Shell_NotifyIcon(NIM_ADD, &tnid);
+
+    if (hicon) DestroyIcon(hicon);
+    
+    return res;
+}
+
 static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                                WPARAM wParam, LPARAM lParam)
 {
     int ret;
     static int menuinprogress;
+    static UINT msgTaskbarCreated = 0;
 
     switch (message) {
+      case WM_CREATE:
+        msgTaskbarCreated = RegisterWindowMessage(_T("TaskbarCreated"));
+        break;
+      default:
+        if (message==msgTaskbarCreated) {
+            /*
+            * Explorer has been restarted, so the tray icon will
+            * have been lost.
+            */
+           AddTrayIcon(hwnd);
+        }
+        break;
+        
       case WM_SYSTRAY:
        if (lParam == WM_RBUTTONUP) {
            POINT cursorpos;
@@ -1092,6 +1168,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
       case WM_SYSCOMMAND:
        switch (wParam & ~0xF) {       /* low 4 bits reserved to Windows */
          case IDM_CLOSE:
+           if (passphrase_box)
+               SendMessage(passphrase_box, WM_CLOSE, 0, 0);
            SendMessage(hwnd, WM_CLOSE, 0, 0);
            break;
          case IDM_VIEWKEYS:
@@ -1109,6 +1187,11 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
            }
            break;
          case IDM_ADDKEY:
+           if (passphrase_box) {
+               MessageBeep(MB_ICONERROR);
+               SetForegroundWindow(passphrase_box);
+               break;
+           }
            prompt_add_keyfile();
            break;
          case IDM_ABOUT:
@@ -1135,9 +1218,12 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
            COPYDATASTRUCT *cds;
            char *mapname;
            void *p;
-           HANDLE filemap, proc;
+           HANDLE filemap;
+#ifndef NO_SECURITY
+           HANDLE proc;
            PSID mapowner, procowner;
            PSECURITY_DESCRIPTOR psd1 = NULL, psd2 = NULL;
+#endif
            int ret = 0;
 
            cds = (COPYDATASTRUCT *) lParam;
@@ -1154,8 +1240,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
            debug(("filemap is %p\n", filemap));
 #endif
            if (filemap != NULL && filemap != INVALID_HANDLE_VALUE) {
-               int rc;
 #ifndef NO_SECURITY
+               int rc;
                if (has_security) {
                    if ((proc = OpenProcess(MAXIMUM_ALLOWED, FALSE,
                                            GetCurrentProcessId())) ==
@@ -1234,7 +1320,7 @@ void spawn_cmd(char *cmdline, int show)
                     NULL, NULL, show) <= (HINSTANCE) 32) {
        TCHAR sMsg[140];
        sprintf(sMsg, _T("Failed to run \"%.100s\", Error: %d"), cmdline,
-               GetLastError());
+               (int)GetLastError());
        MessageBox(NULL, sMsg, APPNAME, MB_OK | MB_ICONEXCLAMATION);
     }
 }
@@ -1317,37 +1403,15 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
                            100, 100, NULL, NULL, inst, NULL);
 
        /* Set up a system tray icon */
-       {
-           BOOL res;
-           NOTIFYICONDATA tnid;
-           HICON hicon;
+       AddTrayIcon(hwnd);
 
-#ifdef NIM_SETVERSION
-           tnid.uVersion = 0;
-           res = Shell_NotifyIcon(NIM_SETVERSION, &tnid);
-#endif
-
-           tnid.cbSize = sizeof(NOTIFYICONDATA);
-           tnid.hWnd = hwnd;
-           tnid.uID = 1;              /* unique within this systray use */
-           tnid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
-           tnid.uCallbackMessage = WM_SYSTRAY;
-           tnid.hIcon = hicon = LoadIcon(instance, MAKEINTRESOURCE(201));
-           strcpy(tnid.szTip, "Pageant (PuTTY authentication agent)");
-
-           res = Shell_NotifyIcon(NIM_ADD, &tnid);
-
-           if (hicon)
-               DestroyIcon(hicon);
-
-           systray_menu = CreatePopupMenu();
-           /* accelerators used: vkxa */
-           AppendMenu(systray_menu, MF_ENABLED, IDM_VIEWKEYS,
-                      "&View Keys");
-           AppendMenu(systray_menu, MF_ENABLED, IDM_ADDKEY, "Add &Key");
-           AppendMenu(systray_menu, MF_ENABLED, IDM_ABOUT, "&About");
-           AppendMenu(systray_menu, MF_ENABLED, IDM_CLOSE, "E&xit");
-       }
+        systray_menu = CreatePopupMenu();
+        /* accelerators used: vkxa */
+        AppendMenu(systray_menu, MF_ENABLED, IDM_VIEWKEYS,
+               "&View Keys");
+        AppendMenu(systray_menu, MF_ENABLED, IDM_ADDKEY, "Add &Key");
+        AppendMenu(systray_menu, MF_ENABLED, IDM_ABOUT, "&About");
+        AppendMenu(systray_menu, MF_ENABLED, IDM_CLOSE, "E&xit");
 
        ShowWindow(hwnd, SW_HIDE);
 
@@ -1367,7 +1431,6 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
     {
        char *p;
        int inquotes = 0;
-       int ignorearg = 0;
        p = cmdline;
        while (*p) {
            while (*p && isspace(*p))