]> asedeno.scripts.mit.edu Git - PuTTY.git/blobdiff - pageant.c
first pass
[PuTTY.git] / pageant.c
index 754af9c6aca103c2b649446f72a92cb1da706aee..2d9a740236739923800f4d2cfc79a540302c5fdb 100644 (file)
--- a/pageant.c
+++ b/pageant.c
@@ -259,25 +259,6 @@ void *pageant_make_keylist2(int *length)
     return ret;
 }
 
-char *fingerprint_ssh2_blob(const void *blob, int bloblen)
-{
-    unsigned char digest[16];
-    char fingerprint_str[16*3];
-    unsigned stringlen;
-    int i;
-
-    MD5Simple(blob, bloblen, digest);
-    for (i = 0; i < 16; i++)
-        sprintf(fingerprint_str + i*3, "%02x%s", digest[i], i==15 ? "" : ":");
-
-    stringlen = GET_32BIT((const unsigned char *)blob);
-    if (stringlen < bloblen-4)
-        return dupprintf("%.*s %s", (int)stringlen, (const char *)blob + 4,
-                         fingerprint_str);
-    else
-        return dupstr(fingerprint_str);        
-}
-
 static void plog(void *logctx, pageant_logfn_t logfn, const char *fmt, ...)
 #ifdef __GNUC__
 __attribute__ ((format (printf, 3, 4)))
@@ -381,7 +362,8 @@ void *pageant_handle_msg(const void *msg, int msglen, int *outlen,
                 int i;
                 struct ssh2_userkey *skey;
                 for (i = 0; NULL != (skey = pageant_nth_ssh2_key(i)); i++) {
-                    char *fingerprint = skey->alg->fingerprint(skey->data);
+                    char *fingerprint = ssh2_fingerprint(skey->alg,
+                                                         skey->data);
                     plog(logctx, logfn, "returned key: %s %s",
                          fingerprint, skey->comment);
                     sfree(fingerprint);
@@ -424,6 +406,7 @@ void *pageant_handle_msg(const void *msg, int msglen, int *outlen,
            if (i < 0) {
                 freebn(reqkey.exponent);
                 freebn(reqkey.modulus);
+               freebn(challenge);
                 fail_reason = "request truncated before challenge";
                goto failure;
             }
@@ -528,7 +511,7 @@ void *pageant_handle_msg(const void *msg, int msglen, int *outlen,
             }
            data = p;
             if (logfn) {
-                char *fingerprint = fingerprint_ssh2_blob(b.blob, b.len);
+                char *fingerprint = ssh2_fingerprint_blob(b.blob, b.len);
                 plog(logctx, logfn, "requested key: %s", fingerprint);
                 sfree(fingerprint);
             }
@@ -692,7 +675,7 @@ void *pageant_handle_msg(const void *msg, int msglen, int *outlen,
            }
 
            bloblen = msgend - p;
-           key->data = key->alg->openssh_createkey(&p, &bloblen);
+           key->data = key->alg->openssh_createkey(key->alg, &p, &bloblen);
            if (!key->data) {
                sfree(key);
                 fail_reason = "key setup failed";
@@ -728,7 +711,7 @@ void *pageant_handle_msg(const void *msg, int msglen, int *outlen,
            key->comment = comment;
 
             if (logfn) {
-                char *fingerprint = key->alg->fingerprint(key->data);
+                char *fingerprint = ssh2_fingerprint(key->alg, key->data);
                 plog(logctx, logfn, "submitted key: %s %s",
                      fingerprint, key->comment);
                 sfree(fingerprint);
@@ -822,7 +805,7 @@ void *pageant_handle_msg(const void *msg, int msglen, int *outlen,
            p += b.len;
 
             if (logfn) {
-                char *fingerprint = fingerprint_ssh2_blob(b.blob, b.len);
+                char *fingerprint = ssh2_fingerprint_blob(b.blob, b.len);
                 plog(logctx, logfn, "unwanted key: %s", fingerprint);
                 sfree(fingerprint);
             }
@@ -1118,6 +1101,7 @@ static int pageant_listen_accepting(Plug plug,
     struct pageant_listen_state *pl = (struct pageant_listen_state *)plug;
     struct pageant_conn_state *pc;
     const char *err;
+    char *peerinfo;
 
     pc = snew(struct pageant_conn_state);
     pc->fn = &connection_fn_table;
@@ -1134,8 +1118,13 @@ static int pageant_listen_accepting(Plug plug,
 
     sk_set_frozen(pc->connsock, 0);
 
-    /* FIXME: can we get any useful peer id info? */
-    plog(pl->logctx, pl->logfn, "%p: new connection", pc);
+    peerinfo = sk_peer_info(pc->connsock);
+    if (peerinfo) {
+        plog(pl->logctx, pl->logfn, "%p: new connection from %s",
+             pc, peerinfo);
+    } else {
+        plog(pl->logctx, pl->logfn, "%p: new connection", pc);
+    }
 
     return 0;
 }
@@ -1190,6 +1179,9 @@ static tree234 *passphrases = NULL;
  */
 void pageant_forget_passphrases(void)
 {
+    if (!passphrases)                  /* in case we never set it up at all */
+        return;
+
     while (count234(passphrases) > 0) {
        char *pp = index234(passphrases, 0);
        smemclr(pp, strlen(pp));
@@ -1205,12 +1197,12 @@ void *pageant_get_keylist1(int *length)
     if (!pageant_local) {
        unsigned char request[5], *response;
        void *vresponse;
-       int resplen, retval;
+       int resplen;
+
        request[4] = SSH1_AGENTC_REQUEST_RSA_IDENTITIES;
        PUT_32BIT(request, 1);
 
-       retval = agent_query(request, 5, &vresponse, &resplen, NULL, NULL);
-       assert(retval == 1);
+        agent_query_synchronous(request, 5, &vresponse, &resplen);
        response = vresponse;
        if (resplen < 5 || response[4] != SSH1_AGENT_RSA_IDENTITIES_ANSWER) {
             sfree(response);
@@ -1236,13 +1228,12 @@ void *pageant_get_keylist2(int *length)
     if (!pageant_local) {
        unsigned char request[5], *response;
        void *vresponse;
-       int resplen, retval;
+       int resplen;
 
        request[4] = SSH2_AGENTC_REQUEST_IDENTITIES;
        PUT_32BIT(request, 1);
 
-       retval = agent_query(request, 5, &vresponse, &resplen, NULL, NULL);
-       assert(retval == 1);
+       agent_query_synchronous(request, 5, &vresponse, &resplen);
        response = vresponse;
        if (resplen < 5 || response[4] != SSH2_AGENT_IDENTITIES_ANSWER) {
             sfree(response);
@@ -1322,11 +1313,15 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
        if (keylist) {
            if (keylistlen < 4) {
                *retstr = dupstr("Received broken key list from agent");
+                sfree(keylist);
+                sfree(blob);
                return PAGEANT_ACTION_FAILURE;
            }
            nkeys = toint(GET_32BIT(keylist));
            if (nkeys < 0) {
                *retstr = dupstr("Received broken key list from agent");
+                sfree(keylist);
+                sfree(blob);
                return PAGEANT_ACTION_FAILURE;
            }
            p = keylist + 4;
@@ -1344,6 +1339,8 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
                    int n = rsa_public_blob_len(p, keylistlen);
                    if (n < 0) {
                         *retstr = dupstr("Received broken key list from agent");
+                        sfree(keylist);
+                        sfree(blob);
                         return PAGEANT_ACTION_FAILURE;
                    }
                    p += n;
@@ -1352,11 +1349,18 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
                    int n;
                    if (keylistlen < 4) {
                         *retstr = dupstr("Received broken key list from agent");
+                        sfree(keylist);
+                        sfree(blob);
                         return PAGEANT_ACTION_FAILURE;
                    }
-                   n = toint(4 + GET_32BIT(p));
-                   if (n < 0 || keylistlen < n) {
+                   n = GET_32BIT(p);
+                    p += 4;
+                    keylistlen -= 4;
+
+                   if (n < 0 || n > keylistlen) {
                         *retstr = dupstr("Received broken key list from agent");
+                        sfree(keylist);
+                        sfree(blob);
                         return PAGEANT_ACTION_FAILURE;
                    }
                    p += n;
@@ -1367,11 +1371,18 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
                    int n;
                    if (keylistlen < 4) {
                         *retstr = dupstr("Received broken key list from agent");
+                        sfree(keylist);
+                        sfree(blob);
                         return PAGEANT_ACTION_FAILURE;
                    }
-                   n = toint(4 + GET_32BIT(p));
-                   if (n < 0 || keylistlen < n) {
+                   n = GET_32BIT(p);
+                    p += 4;
+                    keylistlen -= 4;
+
+                   if (n < 0 || n > keylistlen) {
                         *retstr = dupstr("Received broken key list from agent");
+                        sfree(keylist);
+                        sfree(blob);
                         return PAGEANT_ACTION_FAILURE;
                    }
                    p += n;
@@ -1418,6 +1429,7 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
                  * Run out of passphrases to try.
                  */
                 *retstr = comment;
+                sfree(rkey);
                 return PAGEANT_ACTION_NEED_PP;
             }
        } else
@@ -1441,6 +1453,7 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
              * a bad passphrase.
              */
             *retstr = dupstr(error);
+            sfree(rkey);
             return PAGEANT_ACTION_FAILURE;
         } else if (ret == 1) {
             /*
@@ -1480,7 +1493,7 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
        if (!pageant_local) {
            unsigned char *request, *response;
            void *vresponse;
-           int reqlen, clen, resplen, ret;
+           int reqlen, clen, resplen;
 
            clen = strlen(rkey->comment);
 
@@ -1513,19 +1526,24 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
            reqlen += 4 + clen;
            PUT_32BIT(request, reqlen - 4);
 
-           ret = agent_query(request, reqlen, &vresponse, &resplen,
-                             NULL, NULL);
-           assert(ret == 1);
+           agent_query_synchronous(request, reqlen, &vresponse, &resplen);
            response = vresponse;
            if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) {
                *retstr = dupstr("The already running Pageant "
                                  "refused to add the key.");
+                freersakey(rkey);
+                sfree(rkey);
+                sfree(request);
+                sfree(response);
                 return PAGEANT_ACTION_FAILURE;
             }
+            freersakey(rkey);
+            sfree(rkey);
            sfree(request);
            sfree(response);
        } else {
            if (!pageant_add_ssh1_key(rkey)) {
+                freersakey(rkey);
                sfree(rkey);           /* already present, don't waste RAM */
             }
        }
@@ -1533,7 +1551,7 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
        if (!pageant_local) {
            unsigned char *request, *response;
            void *vresponse;
-           int reqlen, alglen, clen, keybloblen, resplen, ret;
+           int reqlen, alglen, clen, keybloblen, resplen;
            alglen = strlen(skey->alg->name);
            clen = strlen(skey->comment);
 
@@ -1561,13 +1579,13 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
            reqlen += clen + 4;
            PUT_32BIT(request, reqlen - 4);
 
-           ret = agent_query(request, reqlen, &vresponse, &resplen,
-                             NULL, NULL);
-           assert(ret == 1);
+           agent_query_synchronous(request, reqlen, &vresponse, &resplen);
            response = vresponse;
            if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) {
                *retstr = dupstr("The already running Pageant "
                                  "refused to add the key.");
+                sfree(request);
+                sfree(response);
                 return PAGEANT_ACTION_FAILURE;
             }
 
@@ -1642,6 +1660,7 @@ int pageant_enum_keys(pageant_key_enum_fn_t callback, void *callback_ctx,
         p += n, keylistlen -= n;
 
         cbkey.blob = rsa_public_blob(&rkey, &cbkey.bloblen);
+        cbkey.comment = comment;
         cbkey.ssh_version = 1;
         callback(callback_ctx, fingerprint, comment, &cbkey);
         sfree(cbkey.blob);
@@ -1688,7 +1707,7 @@ int pageant_enum_keys(pageant_key_enum_fn_t callback, void *callback_ctx,
             sfree(keylist);
             return PAGEANT_ACTION_FAILURE;
         }
-        fingerprint = fingerprint_ssh2_blob(p, n);
+        fingerprint = ssh2_fingerprint_blob(p, n);
         cbkey.blob = p;
         cbkey.bloblen = n;
         p += n, keylistlen -= n;
@@ -1712,6 +1731,7 @@ int pageant_enum_keys(pageant_key_enum_fn_t callback, void *callback_ctx,
         p += n, keylistlen -= n;
 
         cbkey.ssh_version = 2;
+        cbkey.comment = comment;
         callback(callback_ctx, fingerprint, comment, &cbkey);
         sfree(fingerprint);
         sfree(comment);
@@ -1748,8 +1768,7 @@ int pageant_delete_key(struct pageant_pubkey *key, char **retstr)
         memcpy(request + 9, key->blob, key->bloblen);
     }
 
-    ret = agent_query(request, reqlen, &vresponse, &resplen, NULL, NULL);
-    assert(ret == 1);
+    agent_query_synchronous(request, reqlen, &vresponse, &resplen);
     response = vresponse;
     if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) {
         *retstr = dupstr("Agent failed to delete key");
@@ -1763,18 +1782,54 @@ int pageant_delete_key(struct pageant_pubkey *key, char **retstr)
     return ret;
 }
 
+int pageant_delete_all_keys(char **retstr)
+{
+    unsigned char request[5], *response;
+    int reqlen, resplen, success;
+    void *vresponse;
+
+    PUT_32BIT(request, 1);
+    request[4] = SSH2_AGENTC_REMOVE_ALL_IDENTITIES;
+    reqlen = 5;
+    agent_query_synchronous(request, reqlen, &vresponse, &resplen);
+    response = vresponse;
+    success = (resplen >= 4 && response[4] == SSH_AGENT_SUCCESS);
+    sfree(response);
+    if (!success) {
+        *retstr = dupstr("Agent failed to delete SSH-2 keys");
+        return PAGEANT_ACTION_FAILURE;
+    }
+
+    PUT_32BIT(request, 1);
+    request[4] = SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES;
+    reqlen = 5;
+    agent_query_synchronous(request, reqlen, &vresponse, &resplen);
+    response = vresponse;
+    success = (resplen >= 4 && response[4] == SSH_AGENT_SUCCESS);
+    sfree(response);
+    if (!success) {
+        *retstr = dupstr("Agent failed to delete SSH-1 keys");
+        return PAGEANT_ACTION_FAILURE;
+    }
+
+    *retstr = NULL;
+    return PAGEANT_ACTION_OK;
+}
+
 struct pageant_pubkey *pageant_pubkey_copy(struct pageant_pubkey *key)
 {
     struct pageant_pubkey *ret = snew(struct pageant_pubkey);
     ret->blob = snewn(key->bloblen, unsigned char);
     memcpy(ret->blob, key->blob, key->bloblen);
     ret->bloblen = key->bloblen;
+    ret->comment = key->comment ? dupstr(key->comment) : NULL;
     ret->ssh_version = key->ssh_version;
     return ret;
 }
 
 void pageant_pubkey_free(struct pageant_pubkey *key)
 {
+    sfree(key->comment);
     sfree(key->blob);
     sfree(key);
 }