diff options
author | nelsonb%netscape.com <devnull@localhost> | 2003-11-20 02:33:18 +0000 |
---|---|---|
committer | nelsonb%netscape.com <devnull@localhost> | 2003-11-20 02:33:18 +0000 |
commit | 36608436480bc3358a85acf19455f225f33492cd (patch) | |
tree | b2345302b99de8fdba366faa0680dba6f2174e36 | |
parent | 05fe2f4059868612edbb0e5d871097287728d6c9 (diff) | |
download | nss-hg-36608436480bc3358a85acf19455f225f33492cd.tar.gz |
Implement new "batch mode" (see the -b option). Plug some leaks.
Facilitates memory leak testing of the SMIME library.
This revision combines the patches for Bugzilla bug 225513 and
Bugscape bug 53775. r = relyea and wchang0222
-rw-r--r-- | security/nss/cmd/smimetools/cmsutil.c | 199 |
1 files changed, 161 insertions, 38 deletions
diff --git a/security/nss/cmd/smimetools/cmsutil.c b/security/nss/cmd/smimetools/cmsutil.c index 6b7a06b21..a25e0bd42 100644 --- a/security/nss/cmd/smimetools/cmsutil.c +++ b/security/nss/cmd/smimetools/cmsutil.c @@ -105,6 +105,7 @@ Usage(char *progName) "Usage: %s [-C|-D|-E|-O|-S] [<options>] [-d dbdir] [-u certusage]\n" " -C create a CMS encrypted data message\n" " -D decode a CMS message\n" +" -b decode a batch of files named in infile\n" " -c content use this detached content\n" " -n suppress output of content\n" " -h num display num levels of CMS message info as email headers\n" @@ -155,7 +156,7 @@ struct optionsStr { struct decodeOptionsStr { struct optionsStr *options; - PRFileDesc *contentFile; + SECItem content; int headerLevel; PRBool suppressContent; NSSCMSGetDecryptKeyCallback dkcb; @@ -195,8 +196,7 @@ struct encryptOptionsStr { }; static NSSCMSMessage * -decode(FILE *out, SECItem *output, SECItem *input, - const struct decodeOptionsStr *decodeOptions) +decode(FILE *out, SECItem *input, const struct decodeOptionsStr *decodeOptions) { NSSCMSDecoderContext *dcx; NSSCMSMessage *cmsg; @@ -211,6 +211,7 @@ decode(FILE *out, SECItem *output, SECItem *input, SECItem **digests; SECItem sitem = { 0, 0, 0 }; + PORT_SetError(0); dcx = NSS_CMSDecoder_Start(NULL, NULL, NULL, /* content callback */ pwcb, pwcb_arg, /* password callback */ @@ -242,21 +243,18 @@ decode(FILE *out, SECItem *output, SECItem *input, fprintf(out, "type=signedData; "); sigd = (NSSCMSSignedData *)NSS_CMSContentInfo_GetContent(cinfo); if (sigd == NULL) { - SECU_PrintError(progName, - "problem finding signedData component"); + SECU_PrintError(progName, "signedData component missing"); goto loser; } /* if we have a content file, but no digests for this signedData */ - if (decodeOptions->contentFile != NULL && + if (decodeOptions->content.data != NULL && !NSS_CMSSignedData_HasDigests(sigd)) { PLArenaPool *poolp; SECAlgorithmID **digestalgs; /* detached content: grab content file */ - if (!sitem.data) { - SECU_FileToItem(&sitem, decodeOptions->contentFile); - } + sitem = decodeOptions->content; if ((poolp = PORT_NewArena(1024)) == NULL) { fprintf(stderr, "cmsutil: Out of memory.\n"); @@ -346,11 +344,19 @@ decode(FILE *out, SECItem *output, SECItem *input, if (decodeOptions->headerLevel >= 0) fprintf(out, "type=envelopedData; "); envd = (NSSCMSEnvelopedData *)NSS_CMSContentInfo_GetContent(cinfo); + if (envd == NULL) { + SECU_PrintError(progName, "envelopedData component missing"); + goto loser; + } break; case SEC_OID_PKCS7_ENCRYPTED_DATA: if (decodeOptions->headerLevel >= 0) fprintf(out, "type=encryptedData; "); encd = (NSSCMSEncryptedData *)NSS_CMSContentInfo_GetContent(cinfo); + if (encd == NULL) { + SECU_PrintError(progName, "encryptedData component missing"); + goto loser; + } break; case SEC_OID_PKCS7_DATA: if (decodeOptions->headerLevel >= 0) @@ -363,11 +369,12 @@ decode(FILE *out, SECItem *output, SECItem *input, fprintf(out, "\n"); } - if (!decodeOptions->suppressContent) { - SECItem *item = (sitem.data) - ? &sitem - : NSS_CMSMessage_GetContent(cmsg); - SECITEM_CopyItem(NULL, output, item); + if (!decodeOptions->suppressContent && out) { + SECItem *item = (sitem.data ? &sitem + : NSS_CMSMessage_GetContent(cmsg)); + if (item && item->data && item->len) { + fwrite(item->data, item->len, 1, out); + } } return cmsg; @@ -953,8 +960,87 @@ loser: return NULL; } +static char * +pl_fgets(char * buf, int size, PRFileDesc * fd) +{ + char * bp = buf; + int nb = 0;; + + while (size > 1) { + nb = PR_Read(fd, bp, 1); + if (nb < 0) { + /* deal with error */ + return NULL; + } else if (nb == 0) { + /* deal with EOF */ + return NULL; + } else if (*bp == '\n') { + /* deal with EOL */ + ++bp; /* keep EOL character */ + break; + } else { + /* ordinary character */ + ++bp; + --size; + } + } + *bp = '\0'; + return buf; +} + typedef enum { UNKNOWN, DECODE, SIGN, ENCRYPT, ENVELOPE, CERTSONLY } Mode; +static int +doBatchDecode(FILE *outFile, PRFileDesc *batchFile, + const struct decodeOptionsStr *decodeOptions) +{ + char * str; + int exitStatus = 0; + char batchLine[512]; + + while (NULL != (str = pl_fgets(batchLine, sizeof batchLine, batchFile))) { + NSSCMSMessage *cmsg = NULL; + PRFileDesc * inFile; + int len = strlen(str); + SECStatus rv; + SECItem input = {0, 0, 0}; + char cc; + + while (len > 0 && + ((cc = str[len - 1]) == '\n' || cc == '\r')) { + str[--len] = '\0'; + } + if (!len) /* skip empty line */ + continue; + if (str[0] == '#') + continue; /* skip comment line */ + fprintf(outFile, "========== %s ==========\n", str); + inFile = PR_Open(str, PR_RDONLY, 00660); + if (inFile == NULL) { + fprintf(outFile, "%s: unable to open \"%s\" for reading\n", + progName, str); + exitStatus = 1; + continue; + } + rv = SECU_FileToItem(&input, inFile); + PR_Close(inFile); + if (rv != SECSuccess) { + SECU_PrintError(progName, "unable to read infile"); + exitStatus = 1; + continue; + } + cmsg = decode(outFile, &input, decodeOptions); + SECITEM_FreeItem(&input, PR_FALSE); + if (cmsg) + NSS_CMSMessage_Destroy(cmsg); + else { + SECU_PrintError(progName, "problem decoding"); + exitStatus = 1; + } + } + return exitStatus; +} + int main(int argc, char **argv) { @@ -976,10 +1062,10 @@ main(int argc, char **argv) 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; + PRFileDesc *contentFile = NULL; + PRBool batch = PR_FALSE; progName = strrchr(argv[0], '/'); if (!progName) @@ -990,7 +1076,8 @@ main(int argc, char **argv) outFile = stdout; envFileName = NULL; mode = UNKNOWN; - decodeOptions.contentFile = NULL; + decodeOptions.content.data = NULL; + decodeOptions.content.len = 0; decodeOptions.suppressContent = PR_FALSE; decodeOptions.headerLevel = -1; options.certUsage = certUsageEmailSigner; @@ -1013,7 +1100,7 @@ main(int argc, char **argv) * Parse command line arguments */ optstate = PL_CreateOptState(argc, argv, - "CDEGH:N:OPSTY:c:d:e:h:i:no:p:r:s:u:v"); + "CDEGH:N:OPSTY:bc:d:e:h:i:no:p:r:s:u:v"); while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { switch (optstate->option) { case 'C': @@ -1112,6 +1199,17 @@ main(int argc, char **argv) signOptions.encryptionKeyPreferenceNick = strdup(optstate->value); break; + case 'b': + if (mode != DECODE) { + fprintf(stderr, + "%s: option -b only supported with option -D.\n", + progName); + Usage(progName); + exit(1); + } + batch = PR_TRUE; + break; + case 'c': if (mode != DECODE) { fprintf(stderr, @@ -1120,12 +1218,25 @@ main(int argc, char **argv) Usage(progName); exit(1); } - if ((decodeOptions.contentFile = - PR_Open(optstate->value, PR_RDONLY, 006600)) == NULL) { + contentFile = PR_Open(optstate->value, PR_RDONLY, 006600); + if (contentFile == NULL) { fprintf(stderr, "%s: unable to open \"%s\" for reading.\n", progName, optstate->value); exit(1); } + + rv = SECU_FileToItem(&decodeOptions.content, contentFile); + PR_Close(contentFile); + if (rv != SECSuccess) { + SECU_PrintError(progName, "problem reading content file"); + exit(1); + } + if (!decodeOptions.content.data) { + /* file was zero length */ + decodeOptions.content.data = (unsigned char *)PORT_Strdup(""); + decodeOptions.content.len = 0; + } + break; case 'd': SECU_ConfigDirectory(optstate->value); @@ -1227,10 +1338,16 @@ main(int argc, char **argv) if (mode == UNKNOWN) Usage(progName); - if (mode != CERTSONLY) - SECU_FileToItem(&input, inFile); - if (inFile != PR_STDIN) - PR_Close(inFile); + if (mode != CERTSONLY && !batch) { + rv = SECU_FileToItem(&input, inFile); + if (rv != SECSuccess) { + SECU_PrintError(progName, "unable to read infile"); + exit(1); + } + if (inFile != PR_STDIN) { + PR_Close(inFile); + } + } if (cms_verbose) { fprintf(stderr, "received commands\n"); } @@ -1289,8 +1406,7 @@ main(int argc, char **argv) */ SECU_FileToItem(&envmsg, encryptOptions.envFile); decodeOptions.options = &options; - encryptOptions.envmsg = decode(NULL, &dummy, &envmsg, - &decodeOptions); + encryptOptions.envmsg = decode(NULL, &envmsg, &decodeOptions); if (!encryptOptions.envmsg) { SECU_PrintError(progName, "problem decoding env msg"); exitstatus = 1; @@ -1300,12 +1416,18 @@ main(int argc, char **argv) decodeOptions.dkcb = dkcb; decodeOptions.bulkkey = encryptOptions.bulkkey; } - cmsg = decode(outFile, &output, &input, &decodeOptions); - if (!cmsg) { - SECU_PrintError(progName, "problem decoding"); - exitstatus = 1; + if (!batch) { + cmsg = decode(outFile, &input, &decodeOptions); + if (!cmsg) { + SECU_PrintError(progName, "problem decoding"); + exitstatus = 1; + } + } else { + exitstatus = doBatchDecode(outFile, inFile, &decodeOptions); + if (inFile != PR_STDIN) { + PR_Close(inFile); + } } - fwrite(output.data, output.len, 1, outFile); break; case SIGN: /* -S */ signOptions.options = &options; @@ -1338,8 +1460,7 @@ main(int argc, char **argv) } else { SECU_FileToItem(&envmsg, encryptOptions.envFile); decodeOptions.options = &options; - encryptOptions.envmsg = decode(NULL, &dummy, &envmsg, - &decodeOptions); + encryptOptions.envmsg = decode(NULL, &envmsg, &decodeOptions); if (encryptOptions.envmsg == NULL) { SECU_PrintError(progName, "problem decrypting env msg"); exitstatus = 1; @@ -1433,7 +1554,6 @@ main(int argc, char **argv) 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"); @@ -1445,10 +1565,13 @@ main(int argc, char **argv) if (outFile != stdout) fclose(outFile); - if (decodeOptions.contentFile) - PR_Close(decodeOptions.contentFile); + SECITEM_FreeItem(&decodeOptions.content, PR_FALSE); + SECITEM_FreeItem(&envmsg, PR_FALSE); + SECITEM_FreeItem(&input, PR_FALSE); if (NSS_Shutdown() != SECSuccess) { - exit(1); + SECU_PrintError(progName, "NSS_Shutdown failed"); + exitstatus = 1; } - exit(exitstatus); + PR_Cleanup(); + return exitstatus; } |