if (options.password) { pwdata.source = PW_PLAINTEXT; pwdata.data = options.password; } pwcb = SECU_GetModulePassword; pwcb_arg = (void *)&pwdata;
main(int argc, char **argv){    FILE *outFile;    NSSCMSMessage *cmsg = NULL;    PRFileDesc *inFile;    PLOptState *optstate;    PLOptStatus status;    Mode mode = UNKNOWN;    PK11PasswordFunc pwcb;    void *pwcb_arg;    struct decodeOptionsStr decodeOptions = { 0 };    struct signOptionsStr signOptions = { 0 };    struct envelopeOptionsStr envelopeOptions = { 0 };    struct certsonlyOptionsStr certsonlyOptions = { 0 };    struct encryptOptionsStr encryptOptions = { 0 };    struct optionsStr options = { 0 };    int exitstatus;    static char *ptrarray[128] = { 0 };    int nrecipients = 0;    char *str, *tok;    char *envFileName;    SECItem input = { 0, 0, 0};    SECItem output = { 0, 0, 0};    SECItem dummy = { 0, 0, 0 };    SECItem envmsg = { 0, 0, 0 };    SECStatus rv;    progName = strrchr(argv[0], '/');    if (!progName)       progName = strrchr(argv[0], '\\');    progName = progName ? progName+1 : argv[0];    inFile = PR_STDIN;    outFile = stdout;    envFileName = NULL;    mode = UNKNOWN;    decodeOptions.contentFile = NULL;    decodeOptions.suppressContent = PR_FALSE;    decodeOptions.headerLevel = -1;    options.certUsage = certUsageEmailSigner;    options.password = NULL;    signOptions.nickname = NULL;    signOptions.detached = PR_FALSE;    signOptions.signingTime = PR_FALSE;    signOptions.smimeProfile = PR_FALSE;    signOptions.encryptionKeyPreferenceNick = NULL;    signOptions.hashAlgTag = SEC_OID_SHA1;    envelopeOptions.recipients = NULL;    encryptOptions.recipients = NULL;    encryptOptions.envmsg = NULL;    encryptOptions.envFile = NULL;    encryptOptions.bulkalgtag = SEC_OID_UNKNOWN;    encryptOptions.bulkkey = NULL;    encryptOptions.keysize = -1;    /*     * Parse command line arguments     */    optstate = PL_CreateOptState(argc, argv, 				 "CDEGH:N:OPSTY:c:d:e:h:i:no:p:r:s:u:v");    while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {	switch (optstate->option) {	case 'C':	    mode = ENCRYPT;	    break;	case 'D':	    mode = DECODE;	    break;	case 'E':	    mode = ENVELOPE;	    break;	case 'G':	    if (mode != SIGN) {		fprintf(stderr, 		        "%s: option -G only supported with option -S.\n", 		        progName);		Usage(progName);		exit(1);	    }	    signOptions.signingTime = PR_TRUE;	    break;       case 'H':           if (mode != SIGN) {               fprintf(stderr,                       "%s: option -H only supported with option -S.\n",                       progName);               Usage(progName);               exit(1);           }           decodeOptions.suppressContent = PR_TRUE;           if (!strcmp(optstate->value, "MD2"))               signOptions.hashAlgTag = SEC_OID_MD2;           else if (!strcmp(optstate->value, "MD4"))               signOptions.hashAlgTag = SEC_OID_MD4;           else if (!strcmp(optstate->value, "MD5"))               signOptions.hashAlgTag = SEC_OID_MD5;           else if (!strcmp(optstate->value, "SHA1"))               signOptions.hashAlgTag = SEC_OID_SHA1;           else if (!strcmp(optstate->value, "SHA256"))               signOptions.hashAlgTag = SEC_OID_SHA256;           else if (!strcmp(optstate->value, "SHA384"))               signOptions.hashAlgTag = SEC_OID_SHA384;           else if (!strcmp(optstate->value, "SHA512"))               signOptions.hashAlgTag = SEC_OID_SHA512;           else {               fprintf(stderr,           "%s: -H requires one of MD2,MD4,MD5,SHA1,SHA256,SHA384,SHA512\n",                       progName);               exit(1);           }           break;	case 'N':	    if (mode != SIGN) {		fprintf(stderr, 		        "%s: option -N only supported with option -S.\n", 		        progName);		Usage(progName);		exit(1);	    }	    signOptions.nickname = strdup(optstate->value);	    break;	case 'O':	    mode = CERTSONLY;	    break;	case 'P':	    if (mode != SIGN) {		fprintf(stderr, 		        "%s: option -P only supported with option -S.\n", 		        progName);		Usage(progName);		exit(1);	    }	    signOptions.smimeProfile = PR_TRUE;	    break;	case 'S':	    mode = SIGN;	    break;	case 'T':	    if (mode != SIGN) {		fprintf(stderr, 		        "%s: option -T only supported with option -S.\n", 		        progName);		Usage(progName);		exit(1);	    }	    signOptions.detached = PR_TRUE;	    break;	case 'Y':	    if (mode != SIGN) {		fprintf(stderr, 		        "%s: option -Y only supported with option -S.\n", 		        progName);		Usage(progName);		exit(1);	    }	    signOptions.encryptionKeyPreferenceNick = strdup(optstate->value);	    break;	case 'c':	    if (mode != DECODE) {		fprintf(stderr, 		        "%s: option -c only supported with option -D.\n", 		        progName);		Usage(progName);		exit(1);	    }	    if ((decodeOptions.contentFile = 	          PR_Open(optstate->value, PR_RDONLY, 006600)) == NULL) {		fprintf(stderr, "%s: unable to open \"%s\" for reading.\n",			progName, optstate->value);		exit(1);	    }	    break;	case 'd':	    SECU_ConfigDirectory(optstate->value);	    break;	case 'e':	    envFileName = strdup(optstate->value);	    encryptOptions.envFile = PR_Open(envFileName, PR_RDONLY, 00660);	    break;	case 'h':	    if (mode != DECODE) {		fprintf(stderr, 		        "%s: option -h only supported with option -D.\n", 		        progName);		Usage(progName);		exit(1);	    }	    decodeOptions.headerLevel = atoi(optstate->value);	    if (decodeOptions.headerLevel < 0) {		fprintf(stderr, "option -h cannot have a negative value.\n");		exit(1);	    }	    break;	case 'i':	    inFile = PR_Open(optstate->value, PR_RDONLY, 00660);	    if (inFile == NULL) {		fprintf(stderr, "%s: unable to open \"%s\" for reading\n",			progName, optstate->value);		exit(1);	    }	    break;	case 'n':	    if (mode != DECODE) {		fprintf(stderr, 		        "%s: option -n only supported with option -D.\n", 		        progName);		Usage(progName);		exit(1);	    }	    decodeOptions.suppressContent = PR_TRUE;	    break;	case 'o':	    outFile = fopen(optstate->value, "wb");	    if (outFile == NULL) {		fprintf(stderr, "%s: unable to open \"%s\" for writing\n",			progName, optstate->value);		exit(1);	    }	    break;	case 'p':	    if (!optstate->value) {		fprintf(stderr, "%s: option -p must have a value.\n", progName);		Usage(progName);		exit(1);	    }			    options.password = strdup(optstate->value);	    break;	case 'r':	    if (!optstate->value) {		fprintf(stderr, "%s: option -r must have a value.\n", progName);		Usage(progName);		exit(1);	    }	    envelopeOptions.recipients = ptrarray;	    str = (char *)optstate->value;	    do {		tok = strchr(str, ',');		if (tok) *tok = '\0';		envelopeOptions.recipients[nrecipients++] = strdup(str);		if (tok) str = tok + 1;	    } while (tok);	    envelopeOptions.recipients[nrecipients] = NULL;	    encryptOptions.recipients = envelopeOptions.recipients;	    certsonlyOptions.recipients = envelopeOptions.recipients;	    break;	case 'u': {	    int usageType;	    usageType = atoi (strdup(optstate->value));	    if (usageType < certUsageSSLClient || usageType > certUsageAnyCA)		return -1;	    options.certUsage = (SECCertUsage)usageType;	    break;	  }	case 'v':	    cms_verbose = 1;	    break;	}    }    if (status == PL_OPT_BAD)	Usage(progName);    PL_DestroyOptState(optstate);    if (mode == UNKNOWN)	Usage(progName);    if (mode != CERTSONLY)	SECU_FileToItem(&input, inFile);    if (inFile != PR_STDIN)	PR_Close(inFile);    if (cms_verbose) {	fprintf(stderr, "received commands\n");    }    /* Call the libsec initialization routines */    PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);    rv = NSS_InitReadWrite(SECU_ConfigDirectory(NULL));    if (SECSuccess != rv) {	SECU_PrintError(progName, "NSS_Init failed");	exit(1);    }    if (cms_verbose) {	fprintf(stderr, "NSS has been initialized.\n");    }    options.certHandle = CERT_GetDefaultCertDB();    if (!options.certHandle) {	SECU_PrintError(progName, "No default cert DB");	exit(1);    }    if (cms_verbose) {	fprintf(stderr, "Got default certdb\n");    }#if defined(_WIN32)    if (outFile == stdout) {	/* If we're going to write binary data to stdout, we must put stdout	** into O_BINARY mode or else outgoing \n's will become \r\n's.	*/	int smrv = _setmode(_fileno(stdout), _O_BINARY);	if (smrv == -1) {	    fprintf(stderr,	    "%s: Cannot change stdout to binary mode. Use -o option instead.\n",	            progName);	    return smrv;	}    }#endif    exitstatus = 0;    switch (mode) {    case DECODE:	decodeOptions.options = &options;	if (encryptOptions.envFile) {	    /* Decoding encrypted-data, so get the bulkkey from an	     * enveloped-data message.	     */	    SECU_FileToItem(&envmsg, encryptOptions.envFile);	    decodeOptions.options = &options;	    encryptOptions.envmsg = decode(NULL, &dummy, &envmsg, 	                                   &decodeOptions);	    if (!encryptOptions.envmsg) {		SECU_PrintError(progName, "problem decoding env msg");		exitstatus = 1;		break;	    }	    rv = get_enc_params(&encryptOptions);	    decodeOptions.dkcb = dkcb;	    decodeOptions.bulkkey = encryptOptions.bulkkey;	}	cmsg = decode(outFile, &output, &input, &decodeOptions);	if (!cmsg) {	    SECU_PrintError(progName, "problem decoding");	    exitstatus = 1;	}	fwrite(output.data, output.len, 1, outFile);	break;    case SIGN:	signOptions.options = &options;	cmsg = signed_data(&signOptions);	if (!cmsg) {	    SECU_PrintError(progName, "problem signing");	    exitstatus = 1;	}	break;    case ENCRYPT:	if (!envFileName) {	    fprintf(stderr, "%s: you must specify an envelope file with -e.\n",	            progName);	    exit(1);	}	encryptOptions.options = &options;	encryptOptions.input = &input;	encryptOptions.outfile = outFile;	if (!encryptOptions.envFile) {	    encryptOptions.envFile = PR_Open(envFileName, 	                                     PR_WRONLY|PR_CREATE_FILE, 00660);	    if (!encryptOptions.envFile) {		fprintf(stderr, "%s: failed to create file %s.\n", progName,		        envFileName);		exit(1);	    }	} else {	    SECU_FileToItem(&envmsg, encryptOptions.envFile);	    decodeOptions.options = &options;	    encryptOptions.envmsg = decode(NULL, &dummy, &envmsg, 	                                   &decodeOptions);	    if (encryptOptions.envmsg == NULL) {	    	SECU_PrintError(progName, "problem decrypting env msg");		exitstatus = 1;	    	break;	    }	}	/* decode an enveloped-data message to get the bulkkey (create	 * a new one if neccessary)	 */	rv = get_enc_params(&encryptOptions);	/* create the encrypted-data message */	cmsg = encrypted_data(&encryptOptions);	if (!cmsg) {	    SECU_PrintError(progName, "problem encrypting");	    exitstatus = 1;	}	if (encryptOptions.bulkkey) {	    PK11_FreeSymKey(encryptOptions.bulkkey);	    encryptOptions.bulkkey = NULL;	}	break;    case ENVELOPE:	envelopeOptions.options = &options;	cmsg = enveloped_data(&envelopeOptions);	if (!cmsg) {	    SECU_PrintError(progName, "problem enveloping");	    exitstatus = 1;	}	break;    case CERTSONLY:	certsonlyOptions.options = &options;	cmsg = signed_data_certsonly(&certsonlyOptions);	if (!cmsg) {	    SECU_PrintError(progName, "problem with certs-only");	    exitstatus = 1;	}	break;    default:	fprintf(stderr, "One of options -D, -S or -E must be set.\n");	Usage(progName);	exitstatus = 1;    }    if ( (mode == SIGN || mode == ENVELOPE || mode == CERTSONLY)         && (!exitstatus) ) {	PLArenaPool *arena = PORT_NewArena(1024);	NSSCMSEncoderContext *ecx;	SECItem output = { 0, 0, 0 };	secuPWData pwdata = { PW_NONE, 0 };	if (!arena) {	    fprintf(stderr, "%s: out of memory.\n", progName);	    exit(1);	}	if (options.password)	{    	    pwdata.source = PW_PLAINTEXT;    	    pwdata.data = options.password;	}	pwcb = SECU_GetModulePassword;	pwcb_arg = (void *)&pwdata;	if (cms_verbose) {	    fprintf(stderr, "cmsg [%p]\n", cmsg);	    fprintf(stderr, "arena [%p]\n", arena);	    if (pwcb_arg)		fprintf(stderr, "password [%s]\n", (char *)pwcb_arg);	    else		fprintf(stderr, "password [NULL]\n");	}	ecx = NSS_CMSEncoder_Start(cmsg,                                    NULL, NULL,     /* DER output callback  */                                   &output, arena, /* destination storage  */                                   pwcb, pwcb_arg, /* password callback    */                                   NULL, NULL,     /* decrypt key callback */                                   NULL, NULL );   /* detached digests    */	if (!ecx) {	    fprintf(stderr, "%s: cannot create encoder context.\n", progName);	    exit(1);	}	if (cms_verbose) {	    fprintf(stderr, "input len [%d]\n", input.len);	    { unsigned int j; 		for(j=0;j<input.len;j++)	     fprintf(stderr, "%2x%c", input.data[j], (j>0&&j%35==0)?'\n':' ');	    }	}	if (input.len > 0) { /* skip if certs-only (or other zero content) */	    rv = NSS_CMSEncoder_Update(ecx, (char *)input.data, input.len);	    if (rv) {		fprintf(stderr, 		        "%s: failed to add data to encoder.\n", progName);		exit(1);	    }	}	rv = NSS_CMSEncoder_Finish(ecx);	if (rv) {            SECU_PrintError(progName, "failed to encode data");	    exit(1);	}	if (cms_verbose) {	    fprintf(stderr, "encoding passed\n");	}	/*PR_Write(output.data, output.len);*/	fwrite(output.data, output.len, 1, outFile);	if (cms_verbose) {	    fprintf(stderr, "wrote to file\n");	}	PORT_FreeArena(arena, PR_FALSE);    }    if (cmsg)	NSS_CMSMessage_Destroy(cmsg);    if (outFile != stdout)	fclose(outFile);    if (decodeOptions.contentFile)	PR_Close(decodeOptions.contentFile);    if (NSS_Shutdown() != SECSuccess) {	exit(1);    }    exit(exitstatus);}