outfiletmp = dupcat(outfile, ".tmp");
outfiletmp = dupcat(outfile, ".tmp", NULL);
int main(int argc, char **argv){    char *infile = NULL;    Filename infilename;    enum { NOKEYGEN, RSA1, RSA2, DSA } keytype = NOKEYGEN;        char *outfile = NULL, *outfiletmp = NULL;    Filename outfilename;    enum { PRIVATE, PUBLIC, PUBLICO, FP, OPENSSH, SSHCOM } outtype = PRIVATE;    int bits = 1024;    char *comment = NULL, *origcomment = NULL;    int change_passphrase = FALSE;    int errs = FALSE, nogo = FALSE;    int intype = SSH_KEYTYPE_UNOPENABLE;    int sshver = 0;    struct ssh2_userkey *ssh2key = NULL;    struct RSAKey *ssh1key = NULL;    char *ssh2blob = NULL, *ssh2alg = NULL;    const struct ssh_signkey *ssh2algf = NULL;    int ssh2bloblen;    char *passphrase = NULL;    int load_encrypted;    progfn_t progressfn = is_interactive() ? progress_update : no_progress;    /* ------------------------------------------------------------------     * Parse the command line to figure out what we've been asked to do.     */    /*     * If run with no arguments at all, print the usage message and     * return success.     */    if (argc <= 1) {	usage();	return 0;    }    /*     * Parse command line arguments.     */    while (--argc) {	char *p = *++argv;	if (*p == '-') {	    /*	     * An option.	     */	    while (p && *++p) {		char c = *p;		switch (c) {		  case '-':		    /*		     * Long option.		     */		    {			char *opt, *val;			opt = p++;     /* opt will have _one_ leading - */			while (*p && *p != '=')			    p++;	       /* find end of option */			if (*p == '=') {			    *p++ = '\0';			    val = p;			} else			    val = NULL;			if (!strcmp(opt, "-help")) {			    help();			    nogo = TRUE;			} else if (!strcmp(opt, "-version")) {			    showversion();			    nogo = TRUE;			}			/*			 * A sample option requiring an argument:			 * 			 * else if (!strcmp(opt, "-output")) {			 *     if (!val)			 *         errs = TRUE, error(err_optnoarg, opt);			 *     else			 *         ofile = val;			 * }			 */			else {			    errs = TRUE;			    fprintf(stderr,				    "puttygen: no such option `--%s'\n", opt);			}		    }		    p = NULL;		    break;		  case 'h':		  case 'V':		  case 'P':		  case 'l':		  case 'L':		  case 'p':		  case 'q':		    /*		     * Option requiring no parameter.		     */		    switch (c) {		      case 'h':			help();			nogo = TRUE;			break;		      case 'V':			showversion();			nogo = TRUE;			break;		      case 'P':			change_passphrase = TRUE;			break;		      case 'l':			outtype = FP;			break;		      case 'L':			outtype = PUBLICO;			break;		      case 'p':			outtype = PUBLIC;			break;		      case 'q':			progressfn = no_progress;			break;		    }		    break;		  case 't':		  case 'b':		  case 'C':		  case 'O':		  case 'o':		    /*		     * Option requiring parameter.		     */		    p++;		    if (!*p && argc > 1)			--argc, p = *++argv;		    else if (!*p) {			fprintf(stderr, "puttygen: option `-%c' expects a"				" parameter\n", c);			errs = TRUE;		    }		    /*		     * Now c is the option and p is the parameter.		     */		    switch (c) {		      case 't':			if (!strcmp(p, "rsa") || !strcmp(p, "rsa2"))			    keytype = RSA2, sshver = 2;			else if (!strcmp(p, "rsa1"))			    keytype = RSA1, sshver = 1;			else if (!strcmp(p, "dsa") || !strcmp(p, "dss"))			    keytype = DSA, sshver = 2;			else {			    fprintf(stderr,				    "puttygen: unknown key type `%s'\n", p);			    errs = TRUE;			}                        break;		      case 'b':			bits = atoi(p);                        break;		      case 'C':			comment = p;                        break;		      case 'O':			if (!strcmp(p, "public"))			    outtype = PUBLIC;			else if (!strcmp(p, "public-openssh"))			    outtype = PUBLICO;			else if (!strcmp(p, "private"))			    outtype = PRIVATE;			else if (!strcmp(p, "fingerprint"))			    outtype = FP;			else if (!strcmp(p, "private-openssh"))			    outtype = OPENSSH, sshver = 2;			else if (!strcmp(p, "private-sshcom"))			    outtype = SSHCOM, sshver = 2;			else {			    fprintf(stderr,				    "puttygen: unknown output type `%s'\n", p);			    errs = TRUE;			}                        break;		      case 'o':			outfile = p;                        break;		    }		    p = NULL;	       /* prevent continued processing */		    break;		  default:		    /*		     * Unrecognised option.		     */		    errs = TRUE;		    fprintf(stderr, "puttygen: no such option `-%c'\n", c);		    break;		}	    }	} else {	    /*	     * A non-option argument.	     */	    if (!infile)		infile = p;	    else {		errs = TRUE;		fprintf(stderr, "puttygen: cannot handle more than one"			" input file\n");	    }	}    }    if (errs)	return 1;    if (nogo)	return 0;    /*     * If run with at least one argument _but_ not the required     * ones, print the usage message and return failure.     */    if (!infile && keytype == NOKEYGEN) {	usage();	return 1;    }    /* ------------------------------------------------------------------     * Figure out further details of exactly what we're going to do.     */    /*     * Bomb out if we've been asked to both load and generate a     * key.     */    if (keytype != NOKEYGEN && intype) {	fprintf(stderr, "puttygen: cannot both load and generate a key\n");	return 1;    }    /*     * Analyse the type of the input file, in case this affects our     * course of action.     */    if (infile) {	infilename = filename_from_str(infile);	intype = key_type(&infilename);	switch (intype) {	    /*	     * It would be nice here to be able to load _public_	     * key files, in any of a number of forms, and (a)	     * convert them to other public key types, (b) print	     * out their fingerprints. Or, I suppose, for real	     * orthogonality, (c) change their comment!	     * 	     * In fact this opens some interesting possibilities.	     * Suppose ssh2_userkey_loadpub() were able to load	     * public key files as well as extracting the public	     * key from private ones. And suppose I did the thing	     * I've been wanting to do, where specifying a	     * particular private key file for authentication	     * causes any _other_ key in the agent to be discarded.	     * Then, if you had an agent forwarded to the machine	     * you were running Unix PuTTY or Plink on, and you	     * needed to specify which of the keys in the agent it	     * should use, you could do that by supplying a	     * _public_ key file, thus not needing to trust even	     * your encrypted private key file to the network. Ooh!	     */	  case SSH_KEYTYPE_UNOPENABLE:	  case SSH_KEYTYPE_UNKNOWN:	    fprintf(stderr, "puttygen: unable to load file `%s': %s\n",		    infile, key_type_to_str(intype));	    return 1;	  case SSH_KEYTYPE_SSH1:	    if (sshver == 2) {		fprintf(stderr, "puttygen: conversion from SSH1 to SSH2 keys"			" not supported\n");		return 1;	    }	    sshver = 1;	    break;	  case SSH_KEYTYPE_SSH2:	  case SSH_KEYTYPE_OPENSSH:	  case SSH_KEYTYPE_SSHCOM:	    if (sshver == 1) {		fprintf(stderr, "puttygen: conversion from SSH2 to SSH1 keys"			" not supported\n");		return 1;	    }	    sshver = 2;	    break;	}    }    /*     * Determine the default output file, if none is provided.     *      * This will usually be equal to stdout, except that if the     * input and output file formats are the same then the default     * output is to overwrite the input.     *      * Also in this code, we bomb out if the input and output file     * formats are the same and no other action is performed.     */    if ((intype == SSH_KEYTYPE_SSH1 && outtype == PRIVATE) ||	(intype == SSH_KEYTYPE_SSH2 && outtype == PRIVATE) ||	(intype == SSH_KEYTYPE_OPENSSH && outtype == OPENSSH) ||	(intype == SSH_KEYTYPE_SSHCOM && outtype == SSHCOM)) {	if (!outfile) {	    outfile = infile;	    outfiletmp = dupcat(outfile, ".tmp");	}	if (!change_passphrase && !comment) {	    fprintf(stderr, "puttygen: this command would perform no useful"		    " action\n");	    return 1;	}    } else {	if (!outfile) {	    /*	     * Bomb out rather than automatically choosing to write	     * a private key file to stdout.	     */	    if (outtype==PRIVATE || outtype==OPENSSH || outtype==SSHCOM) {		fprintf(stderr, "puttygen: need to specify an output file\n");		return 1;	    }	}    }    /*     * Figure out whether we need to load the encrypted part of the     * key. This will be the case if either (a) we need to write     * out a private key format, or (b) the entire input key file     * is encrypted.     */    if (outtype == PRIVATE || outtype == OPENSSH || outtype == SSHCOM ||	intype == SSH_KEYTYPE_OPENSSH || intype == SSH_KEYTYPE_SSHCOM)	load_encrypted = TRUE;    else	load_encrypted = FALSE;    /* ------------------------------------------------------------------     * Now we're ready to actually do some stuff.     */    /*     * Either load or generate a key.     */    if (keytype != NOKEYGEN) {	char *entropy;	char default_comment[80];	time_t t;	struct tm *tm;	struct progress prog;	prog.phase = -1;	prog.current = -1;	time(&t);	tm = localtime(&t);	if (keytype == DSA)	    strftime(default_comment, 30, "dsa-key-%Y%m%d", tm);	else	    strftime(default_comment, 30, "rsa-key-%Y%m%d", tm);	random_init();	entropy = get_random_data(bits / 8);	random_add_heavynoise(entropy, bits / 8);	memset(entropy, 0, bits/8);	sfree(entropy);	if (keytype == DSA) {	    struct dss_key *dsskey = snew(struct dss_key);	    dsa_generate(dsskey, bits, progressfn, &prog);	    ssh2key = snew(struct ssh2_userkey);	    ssh2key->data = dsskey;	    ssh2key->alg = &ssh_dss;	    ssh1key = NULL;	} else {	    struct RSAKey *rsakey = snew(struct RSAKey);	    rsa_generate(rsakey, bits, progressfn, &prog);	    if (keytype == RSA1) {		ssh1key = rsakey;	    } else {		ssh2key = snew(struct ssh2_userkey);		ssh2key->data = rsakey;		ssh2key->alg = &ssh_rsa;	    }	}	progressfn(&prog, PROGFN_PROGRESS, INT_MAX, -1);	if (ssh2key)	    ssh2key->comment = dupstr(default_comment);	if (ssh1key)	    ssh1key->comment = dupstr(default_comment);    } else {	const char *error = NULL;	int encrypted;	assert(infile != NULL);	/*	 * Find out whether the input key is encrypted.	 */	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);	/*	 * If so, ask for a passphrase.	 */	if (encrypted && load_encrypted) {	    passphrase = snewn(512, char);	    if (!console_get_line("Enter passphrase to load key: ",				  passphrase, 512, TRUE)) {		perror("puttygen: unable to read passphrase");		return 1;	    }	} else {	    passphrase = NULL;	}	switch (intype) {	    int ret;	  case SSH_KEYTYPE_SSH1:	    ssh1key = snew(struct RSAKey);	    if (!load_encrypted) {		void *vblob;		char *blob;		int n, bloblen;		ret = rsakey_pubblob(&infilename, &vblob, &bloblen, &error);		blob = (char *)vblob;		n = 4;		       /* skip modulus bits */		n += ssh1_read_bignum(blob + n, &ssh1key->exponent);		n += ssh1_read_bignum(blob + n, &ssh1key->modulus);		ssh1key->comment = NULL;	    } else {		ret = loadrsakey(&infilename, ssh1key, passphrase, &error);	    }	    if (ret)		error = NULL;	    else if (!error)		error = "unknown error";	    break;	  case SSH_KEYTYPE_SSH2:	    if (!load_encrypted) {		ssh2blob = ssh2_userkey_loadpub(&infilename, &ssh2alg,						&ssh2bloblen, &error);		ssh2algf = find_pubkey_alg(ssh2alg);		if (ssh2algf)		    bits = ssh2algf->pubkey_bits(ssh2blob, ssh2bloblen);		else		    bits = -1;	    } else {		ssh2key = ssh2_load_userkey(&infilename, passphrase, &error);	    }	    if (ssh2key || ssh2blob)		error = NULL;	    else if (!error) {		if (ssh2key == SSH2_WRONG_PASSPHRASE)		    error = "wrong passphrase";		else		    error = "unknown error";	    }	    break;	  case SSH_KEYTYPE_OPENSSH:	  case SSH_KEYTYPE_SSHCOM:	    ssh2key = import_ssh2(&infilename, intype, passphrase);	    if (ssh2key)		error = NULL;	    else if (!error) {		if (ssh2key == SSH2_WRONG_PASSPHRASE)		    error = "wrong passphrase";		else		    error = "unknown error";	    }	    break;	  default:	    assert(0);	}	if (error) {	    fprintf(stderr, "puttygen: error loading `%s': %s\n",		    infile, error);	    return 1;	}    }    /*     * Change the comment if asked to.     */    if (comment) {	if (sshver == 1) {	    assert(ssh1key);	    sfree(ssh1key->comment);	    ssh1key->comment = dupstr(comment);	} else {	    assert(ssh2key);	    sfree(ssh2key->comment);	    ssh2key->comment = dupstr(comment);	}    }    /*     * Prompt for a new passphrase if we have been asked to, or if     * we have just generated a key.     */    if (change_passphrase || keytype != NOKEYGEN) {	char *passphrase2;	if (passphrase) {	    memset(passphrase, 0, strlen(passphrase));	    sfree(passphrase);	}	passphrase = snewn(512, char);	passphrase2 = snewn(512, char);	if (!console_get_line("Enter passphrase to save key: ",			      passphrase, 512, TRUE) ||	    !console_get_line("Re-enter passphrase to verify: ",			      passphrase2, 512, TRUE)) {	    perror("puttygen: unable to read new passphrase");	    return 1;	}	if (strcmp(passphrase, passphrase2)) {	    fprintf(stderr, "puttygen: passphrases do not match\n");	    return 1;	}	memset(passphrase2, 0, strlen(passphrase2));	sfree(passphrase2);	if (!*passphrase) {	    sfree(passphrase);	    passphrase = NULL;	}    }    /*     * Write output.     *      * (In the case where outfile and outfiletmp are both NULL,     * there is no semantic reason to initialise outfilename at     * all; but we have to write _something_ to it or some compiler     * will probably complain that it might be used uninitialised.)     */    if (outfiletmp)	outfilename = filename_from_str(outfiletmp);    else	outfilename = filename_from_str(outfile ? outfile : "");    switch (outtype) {	int ret;      case PRIVATE:	if (sshver == 1) {	    assert(ssh1key);	    ret = saversakey(&outfilename, ssh1key, passphrase);	    if (!ret) {		fprintf(stderr, "puttygen: unable to save SSH1 private key\n");		return 1;	    }	} else {	    assert(ssh2key);	    ret = ssh2_save_userkey(&outfilename, ssh2key, passphrase); 	    if (!ret) {		fprintf(stderr, "puttygen: unable to save SSH2 private key\n");		return 1;	    }	}	if (outfiletmp)	    move(outfiletmp, outfile);	break;      case PUBLIC:      case PUBLICO:	if (sshver == 1) {	    FILE *fp;	    char *dec1, *dec2;	    assert(ssh1key);	    if (outfile)		fp = f_open(outfilename, "w");	    else		fp = stdout;	    dec1 = bignum_decimal(ssh1key->exponent);	    dec2 = bignum_decimal(ssh1key->modulus);	    fprintf(fp, "%d %s %s %s\n", bignum_bitcount(ssh1key->modulus),		    dec1, dec2, ssh1key->comment);	    sfree(dec1);	    sfree(dec2);	    if (outfile)		fclose(fp);	} else if (outtype == PUBLIC) {	    if (!ssh2blob) {		assert(ssh2key);		ssh2blob = ssh2key->alg->public_blob(ssh2key->data,						     &ssh2bloblen);	    }	    save_ssh2_pubkey(outfile, ssh2key ? ssh2key->comment : origcomment,			     ssh2blob, ssh2bloblen);	} else if (outtype == PUBLICO) {	    char *buffer, *p;	    int i;	    FILE *fp;	    if (!ssh2blob) {		assert(ssh2key);		ssh2blob = ssh2key->alg->public_blob(ssh2key->data,						     &ssh2bloblen);	    }	    if (!ssh2alg) {		assert(ssh2key);		ssh2alg = ssh2key->alg->name;	    }	    if (ssh2key)		comment = ssh2key->comment;	    else		comment = origcomment;	    buffer = snewn(strlen(ssh2alg) +			   4 * ((ssh2bloblen+2) / 3) +			   strlen(comment) + 3, char);	    strcpy(buffer, ssh2alg);	    p = buffer + strlen(buffer);	    *p++ = ' ';	    i = 0;	    while (i < ssh2bloblen) {		int n = (ssh2bloblen - i < 3 ? ssh2bloblen - i : 3);		base64_encode_atom(ssh2blob + i, n, p);		i += n;		p += 4;	    }	    if (*comment) {		*p++ = ' ';		strcpy(p, comment);	    } else		*p++ = '\0';	    if (outfile)		fp = f_open(outfilename, "w");	    else		fp = stdout;	    fprintf(fp, "%s\n", buffer);	    if (outfile)		fclose(fp);	    sfree(buffer);	}	break;      case FP:	{	    FILE *fp;	    char *fingerprint;	    if (sshver == 1) {		assert(ssh1key);		fingerprint = snewn(128, char);		rsa_fingerprint(fingerprint, 128, ssh1key);	    } else {		if (ssh2key) {		    fingerprint = ssh2key->alg->fingerprint(ssh2key->data);		} else {		    assert(ssh2blob);		    fingerprint = blobfp(ssh2alg, bits, ssh2blob, ssh2bloblen);		}	    }	    if (outfile)		fp = f_open(outfilename, "w");	    else		fp = stdout;	    fprintf(fp, "%s\n", fingerprint);	    if (outfile)		fclose(fp);	    sfree(fingerprint);	}	break;	      case OPENSSH:      case SSHCOM:	assert(sshver == 2);	assert(ssh2key);	ret = export_ssh2(&outfilename, outtype, ssh2key, passphrase);	if (!ret) {	    fprintf(stderr, "puttygen: unable to export key\n");	    return 1;	}	if (outfiletmp)	    move(outfiletmp, outfile);	break;    }    if (passphrase) {	memset(passphrase, 0, strlen(passphrase));	sfree(passphrase);    }    if (ssh1key)	freersakey(ssh1key);    if (ssh2key) {	ssh2key->alg->freekey(ssh2key->data);	sfree(ssh2key);    }    return 0;}