X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=windows%2Fwinpgnt.c;h=fe0822e4889f4f10706cbe7b63cae9d53e783252;hb=e22120fea8d39e6a2ef6b2f4ab3ee5502f56169a;hp=e0181599d612e7cd40cbbecdda372b2dfa287f30;hpb=896bb7c74d06200d92f846d666224e3f9c80b634;p=PuTTY.git diff --git a/windows/winpgnt.c b/windows/winpgnt.c index e0181599..fe0822e4 100644 --- a/windows/winpgnt.c +++ b/windows/winpgnt.c @@ -14,6 +14,9 @@ #include "ssh.h" #include "misc.h" #include "tree234.h" +#include "winsecur.h" +#include "pageant.h" +#include "licence.h" #include @@ -33,11 +36,6 @@ #define AGENT_COPYDATA_ID 0x804e50ba /* random goop */ -/* - * FIXME: maybe some day we can sort this out ... - */ -#define AGENT_MAX_MSGLEN 8192 - /* From MSDN: In the WM_SYSCOMMAND message, the four low-order bits of * wParam are used by Windows, and should be masked off, so we shouldn't * attempt to store information in them. Hence all these identifiers have @@ -51,7 +49,7 @@ #define APPNAME "Pageant" -extern char ver[]; +extern const char ver[]; static HWND keylist; static HWND aboutbox; @@ -73,7 +71,7 @@ static int initial_menuitems_count; /* * Print a modal (Really Bad) message box and perform a fatal exit. */ -void modalfatalbox(char *fmt, ...) +void modalfatalbox(const char *fmt, ...) { va_list ap; char *buf; @@ -113,81 +111,22 @@ static void unmungestr(char *in, char *out, int outlen) return; } -static tree234 *rsakeys, *ssh2keys; - static int has_security; -#ifndef NO_SECURITY -DECL_WINDOWS_FUNCTION(extern, DWORD, GetSecurityInfo, - (HANDLE, SE_OBJECT_TYPE, SECURITY_INFORMATION, - PSID *, PSID *, PACL *, PACL *, - PSECURITY_DESCRIPTOR *)); -#endif - -/* - * Forward references - */ -static void *make_keylist1(int *length); -static void *make_keylist2(int *length); -static void *get_keylist1(int *length); -static void *get_keylist2(int *length); - -/* - * We need this to link with the RSA code, because rsaencrypt() - * 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. - */ -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; -} - -/* - * Blob structure for passing to the asymmetric SSH-2 key compare - * function, prototyped here. - */ -struct blob { - unsigned char *blob; - int len; -}; -static int cmpkeys_ssh2_asymm(void *av, void *bv); struct PassphraseProcStruct { char **passphrase; char *comment; }; -static tree234 *passphrases = NULL; - -/* - * After processing a list of filenames, we want to forget the - * passphrases. - */ -static void forget_passphrases(void) -{ - while (count234(passphrases) > 0) { - char *pp = index234(passphrases, 0); - smemclr(pp, strlen(pp)); - delpos234(passphrases, 0); - free(pp); - } -} - /* * Dialog-box function for the Licence box. */ -static int CALLBACK LicenceProc(HWND hwnd, UINT msg, +static INT_PTR CALLBACK LicenceProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_INITDIALOG: + SetDlgItemText(hwnd, 1000, LICENCE_TEXT("\r\n\r\n")); return 1; case WM_COMMAND: switch (LOWORD(wParam)) { @@ -207,12 +146,21 @@ static int CALLBACK LicenceProc(HWND hwnd, UINT msg, /* * Dialog-box function for the About box. */ -static int CALLBACK AboutProc(HWND hwnd, UINT msg, +static INT_PTR CALLBACK AboutProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_INITDIALOG: - SetDlgItemText(hwnd, 100, ver); + { + char *buildinfo_text = buildinfo("\r\n"); + char *text = dupprintf + ("Pageant\r\n\r\n%s\r\n\r\n%s\r\n\r\n%s", + ver, buildinfo_text, + "\251 " SHORT_COPYRIGHT_DETAILS ". All rights reserved."); + sfree(buildinfo_text); + SetDlgItemText(hwnd, 1000, text); + sfree(text); + } return 1; case WM_COMMAND: switch (LOWORD(wParam)) { @@ -242,7 +190,7 @@ static HWND passphrase_box; /* * Dialog-box function for the passphrase box. */ -static int CALLBACK PassphraseProc(HWND hwnd, UINT msg, +static INT_PTR CALLBACK PassphraseProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { static char **passphrase = NULL; @@ -326,7 +274,7 @@ void old_keyfile_warning(void) /* * Update the visible key list. */ -static void keylist_update(void) +void keylist_update(void) { struct RSAKey *rkey; struct ssh2_userkey *skey; @@ -334,7 +282,7 @@ static void keylist_update(void) if (keylist) { SendDlgItemMessage(keylist, 100, LB_RESETCONTENT, 0, 0); - for (i = 0; NULL != (rkey = index234(rsakeys, i)); i++) { + for (i = 0; NULL != (rkey = pageant_nth_ssh1_key(i)); i++) { char listentry[512], *p; /* * Replace two spaces in the fingerprint with tabs, for @@ -352,1069 +300,164 @@ static void keylist_update(void) SendDlgItemMessage(keylist, 100, LB_ADDSTRING, 0, (LPARAM) listentry); } - for (i = 0; NULL != (skey = index234(ssh2keys, i)); i++) { - char listentry[512], *p; - int 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)); - p = strchr(listentry, ' '); - if (p) - *p = '\t'; - p = strchr(listentry, ' '); - if (p) - *p = '\t'; - len = strlen(listentry); - if (len < sizeof(listentry) - 2) { - listentry[len] = '\t'; - strncpy(listentry + len + 1, skey->comment, - sizeof(listentry) - len - 1); - } + for (i = 0; NULL != (skey = pageant_nth_ssh2_key(i)); i++) { + char *listentry, *p; + int pos; + + /* + * For nice alignment in the list box, we would ideally + * want every entry to align to the tab stop settings, and + * have a column for algorithm name, one for bit count, + * one for hex fingerprint, and one for key comment. + * + * Unfortunately, some of the algorithm names are so long + * that they overflow into the bit-count field. + * Fortunately, at the moment, those are _precisely_ the + * algorithm names that don't need a bit count displayed + * anyway (because for NIST-style ECDSA the bit count is + * mentioned in the algorithm name, and for ssh-ed25519 + * there is only one possible value anyway). So we fudge + * this by simply omitting the bit count field in that + * situation. + * + * This is fragile not only in the face of further key + * types that don't follow this pattern, but also in the + * face of font metrics changes - the Windows semantics + * for list box tab stops is that \t aligns to the next + * one you haven't already exceeded, so I have to guess + * when the key type will overflow past the bit-count tab + * stop and leave out a tab character. Urgh. + */ + + p = ssh2_fingerprint(skey->alg, skey->data); + listentry = dupprintf("%s\t%s", p, skey->comment); + sfree(p); + + pos = 0; + while (1) { + pos += strcspn(listentry + pos, " :"); + if (listentry[pos] == ':' || !listentry[pos]) + break; + listentry[pos++] = '\t'; + } + if (skey->alg != &ssh_dss && skey->alg != &ssh_rsa) { + /* + * Remove the bit-count field, which is between the + * first and second \t. + */ + int outpos; + pos = 0; + while (listentry[pos] && listentry[pos] != '\t') + pos++; + outpos = pos; + pos++; + while (listentry[pos] && listentry[pos] != '\t') + pos++; + while (1) { + if ((listentry[outpos] = listentry[pos]) == '\0') + break; + outpos++; + pos++; + } + } + SendDlgItemMessage(keylist, 100, LB_ADDSTRING, 0, (LPARAM) listentry); + sfree(listentry); } SendDlgItemMessage(keylist, 100, LB_SETCURSEL, (WPARAM) - 1, 0); } } -/* - * This function loads a key from a file and adds it. - */ -static void add_keyfile(Filename *filename) +static void answer_msg(void *msgv) { - char *passphrase; - struct RSAKey *rkey = NULL; - struct ssh2_userkey *skey = NULL; - int needs_pass; - int ret; - int attempts; - char *comment; - const char *error = NULL; - int type; - int original_pass; - - type = key_type(filename); - if (type != SSH_KEYTYPE_SSH1 && type != SSH_KEYTYPE_SSH2) { - char *msg = dupprintf("Couldn't load this key (%s)", - key_type_to_str(type)); - message_box(msg, APPNAME, MB_OK | MB_ICONERROR, - HELPCTXID(errors_cantloadkey)); - sfree(msg); - return; - } - - /* - * See if the key is already loaded (in the primary Pageant, - * which may or may not be us). - */ - { - void *blob; - unsigned char *keylist, *p; - int i, nkeys, bloblen, keylistlen; - - if (type == SSH_KEYTYPE_SSH1) { - if (!rsakey_pubblob(filename, &blob, &bloblen, NULL, &error)) { - char *msg = dupprintf("Couldn't load private key (%s)", error); - message_box(msg, APPNAME, MB_OK | MB_ICONERROR, - HELPCTXID(errors_cantloadkey)); - sfree(msg); - return; - } - keylist = get_keylist1(&keylistlen); - } else { - unsigned char *blob2; - blob = ssh2_userkey_loadpub(filename, NULL, &bloblen, - NULL, &error); - if (!blob) { - char *msg = dupprintf("Couldn't load private key (%s)", error); - message_box(msg, APPNAME, MB_OK | MB_ICONERROR, - HELPCTXID(errors_cantloadkey)); - sfree(msg); - return; - } - /* For our purposes we want the blob prefixed with its length */ - blob2 = snewn(bloblen+4, unsigned char); - PUT_32BIT(blob2, bloblen); - memcpy(blob2 + 4, blob, bloblen); - sfree(blob); - blob = blob2; - - keylist = get_keylist2(&keylistlen); - } - if (keylist) { - if (keylistlen < 4) { - MessageBox(NULL, "Received broken key list?!", APPNAME, - MB_OK | MB_ICONERROR); - return; - } - 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; - - for (i = 0; i < nkeys; i++) { - if (!memcmp(blob, p, bloblen)) { - /* Key is already present; we can now leave. */ - sfree(keylist); - sfree(blob); - return; - } - /* Now skip over public blob */ - if (type == SSH_KEYTYPE_SSH1) { - int n = rsa_public_blob_len(p, keylistlen); - if (n < 0) { - MessageBox(NULL, "Received broken key list?!", APPNAME, - MB_OK | MB_ICONERROR); - return; - } - p += n; - keylistlen -= n; - } else { - int n; - if (keylistlen < 4) { - MessageBox(NULL, "Received broken key list?!", APPNAME, - MB_OK | MB_ICONERROR); - return; - } - n = toint(4 + GET_32BIT(p)); - if (n < 0 || keylistlen < n) { - MessageBox(NULL, "Received broken key list?!", APPNAME, - MB_OK | MB_ICONERROR); - return; - } - p += n; - keylistlen -= n; - } - /* Now skip over comment field */ - { - int n; - if (keylistlen < 4) { - MessageBox(NULL, "Received broken key list?!", APPNAME, - MB_OK | MB_ICONERROR); - return; - } - n = toint(4 + GET_32BIT(p)); - if (n < 0 || keylistlen < n) { - MessageBox(NULL, "Received broken key list?!", APPNAME, - MB_OK | MB_ICONERROR); - return; - } - p += n; - keylistlen -= n; - } - } - - sfree(keylist); - } - - sfree(blob); - } - - error = NULL; - if (type == SSH_KEYTYPE_SSH1) - needs_pass = rsakey_encrypted(filename, &comment); - else - needs_pass = ssh2_userkey_encrypted(filename, &comment); - attempts = 0; - if (type == SSH_KEYTYPE_SSH1) - rkey = snew(struct RSAKey); - 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) { - 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); - passphrase_box = NULL; - if (!dlgret) { - if (comment) - sfree(comment); - if (type == SSH_KEYTYPE_SSH1) - sfree(rkey); - return; /* operation cancelled */ - } - - assert(passphrase != NULL); - } - } else - passphrase = dupstr(""); - - if (type == SSH_KEYTYPE_SSH1) - ret = loadrsakey(filename, rkey, passphrase, &error); - else { - skey = ssh2_load_userkey(filename, passphrase, &error); - if (skey == SSH2_WRONG_PASSPHRASE) - ret = -1; - else if (!skey) - ret = 0; - else - ret = 1; - } - attempts++; - } while (ret == -1); - - if(original_pass && ret) { - /* 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); - if (ret == 0) { - char *msg = dupprintf("Couldn't load private key (%s)", error); - message_box(msg, APPNAME, MB_OK | MB_ICONERROR, - HELPCTXID(errors_cantloadkey)); - sfree(msg); - if (type == SSH_KEYTYPE_SSH1) - sfree(rkey); - return; - } - if (type == SSH_KEYTYPE_SSH1) { - if (already_running) { - unsigned char *request, *response; - void *vresponse; - int reqlen, clen, resplen, ret; - - clen = strlen(rkey->comment); - - reqlen = 4 + 1 + /* length, message type */ - 4 + /* bit count */ - ssh1_bignum_length(rkey->modulus) + - ssh1_bignum_length(rkey->exponent) + - ssh1_bignum_length(rkey->private_exponent) + - ssh1_bignum_length(rkey->iqmp) + - ssh1_bignum_length(rkey->p) + - ssh1_bignum_length(rkey->q) + 4 + clen /* comment */ - ; - - request = snewn(reqlen, unsigned char); - - request[4] = SSH1_AGENTC_ADD_RSA_IDENTITY; - reqlen = 5; - PUT_32BIT(request + reqlen, bignum_bitcount(rkey->modulus)); - reqlen += 4; - reqlen += ssh1_write_bignum(request + reqlen, rkey->modulus); - reqlen += ssh1_write_bignum(request + reqlen, rkey->exponent); - reqlen += - ssh1_write_bignum(request + reqlen, - rkey->private_exponent); - reqlen += ssh1_write_bignum(request + reqlen, rkey->iqmp); - reqlen += ssh1_write_bignum(request + reqlen, rkey->p); - reqlen += ssh1_write_bignum(request + reqlen, rkey->q); - PUT_32BIT(request + reqlen, clen); - memcpy(request + reqlen + 4, rkey->comment, clen); - reqlen += 4 + clen; - PUT_32BIT(request, reqlen - 4); - - ret = agent_query(request, reqlen, &vresponse, &resplen, - NULL, NULL); - assert(ret == 1); - response = vresponse; - if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) - MessageBox(NULL, "The already running Pageant " - "refused to add the key.", APPNAME, - MB_OK | MB_ICONERROR); - - sfree(request); - sfree(response); - } else { - if (add234(rsakeys, rkey) != rkey) - sfree(rkey); /* already present, don't waste RAM */ - } + unsigned char *msg = (unsigned char *)msgv; + unsigned msglen; + void *reply; + int replylen; + + msglen = GET_32BIT(msg); + if (msglen > AGENT_MAX_MSGLEN) { + reply = pageant_failure_msg(&replylen); } else { - if (already_running) { - unsigned char *request, *response; - void *vresponse; - int reqlen, alglen, clen, keybloblen, resplen, ret; - alglen = strlen(skey->alg->name); - clen = strlen(skey->comment); - - keybloblen = skey->alg->openssh_fmtkey(skey->data, NULL, 0); - - reqlen = 4 + 1 + /* length, message type */ - 4 + alglen + /* algorithm name */ - keybloblen + /* key data */ - 4 + clen /* comment */ - ; - - request = snewn(reqlen, unsigned char); - - request[4] = SSH2_AGENTC_ADD_IDENTITY; - reqlen = 5; - PUT_32BIT(request + reqlen, alglen); - reqlen += 4; - memcpy(request + reqlen, skey->alg->name, alglen); - reqlen += alglen; - reqlen += skey->alg->openssh_fmtkey(skey->data, - request + reqlen, - keybloblen); - PUT_32BIT(request + reqlen, clen); - memcpy(request + reqlen + 4, skey->comment, clen); - reqlen += clen + 4; - PUT_32BIT(request, reqlen - 4); - - ret = agent_query(request, reqlen, &vresponse, &resplen, - NULL, NULL); - assert(ret == 1); - response = vresponse; - if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) - MessageBox(NULL, "The already running Pageant " - "refused to add the key.", APPNAME, - MB_OK | MB_ICONERROR); - - sfree(request); - sfree(response); - } else { - if (add234(ssh2keys, skey) != skey) { - skey->alg->freekey(skey->data); - sfree(skey); /* already present, don't waste RAM */ - } - } + reply = pageant_handle_msg(msg + 4, msglen, &replylen, NULL, NULL); + if (replylen > AGENT_MAX_MSGLEN) { + smemclr(reply, replylen); + sfree(reply); + reply = pageant_failure_msg(&replylen); + } } -} - -/* - * Create an SSH-1 key list in a malloc'ed buffer; return its - * length. - */ -static void *make_keylist1(int *length) -{ - int i, nkeys, len; - struct RSAKey *key; - unsigned char *blob, *p, *ret; - int bloblen; /* - * Count up the number and length of keys we hold. + * Windows Pageant answers messages in place, by overwriting the + * input message buffer. */ - len = 4; - nkeys = 0; - for (i = 0; NULL != (key = index234(rsakeys, i)); i++) { - nkeys++; - blob = rsa_public_blob(key, &bloblen); - len += bloblen; - sfree(blob); - len += 4 + strlen(key->comment); - } - - /* Allocate the buffer. */ - p = ret = snewn(len, unsigned char); - if (length) *length = len; - - PUT_32BIT(p, nkeys); - p += 4; - for (i = 0; NULL != (key = index234(rsakeys, i)); i++) { - blob = rsa_public_blob(key, &bloblen); - memcpy(p, blob, bloblen); - p += bloblen; - sfree(blob); - PUT_32BIT(p, strlen(key->comment)); - memcpy(p + 4, key->comment, strlen(key->comment)); - p += 4 + strlen(key->comment); - } - - assert(p - ret == len); - return ret; + memcpy(msg, reply, replylen); + smemclr(reply, replylen); + sfree(reply); } -/* - * Create an SSH-2 key list in a malloc'ed buffer; return its - * length. - */ -static void *make_keylist2(int *length) +static void win_add_keyfile(Filename *filename) { - struct ssh2_userkey *key; - int i, len, nkeys; - unsigned char *blob, *p, *ret; - int bloblen; + char *err; + int ret; + char *passphrase = NULL; /* - * Count up the number and length of keys we hold. + * Try loading the key without a passphrase. (Or rather, without a + * _new_ passphrase; pageant_add_keyfile will take care of trying + * all the passphrases we've already stored.) */ - len = 4; - nkeys = 0; - for (i = 0; NULL != (key = index234(ssh2keys, i)); i++) { - nkeys++; - len += 4; /* length field */ - blob = key->alg->public_blob(key->data, &bloblen); - len += bloblen; - sfree(blob); - len += 4 + strlen(key->comment); + ret = pageant_add_keyfile(filename, NULL, &err); + if (ret == PAGEANT_ACTION_OK) { + goto done; + } else if (ret == PAGEANT_ACTION_FAILURE) { + goto error; } - /* Allocate the buffer. */ - p = ret = snewn(len, unsigned char); - if (length) *length = len; - /* - * Packet header is the obvious five bytes, plus four - * bytes for the key count. + * OK, a passphrase is needed, and we've been given the key + * comment to use in the passphrase prompt. */ - PUT_32BIT(p, nkeys); - p += 4; - for (i = 0; NULL != (key = index234(ssh2keys, i)); i++) { - blob = key->alg->public_blob(key->data, &bloblen); - PUT_32BIT(p, bloblen); - p += 4; - memcpy(p, blob, bloblen); - p += bloblen; - sfree(blob); - PUT_32BIT(p, strlen(key->comment)); - memcpy(p + 4, key->comment, strlen(key->comment)); - p += 4 + strlen(key->comment); - } - - assert(p - ret == len); - return ret; -} - -/* - * Acquire a keylist1 from the primary Pageant; this means either - * calling make_keylist1 (if that's us) or sending a message to the - * primary Pageant (if it's not). - */ -static void *get_keylist1(int *length) -{ - void *ret; + while (1) { + INT_PTR dlgret; + struct PassphraseProcStruct pps; - if (already_running) { - unsigned char request[5], *response; - void *vresponse; - int resplen, retval; - request[4] = SSH1_AGENTC_REQUEST_RSA_IDENTITIES; - PUT_32BIT(request, 4); - - retval = agent_query(request, 5, &vresponse, &resplen, NULL, NULL); - assert(retval == 1); - response = vresponse; - if (resplen < 5 || response[4] != SSH1_AGENT_RSA_IDENTITIES_ANSWER) - return NULL; - - ret = snewn(resplen-5, unsigned char); - memcpy(ret, response+5, resplen-5); - sfree(response); - - if (length) - *length = resplen-5; - } else { - ret = make_keylist1(length); - } - return ret; -} + pps.passphrase = &passphrase; + pps.comment = err; + dlgret = DialogBoxParam(hinst, MAKEINTRESOURCE(210), + NULL, PassphraseProc, (LPARAM) &pps); + passphrase_box = NULL; -/* - * Acquire a keylist2 from the primary Pageant; this means either - * calling make_keylist2 (if that's us) or sending a message to the - * primary Pageant (if it's not). - */ -static void *get_keylist2(int *length) -{ - void *ret; - - if (already_running) { - unsigned char request[5], *response; - void *vresponse; - int resplen, retval; + if (!dlgret) + goto done; /* operation cancelled */ - request[4] = SSH2_AGENTC_REQUEST_IDENTITIES; - PUT_32BIT(request, 4); + sfree(err); - retval = agent_query(request, 5, &vresponse, &resplen, NULL, NULL); - assert(retval == 1); - response = vresponse; - if (resplen < 5 || response[4] != SSH2_AGENT_IDENTITIES_ANSWER) - return NULL; + assert(passphrase != NULL); - ret = snewn(resplen-5, unsigned char); - memcpy(ret, response+5, resplen-5); - sfree(response); - - if (length) - *length = resplen-5; - } else { - ret = make_keylist2(length); - } - return ret; -} - -/* - * This is the main agent function that answers messages. - */ -static void answer_msg(void *msg) -{ - unsigned char *p = msg; - unsigned char *ret = msg; - unsigned char *msgend; - int type; - - /* - * Get the message length. - */ - msgend = p + 4 + GET_32BIT(p); - - /* - * Get the message type. - */ - if (msgend < p+5) - goto failure; - type = p[4]; - - p += 5; - switch (type) { - case SSH1_AGENTC_REQUEST_RSA_IDENTITIES: - /* - * Reply with SSH1_AGENT_RSA_IDENTITIES_ANSWER. - */ - { - int len; - void *keylist; - - ret[4] = SSH1_AGENT_RSA_IDENTITIES_ANSWER; - keylist = make_keylist1(&len); - if (len + 5 > AGENT_MAX_MSGLEN) { - sfree(keylist); - goto failure; - } - PUT_32BIT(ret, len + 1); - memcpy(ret + 5, keylist, len); - sfree(keylist); - } - break; - case SSH2_AGENTC_REQUEST_IDENTITIES: - /* - * Reply with SSH2_AGENT_IDENTITIES_ANSWER. - */ - { - int len; - void *keylist; - - ret[4] = SSH2_AGENT_IDENTITIES_ANSWER; - keylist = make_keylist2(&len); - if (len + 5 > AGENT_MAX_MSGLEN) { - sfree(keylist); - goto failure; - } - PUT_32BIT(ret, len + 1); - memcpy(ret + 5, keylist, len); - sfree(keylist); - } - break; - case SSH1_AGENTC_RSA_CHALLENGE: - /* - * Reply with either SSH1_AGENT_RSA_RESPONSE or - * SSH_AGENT_FAILURE, depending on whether we have that key - * or not. - */ - { - struct RSAKey reqkey, *key; - Bignum challenge, response; - unsigned char response_source[48], response_md5[16]; - struct MD5Context md5c; - int i, len; - - p += 4; - i = ssh1_read_bignum(p, msgend - p, &reqkey.exponent); - if (i < 0) - goto failure; - p += i; - i = ssh1_read_bignum(p, msgend - p, &reqkey.modulus); - if (i < 0) - goto failure; - p += i; - i = ssh1_read_bignum(p, msgend - p, &challenge); - if (i < 0) - goto failure; - p += i; - if (msgend < p+16) { - freebn(reqkey.exponent); - freebn(reqkey.modulus); - freebn(challenge); - goto failure; - } - memcpy(response_source + 32, p, 16); - p += 16; - if (msgend < p+4 || - GET_32BIT(p) != 1 || - (key = find234(rsakeys, &reqkey, NULL)) == NULL) { - freebn(reqkey.exponent); - freebn(reqkey.modulus); - freebn(challenge); - goto failure; - } - response = rsadecrypt(challenge, key); - for (i = 0; i < 32; i++) - response_source[i] = bignum_byte(response, 31 - i); - - MD5Init(&md5c); - MD5Update(&md5c, response_source, 48); - MD5Final(response_md5, &md5c); - 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 ... */ - freebn(reqkey.modulus); /* ... while we're at it. */ - - /* - * Packet is the obvious five byte header, plus sixteen - * bytes of MD5. - */ - len = 5 + 16; - PUT_32BIT(ret, len - 4); - ret[4] = SSH1_AGENT_RSA_RESPONSE; - memcpy(ret + 5, response_md5, 16); - } - break; - case SSH2_AGENTC_SIGN_REQUEST: - /* - * Reply with either SSH2_AGENT_SIGN_RESPONSE or - * SSH_AGENT_FAILURE, depending on whether we have that key - * or not. - */ - { - struct ssh2_userkey *key; - struct blob b; - unsigned char *data, *signature; - int datalen, siglen, len; - - if (msgend < p+4) - goto failure; - b.len = toint(GET_32BIT(p)); - if (b.len < 0 || b.len > msgend - (p+4)) - goto failure; - p += 4; - b.blob = p; - p += b.len; - if (msgend < p+4) - goto failure; - datalen = toint(GET_32BIT(p)); - p += 4; - if (datalen < 0 || datalen > msgend - p) - goto failure; - data = p; - key = find234(ssh2keys, &b, cmpkeys_ssh2_asymm); - if (!key) - goto failure; - signature = key->alg->sign(key->data, data, datalen, &siglen); - len = 5 + 4 + siglen; - PUT_32BIT(ret, len - 4); - ret[4] = SSH2_AGENT_SIGN_RESPONSE; - PUT_32BIT(ret + 5, siglen); - memcpy(ret + 5 + 4, signature, siglen); - sfree(signature); - } - break; - case SSH1_AGENTC_ADD_RSA_IDENTITY: - /* - * Add to the list and return SSH_AGENT_SUCCESS, or - * SSH_AGENT_FAILURE if the key was malformed. - */ - { - struct RSAKey *key; - char *comment; - int n, commentlen; - - key = snew(struct RSAKey); - memset(key, 0, sizeof(struct RSAKey)); - - n = makekey(p, msgend - p, key, NULL, 1); - if (n < 0) { - freersakey(key); - sfree(key); - goto failure; - } - p += n; - - n = makeprivate(p, msgend - p, key); - if (n < 0) { - freersakey(key); - sfree(key); - goto failure; - } - p += n; - - n = ssh1_read_bignum(p, msgend - p, &key->iqmp); /* p^-1 mod q */ - if (n < 0) { - freersakey(key); - sfree(key); - goto failure; - } - p += n; - - n = ssh1_read_bignum(p, msgend - p, &key->p); /* p */ - if (n < 0) { - freersakey(key); - sfree(key); - goto failure; - } - p += n; - - n = ssh1_read_bignum(p, msgend - p, &key->q); /* q */ - if (n < 0) { - freersakey(key); - sfree(key); - goto failure; - } - p += n; - - if (msgend < p+4) { - freersakey(key); - sfree(key); - goto failure; - } - commentlen = toint(GET_32BIT(p)); - - if (commentlen < 0 || commentlen > msgend - p) { - freersakey(key); - sfree(key); - goto failure; - } - - comment = snewn(commentlen+1, char); - if (comment) { - memcpy(comment, p + 4, commentlen); - comment[commentlen] = '\0'; - key->comment = comment; - } - PUT_32BIT(ret, 1); - ret[4] = SSH_AGENT_FAILURE; - if (add234(rsakeys, key) == key) { - keylist_update(); - ret[4] = SSH_AGENT_SUCCESS; - } else { - freersakey(key); - sfree(key); - } - } - break; - case SSH2_AGENTC_ADD_IDENTITY: - /* - * Add to the list and return SSH_AGENT_SUCCESS, or - * SSH_AGENT_FAILURE if the key was malformed. - */ - { - struct ssh2_userkey *key; - char *comment, *alg; - int alglen, commlen; - int bloblen; - - - if (msgend < p+4) - goto failure; - alglen = toint(GET_32BIT(p)); - p += 4; - if (alglen < 0 || alglen > msgend - p) - goto failure; - alg = p; - p += alglen; - - key = snew(struct ssh2_userkey); - /* 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; - } - - bloblen = msgend - p; - key->data = key->alg->openssh_createkey(&p, &bloblen); - if (!key->data) { - sfree(key); - goto failure; - } - - /* - * p has been advanced by openssh_createkey, but - * certainly not _beyond_ the end of the buffer. - */ - assert(p <= msgend); - - if (msgend < p+4) { - key->alg->freekey(key->data); - sfree(key); - goto failure; - } - commlen = toint(GET_32BIT(p)); - p += 4; - - if (commlen < 0 || commlen > msgend - p) { - key->alg->freekey(key->data); - sfree(key); - goto failure; - } - comment = snewn(commlen + 1, char); - if (comment) { - memcpy(comment, p, commlen); - comment[commlen] = '\0'; - } - key->comment = comment; - - PUT_32BIT(ret, 1); - ret[4] = SSH_AGENT_FAILURE; - if (add234(ssh2keys, key) == key) { - keylist_update(); - ret[4] = SSH_AGENT_SUCCESS; - } else { - key->alg->freekey(key->data); - sfree(key->comment); - sfree(key); - } - } - break; - case SSH1_AGENTC_REMOVE_RSA_IDENTITY: - /* - * Remove from the list and return SSH_AGENT_SUCCESS, or - * perhaps SSH_AGENT_FAILURE if it wasn't in the list to - * start with. - */ - { - struct RSAKey reqkey, *key; - int n; - - n = makekey(p, msgend - p, &reqkey, NULL, 0); - if (n < 0) - goto failure; - - key = find234(rsakeys, &reqkey, NULL); - freebn(reqkey.exponent); - freebn(reqkey.modulus); - PUT_32BIT(ret, 1); - ret[4] = SSH_AGENT_FAILURE; - if (key) { - del234(rsakeys, key); - keylist_update(); - freersakey(key); - sfree(key); - ret[4] = SSH_AGENT_SUCCESS; - } - } - break; - case SSH2_AGENTC_REMOVE_IDENTITY: - /* - * Remove from the list and return SSH_AGENT_SUCCESS, or - * perhaps SSH_AGENT_FAILURE if it wasn't in the list to - * start with. - */ - { - struct ssh2_userkey *key; - struct blob b; - - if (msgend < p+4) - goto failure; - b.len = toint(GET_32BIT(p)); - p += 4; - - if (b.len < 0 || b.len > msgend - p) - goto failure; - b.blob = p; - p += b.len; - - key = find234(ssh2keys, &b, cmpkeys_ssh2_asymm); - if (!key) - goto failure; - - PUT_32BIT(ret, 1); - ret[4] = SSH_AGENT_FAILURE; - if (key) { - del234(ssh2keys, key); - keylist_update(); - key->alg->freekey(key->data); - sfree(key); - ret[4] = SSH_AGENT_SUCCESS; - } - } - break; - case SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES: - /* - * Remove all SSH-1 keys. Always returns success. - */ - { - struct RSAKey *rkey; - - while ((rkey = index234(rsakeys, 0)) != NULL) { - del234(rsakeys, rkey); - freersakey(rkey); - sfree(rkey); - } - keylist_update(); - - PUT_32BIT(ret, 1); - ret[4] = SSH_AGENT_SUCCESS; - } - break; - case SSH2_AGENTC_REMOVE_ALL_IDENTITIES: - /* - * Remove all SSH-2 keys. Always returns success. - */ - { - struct ssh2_userkey *skey; - - while ((skey = index234(ssh2keys, 0)) != NULL) { - del234(ssh2keys, skey); - skey->alg->freekey(skey->data); - sfree(skey); - } - keylist_update(); - - PUT_32BIT(ret, 1); - ret[4] = SSH_AGENT_SUCCESS; - } - break; - default: - failure: - /* - * Unrecognised message. Return SSH_AGENT_FAILURE. - */ - PUT_32BIT(ret, 1); - ret[4] = SSH_AGENT_FAILURE; - break; - } -} - -/* - * Key comparison function for the 2-3-4 tree of RSA keys. - */ -static int cmpkeys_rsa(void *av, void *bv) -{ - struct RSAKey *a = (struct RSAKey *) av; - struct RSAKey *b = (struct RSAKey *) bv; - Bignum am, bm; - int alen, blen; - - am = a->modulus; - bm = b->modulus; - /* - * Compare by length of moduli. - */ - alen = bignum_bitcount(am); - blen = bignum_bitcount(bm); - if (alen > blen) - return +1; - else if (alen < blen) - return -1; - /* - * Now compare by moduli themselves. - */ - alen = (alen + 7) / 8; /* byte count */ - while (alen-- > 0) { - int abyte, bbyte; - abyte = bignum_byte(am, alen); - bbyte = bignum_byte(bm, alen); - if (abyte > bbyte) - return +1; - else if (abyte < bbyte) - return -1; - } - /* - * Give up. - */ - return 0; -} - -/* - * Key comparison function for the 2-3-4 tree of SSH-2 keys. - */ -static int cmpkeys_ssh2(void *av, void *bv) -{ - struct ssh2_userkey *a = (struct ssh2_userkey *) av; - struct ssh2_userkey *b = (struct ssh2_userkey *) bv; - int i; - int alen, blen; - unsigned char *ablob, *bblob; - int c; - - /* - * Compare purely by public blob. - */ - ablob = a->alg->public_blob(a->data, &alen); - bblob = b->alg->public_blob(b->data, &blen); + ret = pageant_add_keyfile(filename, passphrase, &err); + if (ret == PAGEANT_ACTION_OK) { + goto done; + } else if (ret == PAGEANT_ACTION_FAILURE) { + goto error; + } - c = 0; - for (i = 0; i < alen && i < blen; i++) { - if (ablob[i] < bblob[i]) { - c = -1; - break; - } else if (ablob[i] > bblob[i]) { - c = +1; - break; - } + smemclr(passphrase, strlen(passphrase)); + sfree(passphrase); + passphrase = NULL; } - if (c == 0 && i < alen) - c = +1; /* a is longer */ - if (c == 0 && i < blen) - c = -1; /* a is longer */ - - sfree(ablob); - sfree(bblob); - return c; -} - -/* - * Key comparison function for looking up a blob in the 2-3-4 tree - * of SSH-2 keys. - */ -static int cmpkeys_ssh2_asymm(void *av, void *bv) -{ - struct blob *a = (struct blob *) av; - struct ssh2_userkey *b = (struct ssh2_userkey *) bv; - int i; - int alen, blen; - unsigned char *ablob, *bblob; - int c; - - /* - * Compare purely by public blob. - */ - ablob = a->blob; - alen = a->len; - bblob = b->alg->public_blob(b->data, &blen); - - c = 0; - for (i = 0; i < alen && i < blen; i++) { - if (ablob[i] < bblob[i]) { - c = -1; - break; - } else if (ablob[i] > bblob[i]) { - c = +1; - break; - } + error: + message_box(err, APPNAME, MB_OK | MB_ICONERROR, + HELPCTXID(errors_cantloadkey)); + done: + if (passphrase) { + smemclr(passphrase, strlen(passphrase)); + sfree(passphrase); } - if (c == 0 && i < alen) - c = +1; /* a is longer */ - if (c == 0 && i < blen) - c = -1; /* a is longer */ - - sfree(bblob); - - return c; + sfree(err); + return; } /* @@ -1438,10 +481,12 @@ static void prompt_add_keyfile(void) of.lpstrTitle = "Select Private Key File"; of.Flags = OFN_ALLOWMULTISELECT | OFN_EXPLORER; if (request_file(keypath, &of, TRUE, FALSE)) { - if(strlen(filelist) > of.nFileOffset) + if(strlen(filelist) > of.nFileOffset) { /* Only one filename returned? */ - add_keyfile(filename_from_str(filelist)); - else { + Filename *fn = filename_from_str(filelist); + win_add_keyfile(fn); + filename_free(fn); + } else { /* we are returned a bunch of strings, end to * end. first string is the directory, the * rest the filenames. terminated with an @@ -1451,14 +496,16 @@ static void prompt_add_keyfile(void) char *filewalker = filelist + strlen(dir) + 1; while (*filewalker != '\0') { char *filename = dupcat(dir, "\\", filewalker, NULL); - add_keyfile(filename_from_str(filename)); + Filename *fn = filename_from_str(filename); + win_add_keyfile(fn); + filename_free(fn); sfree(filename); filewalker += strlen(filewalker) + 1; } } keylist_update(); - forget_passphrases(); + pageant_forget_passphrases(); } sfree(filelist); } @@ -1466,7 +513,7 @@ static void prompt_add_keyfile(void) /* * Dialog-box function for the key list box. */ -static int CALLBACK KeyListProc(HWND hwnd, UINT msg, +static INT_PTR CALLBACK KeyListProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { struct RSAKey *rkey; @@ -1501,7 +548,7 @@ static int CALLBACK KeyListProc(HWND hwnd, UINT msg, keylist = hwnd; { - static int tabs[] = { 35, 60, 210 }; + static int tabs[] = { 35, 75, 250 }; SendDlgItemMessage(hwnd, 100, LB_SETTABSTOPS, sizeof(tabs) / sizeof(*tabs), (LPARAM) tabs); @@ -1552,35 +599,35 @@ static int CALLBACK KeyListProc(HWND hwnd, UINT msg, numSelected, (WPARAM)selectedArray); itemNum = numSelected - 1; - rCount = count234(rsakeys); - sCount = count234(ssh2keys); + rCount = pageant_count_ssh1_keys(); + sCount = pageant_count_ssh2_keys(); /* go through the non-rsakeys until we've covered them all, * and/or we're out of selected items to check. note that * we go *backwards*, to avoid complications from deleting * things hence altering the offset of subsequent items */ - for (i = sCount - 1; (itemNum >= 0) && (i >= 0); i--) { - skey = index234(ssh2keys, i); + for (i = sCount - 1; (itemNum >= 0) && (i >= 0); i--) { + skey = pageant_nth_ssh2_key(i); - if (selectedArray[itemNum] == rCount + i) { - del234(ssh2keys, skey); - skey->alg->freekey(skey->data); - sfree(skey); - itemNum--; - } + if (selectedArray[itemNum] == rCount + i) { + pageant_delete_ssh2_key(skey); + skey->alg->freekey(skey->data); + sfree(skey); + itemNum--; + } } /* do the same for the rsa keys */ for (i = rCount - 1; (itemNum >= 0) && (i >= 0); i--) { - rkey = index234(rsakeys, i); - - if(selectedArray[itemNum] == i) { - del234(rsakeys, rkey); - freersakey(rkey); - sfree(rkey); - itemNum--; - } + rkey = pageant_nth_ssh1_key(i); + + if(selectedArray[itemNum] == i) { + pageant_delete_ssh1_key(rkey); + freersakey(rkey); + sfree(rkey); + itemNum--; + } } sfree(selectedArray); @@ -1598,7 +645,7 @@ static int CALLBACK KeyListProc(HWND hwnd, UINT msg, case WM_HELP: { int id = ((LPHELPINFO)lParam)->iCtrlId; - char *topic = NULL; + const char *topic = NULL; switch (id) { case 100: topic = WINHELP_CTX_pageant_keylist; break; case 101: topic = WINHELP_CTX_pageant_addkey; break; @@ -1749,7 +796,6 @@ PSID get_default_sid(void) static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - int ret; static int menuinprogress; static UINT msgTaskbarCreated = 0; @@ -1784,10 +830,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, menuinprogress = 1; update_sessions(); SetForegroundWindow(hwnd); - ret = TrackPopupMenu(systray_menu, - TPM_RIGHTALIGN | TPM_BOTTOMALIGN | - TPM_RIGHTBUTTON, - wParam, lParam, 0, hwnd, NULL); + TrackPopupMenu(systray_menu, + TPM_RIGHTALIGN | TPM_BOTTOMALIGN | + TPM_RIGHTBUTTON, + wParam, lParam, 0, hwnd, NULL); menuinprogress = 0; } break; @@ -1795,7 +841,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, case WM_SYSCOMMAND: switch (wParam & ~0xF) { /* low 4 bits reserved to Windows */ case IDM_PUTTY: - if((int)ShellExecute(hwnd, NULL, putty_path, _T(""), _T(""), + if((INT_PTR)ShellExecute(hwnd, NULL, putty_path, _T(""), _T(""), SW_SHOW) <= 32) { MessageBox(NULL, "Unable to execute PuTTY!", "Error", MB_OK | MB_ICONERROR); @@ -1862,7 +908,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, GetMenuItemInfo(session_menu, wParam, FALSE, &mii); strcpy(param, "@"); strcat(param, mii.dwTypeData); - if((int)ShellExecute(hwnd, NULL, putty_path, param, + if((INT_PTR)ShellExecute(hwnd, NULL, putty_path, param, _T(""), SW_SHOW) <= 32) { MessageBox(NULL, "Unable to execute PuTTY!", "Error", MB_OK | MB_ICONERROR); @@ -1909,6 +955,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, #ifdef DEBUG_IPC debug(("couldn't get user SID\n")); #endif + CloseHandle(filemap); return 0; } @@ -1916,6 +963,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, #ifdef DEBUG_IPC debug(("couldn't get default SID\n")); #endif + CloseHandle(filemap); return 0; } @@ -1927,6 +975,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, debug(("couldn't get owner info for filemap: %d\n", rc)); #endif + CloseHandle(filemap); + sfree(ourself2); return 0; } #ifdef DEBUG_IPC @@ -1945,13 +995,14 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, if (!EqualSid(mapowner, ourself) && !EqualSid(mapowner, ourself2)) { CloseHandle(filemap); + LocalFree(psd); + sfree(ourself2); return 0; /* security ID mismatch! */ } #ifdef DEBUG_IPC debug(("security stuff matched\n")); #endif LocalFree(psd); - sfree(ourself); sfree(ourself2); } else { #ifdef DEBUG_IPC @@ -1984,7 +1035,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, /* * Fork and Exec the command in cmdline. [DBW] */ -void spawn_cmd(char *cmdline, char * args, int show) +void spawn_cmd(const char *cmdline, const char *args, int show) { if (ShellExecute(NULL, _T("open"), cmdline, args, NULL, show) <= (HINSTANCE) 32) { @@ -2018,12 +1069,13 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { WNDCLASS wndclass; MSG msg; - HMODULE advapi; - char *command = NULL; + const char *command = NULL; int added_keys = 0; int argc, i; char **argv, **argstart; + dll_hijacking_protection(); + hinst = inst; hwnd = NULL; @@ -2045,7 +1097,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) /* * Attempt to get the security API we need. */ - if (!init_advapi()) { + if (!got_advapi()) { MessageBox(NULL, "Unable to access security APIs. Pageant will\n" "not run, in case it causes a security breach.", @@ -2059,8 +1111,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) "Pageant Fatal Error", MB_ICONERROR | MB_OK); return 1; #endif - } else - advapi = NULL; + } /* * See if we can find our Help file. @@ -2094,18 +1145,12 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) already_running = agent_exists(); /* - * Initialise storage for RSA keys. + * Initialise the cross-platform Pageant code. */ if (!already_running) { - rsakeys = newtree234(cmpkeys_rsa); - ssh2keys = newtree234(cmpkeys_ssh2); + pageant_init(); } - /* - * Initialise storage for short-term passphrase cache. - */ - passphrases = newtree234(NULL); - /* * Process the command line and add keys as listed on it. */ @@ -2113,9 +1158,11 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) for (i = 0; i < argc; i++) { if (!strcmp(argv[i], "-pgpfp")) { pgp_fingerprints(); - if (advapi) - FreeLibrary(advapi); return 1; + } else if (!strcmp(argv[i], "-restrict-acl") || + !strcmp(argv[i], "-restrict_acl") || + !strcmp(argv[i], "-restrictacl")) { + restrict_process_acl(); } else if (!strcmp(argv[i], "-c")) { /* * If we see `-c', then the rest of the @@ -2128,7 +1175,9 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) command = ""; break; } else { - add_keyfile(filename_from_str(argv[i])); + Filename *fn = filename_from_str(argv[i]); + win_add_keyfile(fn); + filename_free(fn); added_keys = TRUE; } } @@ -2137,7 +1186,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) * Forget any passphrase that we retained while going over * command line keyfiles. */ - forget_passphrases(); + pageant_forget_passphrases(); if (command) { char *args; @@ -2162,8 +1211,6 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) MessageBox(NULL, "Pageant is already running", "Pageant Error", MB_ICONERROR | MB_OK); } - if (advapi) - FreeLibrary(advapi); return 0; } @@ -2198,7 +1245,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) session_menu = CreateMenu(); AppendMenu(systray_menu, MF_ENABLED, IDM_PUTTY, "&New Session"); AppendMenu(systray_menu, MF_POPUP | MF_ENABLED, - (UINT) session_menu, "&Saved Sessions"); + (UINT_PTR) session_menu, "&Saved Sessions"); AppendMenu(systray_menu, MF_SEPARATOR, 0, 0); } AppendMenu(systray_menu, MF_ENABLED, IDM_VIEWKEYS, @@ -2243,9 +1290,6 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) if (keypath) filereq_free(keypath); - if (advapi) - FreeLibrary(advapi); - cleanup_exit(msg.wParam); return msg.wParam; /* just in case optimiser complains */ }