diff -Nru libytnef-1.9.2/ChangeLog libytnef-1.9.3/ChangeLog --- libytnef-1.9.2/ChangeLog 2017-03-07 11:33:17.000000000 +0000 +++ libytnef-1.9.3/ChangeLog 2018-07-20 11:35:04.000000000 +0000 @@ -1,3 +1,19 @@ +v1.9.3 - July 20, 2018 +Special thanks to @evintila, @bestshow, @bingosxs, and @asarubbo for +submitting high quality bug reports via valgrind, afl, and other tools. And +a special thanks to @ohwgiles for submitting a bunchof patches to fix them! + +This version resolves the following CVEs: +* CVE-2017-9470 +* CVE-2017-9471 +* CVE-2017-9474 +* CVE-2017-9058 +* CVE-2017-12142 +* CVE-2017-12141 +* CVE-2017-12144 +* + + v1.9.2 - February 23, 2017 Thanks to @hannob for finding some Out-of-bound exceptions in memory handline. diff -Nru libytnef-1.9.2/configure.ac libytnef-1.9.3/configure.ac --- libytnef-1.9.2/configure.ac 2017-03-07 11:33:17.000000000 +0000 +++ libytnef-1.9.3/configure.ac 2018-07-20 11:35:04.000000000 +0000 @@ -4,7 +4,7 @@ # PATCH version when you make backwards-compatible bug fixes. m4_define([version_major],1) m4_define([version_minor],9) -m4_define([version_micro],2) +m4_define([version_micro],3) m4_define([version_triplet],version_major.version_minor.version_micro) AC_PREREQ([2.63]) diff -Nru libytnef-1.9.2/debian/changelog libytnef-1.9.3/debian/changelog --- libytnef-1.9.2/debian/changelog 2017-05-22 21:51:52.000000000 +0000 +++ libytnef-1.9.3/debian/changelog 2018-10-20 22:36:17.000000000 +0000 @@ -1,3 +1,27 @@ +libytnef (1.9.3-1) unstable; urgency=medium + + * New upstream release fixing the following: + • [CVE-2017-9470] NULL pointer dereference in MAPIPrint. + Closes: #870196. + • [CVE-2017-9471] heap-based-buffer overflow in SwapWord. + Closes: #870194. + • [CVE-2017-9474] heap-based buffer overflow in DecompressRTF. + Closes: #870192. + • [CVE-2017-12142] SEGV in ytnef.c in SwapDWord. + Closes: #870816. + • [CVE-2017-12141] heap-buffer-overflow in TNEFFillMapi. + Closes: #870815. + • [CVE-2017-12144] allocation failure in TNEFFillMapi. + Closes: #870817. + * Remove patch for CVE-2017-9058 already in this release + * New maintainers for package (Closes: #460390) + * Priority extra has been replaced by optional + * Update Vcs-* for current infrastructure + * Standards-Version updated to latest + * Set debhelper compat level to 11 + + -- Ricardo Mones Sun, 21 Oct 2018 00:36:17 +0200 + libytnef (1.9.2-2) unstable; urgency=medium * Add CVE information to previous changelog entry. diff -Nru libytnef-1.9.2/debian/compat libytnef-1.9.3/debian/compat --- libytnef-1.9.2/debian/compat 2017-05-22 21:42:44.000000000 +0000 +++ libytnef-1.9.3/debian/compat 2018-10-20 22:36:17.000000000 +0000 @@ -1 +1 @@ -10 +11 diff -Nru libytnef-1.9.2/debian/control libytnef-1.9.3/debian/control --- libytnef-1.9.2/debian/control 2017-05-22 21:42:44.000000000 +0000 +++ libytnef-1.9.3/debian/control 2018-10-20 22:36:17.000000000 +0000 @@ -1,12 +1,13 @@ Source: libytnef Section: utils -Priority: extra -Maintainer: Debian QA Group -Build-Depends: debhelper (>= 10) -Standards-Version: 3.9.8 +Priority: optional +Maintainer: Ricardo Mones +Uploaders: Jordi Mallach +Build-Depends: debhelper (>= 11) +Standards-Version: 4.2.1 Homepage: https://github.com/Yeraze/ytnef -Vcs-Browser: https://anonscm.debian.org/cgit/collab-maint/ytnef.git -Vcs-Git: https://anonscm.debian.org/git/collab-maint/ytnef.git +Vcs-Git: https://salsa.debian.org/debian/ytnef.git +Vcs-Browser: https://salsa.debian.org/debian/ytnef Package: libytnef0 Architecture: any diff -Nru libytnef-1.9.2/debian/patches/CVE-2017-9058.patch libytnef-1.9.3/debian/patches/CVE-2017-9058.patch --- libytnef-1.9.2/debian/patches/CVE-2017-9058.patch 2017-05-22 21:45:38.000000000 +0000 +++ libytnef-1.9.3/debian/patches/CVE-2017-9058.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -Index: ytnef/lib/ytnef.c -=================================================================== ---- ytnef.orig/lib/ytnef.c -+++ ytnef/lib/ytnef.c -@@ -57,7 +57,7 @@ - - #define ALLOCCHECK(x) { if(!x) { printf("Out of Memory at %s : %i\n", __FILE__, __LINE__); return(-1); } } - #define ALLOCCHECK_CHAR(x) { if(!x) { printf("Out of Memory at %s : %i\n", __FILE__, __LINE__); return(NULL); } } --#define SIZECHECK(x) { if ((((char *)d - (char *)data) + x) > size) { printf("Corrupted file detected at %s : %i\n", __FILE__, __LINE__); return(-1); } } -+#define SIZECHECK(x) { if ((((char *)d - (char *)data) + x) >= size) { printf("Corrupted file detected at %s : %i\n", __FILE__, __LINE__); return(-1); } } - - int TNEFFillMapi(TNEFStruct *TNEF, BYTE *data, DWORD size, MAPIProps *p); - void SetFlip(void); diff -Nru libytnef-1.9.2/debian/patches/series libytnef-1.9.3/debian/patches/series --- libytnef-1.9.2/debian/patches/series 2017-05-22 21:45:11.000000000 +0000 +++ libytnef-1.9.3/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -CVE-2017-9058.patch diff -Nru libytnef-1.9.2/lib/ytnef.c libytnef-1.9.3/lib/ytnef.c --- libytnef-1.9.2/lib/ytnef.c 2017-03-07 11:33:17.000000000 +0000 +++ libytnef-1.9.3/lib/ytnef.c 2018-07-20 11:35:04.000000000 +0000 @@ -55,6 +55,7 @@ #define MIN(x,y) (((x)<(y))?(x):(y)) +#define PREALLOCCHECK(sz,max) { if(sz==0||(unsigned)sz>max) { printf("ERROR: invalid alloc size %u at %s : %i, suspected corruption\n", (unsigned)sz, __FILE__, __LINE__); return(-1); } } #define ALLOCCHECK(x) { if(!x) { printf("Out of Memory at %s : %i\n", __FILE__, __LINE__); return(-1); } } #define ALLOCCHECK_CHAR(x) { if(!x) { printf("Out of Memory at %s : %i\n", __FILE__, __LINE__); return(NULL); } } #define SIZECHECK(x) { if ((((char *)d - (char *)data) + x) > size) { printf("Corrupted file detected at %s : %i\n", __FILE__, __LINE__); return(-1); } } @@ -216,11 +217,7 @@ /* convert 16-bit unicode to UTF8 unicode */ char *to_utf8(size_t len, char *buf) { int i, j = 0; - /* worst case length */ - if (len > 10000) { // deal with this by adding an arbitrary limit - printf("suspecting a corrupt file in UTF8 conversion\n"); - exit(-1); - } + // an arbitrary length limit should be imposed by the caller of this function char *utf8 = malloc(3 * len / 2 + 1); for (i = 0; i < len - 1; i += 2) { @@ -247,7 +244,7 @@ // ----------------------------------------------------------------------------- int TNEFDefaultHandler STD_ARGLIST { if (TNEF->Debug >= 1) - printf("%s: [%i] %s\n", TNEFList[id].name, size, data); + printf("%s: [%i] %.*s\n", TNEFList[id].name, size, size, data); return 0; } @@ -273,7 +270,8 @@ // ----------------------------------------------------------------------------- int TNEFBody STD_ARGLIST { TNEF->body.size = size; - TNEF->body.data = calloc(size, sizeof(BYTE)); + PREALLOCCHECK(size, 100000); + TNEF->body.data = calloc(size+1, sizeof(BYTE)); ALLOCCHECK(TNEF->body.data); memcpy(TNEF->body.data, data, size); return 0; @@ -281,19 +279,21 @@ // ----------------------------------------------------------------------------- int TNEFOriginalMsgClass STD_ARGLIST { TNEF->OriginalMessageClass.size = size; - TNEF->OriginalMessageClass.data = calloc(size, sizeof(BYTE)); + PREALLOCCHECK(size, 100); + TNEF->OriginalMessageClass.data = calloc(size+1, sizeof(BYTE)); ALLOCCHECK(TNEF->OriginalMessageClass.data); memcpy(TNEF->OriginalMessageClass.data, data, size); return 0; } // ----------------------------------------------------------------------------- int TNEFMessageClass STD_ARGLIST { - memcpy(TNEF->messageClass, data, MIN(size, sizeof(TNEF->messageClass))); + memcpy(TNEF->messageClass, data, MIN(size, sizeof(TNEF->messageClass)-1)); return 0; } // ----------------------------------------------------------------------------- int TNEFFromHandler STD_ARGLIST { - TNEF->from.data = calloc(size, sizeof(BYTE)); + PREALLOCCHECK(size, 100); + TNEF->from.data = calloc(size+1, sizeof(BYTE)); ALLOCCHECK(TNEF->from.data); TNEF->from.size = size; memcpy(TNEF->from.data, data, size); @@ -304,7 +304,8 @@ if (TNEF->subject.data) free(TNEF->subject.data); - TNEF->subject.data = calloc(size, sizeof(BYTE)); + PREALLOCCHECK(size, 100); + TNEF->subject.data = calloc(size+1, sizeof(BYTE)); ALLOCCHECK(TNEF->subject.data); TNEF->subject.size = size; memcpy(TNEF->subject.data, data, size); @@ -349,6 +350,7 @@ while (p->next != NULL) p = p->next; p->IconData.size = size; + PREALLOCCHECK(size, 10000); p->IconData.data = calloc(size, sizeof(BYTE)); ALLOCCHECK(p->IconData.data); memcpy(p->IconData.data, data, size); @@ -364,17 +366,18 @@ int current_prop; d = (BYTE*)data; - count = SwapDWord((BYTE*)d, 4); - d += 4; + SIZECHECK(sizeof(DWORD)); + count = SwapDWord((BYTE*)d, sizeof(DWORD)); + d += sizeof(DWORD); // printf("Recipient Table containing %u rows\n", count); return 0; for (current_row = 0; current_row < count; current_row++) { - propcount = SwapDWord((BYTE*)d, 4); + propcount = SwapDWord((BYTE*)d, sizeof(DWORD)); if (TNEF->Debug >= 1) printf("> Row %i contains %i properties\n", current_row, propcount); - d += 4; + d += sizeof(DWORD); for (current_prop = 0; current_prop < propcount; current_prop++) { @@ -415,22 +418,28 @@ WORD temp_word; DWORD temp_dword; DDWORD temp_ddword; + int mp_count = 0, p_count = 0; int count = -1; int offset; d = data; - p->count = SwapDWord((BYTE*)data, 4); - d += 4; - p->properties = calloc(p->count, sizeof(MAPIProperty)); + SIZECHECK(sizeof(DWORD)); + p_count = SwapDWord((BYTE*)data, sizeof(DWORD)); + d += sizeof(DWORD); + // Arbitrary limit on the amount of properties + PREALLOCCHECK(p_count, 1000); + p->properties = calloc(p_count, sizeof(MAPIProperty)); ALLOCCHECK(p->properties); + p->count = p_count; mp = p->properties; for (i = 0; i < p->count; i++) { if (count == -1) { - mp->id = SwapDWord((BYTE*)d, 4); - d += 4; + SIZECHECK(sizeof(DWORD)); + mp->id = SwapDWord((BYTE*)d, sizeof(DWORD)); + d += sizeof(DWORD); mp->custom = 0; - mp->count = 1; + mp_count = 1; mp->namedproperty = 0; length = -1; if (PROP_ID(mp->id) >= 0x8000) { @@ -439,22 +448,24 @@ memcpy(&(mp->guid[0]), d, 16); d += 16; - SIZECHECK(4); - length = SwapDWord((BYTE*)d, 4); + SIZECHECK(sizeof(DWORD)); + length = SwapDWord((BYTE*)d, sizeof(DWORD)); d += sizeof(DWORD); if (length > 0) { - mp->namedproperty = length; + PREALLOCCHECK(length, 1000); mp->propnames = calloc(length, sizeof(variableLength)); ALLOCCHECK(mp->propnames); + mp->namedproperty = length; while (length > 0) { - SIZECHECK(4); - type = SwapDWord((BYTE*)d, 4); - mp->propnames[length - 1].data = calloc(type, sizeof(BYTE)); + SIZECHECK(sizeof(DWORD)); + type = SwapDWord((BYTE*)d, sizeof(DWORD)); + d += sizeof(DWORD); + PREALLOCCHECK(type, 100); + mp->propnames[length - 1].data = calloc(type+1, sizeof(BYTE)); ALLOCCHECK(mp->propnames[length - 1].data); mp->propnames[length - 1].size = type; - d += 4; + SIZECHECK(type); for (j = 0; j < (type >> 1); j++) { - SIZECHECK(j*2); mp->propnames[length - 1].data[j] = d[j * 2]; } d += type + ((type % 4) ? (4 - type % 4) : 0); @@ -474,13 +485,15 @@ PROP_ID(mp->id)); if (PROP_TYPE(mp->id) & MV_FLAG) { mp->id = PROP_TAG(PROP_TYPE(mp->id) - MV_FLAG, PROP_ID(mp->id)); - SIZECHECK(4); - mp->count = SwapDWord((BYTE*)d, 4); - d += 4; + SIZECHECK(sizeof(DWORD)); + mp_count = SwapDWord((BYTE*)d, sizeof(DWORD)); + d += sizeof(DWORD); count = 0; } - mp->data = calloc(mp->count, sizeof(variableLength)); + PREALLOCCHECK(mp_count, 1000); + mp->data = calloc(mp_count, sizeof(variableLength)); ALLOCCHECK(mp->data); + mp->count = mp_count; vl = mp->data; } else { i--; @@ -495,25 +508,28 @@ case PT_UNICODE: // First number of objects (assume 1 for now) if (count == -1) { - SIZECHECK(4); - vl->size = SwapDWord((BYTE*)d, 4); - d += 4; + SIZECHECK(sizeof(DWORD)); + vl->size = SwapDWord((BYTE*)d, sizeof(DWORD)); + d += sizeof(DWORD); } // now size of object - SIZECHECK(4); - vl->size = SwapDWord((BYTE*)d, 4); - d += 4; + SIZECHECK(sizeof(DWORD)); + vl->size = SwapDWord((BYTE*)d, sizeof(DWORD)); + d += sizeof(DWORD); // now actual object - if (vl->size != 0) { - SIZECHECK(vl->size); - if (PROP_TYPE(mp->id) == PT_UNICODE) { - vl->data =(BYTE*) to_utf8(vl->size, (char*)d); - } else { - vl->data = calloc(vl->size, sizeof(BYTE)); - ALLOCCHECK(vl->data); - memcpy(vl->data, d, vl->size); - } + if (vl->size != 0) { + SIZECHECK(vl->size); + PREALLOCCHECK(vl->size, 100000); + if (PROP_TYPE(mp->id) == PT_UNICODE) { + vl->data =(BYTE*) to_utf8(vl->size, (char*)d); + if(vl->data == NULL) + return -1; + } else { + vl->data = calloc(vl->size, sizeof(BYTE)); + ALLOCCHECK(vl->data); + memcpy(vl->data, d, vl->size); + } } else { vl->data = NULL; } @@ -527,6 +543,7 @@ case PT_I2: // Read in 2 bytes, but proceed by 4 bytes vl->size = 2; + PREALLOCCHECK(vl->size, 10000); vl->data = calloc(vl->size, sizeof(WORD)); ALLOCCHECK(vl->data); SIZECHECK(sizeof(WORD)) @@ -541,6 +558,7 @@ case PT_APPTIME: case PT_ERROR: vl->size = 4; + PREALLOCCHECK(vl->size, 10000); vl->data = calloc(vl->size, sizeof(BYTE)); ALLOCCHECK(vl->data); SIZECHECK(4); @@ -552,6 +570,7 @@ case PT_I8: case PT_SYSTIME: vl->size = 8; + PREALLOCCHECK(vl->size, 10000); vl->data = calloc(vl->size, sizeof(BYTE)); ALLOCCHECK(vl->data); SIZECHECK(8); @@ -561,6 +580,7 @@ break; case PT_CLSID: vl->size = 16; + PREALLOCCHECK(vl->size, 10000); vl->data = calloc(vl->size, sizeof(BYTE)); ALLOCCHECK(vl->data); SIZECHECK(vl->size); @@ -569,7 +589,7 @@ break; default: printf("Bad file\n"); - exit(-1); + return -1; } switch (PROP_ID(mp->id)) { @@ -582,7 +602,8 @@ if (TNEF->subject.size == 0) { int i; DEBUG(TNEF->Debug, 3, "Assigning a Subject"); - TNEF->subject.data = calloc(size, sizeof(BYTE)); + PREALLOCCHECK(vl->size, 100); + TNEF->subject.data = calloc(vl->size+1, sizeof(BYTE)); ALLOCCHECK(TNEF->subject.data); TNEF->subject.size = vl->size; memcpy(TNEF->subject.data, vl->data, vl->size); @@ -615,12 +636,14 @@ printf("Read %td bytes, Expected %u bytes\n", (d - data), size); printf("%td bytes missing\n", size - (d - data)); } + return -1; } else if ((d - data) > size) { if (TNEF->Debug >= 1) { printf("ERROR DURING MAPI READ\n"); printf("Read %td bytes, Expected %u bytes\n", (d - data), size); printf("%li bytes extra\n", (d - data) - size); } + return -1; } return 0; } @@ -635,15 +658,17 @@ SIZECHECK(sizeof(WORD)); name_length = SwapWord((BYTE*)d, sizeof(WORD)); d += sizeof(WORD); + SIZECHECK(name_length); if (TNEF->Debug >= 1) - printf("Sent For : %s", d); + printf("Sent For : %.*s", name_length, d); d += name_length; SIZECHECK(sizeof(WORD)); addr_length = SwapWord((BYTE*)d, sizeof(WORD)); d += sizeof(WORD); + SIZECHECK(addr_length); if (TNEF->Debug >= 1) - printf("<%s>\n", d); + printf("<%.*s>\n", addr_length, d); d += addr_length; } return 0; @@ -655,6 +680,9 @@ WORD * tmp_src, *tmp_dst; int i; + if (size < sizeof(dtr)) + return -1; + p = &(TNEF->starting_attach); switch (TNEFList[id].id) { case attDateSent: Date = &(TNEF->dateSent); break; @@ -749,7 +777,8 @@ while (p->next != NULL) p = p->next; p->Title.size = size; - p->Title.data = calloc(size, sizeof(BYTE)); + PREALLOCCHECK(size, 100); + p->Title.data = calloc(size+1, sizeof(BYTE)); ALLOCCHECK(p->Title.data); memcpy(p->Title.data, data, size); @@ -1151,6 +1180,7 @@ printf("ERROR: Field with size of 0\n"); return YTNEF_ERROR_READING_DATA; } + PREALLOCCHECK(size, 100000); data = calloc(size, sizeof(BYTE)); ALLOCCHECK(data); if (TNEFRawRead(TNEF, data, size, &header_checksum) < 0) { @@ -1433,7 +1463,7 @@ } break; case PT_STRING8: - printf(" Value: [%s]\n", mapidata->data); + printf(" Value: [%.*s]\n", mapidata->size, mapidata->data); if (strlen((char*)mapidata->data) != mapidata->size - 1) { printf("Detected Hidden data: ["); for (h = 0; h < mapidata->size; h++) { @@ -1456,7 +1486,7 @@ printf("]\n"); break; default: - printf(" Value: [%s]\n", mapidata->data); + printf(" Value: [%.*s]\n", mapidata->size, mapidata->data); } } } @@ -1464,23 +1494,16 @@ int IsCompressedRTF(variableLength *p) { - unsigned int in; BYTE *src; ULONG magic; - if (p->size < 4) + if (p->size < 3*sizeof(DWORD)) return 0; src = p->data; - in = 0; - - in += 4; - in += 4; - magic = SwapDWord((BYTE*)src + in, 4); + magic = SwapDWord((BYTE*)src + 2*sizeof(DWORD), sizeof(DWORD)); - if (magic == 0x414c454d) { - return 1; - } else if (magic == 0x75465a4c) { + if (magic == 0x414c454d || magic == 0x75465a4c) { return 1; } else { return 0; @@ -1507,13 +1530,12 @@ printf("File too small\n"); return(NULL); } - compressedSize = (ULONG)SwapDWord((BYTE*)src + in, 4); - in += 4; - uncompressedSize = (ULONG)SwapDWord((BYTE*)src + in, 4); - in += 4; - magic = SwapDWord((BYTE*)src + in, 4); - in += 4; - in += 4; + compressedSize = (ULONG)SwapDWord((BYTE*)src + in, sizeof(DWORD)); + in += sizeof(DWORD); + uncompressedSize = (ULONG)SwapDWord((BYTE*)src + in, sizeof(DWORD)); + in += sizeof(DWORD); + magic = SwapDWord((BYTE*)src + in, sizeof(DWORD)); + in += 2*sizeof(DWORD); // check size excluding the size field itself if (compressedSize != p->size - 4) { @@ -1535,7 +1557,7 @@ // Prevent overflow on 32 Bit Systems if (comp_Prebuf.size >= INT_MAX - uncompressedSize) { printf("Corrupted file\n"); - exit(-1); + return NULL; } dst = calloc(comp_Prebuf.size + uncompressedSize, 1); ALLOCCHECK_CHAR(dst); @@ -1568,7 +1590,7 @@ if ((out >= (comp_Prebuf.size + uncompressedSize)) || (in >= p->size)) { printf("Corrupted stream\n"); - exit(-1); + return NULL; } dst[out++] = src[in++]; } diff -Nru libytnef-1.9.2/ytnef/main.c libytnef-1.9.3/ytnef/main.c --- libytnef-1.9.2/ytnef/main.c 2017-03-07 11:33:17.000000000 +0000 +++ libytnef-1.9.3/ytnef/main.c 2018-07-20 11:35:04.000000000 +0000 @@ -33,7 +33,7 @@ int saveRTF = 0; int saveintermediate = 0; char *filepath = NULL; -void ProcessTNEF(TNEFStruct TNEF); +int ProcessTNEF(TNEFStruct TNEF); void SaveVCalendar(TNEFStruct TNEF, int isMtgReq); void SaveVCard(TNEFStruct TNEF); void SaveVTask(TNEFStruct TNEF); @@ -68,7 +68,7 @@ int main(int argc, char **argv) { - int index, i; + int index, i, errors=0; TNEFStruct TNEF; // printf("Size of WORD is %i\n", sizeof(WORD)); @@ -123,16 +123,18 @@ TNEFInitialize(&TNEF); TNEF.Debug = verbose; if (TNEFParseFile(argv[i], &TNEF) == -1) { - printf("ERROR processing file\n"); + fprintf(stderr, "ERROR processing file\n"); + ++errors; continue; } - ProcessTNEF(TNEF); + errors += ProcessTNEF(TNEF); TNEFFree(&TNEF); } - return 0; + return -errors; } -void ProcessTNEF(TNEFStruct TNEF) { +/* Return number of failures */ +int ProcessTNEF(TNEFStruct TNEF) { char *astring; variableLength *filename; variableLength *filedata; @@ -140,7 +142,7 @@ int RealAttachment; int object; char ifilename[MAX_FILENAME_SIZE+1]; - int i, count; + int i, count, failures = 0; int foundCal = 0; FILE *fptr; @@ -191,15 +193,16 @@ strcpy(ifilename, tmp); } - printf("%s\n", ifilename); if ((fptr = fopen(ifilename, "wb")) == NULL) { - printf("ERROR: Error writing file to disk!"); + fprintf(stderr, "ERROR: Error writing %s to disk!\n", ifilename); + ++failures; } else { fwrite(buf.data, sizeof(BYTE), buf.size, fptr); fclose(fptr); + printf("%s\n", ifilename); } free(buf.data); } @@ -232,15 +235,16 @@ CreateUniqueFilename(ifilename, MAX_FILENAME_SIZE, fileNameBase, "rtf", filepath); - printf("%s\n", ifilename); if ((fptr = fopen(ifilename, "wb"))==NULL) { - printf("ERROR: Error writing file to disk!"); + fprintf(stderr, "ERROR: Error writing %s to disk!\n", ifilename); + ++failures; } else { fwrite(buf.data, sizeof(BYTE), buf.size, fptr); fclose(fptr); + printf("%s\n", ifilename); } free(buf.data); } @@ -285,7 +289,7 @@ emb_tnef.Debug = TNEF.Debug; if (TNEFParseMemory(filedata->data + 16, filedata->size - 16, &emb_tnef) != -1) { - ProcessTNEF(emb_tnef); + failures += ProcessTNEF(emb_tnef); RealAttachment = 0; } TNEFFree(&emb_tnef); @@ -300,7 +304,7 @@ emb_tnef.Debug = TNEF.Debug; if (TNEFParseMemory(filedata->data, filedata->size, &emb_tnef) != -1) { - ProcessTNEF(emb_tnef); + failures += ProcessTNEF(emb_tnef); RealAttachment = 0; } TNEFFree(&emb_tnef); @@ -337,10 +341,10 @@ memcpy(tmp, ifilename, MAX_FILENAME_SIZE); snprintf(ifilename, MAX_FILENAME_SIZE, "%s/%s", filepath, tmp); } - printf("%s\n", ifilename); if (savefiles == 1) { if ((fptr = fopen(ifilename, "wb")) == NULL) { - printf("ERROR: Error writing file to disk!"); + fprintf(stderr, "ERROR: Error writing %s to disk!\n", ifilename); + ++failures; } else { if (object == 1) { fwrite(filedata->data + 16, @@ -354,12 +358,15 @@ fptr); } fclose(fptr); + printf("%s\n", ifilename); } // if we opened successfully } // if savefiles == 1 } // if RealAttachment == 1 } // if size>0 p = p->next; } // while p!= null + + return failures; } diff -Nru libytnef-1.9.2/ytnefprint/main.c libytnef-1.9.3/ytnefprint/main.c --- libytnef-1.9.2/ytnefprint/main.c 2017-03-07 11:33:17.000000000 +0000 +++ libytnef-1.9.3/ytnefprint/main.c 2018-07-20 11:35:04.000000000 +0000 @@ -77,7 +77,7 @@ } TNEFInitialize(&TNEF); TNEF.Debug = verbose; - if (TNEFParseFile(argv[i], &TNEF) == -1) { + if (TNEFParseFile(argv[i], &TNEF) < 0) { printf("ERROR processing file\n"); continue; }