summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornelsonb%netscape.com <devnull@localhost>2003-11-20 02:33:18 +0000
committernelsonb%netscape.com <devnull@localhost>2003-11-20 02:33:18 +0000
commit36608436480bc3358a85acf19455f225f33492cd (patch)
treeb2345302b99de8fdba366faa0680dba6f2174e36
parent05fe2f4059868612edbb0e5d871097287728d6c9 (diff)
downloadnss-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.c199
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;
}