~ubuntu-branches/ubuntu/vivid/clamav/vivid

« back to all changes in this revision

Viewing changes to .pc/0007-fix-ssize_t-size_t-off_t-printf-modifier.patch/libclamav/pdf.c

  • Committer: Package Import Robot
  • Author(s): Scott Kitterman, Sebastian Andrzej Siewior, Andreas Cadhalpun, Scott Kitterman, Javier Fernández-Sanguino
  • Date: 2015-01-28 00:25:13 UTC
  • mfrom: (0.48.14 sid)
  • Revision ID: package-import@ubuntu.com-20150128002513-lil2oi74cooy4lzr
Tags: 0.98.6+dfsg-1
[ Sebastian Andrzej Siewior ]
* update "fix-ssize_t-size_t-off_t-printf-modifier", include of misc.h was
  missing but was pulled in via the systemd patch.
* Don't leak return codes from libmspack to clamav API. (Closes: #774686).

[ Andreas Cadhalpun ]
* Add patch to avoid emitting incremental progress messages when not
  outputting to a terminal. (Closes: #767350)
* Update lintian-overrides for unused-file-paragraph-in-dep5-copyright.
* clamav-base.postinst: always chown /var/log/clamav and /var/lib/clamav
  to clamav:clamav, not only on fresh installations. (Closes: #775400)
* Adapt the clamav-daemon and clamav-freshclam logrotate scripts,
  so that they correctly work under systemd.
* Move the PidFile variable from the clamd/freshclam configuration files
  to the init scripts. This makes the init scripts more robust against
  misconfiguration and avoids error messages with systemd. (Closes: #767353)
* debian/copyright: drop files from Files-Excluded only present in github
  tarballs
* Drop Workaround-a-bug-in-libc-on-Hurd.patch, because hurd got fixed.
  (see #752237)
* debian/rules: Remove useless --with-system-tommath --without-included-ltdl
  configure options.

[ Scott Kitterman ]
* Stop stripping llvm when repacking the tarball as the system llvm on some
  releases is too old to use
* New upstream bugfix release
  - Library shared object revisions.
  - Includes a patch from Sebastian Andrzej Siewior making ClamAV pid files
    compatible with systemd.
  - Fix a heap out of bounds condition with crafted Yoda's crypter files.
    This issue was discovered by Felix Groebert of the Google Security Team.
  - Fix a heap out of bounds condition with crafted mew packer files. This
    issue was discovered by Felix Groebert of the Google Security Team.
  - Fix a heap out of bounds condition with crafted upx packer files. This
    issue was discovered by Kevin Szkudlapski of Quarkslab.
  - Fix a heap out of bounds condition with crafted upack packer files. This
    issue was discovered by Sebastian Andrzej Siewior. CVE-2014-9328.
  - Compensate a crash due to incorrect compiler optimization when handling
    crafted petite packer files. This issue was discovered by Sebastian
    Andrzej Siewior.
* Update lintian override for embedded zlib to match new so version

[ Javier Fernández-Sanguino ]
* Updated Spanish Debconf template translation (Closes: #773563)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  Copyright (C) 2007-2014 Sourcefire, Inc.
 
3
 *  Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved.
 
4
 *
 
5
 *  Authors: Nigel Horne, Török Edvin
 
6
 *
 
7
 *  Also based on Matt Olney's pdf parser in snort-nrt.
 
8
 *
 
9
 *  This program is free software; you can redistribute it and/or modify
 
10
 *  it under the terms of the GNU General Public License version 2 as
 
11
 *  published by the Free Software Foundation.
 
12
 *
 
13
 *  This program is distributed in the hope that it will be useful,
 
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
 *  GNU General Public License for more details.
 
17
 *
 
18
 *  You should have received a copy of the GNU General Public License
 
19
 *  along with this program; if not, write to the Free Software
 
20
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
21
 *  MA 02110-1301, USA.
 
22
 *
 
23
 * TODO: Embedded fonts
 
24
 * TODO: Predictor image handling
 
25
 */
 
26
 
 
27
#if HAVE_CONFIG_H
 
28
#include "clamav-config.h"
 
29
#endif
 
30
 
 
31
#include <stdio.h>
 
32
#include <sys/types.h>
 
33
#include <sys/stat.h>
 
34
#include <ctype.h>
 
35
#include <string.h>
 
36
#include <fcntl.h>
 
37
#include <stdlib.h>
 
38
#include <errno.h>
 
39
#ifdef  HAVE_LIMITS_H
 
40
#include <limits.h>
 
41
#endif
 
42
#ifdef  HAVE_UNISTD_H
 
43
#include <unistd.h>
 
44
#endif
 
45
#include <zlib.h>
 
46
 
 
47
#if HAVE_ICONV
 
48
#include <iconv.h>
 
49
#endif
 
50
 
 
51
#include "clamav.h"
 
52
#include "others.h"
 
53
#include "pdf.h"
 
54
#include "scanners.h"
 
55
#include "fmap.h"
 
56
#include "str.h"
 
57
#include "bytecode.h"
 
58
#include "bytecode_api.h"
 
59
#include "arc4.h"
 
60
#include "rijndael.h"
 
61
#include "textnorm.h"
 
62
#include "json_api.h"
 
63
 
 
64
#ifdef  CL_DEBUG
 
65
/*#define       SAVE_TMP        
 
66
 *Save the file being worked on in tmp */
 
67
#endif
 
68
 
 
69
struct pdf_struct;
 
70
 
 
71
static  int     asciihexdecode(const char *buf, off_t len, char *output);
 
72
static  int     ascii85decode(const char *buf, off_t len, unsigned char *output);
 
73
static  const   char    *pdf_nextlinestart(const char *ptr, size_t len);
 
74
static  const   char    *pdf_nextobject(const char *ptr, size_t len);
 
75
 
 
76
/* PDF statistics callbacks and related */
 
77
struct pdfname_action;
 
78
 
 
79
#if HAVE_JSON
 
80
static void pdf_export_json(struct pdf_struct *);
 
81
 
 
82
static void ASCIIHexDecode_cb(struct pdf_struct *, struct pdf_obj *, struct pdfname_action *);
 
83
static void ASCII85Decode_cb(struct pdf_struct *, struct pdf_obj *, struct pdfname_action *);
 
84
static void EmbeddedFile_cb(struct pdf_struct *, struct pdf_obj *, struct pdfname_action *);
 
85
static void FlateDecode_cb(struct pdf_struct *, struct pdf_obj *, struct pdfname_action *);
 
86
static void Image_cb(struct pdf_struct *, struct pdf_obj *, struct pdfname_action *);
 
87
static void LZWDecode_cb(struct pdf_struct *, struct pdf_obj *, struct pdfname_action *);
 
88
static void RunLengthDecode_cb(struct pdf_struct *, struct pdf_obj *, struct pdfname_action *);
 
89
static void CCITTFaxDecode_cb(struct pdf_struct *, struct pdf_obj *, struct pdfname_action *);
 
90
static void JBIG2Decode_cb(struct pdf_struct *, struct pdf_obj *, struct pdfname_action *);
 
91
static void DCTDecode_cb(struct pdf_struct *, struct pdf_obj *, struct pdfname_action *);
 
92
static void JPXDecode_cb(struct pdf_struct *, struct pdf_obj *, struct pdfname_action *);
 
93
static void Crypt_cb(struct pdf_struct *, struct pdf_obj *, struct pdfname_action *);
 
94
static void Standard_cb(struct pdf_struct *, struct pdf_obj *, struct pdfname_action *);
 
95
static void Sig_cb(struct pdf_struct *, struct pdf_obj *, struct pdfname_action *);
 
96
static void JavaScript_cb(struct pdf_struct *, struct pdf_obj *, struct pdfname_action *);
 
97
static void OpenAction_cb(struct pdf_struct *, struct pdf_obj *, struct pdfname_action *);
 
98
static void Launch_cb(struct pdf_struct *, struct pdf_obj *, struct pdfname_action *);
 
99
static void Page_cb(struct pdf_struct *, struct pdf_obj *, struct pdfname_action *);
 
100
static void Author_cb(struct pdf_struct *, struct pdf_obj *, struct pdfname_action *);
 
101
static void Creator_cb(struct pdf_struct *, struct pdf_obj *, struct pdfname_action *);
 
102
static void Producer_cb(struct pdf_struct *, struct pdf_obj *, struct pdfname_action *);
 
103
static void CreationDate_cb(struct pdf_struct *, struct pdf_obj *, struct pdfname_action *);
 
104
static void ModificationDate_cb(struct pdf_struct *, struct pdf_obj *, struct pdfname_action *);
 
105
static void Title_cb(struct pdf_struct *, struct pdf_obj *, struct pdfname_action *);
 
106
static void Subject_cb(struct pdf_struct *, struct pdf_obj *, struct pdfname_action *);
 
107
static void Keywords_cb(struct pdf_struct *, struct pdf_obj *, struct pdfname_action *);
 
108
static void Pages_cb(struct pdf_struct *, struct pdf_obj *, struct pdfname_action *);
 
109
static void Colors_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act);
 
110
static void RichMedia_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act);
 
111
static void AcroForm_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act);
 
112
static void XFA_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act);
 
113
#endif
 
114
/* End PDF statistics callbacks and related */
 
115
 
 
116
static int xrefCheck(const char *xref, const char *eof)
 
117
{
 
118
    const char *q;
 
119
 
 
120
    while (xref < eof && (*xref == ' ' || *xref == '\n' || *xref == '\r'))
 
121
        xref++;
 
122
 
 
123
    if (xref + 4 >= eof)
 
124
        return -1;
 
125
 
 
126
    if (!memcmp(xref, "xref", 4)) {
 
127
        cli_dbgmsg("cli_pdf: found xref\n");
 
128
        return 0;
 
129
    }
 
130
 
 
131
    /* could be xref stream */
 
132
    for (q=xref; q+5 < eof; q++) {
 
133
        if (!memcmp(q,"/XRef",4)) {
 
134
            cli_dbgmsg("cli_pdf: found /XRef\n");
 
135
            return 0;
 
136
        }
 
137
    }
 
138
 
 
139
    return -1;
 
140
}
 
141
 
 
142
/* define this to be noisy about things that we can't parse properly */
 
143
/*#define NOISY*/
 
144
 
 
145
#ifdef NOISY
 
146
#define noisy_msg(pdf, ...) cli_infomsg(pdf->ctx, __VA_ARGS__)
 
147
#define noisy_warnmsg cli_warnmsg
 
148
#else
 
149
#define noisy_msg (void)
 
150
#define noisy_warnmsg (void)
 
151
#endif
 
152
 
 
153
static const char *findNextNonWSBack(const char *q, const char *start)
 
154
{
 
155
    while (q > start && (*q == 0 || *q == 9 || *q == 0xa || *q == 0xc || *q == 0xd || *q == 0x20))
 
156
        q--;
 
157
 
 
158
    return q;
 
159
}
 
160
 
 
161
static int find_stream_bounds(const char *start, off_t bytesleft, off_t bytesleft2, off_t *stream, off_t *endstream, int newline_hack)
 
162
{
 
163
    const char *q2, *q;
 
164
    if ((q2 = cli_memstr(start, bytesleft, "stream", 6))) {
 
165
        q2 += 6;
 
166
        bytesleft -= q2 - start;
 
167
        if (bytesleft < 0)
 
168
            return 0;
 
169
 
 
170
        if (bytesleft >= 2 && q2[0] == '\xd' && q2[1] == '\xa') {
 
171
            q2 += 2;
 
172
            if (newline_hack && (bytesleft > 2) && q2[0] == '\xa')
 
173
                q2++;
 
174
        } else if (bytesleft && q2[0] == '\xa') {
 
175
            q2++;
 
176
        }
 
177
 
 
178
        *stream = q2 - start;
 
179
        bytesleft2 -= q2 - start;
 
180
        if (bytesleft2 <= 0)
 
181
            return 0;
 
182
 
 
183
        q = q2;
 
184
        q2 = cli_memstr(q, bytesleft2, "endstream", 9);
 
185
        if (!q2)
 
186
            q2 = q + bytesleft2-9; /* till EOF */
 
187
 
 
188
        *endstream = q2 - start;
 
189
        if (*endstream < *stream)
 
190
            *endstream = *stream;
 
191
 
 
192
        return 1;
 
193
    }
 
194
 
 
195
    return 0;
 
196
}
 
197
 
 
198
/* Expected returns: 1 if success, 0 if no more objects, -1 if error */
 
199
int pdf_findobj(struct pdf_struct *pdf)
 
200
{
 
201
    const char *start, *q, *q2, *q3, *eof;
 
202
    struct pdf_obj *obj;
 
203
    off_t bytesleft;
 
204
    unsigned genid, objid;
 
205
 
 
206
    pdf->nobjs++;
 
207
    pdf->objs = cli_realloc2(pdf->objs, sizeof(*pdf->objs)*pdf->nobjs);
 
208
    if (!pdf->objs) {
 
209
        cli_warnmsg("cli_pdf: out of memory parsing objects (%u)\n", pdf->nobjs);
 
210
        return -1;
 
211
    }
 
212
 
 
213
    obj = &pdf->objs[pdf->nobjs-1];
 
214
    memset(obj, 0, sizeof(*obj));
 
215
    start = pdf->map+pdf->offset;
 
216
    bytesleft = pdf->size - pdf->offset;
 
217
    while (bytesleft > 0) {
 
218
        q2 = cli_memstr(start, bytesleft, "obj", 3);
 
219
        if (!q2)
 
220
            return 0;/* no more objs */
 
221
 
 
222
        q2--;
 
223
        bytesleft -= q2 - start;
 
224
        if (*q2 != 0 && *q2 != 9 && *q2 != 0xa && *q2 != 0xc && *q2 != 0xd && *q2 != 0x20) {
 
225
            start = q2+4;
 
226
            bytesleft -= 4;
 
227
            continue;
 
228
        }
 
229
 
 
230
        break;
 
231
    }
 
232
 
 
233
    if (bytesleft <= 0)
 
234
        return 0;
 
235
 
 
236
    q = findNextNonWSBack(q2-1, start);
 
237
    while (q > start && isdigit(*q))
 
238
        q--;
 
239
 
 
240
    genid = atoi(q);
 
241
    q = findNextNonWSBack(q-1,start);
 
242
    while (q > start && isdigit(*q))
 
243
        q--;
 
244
 
 
245
    objid = atoi(q);
 
246
    obj->id = (objid << 8) | (genid&0xff);
 
247
    obj->start = q2+4 - pdf->map;
 
248
    obj->flags = 0;
 
249
    bytesleft -= 4;
 
250
    eof = pdf->map + pdf->size;
 
251
    q = pdf->map + obj->start;
 
252
 
 
253
    while (q < eof && bytesleft > 0) {
 
254
        off_t p_stream, p_endstream;
 
255
        q2 = pdf_nextobject(q, bytesleft);
 
256
        if (!q2)
 
257
            q2 = pdf->map + pdf->size;
 
258
 
 
259
        bytesleft -= q2 - q;
 
260
        if (find_stream_bounds(q-1, q2-q, bytesleft + (q2-q), &p_stream, &p_endstream, 1)) {
 
261
            obj->flags |= 1 << OBJ_STREAM;
 
262
            q2 = q-1 + p_endstream + 9;
 
263
            bytesleft -= q2 - q + 1;
 
264
 
 
265
            if (bytesleft < 0) {
 
266
                obj->flags |= 1 << OBJ_TRUNCATED;
 
267
                pdf->offset = pdf->size;
 
268
                return 1;/* truncated */
 
269
            }
 
270
        } else if ((q3 = cli_memstr(q-1, q2-q+1, "endobj", 6))) {
 
271
            q2 = q3 + 6;
 
272
            pdf->offset = q2 - pdf->map;
 
273
            return 1; /* obj found and offset positioned */
 
274
        } else {
 
275
            q2++;
 
276
            bytesleft--;
 
277
        }
 
278
 
 
279
        q = q2;
 
280
    }
 
281
 
 
282
    obj->flags |= 1 << OBJ_TRUNCATED;
 
283
    pdf->offset = pdf->size;
 
284
 
 
285
    return 1;/* truncated */
 
286
}
 
287
 
 
288
static int filter_writen(struct pdf_struct *pdf, struct pdf_obj *obj, int fout, const char *buf, off_t len, off_t *sum)
 
289
{
 
290
    UNUSEDPARAM(obj);
 
291
 
 
292
    if (cli_checklimits("pdf", pdf->ctx, *sum, 0, 0))
 
293
        return len; /* pretend it was a successful write to suppress CL_EWRITE */
 
294
 
 
295
    *sum += len;
 
296
 
 
297
    return cli_writen(fout, buf, len);
 
298
}
 
299
 
 
300
static void pdfobj_flag(struct pdf_struct *pdf, struct pdf_obj *obj, enum pdf_flag flag)
 
301
{
 
302
    const char *s= "";
 
303
    pdf->flags |= 1 << flag;
 
304
    if (!cli_debug_flag)
 
305
        return;
 
306
 
 
307
    switch (flag) {
 
308
    case UNTERMINATED_OBJ_DICT:
 
309
        s = "dictionary not terminated";
 
310
        break;
 
311
    case ESCAPED_COMMON_PDFNAME:
 
312
        /* like /JavaScript */
 
313
        s = "escaped common pdfname";
 
314
        break;
 
315
    case BAD_STREAM_FILTERS:
 
316
        s = "duplicate stream filters";
 
317
        break;
 
318
    case BAD_PDF_VERSION:
 
319
        s = "bad pdf version";
 
320
        break;
 
321
    case BAD_PDF_HEADERPOS:
 
322
        s = "bad pdf header position";
 
323
        break;
 
324
    case BAD_PDF_TRAILER:
 
325
        s = "bad pdf trailer";
 
326
        break;
 
327
    case BAD_PDF_TOOMANYOBJS:
 
328
        s = "too many pdf objs";
 
329
        break;
 
330
    case BAD_FLATE:
 
331
        s = "bad deflate stream";
 
332
        break;
 
333
    case BAD_FLATESTART:
 
334
        s = "bad deflate stream start";
 
335
        break;
 
336
    case BAD_STREAMSTART:
 
337
        s = "bad stream start";
 
338
        break;
 
339
    case UNKNOWN_FILTER:
 
340
        s = "unknown filter used";
 
341
        break;
 
342
    case BAD_ASCIIDECODE:
 
343
        s = "bad ASCII decode";
 
344
        break;
 
345
    case HEX_JAVASCRIPT:
 
346
        s = "hex javascript";
 
347
        break;
 
348
    case BAD_INDOBJ:
 
349
        s = "referencing nonexistent obj";
 
350
        break;
 
351
    case HAS_OPENACTION:
 
352
        s = "has /OpenAction";
 
353
        break;
 
354
    case HAS_LAUNCHACTION:
 
355
        s = "has /LaunchAction";
 
356
        break;
 
357
    case BAD_STREAMLEN:
 
358
        s = "bad /Length, too small";
 
359
        break;
 
360
    case ENCRYPTED_PDF:
 
361
        s = "PDF is encrypted";
 
362
        break;
 
363
    case LINEARIZED_PDF:
 
364
        s = "linearized PDF";
 
365
        break;
 
366
    case MANY_FILTERS:
 
367
        s = "more than 2 filters per obj";
 
368
        break;
 
369
    case DECRYPTABLE_PDF:
 
370
        s = "decryptable PDF";
 
371
        break;
 
372
    }
 
373
 
 
374
    cli_dbgmsg("cli_pdf: %s flagged in object %u %u\n", s, obj->id>>8, obj->id&0xff);
 
375
}
 
376
 
 
377
static int filter_flatedecode(struct pdf_struct *pdf, struct pdf_obj *obj, const char *buf, off_t len, int fout, off_t *sum)
 
378
{
 
379
    int skipped = 0;
 
380
    int zstat;
 
381
    z_stream stream;
 
382
    off_t nbytes;
 
383
    char output[BUFSIZ];
 
384
 
 
385
    if (len == 0)
 
386
        return CL_CLEAN;
 
387
 
 
388
    if (*buf == '\r') {
 
389
        buf++;
 
390
        len--;
 
391
        pdfobj_flag(pdf, obj, BAD_STREAMSTART);
 
392
        /* PDF spec says stream is followed by \r\n or \n, but not \r alone.
 
393
         * Sample 0015315109, it has \r followed by zlib header.
 
394
         * Flag pdf as suspicious, and attempt to extract by skipping the \r.
 
395
         */
 
396
        if (!len)
 
397
            return CL_CLEAN;
 
398
    }
 
399
 
 
400
    memset(&stream, 0, sizeof(stream));
 
401
    stream.next_in = (Bytef *)buf;
 
402
    stream.avail_in = len;
 
403
    stream.next_out = (Bytef *)output;
 
404
    stream.avail_out = sizeof(output);
 
405
 
 
406
    zstat = inflateInit(&stream);
 
407
    if(zstat != Z_OK) {
 
408
        cli_warnmsg("cli_pdf: inflateInit failed\n");
 
409
        return CL_EMEM;
 
410
    }
 
411
 
 
412
    nbytes = 0;
 
413
    while(stream.avail_in) {
 
414
        int written;
 
415
        zstat = inflate(&stream, Z_NO_FLUSH);   /* zlib */
 
416
        switch(zstat) {
 
417
            case Z_OK:
 
418
                if(stream.avail_out == 0) {
 
419
                    if ((written=filter_writen(pdf, obj, fout, output, sizeof(output), sum))!=sizeof(output)) {
 
420
                        cli_errmsg("cli_pdf: failed to write output file\n");
 
421
                        inflateEnd(&stream);
 
422
                        return CL_EWRITE;
 
423
                    }
 
424
 
 
425
                    nbytes += written;
 
426
                    stream.next_out = (Bytef *)output;
 
427
                    stream.avail_out = sizeof(output);
 
428
                }
 
429
 
 
430
                continue;
 
431
            case Z_STREAM_END:
 
432
            default:
 
433
                written = sizeof(output) - stream.avail_out;
 
434
                if (!written && !nbytes && !skipped) {
 
435
                    /* skip till EOL, and try inflating from there, sometimes
 
436
                     * PDFs contain extra whitespace */
 
437
                    const char *q = pdf_nextlinestart(buf, len);
 
438
                    if (q) {
 
439
                        skipped = 1;
 
440
                        inflateEnd(&stream);
 
441
                        len -= q - buf;
 
442
                        buf = q;
 
443
 
 
444
                        stream.next_in = (Bytef *)buf;
 
445
                        stream.avail_in = len;
 
446
                        stream.next_out = (Bytef *)output;
 
447
                        stream.avail_out = sizeof(output);
 
448
                        zstat = inflateInit(&stream);
 
449
 
 
450
                        if(zstat != Z_OK) {
 
451
                            cli_warnmsg("cli_pdf: inflateInit failed\n");
 
452
                            return CL_EMEM;
 
453
                        }
 
454
 
 
455
                        pdfobj_flag(pdf, obj, BAD_FLATESTART);
 
456
                        continue;
 
457
                    }
 
458
                }
 
459
 
 
460
                if (filter_writen(pdf, obj, fout, output, written, sum)!=written) {
 
461
                    cli_errmsg("cli_pdf: failed to write output file\n");
 
462
                    inflateEnd(&stream);
 
463
                    return CL_EWRITE;
 
464
                }
 
465
 
 
466
                nbytes += written;
 
467
                stream.next_out = (Bytef *)output;
 
468
                stream.avail_out = sizeof(output);
 
469
                if (zstat == Z_STREAM_END)
 
470
                    break;
 
471
 
 
472
                if(stream.msg)
 
473
                    cli_dbgmsg("cli_pdf: after writing %lu bytes, got error \"%s\" inflating PDF stream in %u %u obj\n",
 
474
                           (unsigned long)nbytes,
 
475
                           stream.msg, obj->id>>8, obj->id&0xff);
 
476
                else
 
477
                    cli_dbgmsg("cli_pdf: after writing %lu bytes, got error %d inflating PDF stream in %u %u obj\n",
 
478
                           (unsigned long)nbytes, zstat, obj->id>>8, obj->id&0xff);
 
479
 
 
480
                if(stream.msg)
 
481
                    noisy_warnmsg("cli_pdf: after writing %lu bytes, got error \"%s\" inflating PDF stream in %u %u obj\n",
 
482
                           (unsigned long)nbytes,
 
483
                           stream.msg, obj->id>>8, obj->id&0xff);
 
484
                else
 
485
                    noisy_warnmsg("cli_pdf: after writing %lu bytes, got error %d inflating PDF stream in %u %u obj\n",
 
486
                           (unsigned long)nbytes, zstat, obj->id>>8, obj->id&0xff);
 
487
 
 
488
                /* mark stream as bad only if not encrypted */
 
489
                inflateEnd(&stream);
 
490
                if (!nbytes) {
 
491
                    pdfobj_flag(pdf, obj, BAD_FLATESTART);
 
492
                    cli_dbgmsg("filter_flatedecode: No bytes, returning CL_EFORMAT for this stream.\n");
 
493
 
 
494
                    return CL_EFORMAT;
 
495
                } else {
 
496
                    pdfobj_flag(pdf, obj, BAD_FLATE);
 
497
                }
 
498
 
 
499
                return CL_CLEAN;
 
500
            }
 
501
 
 
502
        break;
 
503
    }
 
504
 
 
505
    if(stream.avail_out != sizeof(output)) {
 
506
        if(filter_writen(pdf, obj, fout, output, sizeof(output) - stream.avail_out, sum) < 0) {
 
507
            cli_errmsg("cli_pdf: failed to write output file\n");
 
508
 
 
509
            inflateEnd(&stream);
 
510
 
 
511
            return CL_EWRITE;
 
512
        }
 
513
    }
 
514
 
 
515
    inflateEnd(&stream);
 
516
 
 
517
    return CL_CLEAN;
 
518
}
 
519
 
 
520
struct pdf_obj *find_obj(struct pdf_struct *pdf, struct pdf_obj *obj, uint32_t objid)
 
521
{
 
522
    uint32_t j;
 
523
    uint32_t i;
 
524
 
 
525
    /* search starting at previous obj (if exists) */
 
526
    i = (obj != pdf->objs) ? obj - pdf->objs : 0;
 
527
 
 
528
    for (j=i;j<pdf->nobjs;j++) {
 
529
        obj = &pdf->objs[j];
 
530
        if (obj->id == objid)
 
531
            return obj;
 
532
    }
 
533
 
 
534
    /* restart search from beginning if not found */
 
535
    for (j=0;j<i;j++) {
 
536
        obj = &pdf->objs[j];
 
537
        if (obj->id == objid)
 
538
            return obj;
 
539
    }
 
540
 
 
541
    return NULL;
 
542
}
 
543
 
 
544
static int find_length(struct pdf_struct *pdf, struct pdf_obj *obj, const char *start, off_t len)
 
545
{
 
546
    int length;
 
547
    const char *q;
 
548
 
 
549
    q = cli_memstr(start, len, "/Length", 7);
 
550
    if (!q)
 
551
        return 0;
 
552
 
 
553
    q++;
 
554
    len -= q - start;
 
555
    start = pdf_nextobject(q, len);
 
556
    if (!start)
 
557
        return 0;
 
558
 
 
559
    /* len -= start - q; */
 
560
    q = start;
 
561
    length = atoi(q);
 
562
    while (isdigit(*q))
 
563
        q++;
 
564
 
 
565
    if (*q == ' ') {
 
566
        int genid;
 
567
        q++;
 
568
        genid = atoi(q);
 
569
 
 
570
        while(isdigit(*q))
 
571
            q++;
 
572
 
 
573
        if (q[0] == ' ' && q[1] == 'R') {
 
574
            cli_dbgmsg("cli_pdf: length is in indirect object %u %u\n", length, genid);
 
575
 
 
576
            obj = find_obj(pdf, obj, (length << 8) | (genid&0xff));
 
577
            if (!obj) {
 
578
                cli_dbgmsg("cli_pdf: indirect object not found\n");
 
579
                return 0;
 
580
            }
 
581
 
 
582
            q = pdf_nextobject(pdf->map+obj->start, pdf->size - obj->start);
 
583
            if (!q) {
 
584
                cli_dbgmsg("cli_pdf: next object not found\n");
 
585
                return 0;
 
586
            }
 
587
 
 
588
            length = atoi(q);
 
589
        }
 
590
    }
 
591
 
 
592
    /* limit length */
 
593
    if (start - pdf->map + length+5 > pdf->size)
 
594
        length = pdf->size - (start - pdf->map)-5;
 
595
 
 
596
    return length;
 
597
}
 
598
 
 
599
#define DUMP_MASK ((1 << OBJ_CONTENTS) | (1 << OBJ_FILTER_FLATE) | (1 << OBJ_FILTER_DCT) | (1 << OBJ_FILTER_AH) | (1 << OBJ_FILTER_A85) | (1 << OBJ_EMBEDDED_FILE) | (1 << OBJ_JAVASCRIPT) | (1 << OBJ_OPENACTION) | (1 << OBJ_LAUNCHACTION))
 
600
 
 
601
static int obj_size(struct pdf_struct *pdf, struct pdf_obj *obj, int binary)
 
602
{
 
603
    unsigned i = obj - pdf->objs;
 
604
 
 
605
    i++;
 
606
    if (i < pdf->nobjs) {
 
607
        int s = pdf->objs[i].start - obj->start - 4;
 
608
        if (s > 0) {
 
609
            if (!binary) {
 
610
                const char *p = pdf->map + obj->start;
 
611
                const char *q = p + s;
 
612
 
 
613
                while (q > p && (isspace(*q) || isdigit(*q)))
 
614
                       q--;
 
615
 
 
616
                if (q > p+5 && !memcmp(q-5,"endobj",6))
 
617
                    q -= 6;
 
618
 
 
619
                q = findNextNonWSBack(q, p);
 
620
                q++;
 
621
 
 
622
                return q - p;
 
623
            }
 
624
 
 
625
            return s;
 
626
        }
 
627
    }
 
628
 
 
629
    if (binary)
 
630
        return pdf->size - obj->start;
 
631
 
 
632
    return pdf->offset - obj->start - 6;
 
633
}
 
634
 
 
635
static int run_pdf_hooks(struct pdf_struct *pdf, enum pdf_phase phase, int fd, int dumpid)
 
636
{
 
637
    int ret;
 
638
    struct cli_bc_ctx *bc_ctx;
 
639
    cli_ctx *ctx = pdf->ctx;
 
640
    fmap_t *map;
 
641
 
 
642
    UNUSEDPARAM(dumpid);
 
643
 
 
644
    bc_ctx = cli_bytecode_context_alloc();
 
645
    if (!bc_ctx) {
 
646
        cli_errmsg("cli_pdf: can't allocate memory for bc_ctx");
 
647
        return CL_EMEM;
 
648
    }
 
649
 
 
650
    map = *ctx->fmap;
 
651
    if (fd != -1) {
 
652
        map = fmap(fd, 0, 0);
 
653
        if (!map) {
 
654
            cli_warnmsg("can't mmap pdf extracted obj\n");
 
655
            map = *ctx->fmap;
 
656
            fd = -1;
 
657
        }
 
658
    }
 
659
 
 
660
    cli_bytecode_context_setpdf(bc_ctx, phase, pdf->nobjs, pdf->objs, &pdf->flags, pdf->size, pdf->startoff);
 
661
    cli_bytecode_context_setctx(bc_ctx, ctx);
 
662
    ret = cli_bytecode_runhook(ctx, ctx->engine, bc_ctx, BC_PDF, map);
 
663
    cli_bytecode_context_destroy(bc_ctx);
 
664
 
 
665
    if (fd != -1)
 
666
        funmap(map);
 
667
 
 
668
    return ret;
 
669
}
 
670
 
 
671
static void dbg_printhex(const char *msg, const char *hex, unsigned len);
 
672
 
 
673
static void aes_decrypt(const unsigned char *in, off_t *length, unsigned char *q, char *key, unsigned key_n, int has_iv)
 
674
{
 
675
    unsigned long rk[RKLENGTH(256)];
 
676
    unsigned char iv[16];
 
677
    unsigned len = *length;
 
678
    unsigned char pad, i;
 
679
    int nrounds;
 
680
 
 
681
    cli_dbgmsg("cli_pdf: aes_decrypt: key length: %d, data length: %d\n", key_n, (int)*length);
 
682
    if (key_n > 32) {
 
683
        cli_dbgmsg("cli_pdf: aes_decrypt: key length is %d!\n", key_n*8);
 
684
        return;
 
685
    }
 
686
 
 
687
    if (len < 32) {
 
688
        cli_dbgmsg("cli_pdf: aes_decrypt: len is <32: %d\n", len);
 
689
        noisy_warnmsg("cli_pdf: aes_decrypt: len is <32: %d\n", len);
 
690
        return;
 
691
    }
 
692
 
 
693
    if (has_iv) {
 
694
        memcpy(iv, in, 16);
 
695
        in += 16;
 
696
        len -= 16;
 
697
    } else {
 
698
        memset(iv, 0, sizeof(iv));
 
699
    }
 
700
 
 
701
    cli_dbgmsg("aes_decrypt: Calling rijndaelSetupDecrypt\n");
 
702
    nrounds = rijndaelSetupDecrypt(rk, (const unsigned char *)key, key_n*8);
 
703
    cli_dbgmsg("aes_decrypt: Beginning rijndaelDecrypt\n");
 
704
 
 
705
    while (len >= 16) {
 
706
        unsigned i;
 
707
 
 
708
        rijndaelDecrypt(rk, nrounds, in, q);
 
709
        for (i=0;i<16;i++)
 
710
            q[i] ^= iv[i];
 
711
 
 
712
        memcpy(iv, in, 16);
 
713
 
 
714
        q += 16;
 
715
        in += 16;
 
716
        len -= 16;
 
717
    }
 
718
    if (has_iv) {
 
719
        len += 16;
 
720
        pad = q[-1];
 
721
 
 
722
        if (pad > 0x10) {
 
723
            cli_dbgmsg("cli_pdf: aes_decrypt: bad pad: %x (extra len: %d)\n", pad, len-16);
 
724
            noisy_warnmsg("cli_pdf: aes_decrypt: bad pad: %x (extra len: %d)\n", pad, len-16);
 
725
            *length -= len;
 
726
            return;
 
727
        }
 
728
 
 
729
        q -= pad;
 
730
        for (i=1;i<pad;i++) {
 
731
            if (q[i] != pad) {
 
732
                cli_dbgmsg("cli_pdf: aes_decrypt: bad pad: %x != %x\n",q[i],pad);
 
733
                noisy_warnmsg("cli_pdf: aes_decrypt: bad pad: %x != %x\n",q[i],pad);
 
734
                *length -= len;
 
735
 
 
736
                return;
 
737
            }
 
738
        }
 
739
 
 
740
        len += pad;
 
741
    }
 
742
 
 
743
    *length -= len;
 
744
 
 
745
    cli_dbgmsg("cli_pdf: aes_decrypt: length is %d\n", (int)*length);
 
746
}
 
747
 
 
748
 
 
749
static char *decrypt_any(struct pdf_struct *pdf, uint32_t id, const char *in, off_t *length, enum enc_method enc_method)
 
750
{
 
751
    unsigned char *key, *q, result[16];
 
752
    unsigned n;
 
753
    struct arc4_state arc4;
 
754
 
 
755
    if (!length || !*length || !in) {
 
756
        noisy_warnmsg("decrypt failed for obj %u %u\n", id>>8, id&0xff);
 
757
        return NULL;
 
758
    }
 
759
 
 
760
    n = pdf->keylen + 5;
 
761
    if (enc_method == ENC_AESV2)
 
762
        n += 4;
 
763
 
 
764
    key = cli_malloc(n);
 
765
    if (!key) {
 
766
        noisy_warnmsg("decrypt_any: malloc failed\n");
 
767
        return NULL;
 
768
    }
 
769
 
 
770
    memcpy(key, pdf->key, pdf->keylen);
 
771
    q = key + pdf->keylen;
 
772
    *q++ = id >> 8;
 
773
    *q++ = id >> 16;
 
774
    *q++ = id >> 24;
 
775
    *q++ = id;
 
776
    *q++ = 0;
 
777
    if (enc_method == ENC_AESV2)
 
778
        memcpy(q, "sAlT", 4);
 
779
 
 
780
    cl_hash_data("md5", key, n, result, NULL);
 
781
    free(key);
 
782
 
 
783
    n = pdf->keylen + 5;
 
784
    if (n > 16)
 
785
        n = 16;
 
786
 
 
787
    q = cli_malloc(*length);
 
788
    if (!q) {
 
789
        noisy_warnmsg("decrypt_any: malloc failed\n");
 
790
        return NULL;
 
791
    }
 
792
 
 
793
    switch (enc_method) {
 
794
    case ENC_V2:
 
795
        cli_dbgmsg("cli_pdf: enc is v2\n");
 
796
        memcpy(q, in, *length);
 
797
        arc4_init(&arc4, result, n);
 
798
        arc4_apply(&arc4, q, *length);
 
799
 
 
800
        noisy_msg(pdf, "decrypted ARC4 data\n");
 
801
 
 
802
        break;
 
803
    case ENC_AESV2:
 
804
        cli_dbgmsg("cli_pdf: enc is aesv2\n");
 
805
        aes_decrypt((const unsigned char *)in, length, q, (char *)result, n, 1);
 
806
 
 
807
        noisy_msg(pdf, "decrypted AES(v2) data\n");
 
808
 
 
809
        break;
 
810
    case ENC_AESV3:
 
811
        cli_dbgmsg("cli_pdf: enc is aesv3\n");
 
812
        if (pdf->keylen == 0) {
 
813
            cli_dbgmsg("cli_pdf: no key\n");
 
814
            return NULL;
 
815
        }
 
816
 
 
817
        aes_decrypt((const unsigned char *)in, length, q, pdf->key, pdf->keylen, 1);
 
818
 
 
819
        noisy_msg(pdf, "decrypted AES(v3) data\n");
 
820
 
 
821
        break;
 
822
    case ENC_IDENTITY:
 
823
        cli_dbgmsg("cli_pdf: enc is identity\n");
 
824
        memcpy(q, in, *length);
 
825
 
 
826
        noisy_msg(pdf, "identity encryption\n");
 
827
 
 
828
        break;
 
829
    case ENC_NONE:
 
830
        cli_dbgmsg("cli_pdf: enc is none\n");
 
831
 
 
832
        noisy_msg(pdf, "encryption is none\n");
 
833
 
 
834
        free(q);
 
835
        return NULL;
 
836
    case ENC_UNKNOWN:
 
837
        cli_dbgmsg("cli_pdf: enc is unknown\n");
 
838
        free(q);
 
839
 
 
840
        noisy_warnmsg("decrypt_any: unknown encryption method for obj %u %u\n",
 
841
               id>>8,id&0xff);
 
842
 
 
843
        return NULL;
 
844
    }
 
845
 
 
846
    return (char *)q;
 
847
}
 
848
 
 
849
static enum enc_method get_enc_method(struct pdf_struct *pdf, struct pdf_obj *obj)
 
850
{
 
851
    if (obj->flags & (1 << OBJ_EMBEDDED_FILE))
 
852
        return pdf->enc_method_embeddedfile;
 
853
 
 
854
    if (obj->flags & (1 << OBJ_STREAM))
 
855
        return pdf->enc_method_stream;
 
856
 
 
857
    return pdf->enc_method_string;
 
858
}
 
859
 
 
860
enum cstate {
 
861
    CSTATE_NONE,
 
862
    CSTATE_TJ,
 
863
    CSTATE_TJ_PAROPEN
 
864
};
 
865
 
 
866
static void process(struct text_norm_state *s, enum cstate *st, const char *buf, int length, int fout)
 
867
{
 
868
    do {
 
869
        switch (*st) {
 
870
        case CSTATE_NONE:
 
871
            if (*buf == '[') {
 
872
                *st = CSTATE_TJ;
 
873
            } else {
 
874
                const char *nl = memchr(buf, '\n', length);
 
875
                if (!nl)
 
876
                    return;
 
877
 
 
878
                length -= nl - buf;
 
879
                buf = nl;
 
880
            }
 
881
 
 
882
            break;
 
883
        case CSTATE_TJ:
 
884
            if (*buf == '(')
 
885
                *st = CSTATE_TJ_PAROPEN;
 
886
 
 
887
            break;
 
888
        case CSTATE_TJ_PAROPEN:
 
889
            if (*buf == ')') {
 
890
                *st = CSTATE_TJ;
 
891
            } else {
 
892
                if (text_normalize_buffer(s, (const unsigned char *)buf, 1) != 1) {
 
893
                    cli_writen(fout, s->out, s->out_pos);
 
894
                    text_normalize_reset(s);
 
895
                }
 
896
            }
 
897
 
 
898
            break;
 
899
        }
 
900
 
 
901
        buf++;
 
902
        length--;
 
903
    } while (length > 0);
 
904
}
 
905
 
 
906
static int pdf_scan_contents(int fd, struct pdf_struct *pdf)
 
907
{
 
908
    struct text_norm_state s;
 
909
    char fullname[1024];
 
910
    char outbuff[BUFSIZ];
 
911
    char inbuf[BUFSIZ];
 
912
    int fout, n, rc;
 
913
    enum cstate st = CSTATE_NONE;
 
914
 
 
915
    snprintf(fullname, sizeof(fullname), "%s"PATHSEP"pdf%02u_c", pdf->dir, (pdf->files-1));
 
916
    fout = open(fullname,O_RDWR|O_CREAT|O_EXCL|O_TRUNC|O_BINARY, 0600);
 
917
    if (fout < 0) {
 
918
        char err[128];
 
919
 
 
920
        cli_errmsg("cli_pdf: can't create temporary file %s: %s\n", fullname, cli_strerror(errno, err, sizeof(err)));
 
921
        return CL_ETMPFILE;
 
922
    }
 
923
 
 
924
    text_normalize_init(&s, (unsigned char *)outbuff, sizeof(outbuff));
 
925
    while (1) {
 
926
        n = cli_readn(fd, inbuf, sizeof(inbuf));
 
927
        if (n <= 0)
 
928
            break;
 
929
 
 
930
        process(&s, &st, inbuf, n, fout);
 
931
    }
 
932
 
 
933
    cli_writen(fout, s.out, s.out_pos);
 
934
 
 
935
    lseek(fout, 0, SEEK_SET);
 
936
    rc = cli_magic_scandesc(fout, pdf->ctx);
 
937
    close(fout);
 
938
 
 
939
    if (!pdf->ctx->engine->keeptmp)
 
940
        if (cli_unlink(fullname) && rc != CL_VIRUS)
 
941
            rc = CL_EUNLINK;
 
942
 
 
943
    return rc;
 
944
}
 
945
 
 
946
static const char *pdf_getdict(const char *q0, int* len, const char *key);
 
947
static char *pdf_readval(const char *q, int len, const char *key);
 
948
static enum enc_method parse_enc_method(const char *dict, unsigned len, const char *key, enum enc_method def);
 
949
static char *pdf_readstring(const char *q0, int len, const char *key, unsigned *slen, const char **qend, int noescape);
 
950
 
 
951
int pdf_extract_obj(struct pdf_struct *pdf, struct pdf_obj *obj, uint32_t flags)
 
952
{
 
953
    char fullname[NAME_MAX + 1];
 
954
    int fout;
 
955
    off_t sum = 0;
 
956
    int rc = CL_SUCCESS;
 
957
    char *ascii_decoded = NULL;
 
958
    char *decrypted = NULL;
 
959
    int dump = 1;
 
960
 
 
961
    cli_dbgmsg("pdf_extract_obj: obj %u %u\n", obj->id>>8, obj->id&0xff);
 
962
 
 
963
    /* TODO: call bytecode hook here, allow override dumpability */
 
964
    if ((!(obj->flags & (1 << OBJ_STREAM)) || (obj->flags & (1 << OBJ_HASFILTERS))) && !(obj->flags & DUMP_MASK)) {
 
965
        /* don't dump all streams */
 
966
        dump = 0;
 
967
    }
 
968
 
 
969
    if ((obj->flags & (1 << OBJ_IMAGE)) && !(obj->flags & (1 << OBJ_FILTER_DCT))) {
 
970
        /* don't dump / scan non-JPG images */
 
971
        dump = 0;
 
972
    }
 
973
 
 
974
    if (obj->flags & (1 << OBJ_FORCEDUMP)) {
 
975
        /* bytecode can force dump by setting this flag */
 
976
        dump = 1;
 
977
    }
 
978
 
 
979
    if (!dump)
 
980
        return CL_CLEAN;
 
981
 
 
982
    cli_dbgmsg("cli_pdf: dumping obj %u %u\n", obj->id>>8, obj->id&0xff);
 
983
 
 
984
    snprintf(fullname, sizeof(fullname), "%s"PATHSEP"pdf%02u", pdf->dir, pdf->files++);
 
985
    fout = open(fullname,O_RDWR|O_CREAT|O_EXCL|O_TRUNC|O_BINARY, 0600);
 
986
    if (fout < 0) {
 
987
        char err[128];
 
988
        cli_errmsg("cli_pdf: can't create temporary file %s: %s\n", fullname, cli_strerror(errno, err, sizeof(err)));
 
989
        free(ascii_decoded);
 
990
 
 
991
        return CL_ETMPFILE;
 
992
    }
 
993
 
 
994
    if (!(flags & PDF_EXTRACT_OBJ_SCAN))
 
995
        obj->path = strdup(fullname);
 
996
 
 
997
    do {
 
998
        if (obj->flags & (1 << OBJ_STREAM)) {
 
999
            const char *start = pdf->map + obj->start;
 
1000
            const char *flate_orig;
 
1001
            off_t p_stream = 0, p_endstream = 0;
 
1002
            off_t length, flate_orig_length;
 
1003
 
 
1004
            find_stream_bounds(start, pdf->size - obj->start,
 
1005
                       pdf->size - obj->start,
 
1006
                       &p_stream, &p_endstream,
 
1007
                       pdf->enc_method_stream <= ENC_IDENTITY &&
 
1008
                       pdf->enc_method_embeddedfile <= ENC_IDENTITY);
 
1009
 
 
1010
            if (p_stream && p_endstream) {
 
1011
                const char *flate_in;
 
1012
                long ascii_decoded_size = 0;
 
1013
                size_t size = p_endstream - p_stream;
 
1014
                off_t orig_length;
 
1015
 
 
1016
                length = find_length(pdf, obj, start, p_stream);
 
1017
                if (length < 0)
 
1018
                    length = 0;
 
1019
 
 
1020
                orig_length = length;
 
1021
                if (length > pdf->size || obj->start + p_stream + length > pdf->size) {
 
1022
                    cli_dbgmsg("cli_pdf: length out of file: %ld + %ld > %ld\n",
 
1023
                           p_stream, length, pdf->size);
 
1024
                    noisy_warnmsg("length out of file, truncated: %ld + %ld > %ld\n",
 
1025
                           p_stream, length, pdf->size);
 
1026
                    length = pdf->size - (obj->start + p_stream);
 
1027
                }
 
1028
 
 
1029
                if (!(obj->flags & (1 << OBJ_FILTER_FLATE)) && length <= 0) {
 
1030
                    const char *q = start + p_endstream;
 
1031
                    length = size;
 
1032
                    q--;
 
1033
 
 
1034
                    if (*q == '\n') {
 
1035
                        q--;
 
1036
                        length--;
 
1037
 
 
1038
                        if (*q == '\r')
 
1039
                            length--;
 
1040
                    } else if (*q == '\r') {
 
1041
                        length--;
 
1042
                    }
 
1043
 
 
1044
                    if (length < 0)
 
1045
                        length = 0;
 
1046
 
 
1047
                    cli_dbgmsg("cli_pdf: calculated length %ld\n", length);
 
1048
                } else {
 
1049
                    if (size > (size_t)length+2) {
 
1050
                        cli_dbgmsg("cli_pdf: calculated length %ld < %ld\n",
 
1051
                               length, size);
 
1052
                        length = size;
 
1053
                    }
 
1054
                }
 
1055
 
 
1056
                if (orig_length && size > (size_t)orig_length + 20) {
 
1057
                    cli_dbgmsg("cli_pdf: orig length: %ld, length: %ld, size: %ld\n", orig_length, length, size);
 
1058
                    pdfobj_flag(pdf, obj, BAD_STREAMLEN);
 
1059
                }
 
1060
 
 
1061
                if (!length) {
 
1062
                    length = size;
 
1063
                    if (!length) {
 
1064
                        cli_dbgmsg("pdf_extract_obj: length and size both 0\n");
 
1065
                        break; /* Empty stream, nothing to scan */
 
1066
                    }
 
1067
                }
 
1068
 
 
1069
                flate_orig = flate_in = start + p_stream;
 
1070
                flate_orig_length = length;
 
1071
                if (pdf->flags & (1 << DECRYPTABLE_PDF)) {
 
1072
                    enum enc_method enc = get_enc_method(pdf, obj);
 
1073
 
 
1074
                    if (obj->flags & (1 << OBJ_FILTER_CRYPT)) {
 
1075
                        int len = p_stream;
 
1076
                        const char *q = pdf_getdict(start, &len, "/DecodeParams");
 
1077
 
 
1078
                        enc = ENC_IDENTITY;
 
1079
                        if (q && pdf->CF) {
 
1080
                            char *name = pdf_readval(q, len, "/Name");
 
1081
                            cli_dbgmsg("cli_pdf: Crypt filter %s\n", name);
 
1082
 
 
1083
                            if (name && strcmp(name, "/Identity"))
 
1084
                                enc = parse_enc_method(pdf->CF, pdf->CF_n, name, enc); 
 
1085
 
 
1086
                            free(name);
 
1087
                        }
 
1088
                    }
 
1089
 
 
1090
                    if (cli_memstr(start, p_stream, "/XRef", 5)) {
 
1091
                        cli_dbgmsg("cli_pdf: cross reference stream, skipping\n");
 
1092
                    } else {
 
1093
                        decrypted = decrypt_any(pdf, obj->id, flate_in, &length,
 
1094
                                    enc);
 
1095
 
 
1096
                        if (decrypted)
 
1097
                            flate_in = decrypted;
 
1098
                    }
 
1099
                }
 
1100
 
 
1101
                if (obj->flags & (1 << OBJ_FILTER_AH)) {
 
1102
                    ascii_decoded = cli_malloc(length/2 + 1);
 
1103
                    if (!ascii_decoded) {
 
1104
                        cli_errmsg("Cannot allocate memory for ascii_decoded\n");
 
1105
                        rc = CL_EMEM;
 
1106
                        break;
 
1107
                    }
 
1108
                    ascii_decoded_size = asciihexdecode(flate_in,
 
1109
                                        length,
 
1110
                                        ascii_decoded);
 
1111
                } else if (obj->flags & (1 << OBJ_FILTER_A85)) {
 
1112
                    ascii_decoded = cli_malloc(length*5);
 
1113
                    if (!ascii_decoded) {
 
1114
                        cli_errmsg("Cannot allocate memory for ascii_decoded\n");
 
1115
                        rc = CL_EMEM;
 
1116
                        break;
 
1117
                    }
 
1118
 
 
1119
                    ascii_decoded_size = ascii85decode(flate_in, length, (unsigned char*)ascii_decoded);
 
1120
                }
 
1121
 
 
1122
                if (ascii_decoded_size < 0) {
 
1123
                    /* don't flag for images or truncated objs*/
 
1124
                    if (!(obj->flags & ((1 << OBJ_IMAGE) | (1 << OBJ_TRUNCATED))))
 
1125
                        pdfobj_flag(pdf, obj, BAD_ASCIIDECODE);
 
1126
 
 
1127
                    cli_dbgmsg("cli_pdf: failed to asciidecode in %u %u obj\n", obj->id>>8,obj->id&0xff);
 
1128
                    free(ascii_decoded);
 
1129
                    ascii_decoded = NULL;
 
1130
                    /* attempt to directly flatedecode it */
 
1131
                }
 
1132
 
 
1133
                /* either direct or ascii-decoded input */
 
1134
                if (!ascii_decoded)
 
1135
                    ascii_decoded_size = length;
 
1136
                else
 
1137
                    flate_in = ascii_decoded;
 
1138
 
 
1139
                if (obj->flags & (1 << OBJ_FILTER_FLATE)) {
 
1140
                    cli_dbgmsg("cli_pdf: deflate len %ld (orig %ld)\n", ascii_decoded_size, (long)orig_length);
 
1141
                    rc = filter_flatedecode(pdf, obj, flate_in, ascii_decoded_size, fout, &sum);
 
1142
                    if (rc == CL_EFORMAT) {
 
1143
                        if (decrypted) {
 
1144
                            flate_in = flate_orig;
 
1145
                            ascii_decoded_size = flate_orig_length;
 
1146
                        }
 
1147
 
 
1148
                        cli_dbgmsg("cli_pdf: dumping raw stream (probably encrypted)\n");
 
1149
                        noisy_warnmsg("cli_pdf: dumping raw stream, probably encrypted and we failed to decrypt'n");
 
1150
 
 
1151
                        if (filter_writen(pdf, obj, fout, flate_in, ascii_decoded_size, &sum) != ascii_decoded_size) {
 
1152
                            cli_errmsg("cli_pdf: failed to write output file\n");
 
1153
                            return CL_EWRITE;
 
1154
                        }
 
1155
                    }
 
1156
                } else {
 
1157
                    if (filter_writen(pdf, obj, fout, flate_in, ascii_decoded_size, &sum) != ascii_decoded_size)
 
1158
                        rc = CL_EWRITE;
 
1159
                }
 
1160
            } else {
 
1161
                noisy_warnmsg("cannot find stream bounds for obj %u %u\n", obj->id>>8, obj->id&0xff);
 
1162
            }
 
1163
 
 
1164
        } else if (obj->flags & (1 << OBJ_JAVASCRIPT)) {
 
1165
            const char *q2;
 
1166
            const char *q = pdf->map+obj->start;
 
1167
            /* TODO: get obj-endobj size */
 
1168
            off_t bytesleft = obj_size(pdf, obj, 0);
 
1169
            if (bytesleft < 0)
 
1170
                break;
 
1171
 
 
1172
            do {
 
1173
                char *js = NULL;
 
1174
                off_t js_len = 0;
 
1175
                const char *q3;
 
1176
 
 
1177
                q2 = cli_memstr(q, bytesleft, "/JavaScript", 11);
 
1178
                if (!q2)
 
1179
                    break;
 
1180
 
 
1181
                bytesleft -= q2 - q + 11;
 
1182
                q = q2 + 11;
 
1183
 
 
1184
                js = pdf_readstring(q, bytesleft,  "/JS", NULL, &q2, !(pdf->flags & (1<<DECRYPTABLE_PDF)));
 
1185
                bytesleft -= q2 - q;
 
1186
                q = q2;
 
1187
 
 
1188
                if (js) {
 
1189
                    const char *out = js;
 
1190
                    js_len = strlen(js);
 
1191
                    if (pdf->flags & (1 << DECRYPTABLE_PDF)) {
 
1192
                        cli_dbgmsg("cli_pdf: encrypted string\n");
 
1193
                        decrypted = decrypt_any(pdf, obj->id, js, &js_len,
 
1194
                        pdf->enc_method_string);
 
1195
 
 
1196
                        if (decrypted) {
 
1197
                            noisy_msg(pdf, "decrypted Javascript string from obj %u %u\n", obj->id>>8,obj->id&0xff);
 
1198
                            out = decrypted;
 
1199
                        }
 
1200
                    }
 
1201
 
 
1202
                    if (filter_writen(pdf, obj, fout, out, js_len, &sum) != js_len) {
 
1203
                        rc = CL_EWRITE;
 
1204
                                free(js);
 
1205
                        break;
 
1206
                    }
 
1207
 
 
1208
                    free(js);
 
1209
                    cli_dbgmsg("bytesleft: %d\n", (int)bytesleft);
 
1210
 
 
1211
                    if (bytesleft > 0) {
 
1212
                        q2 = pdf_nextobject(q, bytesleft);
 
1213
                        if (!q2)
 
1214
                            q2 = q + bytesleft - 1;
 
1215
 
 
1216
                        /* non-conforming PDFs that don't escape ) properly */
 
1217
                        q3 = memchr(q, ')', bytesleft);
 
1218
                        if (q3 && q3 < q2)
 
1219
                            q2 = q3;
 
1220
 
 
1221
                        while (q2 > q && q2[-1] == ' ')
 
1222
                            q2--;
 
1223
 
 
1224
                        if (q2 > q) {
 
1225
                            q--;
 
1226
                            filter_writen(pdf, obj, fout, q, q2 - q, &sum);
 
1227
                            q++;
 
1228
                        }
 
1229
                    }
 
1230
                }
 
1231
 
 
1232
            } while (bytesleft > 0);
 
1233
        } else {
 
1234
            off_t bytesleft = obj_size(pdf, obj, 0);
 
1235
 
 
1236
            if (bytesleft < 0)
 
1237
                rc = CL_EFORMAT;
 
1238
            else if (filter_writen(pdf, obj, fout , pdf->map + obj->start, bytesleft,&sum) != bytesleft)
 
1239
                rc = CL_EWRITE;
 
1240
        }
 
1241
    } while (0);
 
1242
 
 
1243
    cli_dbgmsg("cli_pdf: extracted %ld bytes %u %u obj to %s\n", sum, obj->id>>8, obj->id&0xff, fullname);
 
1244
 
 
1245
    if (flags & PDF_EXTRACT_OBJ_SCAN && sum) {
 
1246
        int rc2;
 
1247
 
 
1248
        cli_updatelimits(pdf->ctx, sum);
 
1249
 
 
1250
        /* TODO: invoke bytecode on this pdf obj with metainformation associated */
 
1251
        lseek(fout, 0, SEEK_SET);
 
1252
        rc2 = cli_magic_scandesc(fout, pdf->ctx);
 
1253
        if (rc2 == CL_VIRUS || rc == CL_SUCCESS)
 
1254
            rc = rc2;
 
1255
 
 
1256
        if ((rc == CL_CLEAN) || ((rc == CL_VIRUS) && (pdf->ctx->options & CL_SCAN_ALLMATCHES))) {
 
1257
            rc2 = run_pdf_hooks(pdf, PDF_PHASE_POSTDUMP, fout, obj - pdf->objs);
 
1258
            if (rc2 == CL_VIRUS)
 
1259
                rc = rc2;
 
1260
        }
 
1261
 
 
1262
        if (((rc == CL_CLEAN) || ((rc == CL_VIRUS) && (pdf->ctx->options & CL_SCAN_ALLMATCHES))) && (obj->flags & (1 << OBJ_CONTENTS))) {
 
1263
            lseek(fout, 0, SEEK_SET);
 
1264
            cli_dbgmsg("cli_pdf: dumping contents %u %u\n", obj->id>>8, obj->id&0xff);
 
1265
 
 
1266
            rc2 = pdf_scan_contents(fout, pdf);
 
1267
            if (rc2 == CL_VIRUS)
 
1268
                rc = rc2;
 
1269
 
 
1270
            noisy_msg(pdf, "extracted text from obj %u %u\n", obj->id>>8, obj->id&0xff);
 
1271
        }
 
1272
    }
 
1273
 
 
1274
    close(fout);
 
1275
    free(ascii_decoded);
 
1276
    free(decrypted);
 
1277
 
 
1278
    if (flags & PDF_EXTRACT_OBJ_SCAN && !pdf->ctx->engine->keeptmp)
 
1279
        if (cli_unlink(fullname) && rc != CL_VIRUS)
 
1280
            rc = CL_EUNLINK;
 
1281
 
 
1282
    return rc;
 
1283
}
 
1284
 
 
1285
enum objstate {
 
1286
    STATE_NONE,
 
1287
    STATE_S,
 
1288
    STATE_FILTER,
 
1289
    STATE_JAVASCRIPT,
 
1290
    STATE_OPENACTION,
 
1291
    STATE_LINEARIZED,
 
1292
    STATE_LAUNCHACTION,
 
1293
    STATE_CONTENTS,
 
1294
    STATE_ANY /* for actions table below */
 
1295
};
 
1296
 
 
1297
#define NAMEFLAG_NONE       0x0
 
1298
#define NAMEFLAG_HEURISTIC  0x1
 
1299
 
 
1300
struct pdfname_action {
 
1301
    const char *pdfname;
 
1302
    enum pdf_objflags set_objflag;/* OBJ_DICT is noop */
 
1303
    enum objstate from_state;/* STATE_NONE is noop */
 
1304
    enum objstate to_state;
 
1305
    uint32_t nameflags;
 
1306
#if HAVE_JSON
 
1307
    void (*pdf_stats_cb)(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act);
 
1308
#endif
 
1309
};
 
1310
 
 
1311
#if HAVE_JSON
 
1312
static struct pdfname_action pdfname_actions[] = {
 
1313
    {"ASCIIHexDecode", OBJ_FILTER_AH, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC, ASCIIHexDecode_cb},
 
1314
    {"ASCII85Decode", OBJ_FILTER_A85, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC, ASCII85Decode_cb},
 
1315
    {"A85", OBJ_FILTER_A85, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC, ASCII85Decode_cb},
 
1316
    {"AHx", OBJ_FILTER_AH, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC, ASCIIHexDecode_cb},
 
1317
    {"EmbeddedFile", OBJ_EMBEDDED_FILE, STATE_NONE, STATE_NONE, NAMEFLAG_HEURISTIC, EmbeddedFile_cb},
 
1318
    {"FlateDecode", OBJ_FILTER_FLATE, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC, FlateDecode_cb},
 
1319
    {"Fl", OBJ_FILTER_FLATE, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC, FlateDecode_cb},
 
1320
    {"Image", OBJ_IMAGE, STATE_NONE, STATE_NONE, NAMEFLAG_HEURISTIC, Image_cb},
 
1321
    {"LZWDecode", OBJ_FILTER_LZW, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC, LZWDecode_cb},
 
1322
    {"LZW", OBJ_FILTER_LZW, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC, LZWDecode_cb},
 
1323
    {"RunLengthDecode", OBJ_FILTER_RL, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC, RunLengthDecode_cb},
 
1324
    {"RL", OBJ_FILTER_RL, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC, RunLengthDecode_cb},
 
1325
    {"CCITTFaxDecode", OBJ_FILTER_FAX, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC, CCITTFaxDecode_cb},
 
1326
    {"CCF", OBJ_FILTER_FAX, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC, CCITTFaxDecode_cb},
 
1327
    {"JBIG2Decode", OBJ_FILTER_DCT, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC, JBIG2Decode_cb},
 
1328
    {"DCTDecode", OBJ_FILTER_DCT, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC, DCTDecode_cb},
 
1329
    {"DCT", OBJ_FILTER_DCT, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC, DCTDecode_cb},
 
1330
    {"JPXDecode", OBJ_FILTER_JPX, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC, JPXDecode_cb},
 
1331
    {"Crypt",  OBJ_FILTER_CRYPT, STATE_FILTER, STATE_NONE, NAMEFLAG_HEURISTIC, Crypt_cb},
 
1332
    {"Standard", OBJ_FILTER_STANDARD, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC, Standard_cb},
 
1333
    {"Sig",    OBJ_SIGNED, STATE_ANY, STATE_NONE, NAMEFLAG_HEURISTIC, Sig_cb},
 
1334
    {"V",     OBJ_SIGNED, STATE_ANY, STATE_NONE, NAMEFLAG_HEURISTIC, NULL},
 
1335
    {"R",     OBJ_SIGNED, STATE_ANY, STATE_NONE, NAMEFLAG_HEURISTIC, NULL},
 
1336
    {"Linearized", OBJ_DICT, STATE_NONE, STATE_LINEARIZED, NAMEFLAG_HEURISTIC, NULL},
 
1337
    {"Filter", OBJ_HASFILTERS, STATE_ANY, STATE_FILTER, NAMEFLAG_HEURISTIC, NULL},
 
1338
    {"JavaScript", OBJ_JAVASCRIPT, STATE_S, STATE_JAVASCRIPT, NAMEFLAG_HEURISTIC, JavaScript_cb},
 
1339
    {"Length", OBJ_DICT, STATE_FILTER, STATE_NONE, NAMEFLAG_HEURISTIC, NULL},
 
1340
    {"S", OBJ_DICT, STATE_NONE, STATE_S, NAMEFLAG_HEURISTIC, NULL},
 
1341
    {"Type", OBJ_DICT, STATE_NONE, STATE_NONE, NAMEFLAG_HEURISTIC, NULL},
 
1342
    {"OpenAction", OBJ_OPENACTION, STATE_ANY, STATE_OPENACTION, NAMEFLAG_HEURISTIC, OpenAction_cb},
 
1343
    {"Launch", OBJ_LAUNCHACTION, STATE_ANY, STATE_LAUNCHACTION, NAMEFLAG_HEURISTIC, Launch_cb},
 
1344
    {"Page", OBJ_PAGE, STATE_NONE, STATE_NONE, NAMEFLAG_HEURISTIC, Page_cb},
 
1345
    {"Contents", OBJ_CONTENTS, STATE_NONE, STATE_CONTENTS, NAMEFLAG_HEURISTIC, NULL},
 
1346
    {"Author", OBJ_DICT, STATE_NONE, STATE_NONE, NAMEFLAG_NONE, Author_cb},
 
1347
    {"Producer", OBJ_DICT, STATE_NONE, STATE_NONE, NAMEFLAG_NONE, Producer_cb},
 
1348
    {"CreationDate", OBJ_DICT, STATE_NONE, STATE_NONE, NAMEFLAG_NONE, CreationDate_cb},
 
1349
    {"ModDate", OBJ_DICT, STATE_NONE, STATE_NONE, NAMEFLAG_NONE, ModificationDate_cb},
 
1350
    {"Creator", OBJ_DICT, STATE_NONE, STATE_NONE, NAMEFLAG_NONE, Creator_cb},
 
1351
    {"Title", OBJ_DICT, STATE_NONE, STATE_NONE, NAMEFLAG_NONE, Title_cb},
 
1352
    {"Keywords", OBJ_DICT, STATE_NONE, STATE_NONE, NAMEFLAG_NONE, Keywords_cb},
 
1353
    {"Subject", OBJ_DICT, STATE_NONE, STATE_NONE, NAMEFLAG_NONE, Subject_cb},
 
1354
    {"Pages", OBJ_DICT, STATE_NONE, STATE_NONE, NAMEFLAG_NONE, Pages_cb},
 
1355
    {"Colors", OBJ_DICT, STATE_NONE, STATE_NONE, NAMEFLAG_NONE, Colors_cb},
 
1356
    {"RichMedia", OBJ_DICT, STATE_NONE, STATE_NONE, NAMEFLAG_NONE, RichMedia_cb},
 
1357
    {"AcroForm", OBJ_DICT, STATE_NONE, STATE_NONE, NAMEFLAG_NONE, AcroForm_cb},
 
1358
    {"XFA", OBJ_DICT, STATE_NONE, STATE_NONE, NAMEFLAG_NONE, XFA_cb}
 
1359
};
 
1360
#else
 
1361
static struct pdfname_action pdfname_actions[] = {
 
1362
    {"ASCIIHexDecode", OBJ_FILTER_AH, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC},
 
1363
    {"ASCII85Decode", OBJ_FILTER_A85, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC},
 
1364
    {"A85", OBJ_FILTER_A85, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC},
 
1365
    {"AHx", OBJ_FILTER_AH, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC},
 
1366
    {"EmbeddedFile", OBJ_EMBEDDED_FILE, STATE_NONE, STATE_NONE, NAMEFLAG_HEURISTIC},
 
1367
    {"FlateDecode", OBJ_FILTER_FLATE, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC},
 
1368
    {"Fl", OBJ_FILTER_FLATE, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC},
 
1369
    {"Image", OBJ_IMAGE, STATE_NONE, STATE_NONE, NAMEFLAG_HEURISTIC},
 
1370
    {"LZWDecode", OBJ_FILTER_LZW, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC},
 
1371
    {"LZW", OBJ_FILTER_LZW, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC},
 
1372
    {"RunLengthDecode", OBJ_FILTER_RL, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC},
 
1373
    {"RL", OBJ_FILTER_RL, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC},
 
1374
    {"CCITTFaxDecode", OBJ_FILTER_FAX, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC},
 
1375
    {"CCF", OBJ_FILTER_FAX, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC},
 
1376
    {"JBIG2Decode", OBJ_FILTER_DCT, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC},
 
1377
    {"DCTDecode", OBJ_FILTER_DCT, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC},
 
1378
    {"DCT", OBJ_FILTER_DCT, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC},
 
1379
    {"JPXDecode", OBJ_FILTER_JPX, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC},
 
1380
    {"Crypt",  OBJ_FILTER_CRYPT, STATE_FILTER, STATE_NONE, NAMEFLAG_HEURISTIC},
 
1381
    {"Standard", OBJ_FILTER_STANDARD, STATE_FILTER, STATE_FILTER, NAMEFLAG_HEURISTIC},
 
1382
    {"Sig",    OBJ_SIGNED, STATE_ANY, STATE_NONE, NAMEFLAG_HEURISTIC},
 
1383
    {"V",     OBJ_SIGNED, STATE_ANY, STATE_NONE, NAMEFLAG_HEURISTIC},
 
1384
    {"R",     OBJ_SIGNED, STATE_ANY, STATE_NONE, NAMEFLAG_HEURISTIC},
 
1385
    {"Linearized", OBJ_DICT, STATE_NONE, STATE_LINEARIZED, NAMEFLAG_HEURISTIC},
 
1386
    {"Filter", OBJ_HASFILTERS, STATE_ANY, STATE_FILTER, NAMEFLAG_HEURISTIC},
 
1387
    {"JavaScript", OBJ_JAVASCRIPT, STATE_S, STATE_JAVASCRIPT, NAMEFLAG_HEURISTIC},
 
1388
    {"Length", OBJ_DICT, STATE_FILTER, STATE_NONE, NAMEFLAG_HEURISTIC},
 
1389
    {"S", OBJ_DICT, STATE_NONE, STATE_S, NAMEFLAG_HEURISTIC},
 
1390
    {"Type", OBJ_DICT, STATE_NONE, STATE_NONE, NAMEFLAG_HEURISTIC},
 
1391
    {"OpenAction", OBJ_OPENACTION, STATE_ANY, STATE_OPENACTION, NAMEFLAG_HEURISTIC},
 
1392
    {"Launch", OBJ_LAUNCHACTION, STATE_ANY, STATE_LAUNCHACTION, NAMEFLAG_HEURISTIC},
 
1393
    {"Page", OBJ_PAGE, STATE_NONE, STATE_NONE, NAMEFLAG_HEURISTIC},
 
1394
    {"Contents", OBJ_CONTENTS, STATE_NONE, STATE_CONTENTS, NAMEFLAG_HEURISTIC}
 
1395
};
 
1396
#endif
 
1397
 
 
1398
#define KNOWN_FILTERS ((1 << OBJ_FILTER_AH) | (1 << OBJ_FILTER_RL) | (1 << OBJ_FILTER_A85) | (1 << OBJ_FILTER_FLATE) | (1 << OBJ_FILTER_LZW) | (1 << OBJ_FILTER_FAX) | (1 << OBJ_FILTER_DCT) | (1 << OBJ_FILTER_JPX) | (1 << OBJ_FILTER_CRYPT))
 
1399
 
 
1400
static void handle_pdfname(struct pdf_struct *pdf, struct pdf_obj *obj, const char *pdfname, int escapes, enum objstate *state)
 
1401
{
 
1402
    struct pdfname_action *act = NULL;
 
1403
    unsigned j;
 
1404
 
 
1405
    obj->statsflags |= OBJ_FLAG_PDFNAME_DONE;
 
1406
 
 
1407
    for (j=0;j<sizeof(pdfname_actions)/sizeof(pdfname_actions[0]);j++) {
 
1408
        if (!strcmp(pdfname, pdfname_actions[j].pdfname)) {
 
1409
            act = &pdfname_actions[j];
 
1410
            break;
 
1411
        }
 
1412
    }
 
1413
 
 
1414
    if (!act) {
 
1415
        /* these are digital signature objects, filter doesn't matter,
 
1416
         * we don't need them anyway */
 
1417
        if (*state == STATE_FILTER && !(obj->flags & (1 << OBJ_SIGNED)) && !(obj->flags & KNOWN_FILTERS)) {
 
1418
            cli_dbgmsg("cli_pdf: unknown filter %s\n", pdfname);
 
1419
            obj->flags |= 1 << OBJ_FILTER_UNKNOWN;
 
1420
        }
 
1421
 
 
1422
        return;
 
1423
    }
 
1424
 
 
1425
    if ((act->nameflags & NAMEFLAG_HEURISTIC) && escapes) {
 
1426
        /* if a commonly used PDF name is escaped that is certainly
 
1427
           suspicious. */
 
1428
        cli_dbgmsg("cli_pdf: pdfname %s is escaped\n", pdfname);
 
1429
        pdfobj_flag(pdf, obj, ESCAPED_COMMON_PDFNAME);
 
1430
    }
 
1431
 
 
1432
#if HAVE_JSON
 
1433
    if ((act->pdf_stats_cb))
 
1434
        act->pdf_stats_cb(pdf, obj, act);
 
1435
#endif
 
1436
 
 
1437
    if (act->from_state == *state || act->from_state == STATE_ANY) {
 
1438
        *state = act->to_state;
 
1439
 
 
1440
        if (*state == STATE_FILTER && act->set_objflag !=OBJ_DICT && (obj->flags & (1 << act->set_objflag))) {
 
1441
            cli_dbgmsg("cli_pdf: duplicate stream filter %s\n", pdfname);
 
1442
            pdfobj_flag(pdf, obj, BAD_STREAM_FILTERS);
 
1443
        }
 
1444
 
 
1445
        obj->flags |= 1 << act->set_objflag;
 
1446
    } else {
 
1447
        /* auto-reset states */
 
1448
        switch (*state) {
 
1449
        case STATE_S:
 
1450
            *state = STATE_NONE;
 
1451
            break;
 
1452
        default:
 
1453
            break;
 
1454
        }
 
1455
    }
 
1456
}
 
1457
 
 
1458
static int pdf_readint(const char *q0, int len, const char *key);
 
1459
 
 
1460
static void pdf_parse_encrypt(struct pdf_struct *pdf, const char *enc, int len)
 
1461
{
 
1462
    const char *q, *q2;
 
1463
    uint32_t objid;
 
1464
 
 
1465
    if (len >= 16 && !strncmp(enc, "/EncryptMetadata", 16)) {
 
1466
        q = cli_memstr(enc+16, len-16, "/Encrypt", 8);
 
1467
        if (!q)
 
1468
            return;
 
1469
 
 
1470
        len -= q - enc;
 
1471
        enc = q;
 
1472
    }
 
1473
 
 
1474
    q = enc + 8;
 
1475
    len -= 8;
 
1476
    q2 = pdf_nextobject(q, len);
 
1477
    if (!q2 || !isdigit(*q2))
 
1478
        return;
 
1479
 
 
1480
    objid = atoi(q2) << 8;
 
1481
    len -= q2 - q;
 
1482
    q = q2;
 
1483
    q2 = pdf_nextobject(q, len);
 
1484
    if (!q2 || !isdigit(*q2))
 
1485
        return;
 
1486
 
 
1487
    objid |= atoi(q2) & 0xff;
 
1488
    len -= q2 - q;
 
1489
    q = q2;
 
1490
    q2 = pdf_nextobject(q, len);
 
1491
    if (!q2 || *q2 != 'R')
 
1492
        return;
 
1493
 
 
1494
    cli_dbgmsg("cli_pdf: Encrypt dictionary in obj %d %d\n", objid>>8, objid&0xff);
 
1495
 
 
1496
    pdf->enc_objid = objid;
 
1497
}
 
1498
 
 
1499
static void pdf_parse_trailer(struct pdf_struct *pdf, const char *s, long length)
 
1500
{
 
1501
    const char *enc;
 
1502
 
 
1503
    enc = cli_memstr(s, length, "/Encrypt", 8);
 
1504
    if (enc) {
 
1505
        char *newID;
 
1506
 
 
1507
        pdf->flags |= 1 << ENCRYPTED_PDF;
 
1508
        pdf_parse_encrypt(pdf, enc, s + length - enc);
 
1509
        newID = pdf_readstring(s, length, "/ID", &pdf->fileIDlen, NULL, 0);
 
1510
 
 
1511
        if (newID) {
 
1512
            free(pdf->fileID);
 
1513
            pdf->fileID = newID;
 
1514
        }
 
1515
    }
 
1516
}
 
1517
 
 
1518
void pdf_parseobj(struct pdf_struct *pdf, struct pdf_obj *obj)
 
1519
{
 
1520
    /* enough to hold common pdf names, we don't need all the names */
 
1521
    char pdfname[64];
 
1522
    const char *q2, *q3;
 
1523
    const char *nextobj, *nextopen, *nextclose;
 
1524
    const char *q = obj->start + pdf->map;
 
1525
    const char *dict, *enddict, *start;
 
1526
    off_t dict_length, full_dict_length;
 
1527
    off_t objsize = obj_size(pdf, obj, 1);
 
1528
    off_t bytesleft;
 
1529
    unsigned i, filters=0;
 
1530
    unsigned blockopens=0;
 
1531
    enum objstate objstate = STATE_NONE;
 
1532
#if HAVE_JSON
 
1533
    json_object *pdfobj=NULL, *jsonobj=NULL;
 
1534
#endif
 
1535
 
 
1536
    if (objsize < 0)
 
1537
        return;
 
1538
 
 
1539
    start = q;
 
1540
    bytesleft = objsize;
 
1541
 
 
1542
    /* find start of dictionary */
 
1543
    do {
 
1544
        nextobj = pdf_nextobject(q, bytesleft);
 
1545
        bytesleft -= nextobj -q;
 
1546
 
 
1547
        if (!nextobj || bytesleft < 0) {
 
1548
            cli_dbgmsg("cli_pdf: %u %u obj: no dictionary\n", obj->id>>8, obj->id&0xff);
 
1549
#if HAVE_JSON
 
1550
            if (!(pdfobj) && pdf->ctx->wrkproperty != NULL) {
 
1551
                pdfobj = cli_jsonobj(pdf->ctx->wrkproperty, "PDFStats");
 
1552
                if (!(pdfobj))
 
1553
                    return;
 
1554
            }
 
1555
 
 
1556
            if (pdfobj) {
 
1557
                if (!(jsonobj))
 
1558
                    jsonobj = cli_jsonarray(pdfobj, "ObjectsWithoutDictionaries");
 
1559
                if (jsonobj)
 
1560
                    cli_jsonint_array(jsonobj, obj->id>>8);
 
1561
            }
 
1562
#endif
 
1563
            return;
 
1564
        }
 
1565
 
 
1566
        q3 = memchr(q-1, '<', nextobj-q+1);
 
1567
        nextobj++;
 
1568
        bytesleft--;
 
1569
        q = nextobj;
 
1570
    } while (!q3 || q3[1] != '<');
 
1571
    dict = q3+2;
 
1572
    q = dict;
 
1573
    blockopens++;
 
1574
    bytesleft = objsize - (q - start);
 
1575
    enddict = q + bytesleft - 1;
 
1576
 
 
1577
    /* find end of dictionary block */
 
1578
    if (bytesleft < 0) {
 
1579
        cli_dbgmsg("cli_pdf: %u %u obj: broken dictionary\n", obj->id>>8, obj->id&0xff);
 
1580
#if HAVE_JSON
 
1581
        if (!(pdfobj) && pdf->ctx->wrkproperty != NULL) {
 
1582
            pdfobj = cli_jsonobj(pdf->ctx->wrkproperty, "PDFStats");
 
1583
            if (!(pdfobj))
 
1584
                return;
 
1585
        }
 
1586
 
 
1587
        if (pdfobj) {
 
1588
            if (!(jsonobj))
 
1589
                jsonobj = cli_jsonarray(pdfobj, "ObjectsWithBrokenDictionaries");
 
1590
            if (jsonobj)
 
1591
                cli_jsonint_array(jsonobj, obj->id>>8);
 
1592
        }
 
1593
#endif
 
1594
        return;
 
1595
    }
 
1596
 
 
1597
    /* while still looking ... */
 
1598
    while ((q < enddict-1) && (blockopens > 0)) {
 
1599
        /* find next close */
 
1600
        nextclose = memchr(q, '>', enddict-q);
 
1601
        if (nextclose && (nextclose[1] == '>')) {
 
1602
            /* check for nested open */
 
1603
            while ((nextopen = memchr(q-1, '<', nextclose-q+1)) != NULL) {
 
1604
                if (nextopen[1] == '<') {
 
1605
                    /* nested open */
 
1606
                    blockopens++;
 
1607
                    q = nextopen + 2;
 
1608
                }
 
1609
                else {
 
1610
                    /* unmatched < before next close */
 
1611
                    q = nextopen + 2;
 
1612
                }
 
1613
            }
 
1614
            /* close block */
 
1615
            blockopens--;
 
1616
            q = nextclose + 2;
 
1617
        }
 
1618
        else if (nextclose) {
 
1619
            /* found one > but not two */
 
1620
            q = nextclose + 2;
 
1621
        }
 
1622
        else {
 
1623
            /* next closing not found */
 
1624
            break;
 
1625
        }
 
1626
    }
 
1627
 
 
1628
    /* Was end of dictionary found? */
 
1629
    if (blockopens) {
 
1630
        /* probably truncated */
 
1631
        cli_dbgmsg("cli_pdf: %u %u obj broken dictionary\n", obj->id>>8, obj->id&0xff);
 
1632
#if HAVE_JSON
 
1633
        if (!(pdfobj) && pdf->ctx->wrkproperty != NULL) {
 
1634
            pdfobj = cli_jsonobj(pdf->ctx->wrkproperty, "PDFStats");
 
1635
            if (!(pdfobj))
 
1636
                return;
 
1637
        }
 
1638
 
 
1639
        if (pdfobj) {
 
1640
            if (!(jsonobj))
 
1641
                jsonobj = cli_jsonarray(pdfobj, "ObjectsWithBrokenDictionaries");
 
1642
            if (jsonobj)
 
1643
                cli_jsonint_array(jsonobj, obj->id>>8);
 
1644
        }
 
1645
#endif
 
1646
        return;
 
1647
    }
 
1648
 
 
1649
    enddict = nextclose;
 
1650
    obj->flags |= 1 << OBJ_DICT;
 
1651
    full_dict_length = dict_length = enddict - dict;
 
1652
 
 
1653
    /* This code prints the dictionary content.
 
1654
    {
 
1655
        char * dictionary = malloc(dict_length + 1);
 
1656
        if (dictionary) {
 
1657
            for (i = 0; i < dict_length; i++) {
 
1658
                if (isprint(dict[i]) || isspace(dict[i]))
 
1659
                    dictionary[i] = dict[i];
 
1660
                else
 
1661
                    dictionary[i] = '*';
 
1662
            }
 
1663
            dictionary[dict_length] = '\0';
 
1664
            cli_dbgmsg("cli_pdf: dictionary is <<%s>>\n", dictionary);
 
1665
            free(dictionary);
 
1666
        }
 
1667
    }
 
1668
    */
 
1669
 
 
1670
    /*  process pdf names */
 
1671
    for (q = dict;dict_length > 0;) {
 
1672
        int escapes = 0, breakout=0;
 
1673
        q2 = memchr(q, '/', dict_length);
 
1674
        if (!q2)
 
1675
            break;
 
1676
 
 
1677
        dict_length -= q2 - q;
 
1678
        q = q2;
 
1679
        /* normalize PDF names */
 
1680
        for (i = 0;dict_length > 0 && (i < sizeof(pdfname)-1); i++) {
 
1681
            q++;
 
1682
            dict_length--;
 
1683
 
 
1684
            if (*q == '#') {
 
1685
                if (cli_hex2str_to(q+1, pdfname+i, 2) == -1)
 
1686
                    break;
 
1687
 
 
1688
                q += 2;
 
1689
                dict_length -= 2;
 
1690
                escapes = 1;
 
1691
                continue;
 
1692
            }
 
1693
 
 
1694
            switch (*q) {
 
1695
            case ' ':
 
1696
            case '\t':
 
1697
            case '\r':
 
1698
            case '\n':
 
1699
            case '/':
 
1700
            case '>':
 
1701
            case '[':
 
1702
            case ']':
 
1703
            case '<':
 
1704
            case '(':
 
1705
                breakout = 1;
 
1706
            }
 
1707
 
 
1708
            if (breakout)
 
1709
                break;
 
1710
 
 
1711
            pdfname[i] = *q;
 
1712
        }
 
1713
 
 
1714
        pdfname[i] = '\0';
 
1715
 
 
1716
        handle_pdfname(pdf, obj, pdfname, escapes, &objstate);
 
1717
        if (objstate == STATE_LINEARIZED) {
 
1718
            long trailer_end, trailer;
 
1719
 
 
1720
            pdfobj_flag(pdf, obj, LINEARIZED_PDF);
 
1721
            objstate = STATE_NONE;
 
1722
            trailer_end = pdf_readint(dict, full_dict_length, "/H");
 
1723
            if (trailer_end > 0 && trailer_end < pdf->size) {
 
1724
                trailer = trailer_end - 1024;
 
1725
                if (trailer < 0)
 
1726
                    trailer = 0;
 
1727
 
 
1728
                q2 = pdf->map + trailer;
 
1729
                cli_dbgmsg("cli_pdf: looking for trailer in linearized pdf: %ld - %ld\n", trailer, trailer_end);
 
1730
                pdf_parse_trailer(pdf, q2, trailer_end - trailer);
 
1731
                if (pdf->fileID)
 
1732
                    cli_dbgmsg("cli_pdf: found fileID\n");
 
1733
            }
 
1734
        }
 
1735
 
 
1736
        if (objstate == STATE_LAUNCHACTION)
 
1737
            pdfobj_flag(pdf, obj, HAS_LAUNCHACTION);
 
1738
        if (dict_length > 0 && (objstate == STATE_JAVASCRIPT || objstate == STATE_OPENACTION || objstate == STATE_CONTENTS)) {
 
1739
            if (objstate == STATE_OPENACTION)
 
1740
                pdfobj_flag(pdf, obj, HAS_OPENACTION);
 
1741
 
 
1742
            q2 = pdf_nextobject(q, dict_length);
 
1743
            if (q2 && isdigit(*q2)) {
 
1744
                uint32_t objid = atoi(q2) << 8;
 
1745
                while (isdigit(*q2))
 
1746
                    q2++;
 
1747
 
 
1748
                q2 = pdf_nextobject(q2, dict_length);
 
1749
                if (q2 && isdigit(*q2)) {
 
1750
                    objid |= atoi(q2) & 0xff;
 
1751
                    q2 = pdf_nextobject(q2, dict_length);
 
1752
 
 
1753
                    if (q2 && *q2 == 'R') {
 
1754
                        struct pdf_obj *obj2;
 
1755
 
 
1756
                        cli_dbgmsg("cli_pdf: found %s stored in indirect object %u %u\n", pdfname, objid >> 8, objid&0xff);
 
1757
                        obj2 = find_obj(pdf, obj, objid);
 
1758
                        if (obj2) {
 
1759
                            enum pdf_objflags flag =
 
1760
                                objstate == STATE_JAVASCRIPT ? OBJ_JAVASCRIPT :
 
1761
                                objstate == STATE_OPENACTION ? OBJ_OPENACTION :
 
1762
 
 
1763
                            OBJ_CONTENTS;
 
1764
                            obj2->flags |= 1 << flag;
 
1765
                            obj->flags &= ~(1 << flag);
 
1766
                        } else {
 
1767
                            pdfobj_flag(pdf, obj, BAD_INDOBJ);
 
1768
                        }
 
1769
                    }
 
1770
                }
 
1771
            }
 
1772
 
 
1773
            objstate = STATE_NONE;
 
1774
        }
 
1775
    }
 
1776
 
 
1777
    for (i=0;i<sizeof(pdfname_actions)/sizeof(pdfname_actions[0]);i++) {
 
1778
        const struct pdfname_action *act = &pdfname_actions[i];
 
1779
 
 
1780
        if ((obj->flags & (1 << act->set_objflag)) &&
 
1781
            act->from_state == STATE_FILTER &&
 
1782
            act->to_state == STATE_FILTER &&
 
1783
            act->set_objflag != OBJ_FILTER_CRYPT &&
 
1784
            act->set_objflag != OBJ_FILTER_STANDARD) {
 
1785
            filters++;
 
1786
        }
 
1787
    }
 
1788
 
 
1789
    if (filters > 2) {
 
1790
        /* more than 2 non-crypt filters */
 
1791
        pdfobj_flag(pdf, obj, MANY_FILTERS);
 
1792
    }
 
1793
 
 
1794
    if (obj->flags & ((1 << OBJ_SIGNED) | KNOWN_FILTERS))
 
1795
        obj->flags &= ~(1 << OBJ_FILTER_UNKNOWN);
 
1796
 
 
1797
    if (obj->flags & (1 << OBJ_FILTER_UNKNOWN))
 
1798
        pdfobj_flag(pdf, obj, UNKNOWN_FILTER);
 
1799
 
 
1800
    cli_dbgmsg("cli_pdf: %u %u obj flags: %02x\n", obj->id>>8, obj->id&0xff, obj->flags);
 
1801
}
 
1802
 
 
1803
static const char *pdf_getdict(const char *q0, int* len, const char *key)
 
1804
{
 
1805
    const char *q;
 
1806
 
 
1807
    if (*len <= 0) {
 
1808
        cli_dbgmsg("cli_pdf: bad length %d\n", *len);
 
1809
        return NULL;
 
1810
    }
 
1811
 
 
1812
    if (!q0)
 
1813
        return NULL;
 
1814
 
 
1815
    q = cli_memstr(q0, *len, key, strlen(key));
 
1816
    if (!q) {
 
1817
        cli_dbgmsg("cli_pdf: %s not found in dict\n", key);
 
1818
        return NULL;
 
1819
    }
 
1820
 
 
1821
    *len -= q - q0;
 
1822
    q0 = q;
 
1823
    q = pdf_nextobject(q0 + 1, *len - 1);
 
1824
    if (!q) {
 
1825
        cli_dbgmsg("cli_pdf: %s is invalid in dict\n", key);
 
1826
        return NULL;
 
1827
    }
 
1828
 
 
1829
    if (q[-1] == '<')
 
1830
        q--;
 
1831
 
 
1832
    *len -= q - q0;
 
1833
    return q;
 
1834
}
 
1835
 
 
1836
static char *pdf_readstring(const char *q0, int len, const char *key, unsigned *slen, const char **qend, int noescape)
 
1837
{
 
1838
    char *s, *s0;
 
1839
    const char *start, *q, *end;
 
1840
    if (slen)
 
1841
        *slen = 0;
 
1842
 
 
1843
    if (qend)
 
1844
        *qend = q0;
 
1845
 
 
1846
    q = pdf_getdict(q0, &len, key);
 
1847
    if (!q)
 
1848
        return NULL;
 
1849
 
 
1850
    if (*q == '(') {
 
1851
        int paren = 1;
 
1852
        start = ++q;
 
1853
        for (;paren > 0 && len > 0; q++,len--) {
 
1854
            switch (*q) {
 
1855
            case '(':
 
1856
                paren++;
 
1857
                break;
 
1858
            case ')':
 
1859
                paren--;
 
1860
                break;
 
1861
            case '\\':
 
1862
                q++;
 
1863
                len--;
 
1864
                break;
 
1865
            default:
 
1866
                break;
 
1867
            }
 
1868
        }
 
1869
 
 
1870
        if (qend)
 
1871
            *qend = q;
 
1872
 
 
1873
        q--;
 
1874
        len  = q - start;
 
1875
        s0 = s = cli_malloc(len + 1);
 
1876
        if (!s) {
 
1877
            cli_errmsg("pdf_readstring: Unable to allocate buffer\n");
 
1878
            return NULL;
 
1879
        }
 
1880
 
 
1881
        end = start + len;
 
1882
        if (noescape) {
 
1883
            memcpy(s0, start, len);
 
1884
            s = s0 + len;
 
1885
        } else {
 
1886
            for (q = start;q < end;q++) {
 
1887
                if (*q != '\\') {
 
1888
                    *s++ = *q;
 
1889
                } else {
 
1890
                    q++;
 
1891
                    switch (*q) {
 
1892
                    case 'n':
 
1893
                        *s++ = '\n';
 
1894
                        break;
 
1895
                    case 'r':
 
1896
                        *s++ = '\r';
 
1897
                        break;
 
1898
                    case 't':
 
1899
                        *s++ = '\t';
 
1900
                        break;
 
1901
                    case 'b':
 
1902
                        *s++ = '\b';
 
1903
                        break;
 
1904
                    case 'f':
 
1905
                        *s++ = '\f';
 
1906
                        break;
 
1907
                    case '(':/* fall-through */
 
1908
                    case ')':/* fall-through */
 
1909
                    case '\\':
 
1910
                        *s++ = *q;
 
1911
                        break;
 
1912
                    case '\n':
 
1913
                        /* ignore */
 
1914
                        break;
 
1915
                    case '\r':
 
1916
                        /* ignore */
 
1917
                        if (q+1 < end && q[1] == '\n')
 
1918
                            q++;
 
1919
                        break;
 
1920
                    case '0':
 
1921
                    case '1':
 
1922
                    case '2':
 
1923
                    case '3':
 
1924
                    case '4':
 
1925
                    case '5':
 
1926
                    case '6':
 
1927
                    case '7':
 
1928
                    case '8':
 
1929
                    case '9':
 
1930
                        /* octal escape */
 
1931
                        if (q+2 < end)
 
1932
                            q++;
 
1933
 
 
1934
                        *s++ = 64*(q[0] - '0') + 8*(q[1] - '0') + (q[2] - '0');
 
1935
                        break;
 
1936
                    default:
 
1937
                        /* ignore */
 
1938
                        *s++ = '\\';
 
1939
                        q--;
 
1940
                        break;
 
1941
                    }
 
1942
                }
 
1943
            }
 
1944
        }
 
1945
 
 
1946
        *s++ = '\0';
 
1947
        if (slen)
 
1948
            *slen = s - s0 - 1;
 
1949
 
 
1950
        return s0;
 
1951
    }
 
1952
 
 
1953
    if (*q == '<') {
 
1954
        start = ++q;
 
1955
        q = memchr(q+1, '>', len);
 
1956
        if (!q)
 
1957
            return NULL;
 
1958
 
 
1959
        if (qend)
 
1960
            *qend = q;
 
1961
 
 
1962
        s = cli_malloc((q - start)/2 + 1);
 
1963
        if (s == NULL) { /* oops, couldn't allocate memory */
 
1964
          cli_dbgmsg("cli_pdf: unable to allocate memory...\n");
 
1965
          return NULL;
 
1966
        }
 
1967
 
 
1968
        if (cli_hex2str_to(start, s, q - start)) {
 
1969
            cli_dbgmsg("cli_pdf: %s has bad hex value\n", key);
 
1970
            free(s);
 
1971
            return NULL;
 
1972
        }
 
1973
 
 
1974
        s[(q-start)/2] = '\0';
 
1975
        if (slen)
 
1976
            *slen = (q - start)/2;
 
1977
 
 
1978
        return s;
 
1979
    }
 
1980
 
 
1981
    cli_dbgmsg("cli_pdf: %s is invalid string in dict\n", key);
 
1982
    return NULL;
 
1983
}
 
1984
 
 
1985
static char *pdf_readval(const char *q, int len, const char *key)
 
1986
{
 
1987
    const char *end;
 
1988
    char *s;
 
1989
 
 
1990
    q = pdf_getdict(q, &len, key);
 
1991
    if (!q || len <= 0)
 
1992
        return NULL;
 
1993
 
 
1994
    while (len > 0 && *q && *q == ' ') {
 
1995
        q++;
 
1996
        len--;
 
1997
    }
 
1998
 
 
1999
    if (*q != '/')
 
2000
        return NULL;
 
2001
 
 
2002
    q++;
 
2003
    len--;
 
2004
    end = q;
 
2005
 
 
2006
    while (len > 0 && *end && !(*end == '/' || (len > 1 && end[0] == '>' && end[1] == '>'))) {
 
2007
        end++;
 
2008
        len--;
 
2009
    }
 
2010
 
 
2011
    s = cli_malloc(end - q + 1);
 
2012
    if (!s)
 
2013
        return NULL;
 
2014
 
 
2015
    memcpy(s, q, end-q);
 
2016
    s[end-q] = '\0';
 
2017
 
 
2018
    return s;
 
2019
}
 
2020
 
 
2021
static int pdf_readint(const char *q0, int len, const char *key)
 
2022
{
 
2023
    const char *q  = pdf_getdict(q0, &len, key);
 
2024
 
 
2025
    return (q != NULL) ? atoi(q) : -1;
 
2026
}
 
2027
 
 
2028
static int pdf_readbool(const char *q0, int len, const char *key, int Default)
 
2029
{
 
2030
    const char *q  = pdf_getdict(q0, &len, key);
 
2031
 
 
2032
    if (!q || len < 5)
 
2033
        return Default;
 
2034
 
 
2035
    if (!strncmp(q, "true", 4))
 
2036
        return 1;
 
2037
 
 
2038
    if (!strncmp(q, "false", 5))
 
2039
        return 0;
 
2040
 
 
2041
    cli_dbgmsg("cli_pdf: invalid value for %s bool\n", key);
 
2042
 
 
2043
    return Default;
 
2044
}
 
2045
 
 
2046
static const char *key_padding =
 
2047
"\x28\xBF\x4E\x5E\x4E\x75\x8A\x41\x64\x00\x4e\x56\xff\xfa\x01\x08"
 
2048
"\x2e\x2e\x00\xB6\xD0\x68\x3E\x80\x2F\x0C\xA9\xFE\x64\x53\x69\x7A";
 
2049
 
 
2050
static void dbg_printhex(const char *msg, const char *hex, unsigned len)
 
2051
{
 
2052
    if (cli_debug_flag) {
 
2053
        char *kh = cli_str2hex(hex, len);
 
2054
 
 
2055
        cli_dbgmsg("cli_pdf: %s: %s\n", msg, kh);
 
2056
 
 
2057
        free(kh);
 
2058
    }
 
2059
}
 
2060
 
 
2061
static void check_user_password(struct pdf_struct *pdf, int R, const char *O,
 
2062
                                const char *U, int32_t P, int EM,
 
2063
                                const char *UE,
 
2064
                                unsigned length, unsigned oulen)
 
2065
{
 
2066
    unsigned i;
 
2067
    uint8_t result[16];
 
2068
    char data[32];
 
2069
    struct arc4_state arc4;
 
2070
    unsigned password_empty = 0;
 
2071
 
 
2072
    UNUSEDPARAM(oulen);
 
2073
 
 
2074
    dbg_printhex("U: ", U, 32);
 
2075
    dbg_printhex("O: ", O, 32);
 
2076
    if (R == 5) {
 
2077
        uint8_t result2[32];
 
2078
 
 
2079
        /* supplement to ISO3200, 3.5.2 Algorithm 3.11 */
 
2080
        /* user validation salt */
 
2081
        cl_sha256(U+32, 8, result2, NULL);
 
2082
        dbg_printhex("Computed U", (const char *)result2, 32);
 
2083
        if (!memcmp(result2, U, 32)) {
 
2084
            off_t n;
 
2085
 
 
2086
            /* Algorithm 3.2a could be used to recover encryption key */
 
2087
            password_empty = 1;
 
2088
            cl_sha256(U+40, 8, result2, NULL);
 
2089
            n = UE ? strlen(UE) : 0;
 
2090
            if (n != 32) {
 
2091
                cli_dbgmsg("cli_pdf: UE length is not 32: %d\n", (int)n);
 
2092
                noisy_warnmsg("cli_pdf: UE length is not 32: %d\n", n);
 
2093
            } else {
 
2094
                pdf->keylen = 32;
 
2095
                pdf->key = cli_malloc(32);
 
2096
                if (!pdf->key) {
 
2097
                    cli_errmsg("check_user_password: Cannot allocate memory for pdf->key\n");
 
2098
                    return;
 
2099
                }
 
2100
 
 
2101
                aes_decrypt((const unsigned char *)UE, &n, (unsigned char *)(pdf->key), (char *)result2, 32, 0);
 
2102
                dbg_printhex("cli_pdf: Candidate encryption key", pdf->key, pdf->keylen);
 
2103
            }
 
2104
        }
 
2105
    } else if ((R >= 2) && (R <= 4)) {
 
2106
        unsigned char *d;
 
2107
        size_t sz = 68 + pdf->fileIDlen + (R >= 4 && !EM ? 4 : 0);
 
2108
        d = calloc(1, sz);
 
2109
 
 
2110
        if (!(d))
 
2111
            return;
 
2112
 
 
2113
        memcpy(d, key_padding, 32);
 
2114
        memcpy(d+32, O, 32);
 
2115
        P = le32_to_host(P);
 
2116
        memcpy(d+64, &P, 4);
 
2117
        memcpy(d+68, pdf->fileID, pdf->fileIDlen);
 
2118
 
 
2119
        /* 7.6.3.3 Algorithm 2 */
 
2120
        /* empty password, password == padding */
 
2121
        if (R >= 4 && !EM) {
 
2122
            uint32_t v = 0xFFFFFFFF;
 
2123
            memcpy(d+68+pdf->fileIDlen, &v, 4);
 
2124
        }
 
2125
 
 
2126
        cl_hash_data("md5", d, sz, result, NULL);
 
2127
        free(d);
 
2128
        if (length > 128)
 
2129
            length = 128;
 
2130
        if (R >= 3) {
 
2131
            /* Yes, this really is on purpose */
 
2132
            for (i=0;i<50;i++)
 
2133
                cl_hash_data("md5", result, length/8, result, NULL);
 
2134
        }
 
2135
        if (R == 2)
 
2136
            length = 40;
 
2137
 
 
2138
        pdf->keylen = length / 8;
 
2139
        pdf->key = cli_malloc(pdf->keylen);
 
2140
        if (!pdf->key)
 
2141
            return;
 
2142
 
 
2143
        memcpy(pdf->key, result, pdf->keylen);
 
2144
        dbg_printhex("md5", (const char *)result, 16);
 
2145
        dbg_printhex("Candidate encryption key", pdf->key, pdf->keylen);
 
2146
 
 
2147
        /* 7.6.3.3 Algorithm 6 */
 
2148
        if (R == 2) {
 
2149
            /* 7.6.3.3 Algorithm 4 */
 
2150
            memcpy(data, key_padding, 32);
 
2151
            arc4_init(&arc4, (const uint8_t *)(pdf->key), pdf->keylen);
 
2152
            arc4_apply(&arc4, (uint8_t *)data, 32);
 
2153
            dbg_printhex("computed U (R2)", data, 32);
 
2154
            if (!memcmp(data, U, 32))
 
2155
                password_empty = 1;
 
2156
        } else if (R >= 3) {
 
2157
            unsigned len = pdf->keylen;
 
2158
            unsigned char *d;
 
2159
 
 
2160
            d = calloc(1, 32 + pdf->fileIDlen);
 
2161
            if (!(d))
 
2162
                return;
 
2163
 
 
2164
            /* 7.6.3.3 Algorithm 5 */
 
2165
            memcpy(d, key_padding, 32);
 
2166
            memcpy(d+32, pdf->fileID, pdf->fileIDlen);
 
2167
            cl_hash_data("md5", d, 32 + pdf->fileIDlen, result, NULL);
 
2168
            memcpy(data, pdf->key, len);
 
2169
 
 
2170
            arc4_init(&arc4, (const uint8_t *)data, len);
 
2171
            arc4_apply(&arc4, result, 16);
 
2172
            for (i=1;i<=19;i++) {
 
2173
                unsigned j;
 
2174
 
 
2175
                for (j=0;j<len;j++)
 
2176
                    data[j] = pdf->key[j] ^ i;
 
2177
 
 
2178
                arc4_init(&arc4, (const uint8_t *)data, len);
 
2179
                arc4_apply(&arc4, result, 16);
 
2180
            }
 
2181
 
 
2182
            dbg_printhex("fileID", pdf->fileID, pdf->fileIDlen);
 
2183
            dbg_printhex("computed U (R>=3)", (const char *)result, 16);
 
2184
            if (!memcmp(result, U, 16))
 
2185
                password_empty = 1;
 
2186
            free(d);
 
2187
        } else {
 
2188
            cli_dbgmsg("cli_pdf: invalid revision %d\n", R);
 
2189
            noisy_warnmsg("cli_pdf: invalid revision %d\n", R);
 
2190
        }
 
2191
    } else {
 
2192
        /* Supported R is in {2,3,4,5} */
 
2193
        cli_dbgmsg("cli_pdf: R value out of range\n");
 
2194
        noisy_warnmsg("cli_pdf: R value out of range\n");
 
2195
 
 
2196
        return;
 
2197
    }
 
2198
 
 
2199
    if (password_empty) {
 
2200
        cli_dbgmsg("cli_pdf: user password is empty\n");
 
2201
        noisy_msg(pdf, "cli_pdf: encrypted PDF found, user password is empty, will attempt to decrypt\n");
 
2202
        /* The key we computed above is the key used to encrypt the streams.
 
2203
         * We could decrypt it now if we wanted to */
 
2204
        pdf->flags |= 1 << DECRYPTABLE_PDF;
 
2205
    } else {
 
2206
        /* the key is not valid, we would need the user or the owner password to decrypt */
 
2207
        cli_dbgmsg("cli_pdf: user/owner password would be required for decryption\n");
 
2208
        noisy_warnmsg("cli_pdf: encrypted PDF found, user password is NOT empty, cannot decrypt!\n");
 
2209
    }
 
2210
}
 
2211
 
 
2212
static enum enc_method parse_enc_method(const char *dict, unsigned len, const char *key, enum enc_method def)
 
2213
{
 
2214
    const char *q;
 
2215
    char *CFM = NULL;
 
2216
    enum enc_method ret = ENC_UNKNOWN;
 
2217
 
 
2218
    if (!key)
 
2219
        return def;
 
2220
 
 
2221
    if (!strcmp(key, "Identity"))
 
2222
        return ENC_IDENTITY;
 
2223
 
 
2224
    q = pdf_getdict(dict, (int *)(&len), key);
 
2225
    if (!q)
 
2226
        return def;
 
2227
 
 
2228
    CFM = pdf_readval(q, len, "/CFM");
 
2229
    if (CFM) {
 
2230
        cli_dbgmsg("cli_pdf: %s CFM: %s\n", key, CFM);
 
2231
        if (!strncmp(CFM,"V2", 2))
 
2232
            ret = ENC_V2;
 
2233
        else if (!strncmp(CFM,"AESV2",5))
 
2234
            ret = ENC_AESV2;
 
2235
        else if (!strncmp(CFM,"AESV3",5))
 
2236
            ret = ENC_AESV3;
 
2237
        else if (!strncmp(CFM,"None",4))
 
2238
            ret = ENC_NONE;
 
2239
 
 
2240
        free(CFM);
 
2241
    }
 
2242
 
 
2243
    return ret;
 
2244
}
 
2245
 
 
2246
static void pdf_handle_enc(struct pdf_struct *pdf)
 
2247
{
 
2248
    struct pdf_obj *obj;
 
2249
    uint32_t len, n, R, P, length, EM = 1, i, oulen;
 
2250
    char *O, *U, *UE, *StmF, *StrF, *EFF;
 
2251
    const char *q, *q2;
 
2252
 
 
2253
    if (pdf->enc_objid == ~0u)
 
2254
        return;
 
2255
    if (!pdf->fileID) {
 
2256
        cli_dbgmsg("cli_pdf: pdf_handle_enc no file ID\n");
 
2257
        noisy_warnmsg("cli_pdf: pdf_handle_enc no file ID\n");
 
2258
        return;
 
2259
    }
 
2260
 
 
2261
    obj = find_obj(pdf, pdf->objs, pdf->enc_objid);
 
2262
    if (!obj) {
 
2263
        cli_dbgmsg("cli_pdf: can't find encrypted object %d %d\n", pdf->enc_objid>>8, pdf->enc_objid&0xff);
 
2264
        noisy_warnmsg("cli_pdf: can't find encrypted object %d %d\n", pdf->enc_objid>>8, pdf->enc_objid&0xff);
 
2265
        return;
 
2266
    }
 
2267
 
 
2268
    len = obj_size(pdf, obj, 1);
 
2269
    q = pdf->map + obj->start;
 
2270
 
 
2271
    O = U = UE = StmF = StrF = EFF = NULL;
 
2272
    do {
 
2273
 
 
2274
        pdf->enc_method_string = ENC_UNKNOWN;
 
2275
        pdf->enc_method_stream = ENC_UNKNOWN;
 
2276
        pdf->enc_method_embeddedfile = ENC_UNKNOWN;
 
2277
        P = pdf_readint(q, len, "/P");
 
2278
        if (P == ~0u) {
 
2279
            cli_dbgmsg("cli_pdf: invalid P\n");
 
2280
            noisy_warnmsg("cli_pdf: invalid P\n");
 
2281
            break;
 
2282
        }
 
2283
 
 
2284
        q2 = cli_memstr(q, len, "/Standard", 9);
 
2285
        if (!q2) {
 
2286
            cli_dbgmsg("cli_pdf: /Standard not found\n");
 
2287
            noisy_warnmsg("cli_pdf: /Standard not found\n");
 
2288
            break;
 
2289
        }
 
2290
 
 
2291
        /* we can have both of these:
 
2292
        * /AESV2/Length /Standard/Length
 
2293
        * /Length /Standard
 
2294
        * make sure we don't mistake AES's length for Standard's */
 
2295
        length = pdf_readint(q2, len - (q2 - q), "/Length");
 
2296
        if (length == ~0u)
 
2297
            length = pdf_readint(q, len, "/Length");
 
2298
 
 
2299
        if (length < 40) {
 
2300
            cli_dbgmsg("cli_pdf: invalid length: %d\n", length);
 
2301
            length = 40;
 
2302
        }
 
2303
 
 
2304
        R = pdf_readint(q, len, "/R");
 
2305
        if (R == ~0u) {
 
2306
            cli_dbgmsg("cli_pdf: invalid R\n");
 
2307
            noisy_warnmsg("cli_pdf: invalid R\n");
 
2308
            break;
 
2309
        }
 
2310
 
 
2311
        if ((R > 5) || (R < 2)) {
 
2312
            cli_dbgmsg("cli_pdf: R value outside supported range [2..5]\n");
 
2313
            noisy_warnmsg("cli_pdf: R value outside supported range [2..5]\n");
 
2314
            break;
 
2315
        }
 
2316
 
 
2317
        if (R < 5)
 
2318
            oulen = 32;
 
2319
        else
 
2320
            oulen = 48;
 
2321
 
 
2322
        if (R == 2 || R == 3) {
 
2323
            pdf->enc_method_stream = ENC_V2;
 
2324
            pdf->enc_method_string = ENC_V2;
 
2325
            pdf->enc_method_embeddedfile = ENC_V2;
 
2326
        } else if (R == 4 || R == 5) {
 
2327
            EM = pdf_readbool(q, len, "/EncryptMetadata", 1);
 
2328
            StmF = pdf_readval(q, len, "/StmF");
 
2329
            StrF = pdf_readval(q, len, "/StrF");
 
2330
            EFF = pdf_readval(q, len, "/EFF");
 
2331
            n = len;
 
2332
            pdf->CF = pdf_getdict(q, (int *)(&n), "/CF");
 
2333
            pdf->CF_n = n;
 
2334
 
 
2335
            if (StmF)
 
2336
                cli_dbgmsg("cli_pdf: StmF: %s\n", StmF);
 
2337
            if (StrF)
 
2338
                cli_dbgmsg("cli_pdf: StrF: %s\n", StrF);
 
2339
            if (EFF)
 
2340
                cli_dbgmsg("cli_pdf: EFF: %s\n", EFF);
 
2341
 
 
2342
            pdf->enc_method_stream = parse_enc_method(pdf->CF, n, StmF, ENC_IDENTITY);
 
2343
            pdf->enc_method_string = parse_enc_method(pdf->CF, n, StrF, ENC_IDENTITY);
 
2344
            pdf->enc_method_embeddedfile = parse_enc_method(pdf->CF, n, EFF, pdf->enc_method_stream);
 
2345
 
 
2346
            free(StmF);
 
2347
            free(StrF);
 
2348
            free(EFF);
 
2349
 
 
2350
            cli_dbgmsg("cli_pdf: EncryptMetadata: %s\n", EM ? "true" : "false");
 
2351
 
 
2352
            if (R == 4) {
 
2353
                length = 128;
 
2354
            } else {
 
2355
                n = 0;
 
2356
                UE = pdf_readstring(q, len, "/UE", &n, NULL, 0);
 
2357
                length = 256;
 
2358
            }
 
2359
        }
 
2360
 
 
2361
        if (length == ~0u)
 
2362
            length = 40;
 
2363
 
 
2364
        n = 0;
 
2365
        O = pdf_readstring(q, len, "/O", &n, NULL, 0);
 
2366
        if (!O || n < oulen) {
 
2367
            cli_dbgmsg("cli_pdf: invalid O: %d\n", n);
 
2368
            cli_dbgmsg("cli_pdf: invalid O: %d\n", n);
 
2369
            if (O)
 
2370
                dbg_printhex("invalid O", O, n);
 
2371
 
 
2372
            break;
 
2373
        }
 
2374
        if (n > oulen) {
 
2375
            for (i=oulen;i<n;i++)
 
2376
                if (O[i])
 
2377
                    break;
 
2378
 
 
2379
            if (i != n) {
 
2380
                dbg_printhex("too long O", O, n);
 
2381
                noisy_warnmsg("too long O", O, n);
 
2382
                break;
 
2383
            }
 
2384
        }
 
2385
 
 
2386
        n = 0;
 
2387
        U = pdf_readstring(q, len, "/U", &n, NULL, 0);
 
2388
        if (!U || n < oulen) {
 
2389
            cli_dbgmsg("cli_pdf: invalid U: %d\n", n);
 
2390
            noisy_warnmsg("cli_pdf: invalid U: %d\n", n);
 
2391
 
 
2392
            if (U)
 
2393
                dbg_printhex("invalid U", U, n);
 
2394
 
 
2395
            break;
 
2396
        }
 
2397
 
 
2398
        if (n > oulen) {
 
2399
            for (i=oulen;i<n;i++)
 
2400
                if (U[i])
 
2401
                    break;
 
2402
            if (i != n) {
 
2403
                dbg_printhex("too long U", U, n);
 
2404
                break;
 
2405
            }
 
2406
        }
 
2407
 
 
2408
        cli_dbgmsg("cli_pdf: Encrypt R: %d, P %x, length: %d\n", R, P, length);
 
2409
        if (length % 8) {
 
2410
            cli_dbgmsg("cli_pdf: wrong key length, not multiple of 8\n");
 
2411
            noisy_warnmsg("cli_pdf: wrong key length, not multiple of 8\n");
 
2412
            break;
 
2413
        }
 
2414
        check_user_password(pdf, R, O, U, P, EM, UE, length, oulen);
 
2415
    } while (0);
 
2416
 
 
2417
    free(O);
 
2418
    free(U);
 
2419
    free(UE);
 
2420
}
 
2421
 
 
2422
int cli_pdf(const char *dir, cli_ctx *ctx, off_t offset)
 
2423
{
 
2424
    struct pdf_struct pdf;
 
2425
    fmap_t *map = *ctx->fmap;
 
2426
    size_t size = map->len - offset;
 
2427
    off_t versize = size > 1032 ? 1032 : size;
 
2428
    off_t map_off, bytesleft;
 
2429
    long xref;
 
2430
    const char *pdfver, *start, *eofmap, *q, *eof;
 
2431
    int rc, badobjects = 0;
 
2432
    unsigned i, alerts = 0;
 
2433
#if HAVE_JSON
 
2434
    json_object *pdfobj=NULL;
 
2435
    char *begin, *end, *p1;
 
2436
#endif
 
2437
 
 
2438
    cli_dbgmsg("in cli_pdf(%s)\n", dir);
 
2439
    memset(&pdf, 0, sizeof(pdf));
 
2440
    pdf.ctx = ctx;
 
2441
    pdf.dir = dir;
 
2442
    pdf.enc_objid = ~0u;
 
2443
 
 
2444
    pdfver = start = fmap_need_off_once(map, offset, versize);
 
2445
 
 
2446
    /* Check PDF version */
 
2447
    if (!pdfver) {
 
2448
        cli_errmsg("cli_pdf: mmap() failed (1)\n");
 
2449
        return CL_EMAP;
 
2450
    }
 
2451
 
 
2452
#if HAVE_JSON
 
2453
    if (ctx->wrkproperty)
 
2454
        pdfobj = cli_jsonobj(ctx->wrkproperty, "PDFStats");
 
2455
#endif
 
2456
 
 
2457
    /* offset is 0 when coming from filetype2 */
 
2458
    pdfver = cli_memstr(pdfver, versize, "%PDF-", 5);
 
2459
    if (!pdfver) {
 
2460
        cli_dbgmsg("cli_pdf: no PDF- header found\n");
 
2461
        noisy_warnmsg("cli_pdf: no PDF- header found\n");
 
2462
#if HAVE_JSON
 
2463
        pdf_export_json(&pdf);
 
2464
#endif
 
2465
        return CL_SUCCESS;
 
2466
    }
 
2467
 
 
2468
    /* Check for PDF-1.[0-9]. Although 1.7 is highest now, allow for future versions */
 
2469
    if (pdfver[5] != '1' || pdfver[6] != '.' ||
 
2470
        pdfver[7] < '1' || pdfver[7] > '9') {
 
2471
        pdf.flags |= 1 << BAD_PDF_VERSION;
 
2472
        cli_dbgmsg("cli_pdf: bad pdf version: %.8s\n", pdfver);
 
2473
#if HAVE_JSON
 
2474
        if (pdfobj)
 
2475
            cli_jsonbool(pdfobj, "BadVersion", 1);
 
2476
#endif
 
2477
    } else {
 
2478
#if HAVE_JSON
 
2479
        if (pdfobj) {
 
2480
            begin = (char *)(pdfver+5);
 
2481
            end = begin+2;
 
2482
            strtoul(end, &end, 10);
 
2483
            p1 = cli_calloc((end - begin) + 2, 1);
 
2484
            if (p1) {
 
2485
                strncpy(p1, begin, end - begin);
 
2486
                p1[end - begin] = '\0';
 
2487
                cli_jsonstr(pdfobj, "PDFVersion", p1);
 
2488
                free(p1);
 
2489
            }
 
2490
        }
 
2491
#endif
 
2492
    }
 
2493
 
 
2494
    if (pdfver != start || offset) {
 
2495
        pdf.flags |= 1 << BAD_PDF_HEADERPOS;
 
2496
        cli_dbgmsg("cli_pdf: PDF header is not at position 0: %ld\n",pdfver-start+offset);
 
2497
#if HAVE_JSON
 
2498
        if (pdfobj)
 
2499
            cli_jsonbool(pdfobj, "BadVersionLocation", 1);
 
2500
#endif
 
2501
    }
 
2502
 
 
2503
    offset += pdfver - start;
 
2504
 
 
2505
    /* find trailer and xref, don't fail if not found */
 
2506
    map_off = (off_t)map->len - 2048;
 
2507
    if (map_off < 0)
 
2508
        map_off = 0;
 
2509
 
 
2510
    bytesleft = map->len - map_off;
 
2511
 
 
2512
    eofmap = fmap_need_off_once(map, map_off, bytesleft);
 
2513
    if (!eofmap) {
 
2514
        cli_errmsg("cli_pdf: mmap() failed (2)\n");
 
2515
#if HAVE_JSON
 
2516
        pdf_export_json(&pdf);
 
2517
#endif
 
2518
        return CL_EMAP;
 
2519
    }
 
2520
 
 
2521
    eof = eofmap + bytesleft;
 
2522
    for (q=&eofmap[bytesleft-5]; q > eofmap; q--) {
 
2523
        if (memcmp(q, "%%EOF", 5) == 0)
 
2524
            break;
 
2525
    }
 
2526
 
 
2527
    if (q <= eofmap) {
 
2528
        pdf.flags |= 1 << BAD_PDF_TRAILER;
 
2529
        cli_dbgmsg("cli_pdf: %%%%EOF not found\n");
 
2530
#if HAVE_JSON
 
2531
        if (pdfobj)
 
2532
            cli_jsonbool(pdfobj, "NoEOF", 1);
 
2533
#endif
 
2534
    } else {
 
2535
        const char *t;
 
2536
 
 
2537
        /*size = q - eofmap + map_off;*/
 
2538
        q -= 9;
 
2539
        for (;q > eofmap;q--) {
 
2540
            if (memcmp(q, "startxref", 9) == 0)
 
2541
                break;
 
2542
        }
 
2543
 
 
2544
        if (q <= eofmap) {
 
2545
            pdf.flags |= 1 << BAD_PDF_TRAILER;
 
2546
            cli_dbgmsg("cli_pdf: startxref not found\n");
 
2547
#if HAVE_JSON
 
2548
            if (pdfobj)
 
2549
                cli_jsonbool(pdfobj, "NoXREF", 1);
 
2550
#endif
 
2551
        } else {
 
2552
            for (t=q;t > eofmap; t--) {
 
2553
                if (memcmp(t,"trailer",7) == 0)
 
2554
                    break;
 
2555
            }
 
2556
 
 
2557
            pdf_parse_trailer(&pdf, eofmap, eof - eofmap);
 
2558
            q += 9;
 
2559
 
 
2560
            while (q < eof && (*q == ' ' || *q == '\n' || *q == '\r')) { q++; }
 
2561
 
 
2562
            xref = atol(q);
 
2563
            bytesleft = map->len - offset - xref;
 
2564
            if (bytesleft > 4096)
 
2565
                bytesleft = 4096;
 
2566
 
 
2567
            q = fmap_need_off_once(map, offset + xref, bytesleft);
 
2568
            if (!q || xrefCheck(q, q+bytesleft) == -1) {
 
2569
                cli_dbgmsg("cli_pdf: did not find valid xref\n");
 
2570
                pdf.flags |= 1 << BAD_PDF_TRAILER;
 
2571
            }
 
2572
        }
 
2573
    }
 
2574
 
 
2575
    size -= offset;
 
2576
    pdf.size = size;
 
2577
    pdf.map = fmap_need_off(map, offset, size);
 
2578
    if (!pdf.map) {
 
2579
        cli_errmsg("cli_pdf: mmap() failed (3)\n");
 
2580
#if HAVE_JSON
 
2581
        pdf_export_json(&pdf);
 
2582
#endif
 
2583
        return CL_EMAP;
 
2584
    }
 
2585
 
 
2586
    pdf.startoff = offset;
 
2587
 
 
2588
    rc = run_pdf_hooks(&pdf, PDF_PHASE_PRE, -1, -1);
 
2589
    if ((rc == CL_VIRUS) && SCAN_ALL) {
 
2590
        cli_dbgmsg("cli_pdf: (pre hooks) returned %d\n", rc);
 
2591
        alerts++;
 
2592
        rc = CL_CLEAN;
 
2593
    } else if (rc) {
 
2594
        cli_dbgmsg("cli_pdf: (pre hooks) returning %d\n", rc);
 
2595
#if HAVE_JSON
 
2596
        pdf_export_json(&pdf);
 
2597
#endif
 
2598
        return rc == CL_BREAK ? CL_CLEAN : rc;
 
2599
    }
 
2600
 
 
2601
    /* parse PDF and find obj offsets */
 
2602
    while ((rc = pdf_findobj(&pdf)) > 0) {
 
2603
        struct pdf_obj *obj = &pdf.objs[pdf.nobjs-1];
 
2604
 
 
2605
        cli_dbgmsg("cli_pdf: found %d %d obj @%ld\n", obj->id >> 8, obj->id&0xff, obj->start + offset);
 
2606
    }
 
2607
 
 
2608
    if (pdf.nobjs)
 
2609
        pdf.nobjs--;
 
2610
 
 
2611
    if (rc == -1)
 
2612
        pdf.flags |= 1 << BAD_PDF_TOOMANYOBJS;
 
2613
 
 
2614
    /* must parse after finding all objs, so we can flag indirect objects */
 
2615
    for (i=0;i<pdf.nobjs;i++) {
 
2616
        struct pdf_obj *obj = &pdf.objs[i];
 
2617
 
 
2618
        if (cli_checktimelimit(ctx) != CL_SUCCESS) {
 
2619
            cli_errmsg("Timeout reached in the PDF parser\n");
 
2620
#if HAVE_JSON
 
2621
            pdf_export_json(&pdf);
 
2622
#endif
 
2623
            free(pdf.objs);
 
2624
            if (pdf.fileID)
 
2625
                free(pdf.fileID);
 
2626
            if (pdf.key)
 
2627
                free(pdf.key);
 
2628
            return CL_ETIMEOUT;
 
2629
        }
 
2630
 
 
2631
        pdf_parseobj(&pdf, obj);
 
2632
    }
 
2633
 
 
2634
    pdf_handle_enc(&pdf);
 
2635
    if (pdf.flags & (1 << ENCRYPTED_PDF))
 
2636
        cli_dbgmsg("cli_pdf: encrypted pdf found, %s!\n",
 
2637
               (pdf.flags & (1 << DECRYPTABLE_PDF)) ?
 
2638
               "decryptable" : "not decryptable, stream will probably fail to decompress");
 
2639
 
 
2640
    if (DETECT_ENCRYPTED &&
 
2641
       (pdf.flags & (1 << ENCRYPTED_PDF)) &&
 
2642
       !(pdf.flags & (1 << DECRYPTABLE_PDF))) {
 
2643
        /* It is encrypted, and a password/key needs to be supplied to decrypt.
 
2644
         * This doesn't trigger for PDFs that are encrypted but don't need
 
2645
         * a password to decrypt */
 
2646
        cli_append_virus(ctx, "Heuristics.Encrypted.PDF");
 
2647
        alerts++;
 
2648
        if (!SCAN_ALL)
 
2649
            rc = CL_VIRUS;
 
2650
    }
 
2651
 
 
2652
    if (!rc) {
 
2653
        rc = run_pdf_hooks(&pdf, PDF_PHASE_PARSED, -1, -1);
 
2654
        cli_dbgmsg("cli_pdf: (parsed hooks) returned %d\n", rc);
 
2655
        if (rc == CL_VIRUS) {
 
2656
            alerts++;
 
2657
            if (SCAN_ALL) {
 
2658
                rc = CL_CLEAN;
 
2659
            }
 
2660
        }
 
2661
    }
 
2662
 
 
2663
    /* extract PDF objs */
 
2664
    for (i=0;!rc && i<pdf.nobjs;i++) {
 
2665
        struct pdf_obj *obj = &pdf.objs[i];
 
2666
 
 
2667
        if (cli_checktimelimit(ctx) != CL_SUCCESS) {
 
2668
            cli_errmsg("Timeout reached in the PDF parser\n");
 
2669
#if HAVE_JSON
 
2670
            pdf_export_json(&pdf);
 
2671
#endif
 
2672
            free(pdf.objs);
 
2673
            if (pdf.fileID)
 
2674
                free(pdf.fileID);
 
2675
            if (pdf.key)
 
2676
                free(pdf.key);
 
2677
            return CL_ETIMEOUT;
 
2678
        }
 
2679
 
 
2680
        rc = pdf_extract_obj(&pdf, obj, PDF_EXTRACT_OBJ_SCAN);
 
2681
        switch (rc) {
 
2682
            case CL_EFORMAT:
 
2683
                /* Don't halt on one bad object */
 
2684
                cli_dbgmsg("cli_pdf: bad format object, skipping to next\n");
 
2685
                badobjects++;
 
2686
                pdf.stats.ninvalidobjs++;
 
2687
                rc = CL_CLEAN;
 
2688
                break;
 
2689
            case CL_VIRUS:
 
2690
                alerts++;
 
2691
                if (SCAN_ALL) {
 
2692
                    rc = CL_CLEAN;
 
2693
                }
 
2694
                break;
 
2695
            default:
 
2696
                break;
 
2697
        }
 
2698
    }
 
2699
 
 
2700
    if (pdf.flags & (1 << ENCRYPTED_PDF))
 
2701
        pdf.flags &= ~ ((1 << BAD_FLATESTART) | (1 << BAD_STREAMSTART) | (1 << BAD_ASCIIDECODE));
 
2702
 
 
2703
   if (pdf.flags && !rc) {
 
2704
        cli_dbgmsg("cli_pdf: flags 0x%02x\n", pdf.flags);
 
2705
        rc = run_pdf_hooks(&pdf, PDF_PHASE_END, -1, -1);
 
2706
        if (rc == CL_VIRUS) {
 
2707
            alerts++;
 
2708
            if (SCAN_ALL) {
 
2709
                rc = CL_CLEAN;
 
2710
            }
 
2711
        }
 
2712
 
 
2713
        if (!rc && SCAN_ALGO && (ctx->dconf->other & OTHER_CONF_PDFNAMEOBJ)) {
 
2714
            if (pdf.flags & (1 << ESCAPED_COMMON_PDFNAME)) {
 
2715
                /* for example /Fl#61te#44#65#63#6f#64#65 instead of /FlateDecode */
 
2716
                cli_append_virus(ctx, "Heuristics.PDF.ObfuscatedNameObject");
 
2717
                rc = cli_found_possibly_unwanted(ctx);
 
2718
            }
 
2719
        }
 
2720
#if 0
 
2721
        /* TODO: find both trailers, and /Encrypt settings */
 
2722
        if (pdf.flags & (1 << LINEARIZED_PDF))
 
2723
            pdf.flags &= ~ (1 << BAD_ASCIIDECODE);
 
2724
        if (pdf.flags & (1 << MANY_FILTERS))
 
2725
            pdf.flags &= ~ (1 << BAD_ASCIIDECODE);
 
2726
        if (!rc && (pdf.flags &
 
2727
            ((1 << BAD_PDF_TOOMANYOBJS) | (1 << BAD_STREAM_FILTERS) |
 
2728
             (1<<BAD_FLATE) | (1<<BAD_ASCIIDECODE)|
 
2729
             (1<<UNTERMINATED_OBJ_DICT) | (1<<UNKNOWN_FILTER)))) {
 
2730
            rc = CL_EUNPACK;
 
2731
        }
 
2732
#endif
 
2733
    }
 
2734
 
 
2735
    if (alerts) {
 
2736
        rc = CL_VIRUS;
 
2737
    }
 
2738
 
 
2739
    else if (!rc && badobjects) {
 
2740
        rc = CL_EFORMAT;
 
2741
    }
 
2742
 
 
2743
#if HAVE_JSON
 
2744
    pdf_export_json(&pdf);
 
2745
#endif
 
2746
 
 
2747
    cli_dbgmsg("cli_pdf: returning %d\n", rc);
 
2748
    free(pdf.objs);
 
2749
    free(pdf.fileID);
 
2750
    free(pdf.key);
 
2751
 
 
2752
    /* PDF hooks may abort, don't return CL_BREAK to caller! */
 
2753
    return rc == CL_BREAK ? CL_CLEAN : rc;
 
2754
}
 
2755
 
 
2756
static int asciihexdecode(const char *buf, off_t len, char *output)
 
2757
{
 
2758
    unsigned i,j;
 
2759
    for (i=0,j=0;i+1<len;i++) {
 
2760
        if (buf[i] == ' ')
 
2761
            continue;
 
2762
 
 
2763
        if (buf[i] == '>')
 
2764
            break;
 
2765
 
 
2766
        if (cli_hex2str_to(buf+i, output+j, 2) == -1) {
 
2767
            if (len - i < 4)
 
2768
                continue;
 
2769
 
 
2770
            return -1;
 
2771
        }
 
2772
 
 
2773
        j++;
 
2774
        i++;
 
2775
    }
 
2776
 
 
2777
    return j;
 
2778
}
 
2779
 
 
2780
/*
 
2781
 * ascii85 inflation, returns number of bytes in output, -1 for error
 
2782
 *
 
2783
 * See http://www.piclist.com/techref/method/encode.htm (look for base85)
 
2784
 */
 
2785
static int
 
2786
ascii85decode(const char *buf, off_t len, unsigned char *output)
 
2787
{
 
2788
    const char *ptr;
 
2789
    uint32_t sum = 0;
 
2790
    int quintet = 0;
 
2791
    int ret = 0;
 
2792
 
 
2793
    if(cli_memstr(buf, len, "~>", 2) == NULL)
 
2794
        cli_dbgmsg("cli_pdf: ascii85decode: no EOF marker found\n");
 
2795
 
 
2796
    ptr = buf;
 
2797
 
 
2798
    cli_dbgmsg("cli_pdf: ascii85decode %lu bytes\n", (unsigned long)len);
 
2799
 
 
2800
    while(len > 0) {
 
2801
        int byte = (len--) ? (int)*ptr++ : EOF;
 
2802
 
 
2803
        if((byte == '~') && (len > 0) && (*ptr == '>'))
 
2804
            byte = EOF;
 
2805
 
 
2806
        if(byte >= '!' && byte <= 'u') {
 
2807
            sum = (sum * 85) + ((uint32_t)byte - '!');
 
2808
            if(++quintet == 5) {
 
2809
                *output++ = (unsigned char)(sum >> 24);
 
2810
                *output++ = (unsigned char)((sum >> 16) & 0xFF);
 
2811
                *output++ = (unsigned char)((sum >> 8) & 0xFF);
 
2812
                *output++ = (unsigned char)(sum & 0xFF);
 
2813
                ret += 4;
 
2814
                quintet = 0;
 
2815
                sum = 0;
 
2816
            }
 
2817
        } else if(byte == 'z') {
 
2818
            if(quintet) {
 
2819
                cli_dbgmsg("cli_pdf: ascii85decode: unexpected 'z'\n");
 
2820
                return -1;
 
2821
            }
 
2822
 
 
2823
            *output++ = '\0';
 
2824
            *output++ = '\0';
 
2825
            *output++ = '\0';
 
2826
            *output++ = '\0';
 
2827
            ret += 4;
 
2828
        } else if(byte == EOF) {
 
2829
            cli_dbgmsg("cli_pdf: ascii85decode: quintet %d\n", quintet);
 
2830
            if(quintet) {
 
2831
                int i;
 
2832
 
 
2833
                if(quintet == 1) {
 
2834
                    cli_dbgmsg("cli_pdf: ascii85Decode: only 1 byte in last quintet\n");
 
2835
                    return -1;
 
2836
                }
 
2837
 
 
2838
                for(i = quintet; i < 5; i++)
 
2839
                    sum *= 85;
 
2840
 
 
2841
                if(quintet > 1)
 
2842
                    sum += (0xFFFFFF >> ((quintet - 2) * 8));
 
2843
 
 
2844
                ret += quintet-1;
 
2845
                for(i = 0; i < quintet - 1; i++)
 
2846
                    *output++ = (unsigned char)((sum >> (24 - 8 * i)) & 0xFF);
 
2847
            }
 
2848
 
 
2849
            break;
 
2850
        } else if(!isspace(byte)) {
 
2851
            cli_dbgmsg("cli_pdf: ascii85Decode: invalid character 0x%x, len %lu\n", byte & 0xFF, (unsigned long)len);
 
2852
 
 
2853
            return -1;
 
2854
        }
 
2855
    }
 
2856
    return ret;
 
2857
}
 
2858
 
 
2859
/*
 
2860
 * Find the start of the next line
 
2861
 */
 
2862
static const char *
 
2863
pdf_nextlinestart(const char *ptr, size_t len)
 
2864
{
 
2865
    while(strchr("\r\n", *ptr) == NULL) {
 
2866
        if(--len == 0L)
 
2867
            return NULL;
 
2868
 
 
2869
        ptr++;
 
2870
    }
 
2871
 
 
2872
    while(strchr("\r\n", *ptr) != NULL) {
 
2873
        if(--len == 0L)
 
2874
            return NULL;
 
2875
 
 
2876
        ptr++;
 
2877
    }
 
2878
 
 
2879
    return ptr;
 
2880
}
 
2881
 
 
2882
/*
 
2883
 * Return the start of the next PDF object.
 
2884
 * This assumes that we're not in a stream.
 
2885
 */
 
2886
static const char *
 
2887
pdf_nextobject(const char *ptr, size_t len)
 
2888
{
 
2889
    const char *p;
 
2890
    int inobject = 1;
 
2891
 
 
2892
    while(len) {
 
2893
        switch(*ptr) {
 
2894
        case '\n':
 
2895
        case '\r':
 
2896
        case '%':   /* comment */
 
2897
            p = pdf_nextlinestart(ptr, len);
 
2898
            if(p == NULL)
 
2899
                return NULL;
 
2900
 
 
2901
            len -= (size_t)(p - ptr);
 
2902
            ptr = p;
 
2903
            inobject = 0;
 
2904
 
 
2905
            break;
 
2906
        case ' ':
 
2907
        case '\t':
 
2908
        case '[':   /* Start of an array object */
 
2909
        case '\v':
 
2910
        case '\f':
 
2911
        case '<':   /* Start of a dictionary object */
 
2912
            inobject = 0;
 
2913
            ptr++;
 
2914
            len--;
 
2915
 
 
2916
            break;
 
2917
        case '/':   /* Start of a name object */
 
2918
            return ptr;
 
2919
        case '(': /* start of JS */
 
2920
            return ptr;
 
2921
        default:
 
2922
            if(!inobject) {
 
2923
                /* TODO: parse and return object type */
 
2924
                return ptr;
 
2925
            }
 
2926
 
 
2927
            ptr++;
 
2928
            len--;
 
2929
        }
 
2930
    }
 
2931
 
 
2932
    return NULL;
 
2933
}
 
2934
 
 
2935
/* PDF statistics */
 
2936
#if HAVE_JSON
 
2937
static void ASCIIHexDecode_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
2938
{
 
2939
    UNUSEDPARAM(obj);
 
2940
    UNUSEDPARAM(act);
 
2941
 
 
2942
    if (!(pdf))
 
2943
        return;
 
2944
 
 
2945
    pdf->stats.nasciihexdecode++;
 
2946
}
 
2947
#endif
 
2948
 
 
2949
#if HAVE_JSON
 
2950
static void ASCII85Decode_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
2951
{
 
2952
    UNUSEDPARAM(obj);
 
2953
    UNUSEDPARAM(act);
 
2954
 
 
2955
    if (!(pdf))
 
2956
        return;
 
2957
 
 
2958
    pdf->stats.nascii85decode++;
 
2959
}
 
2960
#endif
 
2961
 
 
2962
#if HAVE_JSON
 
2963
static void EmbeddedFile_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
2964
{
 
2965
    UNUSEDPARAM(obj);
 
2966
    UNUSEDPARAM(act);
 
2967
 
 
2968
    if (!(pdf))
 
2969
        return;
 
2970
 
 
2971
    pdf->stats.nembeddedfile++;
 
2972
}
 
2973
#endif
 
2974
 
 
2975
#if HAVE_JSON
 
2976
static void FlateDecode_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
2977
{
 
2978
    UNUSEDPARAM(obj);
 
2979
    UNUSEDPARAM(act);
 
2980
 
 
2981
    if (!(pdf))
 
2982
        return;
 
2983
 
 
2984
    pdf->stats.nflate++;
 
2985
}
 
2986
#endif
 
2987
 
 
2988
#if HAVE_JSON
 
2989
static void Image_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
2990
{
 
2991
    UNUSEDPARAM(obj);
 
2992
    UNUSEDPARAM(act);
 
2993
 
 
2994
    if (!(pdf))
 
2995
        return;
 
2996
 
 
2997
    pdf->stats.nimage++;
 
2998
}
 
2999
#endif
 
3000
 
 
3001
#if HAVE_JSON
 
3002
static void LZWDecode_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
3003
{
 
3004
    UNUSEDPARAM(obj);
 
3005
    UNUSEDPARAM(act);
 
3006
 
 
3007
    if (!(pdf))
 
3008
        return;
 
3009
 
 
3010
    pdf->stats.nlzw++;
 
3011
}
 
3012
#endif
 
3013
 
 
3014
#if HAVE_JSON
 
3015
static void RunLengthDecode_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
3016
{
 
3017
    UNUSEDPARAM(obj);
 
3018
    UNUSEDPARAM(act);
 
3019
 
 
3020
    if (!(pdf))
 
3021
        return;
 
3022
 
 
3023
    pdf->stats.nrunlengthdecode++;
 
3024
}
 
3025
#endif
 
3026
 
 
3027
#if HAVE_JSON
 
3028
static void CCITTFaxDecode_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
3029
{
 
3030
    UNUSEDPARAM(obj);
 
3031
    UNUSEDPARAM(act);
 
3032
 
 
3033
    if (!(pdf))
 
3034
        return;
 
3035
 
 
3036
    pdf->stats.nfaxdecode++;
 
3037
}
 
3038
#endif
 
3039
 
 
3040
#if HAVE_JSON
 
3041
static void JBIG2Decode_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
3042
{
 
3043
    struct json_object *pdfobj, *jbig2arr;
 
3044
 
 
3045
    UNUSEDPARAM(obj);
 
3046
    UNUSEDPARAM(act);
 
3047
 
 
3048
    if (!(pdf))
 
3049
        return;
 
3050
 
 
3051
    if (!(pdf->ctx->options & CL_SCAN_FILE_PROPERTIES))
 
3052
        return;
 
3053
 
 
3054
    if (!(pdf->ctx->wrkproperty))
 
3055
        return;
 
3056
 
 
3057
    pdfobj = cli_jsonobj(pdf->ctx->wrkproperty, "PDFStats");
 
3058
    if (!(pdfobj))
 
3059
        return;
 
3060
 
 
3061
    jbig2arr = cli_jsonarray(pdfobj, "JBIG2Objects");
 
3062
    if (!(jbig2arr))
 
3063
        return;
 
3064
 
 
3065
    cli_jsonint_array(jbig2arr, obj->id>>8);
 
3066
 
 
3067
    pdf->stats.njbig2decode++;
 
3068
}
 
3069
#endif
 
3070
 
 
3071
#if HAVE_JSON
 
3072
static void DCTDecode_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
3073
{
 
3074
    UNUSEDPARAM(obj);
 
3075
    UNUSEDPARAM(act);
 
3076
 
 
3077
    if (!(pdf))
 
3078
        return;
 
3079
 
 
3080
    pdf->stats.ndctdecode++;
 
3081
}
 
3082
#endif
 
3083
 
 
3084
#if HAVE_JSON
 
3085
static void JPXDecode_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
3086
{
 
3087
    UNUSEDPARAM(obj);
 
3088
    UNUSEDPARAM(act);
 
3089
 
 
3090
    if (!(pdf))
 
3091
        return;
 
3092
 
 
3093
    pdf->stats.njpxdecode++;
 
3094
}
 
3095
#endif
 
3096
 
 
3097
#if HAVE_JSON
 
3098
static void Crypt_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
3099
{
 
3100
    UNUSEDPARAM(obj);
 
3101
    UNUSEDPARAM(act);
 
3102
 
 
3103
    if (!(pdf))
 
3104
        return;
 
3105
 
 
3106
    pdf->stats.ncrypt++;
 
3107
}
 
3108
#endif
 
3109
 
 
3110
#if HAVE_JSON
 
3111
static void Standard_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
3112
{
 
3113
    UNUSEDPARAM(obj);
 
3114
    UNUSEDPARAM(act);
 
3115
 
 
3116
    if (!(pdf))
 
3117
        return;
 
3118
 
 
3119
    pdf->stats.nstandard++;
 
3120
}
 
3121
#endif
 
3122
 
 
3123
#if HAVE_JSON
 
3124
static void Sig_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
3125
{
 
3126
    UNUSEDPARAM(obj);
 
3127
    UNUSEDPARAM(act);
 
3128
 
 
3129
    if (!(pdf))
 
3130
        return;
 
3131
 
 
3132
    pdf->stats.nsigned++;
 
3133
}
 
3134
#endif
 
3135
 
 
3136
#if HAVE_JSON
 
3137
static void JavaScript_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
3138
{
 
3139
    struct json_object *pdfobj, *jbig2arr;
 
3140
 
 
3141
    UNUSEDPARAM(act);
 
3142
 
 
3143
    if (!(pdf))
 
3144
        return;
 
3145
 
 
3146
    if (!(pdf->ctx->options & CL_SCAN_FILE_PROPERTIES))
 
3147
        return;
 
3148
 
 
3149
    if (!(pdf->ctx->wrkproperty))
 
3150
        return;
 
3151
 
 
3152
    pdfobj = cli_jsonobj(pdf->ctx->wrkproperty, "PDFStats");
 
3153
    if (!(pdfobj))
 
3154
        return;
 
3155
 
 
3156
    jbig2arr = cli_jsonarray(pdfobj, "JavascriptObjects");
 
3157
    if (!(jbig2arr))
 
3158
        return;
 
3159
 
 
3160
    cli_jsonint_array(jbig2arr, obj->id>>8);
 
3161
 
 
3162
    pdf->stats.njs++;
 
3163
}
 
3164
#endif
 
3165
 
 
3166
#if HAVE_JSON
 
3167
static void OpenAction_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
3168
{
 
3169
    UNUSEDPARAM(obj);
 
3170
    UNUSEDPARAM(act);
 
3171
 
 
3172
    if (!(pdf))
 
3173
        return;
 
3174
 
 
3175
    pdf->stats.nopenaction++;
 
3176
}
 
3177
#endif
 
3178
 
 
3179
#if HAVE_JSON
 
3180
static void Launch_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
3181
{
 
3182
    UNUSEDPARAM(obj);
 
3183
    UNUSEDPARAM(act);
 
3184
 
 
3185
    if (!(pdf))
 
3186
        return;
 
3187
 
 
3188
    pdf->stats.nlaunch++;
 
3189
}
 
3190
#endif
 
3191
 
 
3192
#if HAVE_JSON
 
3193
static void Page_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
3194
{
 
3195
    UNUSEDPARAM(obj);
 
3196
    UNUSEDPARAM(act);
 
3197
 
 
3198
    if (!(pdf))
 
3199
        return;
 
3200
 
 
3201
    pdf->stats.npage++;
 
3202
}
 
3203
#endif
 
3204
 
 
3205
#if HAVE_JSON
 
3206
static void Author_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
3207
{
 
3208
    UNUSEDPARAM(act);
 
3209
 
 
3210
    if (!(pdf))
 
3211
        return;
 
3212
 
 
3213
    if (!(pdf->ctx->options & CL_SCAN_FILE_PROPERTIES))
 
3214
        return;
 
3215
 
 
3216
    if (!(pdf->stats.author))
 
3217
        pdf->stats.author = pdf_parse_string(pdf, obj, obj->start + pdf->map, obj_size(pdf, obj, 1), "/Author", NULL);
 
3218
}
 
3219
#endif
 
3220
 
 
3221
#if HAVE_JSON
 
3222
static void Creator_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
3223
{
 
3224
    UNUSEDPARAM(act);
 
3225
 
 
3226
    if (!(pdf))
 
3227
        return;
 
3228
 
 
3229
    if (!(pdf->ctx->options & CL_SCAN_FILE_PROPERTIES))
 
3230
        return;
 
3231
 
 
3232
    if (!(pdf->stats.creator))
 
3233
        pdf->stats.creator = pdf_parse_string(pdf, obj, obj->start + pdf->map, obj_size(pdf, obj, 1), "/Creator", NULL);
 
3234
}
 
3235
#endif
 
3236
 
 
3237
#if HAVE_JSON
 
3238
static void ModificationDate_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
3239
{
 
3240
    UNUSEDPARAM(act);
 
3241
 
 
3242
    if (!(pdf))
 
3243
        return;
 
3244
 
 
3245
    if (!(pdf->ctx->options & CL_SCAN_FILE_PROPERTIES))
 
3246
        return;
 
3247
 
 
3248
    if (!(pdf->stats.modificationdate))
 
3249
        pdf->stats.modificationdate = pdf_parse_string(pdf, obj, obj->start + pdf->map, obj_size(pdf, obj, 1), "/ModDate", NULL);
 
3250
}
 
3251
#endif
 
3252
 
 
3253
#if HAVE_JSON
 
3254
static void CreationDate_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
3255
{
 
3256
    UNUSEDPARAM(act);
 
3257
 
 
3258
    if (!(pdf))
 
3259
        return;
 
3260
 
 
3261
    if (!(pdf->ctx->options & CL_SCAN_FILE_PROPERTIES))
 
3262
        return;
 
3263
 
 
3264
    if (!(pdf->stats.creationdate))
 
3265
        pdf->stats.creationdate = pdf_parse_string(pdf, obj, obj->start + pdf->map, obj_size(pdf, obj, 1), "/CreationDate", NULL);
 
3266
}
 
3267
#endif
 
3268
 
 
3269
#if HAVE_JSON
 
3270
static void Producer_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
3271
{
 
3272
    UNUSEDPARAM(act);
 
3273
 
 
3274
    if (!(pdf))
 
3275
        return;
 
3276
 
 
3277
    if (!(pdf->ctx->options & CL_SCAN_FILE_PROPERTIES))
 
3278
        return;
 
3279
 
 
3280
    if (!(pdf->stats.producer))
 
3281
        pdf->stats.producer = pdf_parse_string(pdf, obj, obj->start + pdf->map, obj_size(pdf, obj, 1), "/Producer", NULL);
 
3282
}
 
3283
#endif
 
3284
 
 
3285
#if HAVE_JSON
 
3286
static void Title_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
3287
{
 
3288
    UNUSEDPARAM(act);
 
3289
 
 
3290
    if (!(pdf))
 
3291
        return;
 
3292
 
 
3293
    if (!(pdf->ctx->options & CL_SCAN_FILE_PROPERTIES))
 
3294
        return;
 
3295
 
 
3296
    if (!(pdf->stats.title))
 
3297
        pdf->stats.title = pdf_parse_string(pdf, obj, obj->start + pdf->map, obj_size(pdf, obj, 1), "/Title", NULL);
 
3298
}
 
3299
#endif
 
3300
 
 
3301
#if HAVE_JSON
 
3302
static void Keywords_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
3303
{
 
3304
    UNUSEDPARAM(act);
 
3305
 
 
3306
    if (!(pdf))
 
3307
        return;
 
3308
 
 
3309
    if (!(pdf->ctx->options & CL_SCAN_FILE_PROPERTIES))
 
3310
        return;
 
3311
 
 
3312
    if (!(pdf->stats.keywords))
 
3313
        pdf->stats.keywords = pdf_parse_string(pdf, obj, obj->start + pdf->map, obj_size(pdf, obj, 1), "/Keywords", NULL);
 
3314
}
 
3315
#endif
 
3316
 
 
3317
#if HAVE_JSON
 
3318
static void Subject_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
3319
{
 
3320
    UNUSEDPARAM(act);
 
3321
 
 
3322
    if (!(pdf))
 
3323
        return;
 
3324
 
 
3325
    if (!(pdf->ctx->options & CL_SCAN_FILE_PROPERTIES))
 
3326
        return;
 
3327
 
 
3328
    if (!(pdf->stats.subject))
 
3329
        pdf->stats.subject = pdf_parse_string(pdf, obj, obj->start + pdf->map, obj_size(pdf, obj, 1), "/Subject", NULL);
 
3330
}
 
3331
#endif
 
3332
 
 
3333
#if HAVE_JSON
 
3334
static void RichMedia_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
3335
{
 
3336
    UNUSEDPARAM(obj);
 
3337
    UNUSEDPARAM(act);
 
3338
 
 
3339
    if (!(pdf))
 
3340
        return;
 
3341
 
 
3342
    pdf->stats.nrichmedia++;
 
3343
}
 
3344
#endif
 
3345
 
 
3346
#if HAVE_JSON
 
3347
static void AcroForm_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
3348
{
 
3349
    UNUSEDPARAM(obj);
 
3350
    UNUSEDPARAM(act);
 
3351
 
 
3352
    if (!(pdf))
 
3353
        return;
 
3354
 
 
3355
    pdf->stats.nacroform++;
 
3356
}
 
3357
#endif
 
3358
 
 
3359
#if HAVE_JSON
 
3360
static void XFA_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
3361
{
 
3362
    UNUSEDPARAM(obj);
 
3363
    UNUSEDPARAM(act);
 
3364
 
 
3365
    if (!(pdf))
 
3366
        return;
 
3367
 
 
3368
    pdf->stats.nxfa++;
 
3369
}
 
3370
#endif
 
3371
 
 
3372
#if HAVE_JSON
 
3373
static void Pages_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
3374
{
 
3375
    struct pdf_array *array;
 
3376
    const char *objstart = (const char *)(obj->start + pdf->map);
 
3377
    const char *begin;
 
3378
    unsigned int objsz;
 
3379
    unsigned long npages=0, count;
 
3380
    struct pdf_array_node *node;
 
3381
    json_object *pdfobj;
 
3382
 
 
3383
    UNUSEDPARAM(act);
 
3384
 
 
3385
    if (!(pdf) || !(pdf->ctx->wrkproperty))
 
3386
        return;
 
3387
 
 
3388
    if (!(pdf->ctx->options & CL_SCAN_FILE_PROPERTIES))
 
3389
        return;
 
3390
 
 
3391
    objsz = obj_size(pdf, obj, 1);
 
3392
 
 
3393
    pdfobj = cli_jsonobj(pdf->ctx->wrkproperty, "PDFStats");
 
3394
    if (!(pdfobj))
 
3395
        return;
 
3396
 
 
3397
    begin = cli_memstr(objstart, objsz, "/Kids", 5);
 
3398
    if (!(begin))
 
3399
        return;
 
3400
 
 
3401
    begin += 5;
 
3402
 
 
3403
    array = pdf_parse_array(pdf, obj, objsz, (char *)begin, NULL);
 
3404
    if (!(array)) {
 
3405
        cli_jsonbool(pdfobj, "IncorrectPagesCount", 1);
 
3406
        return;
 
3407
    }
 
3408
 
 
3409
    for (node = array->nodes; node != NULL; node = node->next)
 
3410
        if (node->datasz)
 
3411
            if (strchr((char *)(node->data), 'R'))
 
3412
                npages++;
 
3413
 
 
3414
    begin = cli_memstr(obj->start + pdf->map, objsz, "/Count", 6);
 
3415
    if (!(begin)) {
 
3416
        cli_jsonbool(pdfobj, "IncorrectPagesCount", 1);
 
3417
        goto cleanup;
 
3418
    }
 
3419
 
 
3420
    begin += 6;
 
3421
    while (begin - objstart <  objsz && isspace(begin[0]))
 
3422
        begin++;
 
3423
 
 
3424
    if (begin - objstart >= objsz) {
 
3425
        goto cleanup;
 
3426
    }
 
3427
 
 
3428
    count = strtoul(begin, NULL, 10);
 
3429
    if (count != npages)
 
3430
        cli_jsonbool(pdfobj, "IncorrectPagesCount", 1);
 
3431
 
 
3432
cleanup:
 
3433
    pdf_free_array(array);
 
3434
}
 
3435
#endif
 
3436
 
 
3437
#if HAVE_JSON
 
3438
static void Colors_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_action *act)
 
3439
{
 
3440
    json_object *colorsobj, *pdfobj;
 
3441
    unsigned long ncolors;
 
3442
    char *start, *p1;
 
3443
    size_t objsz;
 
3444
 
 
3445
    UNUSEDPARAM(act);
 
3446
 
 
3447
    if (!(pdf) || !(pdf->ctx) || !(pdf->ctx->wrkproperty))
 
3448
        return;
 
3449
 
 
3450
    if (!(pdf->ctx->options & CL_SCAN_FILE_PROPERTIES))
 
3451
        return;
 
3452
 
 
3453
    objsz = obj_size(pdf, obj, 1);
 
3454
 
 
3455
    start = (char *)(obj->start + pdf->map);
 
3456
 
 
3457
    p1 = (char *)cli_memstr(start, objsz, "/Colors", 7);
 
3458
    if (!(p1))
 
3459
        return;
 
3460
 
 
3461
    p1 += 7;
 
3462
 
 
3463
    /* Ensure that we have at least one whitespace character plus at least one number */
 
3464
    if (objsz - (p1 - start) < 2)
 
3465
        return;
 
3466
 
 
3467
    while (p1 - start < objsz && isspace(p1[0]))
 
3468
        p1++;
 
3469
 
 
3470
    if ((size_t)(p1 - start) == objsz)
 
3471
        return;
 
3472
 
 
3473
    ncolors = strtoul(p1, NULL, 10);
 
3474
 
 
3475
    /* We only care if the number of colors > 2**24 */
 
3476
    if (ncolors < 1<<24)
 
3477
        return;
 
3478
 
 
3479
    pdfobj = cli_jsonobj(pdf->ctx->wrkproperty, "PDFStats");
 
3480
    if (!(pdfobj))
 
3481
        return;
 
3482
 
 
3483
    colorsobj = cli_jsonarray(pdfobj, "BigColors");
 
3484
    if (!(colorsobj))
 
3485
        return;
 
3486
 
 
3487
    cli_jsonint_array(colorsobj, obj->id>>8);
 
3488
}
 
3489
#endif
 
3490
 
 
3491
#if HAVE_JSON
 
3492
static void pdf_export_json(struct pdf_struct *pdf)
 
3493
{
 
3494
    json_object *pdfobj;
 
3495
    unsigned long i;
 
3496
 
 
3497
    if (!(pdf))
 
3498
        return;
 
3499
 
 
3500
    if (!(pdf->ctx)) {
 
3501
        goto cleanup;
 
3502
    }
 
3503
 
 
3504
    if (!(pdf->ctx->options & CL_SCAN_FILE_PROPERTIES) || !(pdf->ctx->wrkproperty)) {
 
3505
        goto cleanup;
 
3506
    }
 
3507
 
 
3508
    pdfobj = cli_jsonobj(pdf->ctx->wrkproperty, "PDFStats");
 
3509
    if (!(pdfobj)) {
 
3510
        goto cleanup;
 
3511
    }
 
3512
 
 
3513
    if (pdf->stats.author)
 
3514
        cli_jsonstr(pdfobj, "Author", pdf->stats.author);
 
3515
    if (pdf->stats.creator)
 
3516
        cli_jsonstr(pdfobj, "Creator", pdf->stats.creator);
 
3517
    if (pdf->stats.producer)
 
3518
        cli_jsonstr(pdfobj, "Producer", pdf->stats.producer);
 
3519
    if (pdf->stats.modificationdate)
 
3520
        cli_jsonstr(pdfobj, "ModificationDate", pdf->stats.modificationdate);
 
3521
    if (pdf->stats.creationdate)
 
3522
        cli_jsonstr(pdfobj, "CreationDate", pdf->stats.creationdate);
 
3523
    if (pdf->stats.title)
 
3524
        cli_jsonstr(pdfobj, "Title", pdf->stats.title);
 
3525
    if (pdf->stats.subject)
 
3526
        cli_jsonstr(pdfobj, "Subject", pdf->stats.subject);
 
3527
    if (pdf->stats.keywords)
 
3528
        cli_jsonstr(pdfobj, "Keywords", pdf->stats.keywords);
 
3529
    if (pdf->stats.ninvalidobjs)
 
3530
        cli_jsonint(pdfobj, "InvalidObjectCount", pdf->stats.ninvalidobjs);
 
3531
    if (pdf->stats.njs)
 
3532
        cli_jsonint(pdfobj, "JavaScriptObjectCount", pdf->stats.njs);
 
3533
    if (pdf->stats.nflate)
 
3534
        cli_jsonint(pdfobj, "DeflateObjectCount", pdf->stats.nflate);
 
3535
    if (pdf->stats.nactivex)
 
3536
        cli_jsonint(pdfobj, "ActiveXObjectCount", pdf->stats.nactivex);
 
3537
    if (pdf->stats.nflash)
 
3538
        cli_jsonint(pdfobj, "FlashObjectCount", pdf->stats.nflash);
 
3539
    if (pdf->stats.ncolors)
 
3540
        cli_jsonint(pdfobj, "ColorCount", pdf->stats.ncolors);
 
3541
    if (pdf->stats.nasciihexdecode)
 
3542
        cli_jsonint(pdfobj, "AsciiHexDecodeObjectCount", pdf->stats.nasciihexdecode);
 
3543
    if (pdf->stats.nascii85decode)
 
3544
        cli_jsonint(pdfobj, "Ascii85DecodeObjectCount", pdf->stats.nascii85decode);
 
3545
    if (pdf->stats.nembeddedfile)
 
3546
        cli_jsonint(pdfobj, "EmbeddedFileCount", pdf->stats.nembeddedfile);
 
3547
    if (pdf->stats.nimage)
 
3548
        cli_jsonint(pdfobj, "ImageCount", pdf->stats.nimage);
 
3549
    if (pdf->stats.nlzw)
 
3550
        cli_jsonint(pdfobj, "LZWCount", pdf->stats.nlzw);
 
3551
    if (pdf->stats.nrunlengthdecode)
 
3552
        cli_jsonint(pdfobj, "RunLengthDecodeCount", pdf->stats.nrunlengthdecode);
 
3553
    if (pdf->stats.nfaxdecode)
 
3554
        cli_jsonint(pdfobj, "FaxDecodeCount", pdf->stats.nfaxdecode);
 
3555
    if (pdf->stats.njbig2decode)
 
3556
        cli_jsonint(pdfobj, "JBIG2DecodeCount", pdf->stats.njbig2decode);
 
3557
    if (pdf->stats.ndctdecode)
 
3558
        cli_jsonint(pdfobj, "DCTDecodeCount", pdf->stats.ndctdecode);
 
3559
    if (pdf->stats.njpxdecode)
 
3560
        cli_jsonint(pdfobj, "JPXDecodeCount", pdf->stats.njpxdecode);
 
3561
    if (pdf->stats.ncrypt)
 
3562
        cli_jsonint(pdfobj, "CryptCount", pdf->stats.ncrypt);
 
3563
    if (pdf->stats.nstandard)
 
3564
        cli_jsonint(pdfobj, "StandardCount", pdf->stats.nstandard);
 
3565
    if (pdf->stats.nsigned)
 
3566
        cli_jsonint(pdfobj, "SignedCount", pdf->stats.nsigned);
 
3567
    if (pdf->stats.nopenaction)
 
3568
        cli_jsonint(pdfobj, "OpenActionCount", pdf->stats.nopenaction);
 
3569
    if (pdf->stats.nlaunch)
 
3570
        cli_jsonint(pdfobj, "LaunchCount", pdf->stats.nlaunch);
 
3571
    if (pdf->stats.npage)
 
3572
        cli_jsonint(pdfobj, "PageCount", pdf->stats.npage);
 
3573
    if (pdf->stats.nrichmedia)
 
3574
        cli_jsonint(pdfobj, "RichMediaCount", pdf->stats.nrichmedia);
 
3575
    if (pdf->stats.nacroform)
 
3576
        cli_jsonint(pdfobj, "AcroFormCount", pdf->stats.nacroform);
 
3577
    if (pdf->stats.nxfa)
 
3578
        cli_jsonint(pdfobj, "XFACount", pdf->stats.nxfa);
 
3579
    if (pdf->flags & (1 << BAD_PDF_VERSION))
 
3580
        cli_jsonbool(pdfobj, "BadVersion", 1);
 
3581
    if (pdf->flags & (1 << BAD_PDF_HEADERPOS))
 
3582
        cli_jsonbool(pdfobj, "BadHeaderPosition", 1);
 
3583
    if (pdf->flags & (1 << BAD_PDF_TRAILER))
 
3584
        cli_jsonbool(pdfobj, "BadTrailer", 1);
 
3585
    if (pdf->flags & (1 << BAD_PDF_TOOMANYOBJS))
 
3586
        cli_jsonbool(pdfobj, "TooManyObjects", 1);
 
3587
    if (pdf->flags & (1 << ENCRYPTED_PDF)) {
 
3588
        cli_jsonbool(pdfobj, "Encrypted", 1);
 
3589
        if (pdf->flags & (1 << DECRYPTABLE_PDF))
 
3590
            cli_jsonbool(pdfobj, "Decryptable", 1);
 
3591
    }
 
3592
 
 
3593
    for (i=0; i < pdf->nobjs; i++) {
 
3594
        if (pdf->objs[i].flags & (1<<OBJ_TRUNCATED)) {
 
3595
            json_object *truncobj;
 
3596
 
 
3597
            truncobj = cli_jsonarray(pdfobj, "TruncatedObjects");
 
3598
            if (!(truncobj))
 
3599
                continue;
 
3600
 
 
3601
            cli_jsonint_array(truncobj, pdf->objs[i].id>>8);
 
3602
        }
 
3603
    }
 
3604
 
 
3605
cleanup:
 
3606
    if ((pdf->stats.author)) {
 
3607
        free(pdf->stats.author);
 
3608
        pdf->stats.author = NULL;
 
3609
    }
 
3610
 
 
3611
    if (pdf->stats.creator) {
 
3612
        free(pdf->stats.creator);
 
3613
        pdf->stats.creator = NULL;
 
3614
    }
 
3615
 
 
3616
    if (pdf->stats.producer) {
 
3617
        free(pdf->stats.producer);
 
3618
        pdf->stats.producer = NULL;
 
3619
    }
 
3620
 
 
3621
    if (pdf->stats.modificationdate) {
 
3622
        free(pdf->stats.modificationdate);
 
3623
        pdf->stats.modificationdate = NULL;
 
3624
    }
 
3625
 
 
3626
    if (pdf->stats.creationdate) {
 
3627
        free(pdf->stats.creationdate);
 
3628
        pdf->stats.creationdate = NULL;
 
3629
    }
 
3630
 
 
3631
    if (pdf->stats.title) {
 
3632
        free(pdf->stats.title);
 
3633
        pdf->stats.title = NULL;
 
3634
    }
 
3635
 
 
3636
    if (pdf->stats.subject) {
 
3637
        free(pdf->stats.subject);
 
3638
        pdf->stats.subject = NULL;
 
3639
    }
 
3640
 
 
3641
    if (pdf->stats.keywords) {
 
3642
        free(pdf->stats.keywords);
 
3643
        pdf->stats.keywords = NULL;
 
3644
    }
 
3645
}
 
3646
#endif