コード例 #1
0
ファイル: uxcons.c プロジェクト: aswinpj/FileZilla
int askhk(void *frontend, const char *algname, const char *betteralgs,
          void (*callback)(void *ctx, int result), void *ctx)
{
    /*static const char msg[] =
	"The first host key type we have stored for this server\n"
	"is %s, which is below the configured warning threshold.\n"
	"The server also provides the following types of host key\n"
        "above the threshold, which we do not have stored:\n"
        "%s\n"
	"Continue with connection? (y/n) ";*/
    static const char msg_batch[] =
	"The first host key type we have stored for this server\n"
	"is %s, which is below the configured warning threshold.\n"
	"The server also provides the following types of host key\n"
        "above the threshold, which we do not have stored:\n"
        "%s\n"
	"Connection abandoned.\n";
    static const char abandoned[] = "Connection abandoned.";

    char line[32];
//FZ    struct termios cf;

//FZ    premsg(&cf);
    if (console_batch_mode) {
	fprintf(stderr, msg_batch, algname, betteralgs);
	return 0;
    }

    fzprintf_raw(sftpRequest, "%d%s\n%s\n", (int)sftpReqHostkeyBetteralg, algname, betteralgs);

    {
	struct termios oldmode, newmode;
	tcgetattr(0, &oldmode);
	newmode = oldmode;
	newmode.c_lflag |= ISIG | ICANON;
	tcsetattr(0, TCSANOW, &newmode);
	line[0] = '\0';
	int ret;
	do
	{
	    ret = read(0, line, sizeof(line) - 1);
	} while (ret == -1 && (errno == EINTR || errno == EAGAIN));

	tcsetattr(0, TCSANOW, &oldmode);
    }

    if (line[0] == 'y' || line[0] == 'Y') {
//FZ	postmsg(&cf);
	return 1;
    } else {
	fzprintf(sftpError, abandoned);
//FZ	postmsg(&cf);
	return 0;
    }
}
コード例 #2
0
ファイル: cmdgen.c プロジェクト: zedfoxus/filezilla-client
void nonfatal(const char *fmt, ...)
{
    va_list ap;
    char* str;

    va_start(ap, fmt);
    str = dupvprintf(fmt, ap);
    va_end(ap);
    fzprintf(sftpError, "Error: %s", str);
    sfree(str);
}
コード例 #3
0
ファイル: cmdgen.c プロジェクト: zedfoxus/filezilla-client
void modalfatalbox(const char *fmt, ...)
{
    va_list ap;
    char* str;

    va_start(ap, fmt);
    str = dupvprintf(fmt, ap);
    va_end(ap);
    fzprintf(sftpError, "Fatal error: %s", str);
    sfree(str);

    cleanup_exit(1);
}
コード例 #4
0
ファイル: logging.c プロジェクト: AbelTian/filezilla
/*
 * Log an Event Log entry. Used in SSH packet logging mode; this is
 * also as convenient a place as any to put the output of Event Log
 * entries to stderr when a command-line tool is in verbose mode.
 * (In particular, this is a better place to put it than in the
 * front ends, because it only has to be done once for all
 * platforms. Platforms which don't have a meaningful stderr can
 * just avoid defining FLAG_STDERR.
 */
void log_eventlog(void *handle, const char *event)
{
    struct LogContext *ctx = (struct LogContext *)handle;
    if ((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)) {
	fzprintf(sftpVerbose, event);
    }
    /* If we don't have a context yet (eg winnet.c init) then skip entirely */
    if (!ctx)
	return;
    if (ctx->cfg.logtype != LGTYP_PACKETS &&
	ctx->cfg.logtype != LGTYP_SSHRAW)
	return;
    logprintf(ctx, "Event Log: %s\r\n", event);
    logflush(ctx);
}
コード例 #5
0
ファイル: uxcons.c プロジェクト: ErichKrause/filezilla
/*
 * Warn about the obsolescent key file format.
 * 
 * Uniquely among these functions, this one does _not_ expect a
 * frontend handle. This means that if PuTTY is ported to a
 * platform which requires frontend handles, this function will be
 * an anomaly. Fortunately, the problem it addresses will not have
 * been present on that platform, so it can plausibly be
 * implemented as an empty function.
 */
void old_keyfile_warning(void)
{
    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"
	"Once the key is loaded into PuTTYgen, you can perform\n"
	"this conversion simply by saving it again.\n";

//FZ struct termios cf;
//FZ premsg(&cf);
    fzprintf(sftpStatus, message);
//FZ postmsg(&cf);
}
コード例 #6
0
ファイル: uxcons.c プロジェクト: aswinpj/FileZilla
/*
 * Ask whether the selected algorithm is acceptable (since it was
 * below the configured 'warn' threshold).
 */
int askalg(void *frontend, const char *algtype, const char *algname,
	   void (*callback)(void *ctx, int result), void *ctx)
{
    fzprintf(sftpError, "The first %s supported by the server is %s, which is no longer secure. Aborting connection.", algtype, algname);
    return 0;
}
コード例 #7
0
ファイル: uxcons.c プロジェクト: aswinpj/FileZilla
int verify_ssh_host_key(void *frontend, char *host, int port,
                        const char *keytype, char *keystr, char *fingerprint,
                        void (*callback)(void *ctx, int result), void *ctx)
{
    int ret;

    static const char absentmsg_batch[] =
	"The server's host key is not cached. You have no guarantee\n"
	"that the server is the computer you think it is.\n"
	"The server's %s key fingerprint is:\n"
	"%s\n"
	"Connection abandoned.\n";
/*    static const char absentmsg[] =
	"The server's host key is not cached. You have no guarantee\n"
	"that the server is the computer you think it is.\n"
	"The server's %s key fingerprint is:\n"
	"%s\n"
	"If you trust this host, enter \"y\" to add the key to\n"
	"PuTTY's cache and carry on connecting.\n"
	"If you want to carry on connecting just once, without\n"
	"adding the key to the cache, enter \"n\".\n"
	"If you do not trust this host, press Return to abandon the\n"
	"connection.\n"
	"Store key in cache? (y/n) ";
*/
    static const char wrongmsg_batch[] =
	"WARNING - POTENTIAL SECURITY BREACH!\n"
	"The server's host key does not match the one PuTTY has\n"
	"cached. This means that either the server administrator\n"
	"has changed the host key, or you have actually connected\n"
	"to another computer pretending to be the server.\n"
	"The new %s key fingerprint is:\n"
	"%s\n"
	"Connection abandoned.\n";
/*    static const char wrongmsg[] =
	"WARNING - POTENTIAL SECURITY BREACH!\n"
	"The server's host key does not match the one PuTTY has\n"
	"cached. This means that either the server administrator\n"
	"has changed the host key, or you have actually connected\n"
	"to another computer pretending to be the server.\n"
	"The new %s key fingerprint is:\n"
	"%s\n"
	"If you were expecting this change and trust the new key,\n"
	"enter \"y\" to update PuTTY's cache and continue connecting.\n"
	"If you want to carry on connecting but without updating\n"
	"the cache, enter \"n\".\n"
	"If you want to abandon the connection completely, press\n"
	"Return to cancel. Pressing Return is the ONLY guaranteed\n"
	"safe choice.\n"
	"Update cached key? (y/n, Return cancels connection) ";
*/
    static const char abandoned[] = "Connection abandoned.\n";

    char line[32];
//FZ struct termios cf;

    /*
     * Verify the key.
     */
    ret = verify_host_key(host, port, keytype, keystr);

    if (ret == 0)		       /* success - key matched OK */
	return 1;

//FZ premsg(&cf);
    if (ret == 2) {		       /* key was different */
	if (console_batch_mode) {
	    fprintf(stderr, wrongmsg_batch, keytype, fingerprint);
	    return 0;
	}
	fzprintf_raw(sftpRequest, "%d%s\n%d\n%s\n", (int)sftpReqHostkeyChanged, host, port, fingerprint);
    }
    if (ret == 1) {		       /* key was absent */
	if (console_batch_mode) {
	    fprintf(stderr, absentmsg_batch, keytype, fingerprint);
	    return 0;
	}
	fzprintf_raw(sftpRequest, "%d%s\n%d\n%s\n", (int)sftpReqHostkey, host, port, fingerprint);
    }

    {
	struct termios oldmode, newmode;
	tcgetattr(0, &oldmode);
	newmode = oldmode;
	newmode.c_lflag |= ISIG | ICANON;
	tcsetattr(0, TCSANOW, &newmode);
	line[0] = '\0';
	int ret;
	do
	{
	    ret = read(0, line, sizeof(line) - 1);
	} while (ret == -1 && (errno == EINTR || errno == EAGAIN));

	tcsetattr(0, TCSANOW, &oldmode);
    }

    if (line[0] != '\0' && line[0] != '\r' && line[0] != '\n') {
	if (line[0] == 'y' || line[0] == 'Y')
	    store_host_key(host, port, keytype, keystr);
//FZ	postmsg(&cf);
        return 1;
    } else {
	fzprintf(sftpError, abandoned);
//FZ	postmsg(&cf);
        return 0;
    }
}
コード例 #8
0
ファイル: cmdgen.c プロジェクト: zedfoxus/filezilla-client
int main(int argc, char **argv)
{
    Filename *infilename = NULL;
    int intype = SSH_KEYTYPE_UNOPENABLE;
    int encrypted = 0;
    char* origcomment = 0;
    char* line = 0;
    char* passphrase = 0;
    struct ssh2_userkey *ssh2key = NULL;
    char* fingerprint = 0;

    printf("fzputtygen\n");
    printf("Copyright (C) 2008-2016  Tim Kosse\n");
    printf("Based on PuTTY's puttygen\n");
    printf("Copyright (C) 1997-2015  Simon Tatham and the PuTTY team\n");
    printf("Converts private SSH keys into PuTTY's format.\n");
    printf("This program is used by FileZilla and not intended to be used directly.\n");
    printf("Use the puttygen tool from PuTTY for a human-usable tool.\n");
    printf("\n");
    fflush(stdout);

    while (1) {
	sfree(line);

	line = fgetline(stdin);
	if (!line || !*line || *line == '\n')
	    break;

	line[strlen(line) - 1] = 0;
	char* cmd = line, *args = line;
	
	while (*args) {
	    if (*args == ' ') {
		*(args++) = 0;
		break;
	    }
	    args++;
	}
	if (!*args)
	    args = 0;

	if (!strcmp(cmd, "file")) {
	    char const* ret = NULL;
	    if (ssh2key) {
		ssh2key->alg->freekey(ssh2key->data);
		sfree(ssh2key);
		ssh2key = 0;
	    }
	    sfree(passphrase);
	    passphrase = 0;
	    sfree(fingerprint);
	    fingerprint = 0;
	    
	    if (!args) {
		fzprintf(sftpError, "No argument given");
		continue;
	    }

	    if (infilename) {
		filename_free(infilename);
	    }
	    infilename = filename_from_str(args);

	    intype = key_type(infilename);
	    switch (intype)
	    {
	    case SSH_KEYTYPE_SSH1:
		ret = "incompatible";
		intype = SSH_KEYTYPE_UNOPENABLE;
		break;
	    case SSH_KEYTYPE_SSH2:
		ret = "ok";
		encrypted = ssh2_userkey_encrypted(infilename, &origcomment);
		break;
	    case SSH_KEYTYPE_UNKNOWN:
	    case SSH_KEYTYPE_UNOPENABLE:
	    default:
		ret = "error";
		intype = SSH_KEYTYPE_UNOPENABLE;
		break;
	    case SSH_KEYTYPE_OPENSSH_PEM:
	    case SSH_KEYTYPE_OPENSSH_NEW:
	    case SSH_KEYTYPE_SSHCOM:
		encrypted = import_encrypted(infilename, intype, &origcomment);
		ret = encrypted ? "convertible" : "ok";
		break;
	    }
	    fzprintf(sftpReply, "%s", ret);
	}
	else if (!strcmp(cmd, "encrypted")) {
	    if (intype == SSH_KEYTYPE_UNOPENABLE) {
		fzprintf(sftpError, "No key file opened");
		continue;
	    }
	    
	    fzprintf(sftpReply, "%d", encrypted ? 1 : 0);
	}
	else if (!strcmp(cmd, "comment")) {
	    if (intype == SSH_KEYTYPE_UNOPENABLE) {
		fzprintf(sftpError, "No key file opened");
		continue;
	    }
	    if (ssh2key && ssh2key->comment) {
		fzprintf(sftpReply, "%s", ssh2key->comment);
	    }
	    else if (origcomment)
		fzprintf(sftpReply, "%s", origcomment);
	    else
		fzprintf(sftpReply, "");
	}
	else if (!strcmp(cmd, "password")) {
	    const char* error = NULL;

	    if (!args) {
		fzprintf(sftpError, "No argument given");
		continue;
	    }

	    if (intype == SSH_KEYTYPE_UNOPENABLE) {
		fzprintf(sftpError, "No key file opened");
		continue;
	    }

	    if (!encrypted) {
		fzprintf(sftpError, "File is not encrypted");
		continue;
	    }

	    if (ssh2key) {
		fzprintf(sftpError, "Already opened file");
		continue;
	    }

	    sfree(passphrase);
	    passphrase = strdup(args);

	    switch (intype) {
		case SSH_KEYTYPE_SSH2:
		    ssh2key = ssh2_load_userkey(infilename, passphrase, &error);
		    break;
		case SSH_KEYTYPE_OPENSSH_PEM:
		case SSH_KEYTYPE_OPENSSH_NEW:
		case SSH_KEYTYPE_SSHCOM:
		    ssh2key = import_ssh2(infilename, intype, passphrase, &error);
		    break;
		default:
		    break;
	    }
	    if (ssh2key == SSH2_WRONG_PASSPHRASE) {
		error = "wrong passphrase";
		ssh2key = 0;
	    }
	    if (ssh2key) {
		error = NULL;
	    }
	    else if (!error) {
		error = "unknown error";
	    }

	    if (error)
		fzprintf(sftpError, "Error loading file: %s", error);
	    else
		fzprintf(sftpReply, "");
	}
	else if (!strcmp(cmd, "fingerprint")) {
	    const char* error = 0;

	    if (!fingerprint) {
		if (ssh2key) {
		    fingerprint = ssh2_fingerprint(ssh2key->alg, ssh2key->data);
		}
		else {
		    switch (intype) {
			 case SSH_KEYTYPE_SSH2:
			{
			    void* ssh2blob;
			    int bloblen = 0;
			    char* comment = NULL;

			    ssh2blob = ssh2_userkey_loadpub(infilename, 0, &bloblen, &comment, &error);
			    if (ssh2blob) {
				fingerprint = ssh2_fingerprint_blob(ssh2blob, bloblen);
				sfree(ssh2blob);
			    }
			    else if (!error) {
				error = "unknown error";
			    }

			    if (comment) {
				sfree(origcomment);
				origcomment = comment;
			    }
			    break;
			}
			case SSH_KEYTYPE_OPENSSH_PEM:
			case SSH_KEYTYPE_OPENSSH_NEW:
			case SSH_KEYTYPE_SSHCOM:
			    ssh2key = import_ssh2(infilename, intype, "", &error);
			    if (ssh2key) {
				if (ssh2key != SSH2_WRONG_PASSPHRASE) {
				    error = NULL;
				    fingerprint = ssh2_fingerprint(ssh2key->alg, ssh2key->data);
				}
				else {
				    ssh2key = NULL;
				    error = "wrong passphrase";
				}
			    }
			    else if (!error)
				error = "unknown error";
			    break;
			default:
			    error = "No file loaded";
			    break;
		    }
		}
	    }

	    if (!fingerprint && !error) {
		error = "Could not get fingerprint";
	    }

	    if (error)
		fzprintf(sftpError, "Error loading file: %s", error);
	    else
		fzprintf(sftpReply, "%s", fingerprint);
	}
	else if (!strcmp(cmd, "write")) {
	    Filename* outfilename;

	    int ret;
	    if (!args) {
		fzprintf(sftpError, "No argument given");
		continue;
	    }

	    if (!ssh2key) {
		fzprintf(sftpError, "No key loaded");
		continue;
	    }

	    outfilename = filename_from_str(args);

	    ret = ssh2_save_userkey(outfilename, ssh2key, passphrase);
	     if (!ret) {
		fzprintf(sftpError, "Unable to save SSH-2 private key");
		continue;
	    }

	    filename_free(outfilename);

	    fzprintf(sftpReply, "");
	}
	else
		fzprintf(sftpError, "Unknown command");
    }

    if (infilename) {
	filename_free(infilename);
    }
    sfree(line);
    sfree(passphrase);
    if (ssh2key) {
	ssh2key->alg->freekey(ssh2key->data);
	sfree(ssh2key);
    }
    sfree(fingerprint);
    sfree(origcomment);

    return 0;
}
コード例 #9
0
ファイル: cmdgen.c プロジェクト: Typz/FileZilla
int main(int argc, char **argv)
{
    Filename *infilename = NULL, *outfilename = NULL;
    int intype = SSH_KEYTYPE_UNOPENABLE;
    int encrypted = 0;
    char* origcomment = 0;
    char* line = 0;
    char* passphrase = 0;
    struct ssh2_userkey *ssh2key = NULL;
    struct RSAKey *ssh1key = NULL;

    printf("fzputtygen\n");
    printf("Copyright (C) 2008-2015  Tim Kosse\n");
    printf("Based on PuTTY's puttygen\n");
    printf("Copyright (C) 1997-2015  Simon Tatham and the PuTTY team\n");
    printf("Converts private SSH keys into PuTTY's format.\n");
    printf("This program is used by FileZilla and not intended to be used directly.\n");
    printf("Use the puttygen tool from PuTTY for a human-usable tool.\n");
    printf("\n");
    fflush(stdout);

    while (1)
    {
        if (line)
            sfree(line);

        line = fgetline(stdin);
        if (!line || !*line || *line == '\n')
            break;

        line[strlen(line) - 1] = 0;
        char* cmd = line, *args = line;

        while (*args)
        {
            if (*args == ' ') {
                *(args++) = 0;
                break;
            }
            args++;
        }
        if (!*args)
            args = 0;

        if (!strcmp(cmd, "file"))
        {
            if (ssh1key)
            {
                freersakey(ssh1key);
                ssh1key = 0;
            }
            if (ssh2key)
            {
                ssh2key->alg->freekey(ssh2key->data);
                sfree(ssh2key);
                ssh2key = 0;
            }
            if (passphrase)
            {
                sfree(passphrase);
                passphrase = 0;
            }

            if (!args) {
                fzprintf(sftpError, "No argument given");
                continue;
            }

            infilename = filename_from_str(args);

            intype = key_type(infilename);
            switch (intype)
            {
            case SSH_KEYTYPE_SSH1:
            case SSH_KEYTYPE_SSH2:
                fzprintf(sftpReply, "0");
                break;
            case SSH_KEYTYPE_UNKNOWN:
            case SSH_KEYTYPE_UNOPENABLE:
            default:
                fzprintf(sftpReply, "2");
                intype = SSH_KEYTYPE_UNOPENABLE;
                break;
            case SSH_KEYTYPE_OPENSSH:
            case SSH_KEYTYPE_SSHCOM:
                fzprintf(sftpReply, "1");
                break;
            }
        }
        else if (!strcmp(cmd, "encrypted"))
        {
            if (intype == SSH_KEYTYPE_UNOPENABLE)
            {
                fzprintf(sftpError, "No keyfile opened");
                continue;
            }

            if (intype == SSH_KEYTYPE_SSH1)
                encrypted = rsakey_encrypted(infilename, &origcomment);
            else if (intype == SSH_KEYTYPE_SSH2)
                encrypted = ssh2_userkey_encrypted(infilename, &origcomment);
            else
                encrypted = import_encrypted(infilename, intype, &origcomment);

            fzprintf(sftpReply, "%d", encrypted ? 1 : 0);
        }
        else if (!strcmp(cmd, "comment"))
        {
            if (intype == SSH_KEYTYPE_UNOPENABLE)
            {
                fzprintf(sftpError, "No keyfile opened");
                continue;
            }
            if (origcomment)
                fzprintf(sftpReply, "%s", origcomment);
            else
                fzprintf(sftpReply, "");
        }
        else if (!strcmp(cmd, "password"))
        {
            if (!args) {
                fzprintf(sftpError, "No argument given");
                continue;
            }

            if (intype == SSH_KEYTYPE_UNOPENABLE)
            {
                fzprintf(sftpError, "No keyfile opened");
                continue;
            }

            if (passphrase)
                sfree(passphrase);
            passphrase = strdup(args);
            fzprintf(sftpReply, "");
        }
        else if (!strcmp(cmd, "load"))
        {
            const char* error = 0;

            if (ssh1key)
            {
                freersakey(ssh1key);
                ssh1key = 0;
            }
            if (ssh2key)
            {
                ssh2key->alg->freekey(ssh2key->data);
                sfree(ssh2key);
                ssh2key = 0;
            }

            if (intype == SSH_KEYTYPE_UNOPENABLE)
            {
                fzprintf(sftpError, "No keyfile opened");
                continue;
            }

            if (encrypted && !passphrase)
            {
                fzprintf(sftpError, "No password given");
                continue;
            }

            switch (intype)
            {
                int ret;

            case SSH_KEYTYPE_SSH1:
                ssh1key = snew(struct RSAKey);
                ret = loadrsakey(infilename, ssh1key, passphrase, &error);
                if (ret > 0)
                    error = NULL;
                else if (!error)
                    error = "unknown error";
                break;

            case SSH_KEYTYPE_SSH2:
                ssh2key = ssh2_load_userkey(infilename, passphrase, &error);
                if (ssh2key == SSH2_WRONG_PASSPHRASE)
                {
                    error = "wrong passphrase";
                    ssh2key = 0;
                }
                else if (ssh2key)
                    error = NULL;
                else if (!error)
                    error = "unknown error";
                break;

            case SSH_KEYTYPE_OPENSSH:
            case SSH_KEYTYPE_SSHCOM:
                ssh2key = import_ssh2(infilename, intype, passphrase, &error);
                if (ssh2key) {
                    if (ssh2key != SSH2_WRONG_PASSPHRASE)
                        error = NULL;
                    else {
                        ssh2key = NULL;
                        error = "wrong passphrase";
                    }
                } else if (!error)
                    error = "unknown error";
                break;
            default:
                assert(0);
            }

            if (error)
                fzprintf(sftpError, "Error loading file: %s", error);
            else
                fzprintf(sftpReply, "");
        }
        else if (!strcmp(cmd, "data"))
        {
            if (!ssh1key && !ssh2key) {
                fzprintf(sftpError, "No key loaded");
                continue;
            }

            if (ssh1key)
            {
                char data[512];
                char* p;

                strcpy(data, "ssh1 ");
                p = data + strlen(data);
                rsa_fingerprint(p, sizeof(data) - (p - data), ssh1key);
                fzprintf(sftpReply, "%s", data);
                continue;
            }

            if (ssh2key)
            {
                char* fingerprint = ssh2key->alg->fingerprint(ssh2key->data);
                if (fingerprint)
                {
                    fzprintf(sftpReply, "%s", fingerprint);
                    continue;
                }
            }
            fzprintf(sftpReply, "");
        }
        else if (!strcmp(cmd, "write"))
        {
            int ret;
            if (!args) {
                fzprintf(sftpError, "No argument given");
                continue;
            }

            if (!ssh1key && !ssh2key) {
                fzprintf(sftpError, "No key loaded");
                continue;
            }

            outfilename = filename_from_str(args);

            if (ssh1key)
            {
                ret = saversakey(outfilename, ssh1key, 0);
                if (!ret) {
                    fzprintf(sftpError, "Unable to save SSH-1 private key");
                    continue;
                }
            }
            else if (ssh2key)
            {
                ret = ssh2_save_userkey(outfilename, ssh2key, 0);
                if (!ret) {
                    fzprintf(sftpError, "Unable to save SSH-2 private key");
                    continue;
                }
            }

            fzprintf(sftpReply, "");
        }
        else
            fzprintf(sftpError, "Unknown command");
    }
コード例 #10
0
ファイル: wincons.c プロジェクト: ErichKrause/filezilla
int verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
                        char *keystr, char *fingerprint,
                        void (*callback)(void *ctx, int result), void *ctx)
{
    int ret;
    HANDLE hin;
    DWORD savemode, i;

    static const char absentmsg_batch[] =
	"The server's host key is not cached in the registry. You\n"
	"have no guarantee that the server is the computer you\n"
	"think it is.\n"
	"The server's %s key fingerprint is:\n"
	"%s\n"
	"Connection abandoned.\n";
    static const char absentmsg[] =
	"The server's host key is not cached in the registry. You\n"
	"have no guarantee that the server is the computer you\n"
	"think it is.\n"
	"The server's %s key fingerprint is:\n"
	"%s\n"
	"If you trust this host, enter \"y\" to add the key to\n"
	"PuTTY's cache and carry on connecting.\n"
	"If you want to carry on connecting just once, without\n"
	"adding the key to the cache, enter \"n\".\n"
	"If you do not trust this host, press Return to abandon the\n"
	"connection.\n"
	"Store key in cache? (y/n) ";

    static const char wrongmsg_batch[] =
	"WARNING - POTENTIAL SECURITY BREACH!\n"
	"The server's host key does not match the one PuTTY has\n"
	"cached in the registry. This means that either the\n"
	"server administrator has changed the host key, or you\n"
	"have actually connected to another computer pretending\n"
	"to be the server.\n"
	"The new %s key fingerprint is:\n"
	"%s\n"
	"Connection abandoned.\n";
    static const char wrongmsg[] =
	"WARNING - POTENTIAL SECURITY BREACH!\n"
	"The server's host key does not match the one PuTTY has\n"
	"cached in the registry. This means that either the\n"
	"server administrator has changed the host key, or you\n"
	"have actually connected to another computer pretending\n"
	"to be the server.\n"
	"The new %s key fingerprint is:\n"
	"%s\n"
	"If you were expecting this change and trust the new key,\n"
	"enter \"y\" to update PuTTY's cache and continue connecting.\n"
	"If you want to carry on connecting but without updating\n"
	"the cache, enter \"n\".\n"
	"If you want to abandon the connection completely, press\n"
	"Return to cancel. Pressing Return is the ONLY guaranteed\n"
	"safe choice.\n"
	"Update cached key? (y/n, Return cancels connection) ";

    static const char abandoned[] = "Connection abandoned.";

    char line[32];

    /*
     * Verify the key against the registry.
     */
    ret = verify_host_key(host, port, keytype, keystr);

    if (ret == 0)		       /* success - key matched OK */
	return 1;

    if (ret == 2) {		       /* key was different */
	if (console_batch_mode) {
	    fprintf(stderr, wrongmsg_batch, keytype, fingerprint);
            return 0;
	}
	fzprintf_raw(sftpRequest, "%d%s\n%d\n%s\n", (int)sftpReqHostkeyChanged, host, port, fingerprint);
    }
    if (ret == 1) {		       /* key was absent */
	fzprintf_raw(sftpRequest, "%d%s\n%d\n%s\n", (int)sftpReqHostkey, host, port, fingerprint);
    }

    hin = GetStdHandle(STD_INPUT_HANDLE);
    GetConsoleMode(hin, &savemode);
    SetConsoleMode(hin, (savemode | 
			 ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
    ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
    SetConsoleMode(hin, savemode);

    if (line[0] != '\0' && line[0] != '\r' && line[0] != '\n') {
	if (line[0] == 'y' || line[0] == 'Y')
	    store_host_key(host, port, keytype, keystr);
        return 1;
    } else {
	fzprintf(sftpError, abandoned);
        return 0;
    }
}