X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=pageant.c;h=31a5540c45f9d36275d532de5fad93d6e6f36b50;hb=ca8876f0044c2eb7dbc5a61a432e799973e7e51c;hp=76e5911aab83e36a6f2d6d0b89e0c16a51b45400;hpb=2069de8c8f9b54fcdc9af71fefc55ada725ebc49;p=PuTTY.git diff --git a/pageant.c b/pageant.c index 76e5911a..31a5540c 100644 --- 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); @@ -528,7 +510,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 +674,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 +710,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 +804,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 +1100,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 +1117,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 +1178,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 +1196,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, 4); + 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 +1227,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, 4); + 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); @@ -1354,8 +1344,11 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase, *retstr = dupstr("Received broken key list from agent"); 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"); return PAGEANT_ACTION_FAILURE; } @@ -1369,8 +1362,11 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase, *retstr = dupstr("Received broken key list from agent"); 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"); return PAGEANT_ACTION_FAILURE; } @@ -1480,7 +1476,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,9 +1509,7 @@ 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 " @@ -1533,7 +1527,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,9 +1555,7 @@ 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 " @@ -1582,3 +1574,236 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase, } return PAGEANT_ACTION_OK; } + +int pageant_enum_keys(pageant_key_enum_fn_t callback, void *callback_ctx, + char **retstr) +{ + unsigned char *keylist, *p; + int i, nkeys, keylistlen; + char *comment; + struct pageant_pubkey cbkey; + + keylist = pageant_get_keylist1(&keylistlen); + if (keylistlen < 4) { + *retstr = dupstr("Received broken SSH-1 key list from agent"); + sfree(keylist); + return PAGEANT_ACTION_FAILURE; + } + nkeys = toint(GET_32BIT(keylist)); + if (nkeys < 0) { + *retstr = dupstr("Received broken SSH-1 key list from agent"); + sfree(keylist); + return PAGEANT_ACTION_FAILURE; + } + p = keylist + 4; + keylistlen -= 4; + + for (i = 0; i < nkeys; i++) { + struct RSAKey rkey; + char fingerprint[128]; + int n; + + /* public blob and fingerprint */ + memset(&rkey, 0, sizeof(rkey)); + n = makekey(p, keylistlen, &rkey, NULL, 0); + if (n < 0 || n > keylistlen) { + freersakey(&rkey); + *retstr = dupstr("Received broken SSH-1 key list from agent"); + sfree(keylist); + return PAGEANT_ACTION_FAILURE; + } + p += n, keylistlen -= n; + rsa_fingerprint(fingerprint, sizeof(fingerprint), &rkey); + + /* comment */ + if (keylistlen < 4) { + *retstr = dupstr("Received broken SSH-1 key list from agent"); + freersakey(&rkey); + sfree(keylist); + return PAGEANT_ACTION_FAILURE; + } + n = toint(GET_32BIT(p)); + p += 4, keylistlen -= 4; + if (n < 0 || keylistlen < n) { + *retstr = dupstr("Received broken SSH-1 key list from agent"); + freersakey(&rkey); + sfree(keylist); + return PAGEANT_ACTION_FAILURE; + } + comment = dupprintf("%.*s", (int)n, (const char *)p); + 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); + freersakey(&rkey); + sfree(comment); + } + + sfree(keylist); + + if (keylistlen != 0) { + *retstr = dupstr("Received broken SSH-1 key list from agent"); + return PAGEANT_ACTION_FAILURE; + } + + keylist = pageant_get_keylist2(&keylistlen); + if (keylistlen < 4) { + *retstr = dupstr("Received broken SSH-2 key list from agent"); + sfree(keylist); + return PAGEANT_ACTION_FAILURE; + } + nkeys = toint(GET_32BIT(keylist)); + if (nkeys < 0) { + *retstr = dupstr("Received broken SSH-2 key list from agent"); + sfree(keylist); + return PAGEANT_ACTION_FAILURE; + } + p = keylist + 4; + keylistlen -= 4; + + for (i = 0; i < nkeys; i++) { + char *fingerprint; + int n; + + /* public blob */ + if (keylistlen < 4) { + *retstr = dupstr("Received broken SSH-2 key list from agent"); + sfree(keylist); + return PAGEANT_ACTION_FAILURE; + } + n = toint(GET_32BIT(p)); + p += 4, keylistlen -= 4; + if (n < 0 || keylistlen < n) { + *retstr = dupstr("Received broken SSH-2 key list from agent"); + sfree(keylist); + return PAGEANT_ACTION_FAILURE; + } + fingerprint = ssh2_fingerprint_blob(p, n); + cbkey.blob = p; + cbkey.bloblen = n; + p += n, keylistlen -= n; + + /* comment */ + if (keylistlen < 4) { + *retstr = dupstr("Received broken SSH-2 key list from agent"); + sfree(fingerprint); + sfree(keylist); + return PAGEANT_ACTION_FAILURE; + } + n = toint(GET_32BIT(p)); + p += 4, keylistlen -= 4; + if (n < 0 || keylistlen < n) { + *retstr = dupstr("Received broken SSH-2 key list from agent"); + sfree(fingerprint); + sfree(keylist); + return PAGEANT_ACTION_FAILURE; + } + comment = dupprintf("%.*s", (int)n, (const char *)p); + p += n, keylistlen -= n; + + cbkey.ssh_version = 2; + cbkey.comment = comment; + callback(callback_ctx, fingerprint, comment, &cbkey); + sfree(fingerprint); + sfree(comment); + } + + sfree(keylist); + + if (keylistlen != 0) { + *retstr = dupstr("Received broken SSH-1 key list from agent"); + return PAGEANT_ACTION_FAILURE; + } + + return PAGEANT_ACTION_OK; +} + +int pageant_delete_key(struct pageant_pubkey *key, char **retstr) +{ + unsigned char *request, *response; + int reqlen, resplen, ret; + void *vresponse; + + if (key->ssh_version == 1) { + reqlen = 5 + key->bloblen; + request = snewn(reqlen, unsigned char); + PUT_32BIT(request, reqlen - 4); + request[4] = SSH1_AGENTC_REMOVE_RSA_IDENTITY; + memcpy(request + 5, key->blob, key->bloblen); + } else { + reqlen = 9 + key->bloblen; + request = snewn(reqlen, unsigned char); + PUT_32BIT(request, reqlen - 4); + request[4] = SSH2_AGENTC_REMOVE_IDENTITY; + PUT_32BIT(request + 5, key->bloblen); + memcpy(request + 9, key->blob, key->bloblen); + } + + agent_query_synchronous(request, reqlen, &vresponse, &resplen); + response = vresponse; + if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) { + *retstr = dupstr("Agent failed to delete key"); + ret = PAGEANT_ACTION_FAILURE; + } else { + *retstr = NULL; + ret = PAGEANT_ACTION_OK; + } + sfree(request); + sfree(response); + 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); +}