xref: /PHP-7.2/ext/zip/lib/zip_open.c (revision 10dc1950)
1 /*
2   zip_open.c -- open zip archive by name
3   Copyright (C) 1999-2015 Dieter Baron and Thomas Klausner
4 
5   This file is part of libzip, a library to manipulate ZIP archives.
6   The authors can be contacted at <libzip@nih.at>
7 
8   Redistribution and use in source and binary forms, with or without
9   modification, are permitted provided that the following conditions
10   are met:
11   1. Redistributions of source code must retain the above copyright
12      notice, this list of conditions and the following disclaimer.
13   2. Redistributions in binary form must reproduce the above copyright
14      notice, this list of conditions and the following disclaimer in
15      the documentation and/or other materials provided with the
16      distribution.
17   3. The names of the authors may not be used to endorse or promote
18      products derived from this software without specific prior
19      written permission.
20 
21   THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
22   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
25   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
29   IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
31   IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33 
34 
35 #include <sys/stat.h>
36 #include <limits.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 
41 #include "zipint.h"
42 
43 typedef enum {
44     EXISTS_ERROR = -1,
45     EXISTS_NOT = 0,
46     EXISTS_EMPTY,
47     EXISTS_NONEMPTY,
48 } exists_t;
49 static zip_t *_zip_allocate_new(zip_source_t *src, unsigned int flags, zip_error_t *error);
50 static zip_int64_t _zip_checkcons(zip_t *za, zip_cdir_t *cdir, zip_error_t *error);
51 static zip_cdir_t *_zip_find_central_dir(zip_t *za, zip_uint64_t len);
52 static exists_t _zip_file_exists(zip_source_t *src, zip_error_t *error);
53 static int _zip_headercomp(const zip_dirent_t *, const zip_dirent_t *);
54 static unsigned char *_zip_memmem(const unsigned char *, size_t, const unsigned char *, size_t);
55 static zip_cdir_t *_zip_read_cdir(zip_t *za, zip_buffer_t *buffer, zip_uint64_t buf_offset, zip_error_t *error);
56 static zip_cdir_t *_zip_read_eocd(zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error);
57 static zip_cdir_t *_zip_read_eocd64(zip_source_t *src, zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error);
58 
59 
60 ZIP_EXTERN zip_t *
zip_open(const char * fn,int _flags,int * zep)61 zip_open(const char *fn, int _flags, int *zep)
62 {
63     zip_t *za;
64     zip_source_t *src;
65     struct zip_error error;
66 
67     zip_error_init(&error);
68     if ((src = zip_source_file_create(fn, 0, -1, &error)) == NULL) {
69 	_zip_set_open_error(zep, &error, 0);
70 	zip_error_fini(&error);
71 	return NULL;
72     }
73 
74     if ((za = zip_open_from_source(src, _flags, &error)) == NULL) {
75 	zip_source_free(src);
76 	_zip_set_open_error(zep, &error, 0);
77 	zip_error_fini(&error);
78 	return NULL;
79     }
80 
81     zip_error_fini(&error);
82     return za;
83 }
84 
85 
86 ZIP_EXTERN zip_t *
zip_open_from_source(zip_source_t * src,int _flags,zip_error_t * error)87 zip_open_from_source(zip_source_t *src, int _flags, zip_error_t *error)
88 {
89     static zip_int64_t needed_support_read = -1;
90     static zip_int64_t needed_support_write = -1;
91 
92     unsigned int flags;
93     zip_int64_t supported;
94     exists_t exists;
95 
96     if (_flags < 0 || src == NULL) {
97 	zip_error_set(error, ZIP_ER_INVAL, 0);
98         return NULL;
99     }
100     flags = (unsigned int)_flags;
101 
102     supported = zip_source_supports(src);
103     if (needed_support_read == -1) {
104         needed_support_read = zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_SEEK, ZIP_SOURCE_TELL, ZIP_SOURCE_STAT, -1);
105         needed_support_write = zip_source_make_command_bitmap(ZIP_SOURCE_BEGIN_WRITE, ZIP_SOURCE_COMMIT_WRITE, ZIP_SOURCE_ROLLBACK_WRITE, ZIP_SOURCE_SEEK_WRITE, ZIP_SOURCE_TELL_WRITE, ZIP_SOURCE_REMOVE, -1);
106     }
107     if ((supported & needed_support_read) != needed_support_read) {
108         zip_error_set(error, ZIP_ER_OPNOTSUPP, 0);
109         return NULL;
110     }
111     if ((supported & needed_support_write) != needed_support_write) {
112         flags |= ZIP_RDONLY;
113     }
114 
115     if ((flags & (ZIP_RDONLY|ZIP_TRUNCATE)) == (ZIP_RDONLY|ZIP_TRUNCATE)) {
116 	zip_error_set(error, ZIP_ER_RDONLY, 0);
117 	return NULL;
118     }
119 
120     exists = _zip_file_exists(src, error);
121     switch (exists) {
122     case EXISTS_ERROR:
123 	return NULL;
124 
125     case EXISTS_NOT:
126 	if ((flags & ZIP_CREATE) == 0) {
127 	    zip_error_set(error, ZIP_ER_NOENT, 0);
128 	    return NULL;
129 	}
130 	return _zip_allocate_new(src, flags, error);
131 
132     default: {
133 	zip_t *za;
134 	if (flags & ZIP_EXCL) {
135 	    zip_error_set(error, ZIP_ER_EXISTS, 0);
136 	    return NULL;
137 	}
138 	if (zip_source_open(src) < 0) {
139 	    _zip_error_set_from_source(error, src);
140 	    return NULL;
141 	}
142 
143 	if (flags & ZIP_TRUNCATE) {
144 	    za = _zip_allocate_new(src, flags, error);
145 	}
146 	else {
147 	    /* ZIP_CREATE gets ignored if file exists and not ZIP_EXCL, just like open() */
148 	    za = _zip_open(src, flags, error);
149 	}
150 
151 	if (za == NULL) {
152 	    zip_source_close(src);
153 	    return NULL;
154 	}
155 	return za;
156     }
157     }
158 }
159 
160 ZIP_EXTERN int
zip_archive_set_tempdir(zip_t * za,const char * tempdir)161 zip_archive_set_tempdir(zip_t *za, const char *tempdir)
162 {
163     char *new_tempdir;
164 
165     if (tempdir) {
166         if ((new_tempdir = strdup(tempdir)) == NULL) {
167             zip_error_set(&za->error, ZIP_ER_MEMORY, errno);
168             return -1;
169         }
170     }
171     else
172         new_tempdir = NULL;
173 
174     free(za->tempdir);
175     za->tempdir = new_tempdir;
176 
177     return 0;
178 }
179 
180 zip_t *
_zip_open(zip_source_t * src,unsigned int flags,zip_error_t * error)181 _zip_open(zip_source_t *src, unsigned int flags, zip_error_t *error)
182 {
183     zip_t *za;
184     zip_cdir_t *cdir;
185     struct zip_stat st;
186     zip_uint64_t len, idx;
187 
188     zip_stat_init(&st);
189     if (zip_source_stat(src, &st) < 0) {
190 	_zip_error_set_from_source(error, src);
191 	return NULL;
192     }
193     if ((st.valid & ZIP_STAT_SIZE) == 0) {
194 	zip_error_set(error, ZIP_ER_SEEK, EOPNOTSUPP);
195 	return NULL;
196     }
197     len = st.size;
198 
199     /* treat empty files as empty archives */
200     if (len == 0) {
201 	if ((za=_zip_allocate_new(src, flags, error)) == NULL) {
202 	    zip_source_free(src);
203 	    return NULL;
204 	}
205 
206 	return za;
207     }
208 
209     if ((za=_zip_allocate_new(src, flags, error)) == NULL) {
210         return NULL;
211     }
212 
213     if ((cdir = _zip_find_central_dir(za, len)) == NULL) {
214         _zip_error_copy(error, &za->error);
215 	/* keep src so discard does not get rid of it */
216 	zip_source_keep(src);
217 	zip_discard(za);
218 	return NULL;
219     }
220 
221     za->entry = cdir->entry;
222     za->nentry = cdir->nentry;
223     za->nentry_alloc = cdir->nentry_alloc;
224     za->comment_orig = cdir->comment;
225 
226     free(cdir);
227 
228     for (idx = 0; idx < za->nentry; idx++) {
229 	const zip_uint8_t *name = _zip_string_get(za->entry[idx].orig->filename, NULL, 0, error);
230 	if (name == NULL) {
231 		/* keep src so discard does not get rid of it */
232 		zip_source_keep(src);
233 		zip_discard(za);
234 		return NULL;
235 	}
236 
237 	if (_zip_hash_add(za->names, name, idx, ZIP_FL_UNCHANGED, &za->error) == false) {
238 	    if (za->error.zip_err != ZIP_ER_EXISTS || (flags & ZIP_CHECKCONS)) {
239 		_zip_error_copy(error, &za->error);
240 		/* keep src so discard does not get rid of it */
241 		zip_source_keep(src);
242 		zip_discard(za);
243 		return NULL;
244 	    }
245 	}
246     }
247 
248     za->ch_flags = za->flags;
249 
250     return za;
251 }
252 
253 
254 void
_zip_set_open_error(int * zep,const zip_error_t * err,int ze)255 _zip_set_open_error(int *zep, const zip_error_t *err, int ze)
256 {
257     if (err) {
258 	ze = zip_error_code_zip(err);
259 	if (zip_error_system_type(err) == ZIP_ET_SYS) {
260 	    errno = zip_error_code_system(err);
261 	}
262     }
263 
264     if (zep)
265 	*zep = ze;
266 }
267 
268 
269 /* _zip_readcdir:
270    tries to find a valid end-of-central-directory at the beginning of
271    buf, and then the corresponding central directory entries.
272    Returns a struct zip_cdir which contains the central directory
273    entries, or NULL if unsuccessful. */
274 
275 static zip_cdir_t *
_zip_read_cdir(zip_t * za,zip_buffer_t * buffer,zip_uint64_t buf_offset,zip_error_t * error)276 _zip_read_cdir(zip_t *za, zip_buffer_t *buffer, zip_uint64_t buf_offset, zip_error_t *error)
277 {
278     zip_cdir_t *cd;
279     zip_uint16_t comment_len;
280     zip_uint64_t i, left;
281     zip_uint64_t eocd_offset = _zip_buffer_offset(buffer);
282     zip_buffer_t *cd_buffer;
283 
284     if (_zip_buffer_left(buffer) < EOCDLEN) {
285 	/* not enough bytes left for comment */
286 	zip_error_set(error, ZIP_ER_NOZIP, 0);
287 	return NULL;
288     }
289 
290     /* check for end-of-central-dir magic */
291     if (memcmp(_zip_buffer_get(buffer, 4), EOCD_MAGIC, 4) != 0) {
292 	zip_error_set(error, ZIP_ER_NOZIP, 0);
293 	return NULL;
294     }
295 
296     if (eocd_offset >= EOCD64LOCLEN && memcmp(_zip_buffer_data(buffer) + eocd_offset - EOCD64LOCLEN, EOCD64LOC_MAGIC, 4) == 0) {
297         _zip_buffer_set_offset(buffer, eocd_offset - EOCD64LOCLEN);
298         cd = _zip_read_eocd64(za->src, buffer, buf_offset, za->flags, error);
299     }
300     else {
301         _zip_buffer_set_offset(buffer, eocd_offset);
302         cd = _zip_read_eocd(buffer, buf_offset, za->flags, error);
303     }
304 
305     if (cd == NULL)
306 	return NULL;
307 
308     _zip_buffer_set_offset(buffer, eocd_offset + 20);
309     comment_len = _zip_buffer_get_16(buffer);
310 
311     if (cd->offset + cd->size > buf_offset + eocd_offset) {
312 	/* cdir spans past EOCD record */
313 	zip_error_set(error, ZIP_ER_INCONS, 0);
314 	_zip_cdir_free(cd);
315 	return NULL;
316     }
317 
318     if (comment_len || (za->open_flags & ZIP_CHECKCONS)) {
319         zip_uint64_t tail_len;
320 
321         _zip_buffer_set_offset(buffer, eocd_offset + EOCDLEN);
322         tail_len = _zip_buffer_left(buffer);
323 
324         if (tail_len < comment_len || ((za->open_flags & ZIP_CHECKCONS) && tail_len != comment_len)) {
325             zip_error_set(error, ZIP_ER_INCONS, 0);
326             _zip_cdir_free(cd);
327             return NULL;
328         }
329 
330         if (comment_len) {
331             if ((cd->comment=_zip_string_new(_zip_buffer_get(buffer, comment_len), comment_len, ZIP_FL_ENC_GUESS, error)) == NULL) {
332                 _zip_cdir_free(cd);
333                 return NULL;
334             }
335         }
336     }
337 
338     if (cd->offset >= buf_offset) {
339         zip_uint8_t *data;
340 	/* if buffer already read in, use it */
341         _zip_buffer_set_offset(buffer, cd->offset - buf_offset);
342 
343         if ((data = _zip_buffer_get(buffer, cd->size)) == NULL) {
344             zip_error_set(error, ZIP_ER_INCONS, 0);
345             _zip_cdir_free(cd);
346             return NULL;
347         }
348         if ((cd_buffer = _zip_buffer_new(data, cd->size)) == NULL) {
349             zip_error_set(error, ZIP_ER_MEMORY, 0);
350             _zip_cdir_free(cd);
351             return NULL;
352         }
353     }
354     else {
355         cd_buffer = NULL;
356 
357         if (zip_source_seek(za->src, (zip_int64_t)cd->offset, SEEK_SET) < 0) {
358             _zip_error_set_from_source(error, za->src);
359             _zip_cdir_free(cd);
360             return NULL;
361         }
362 
363 	/* possible consistency check: cd->offset = len-(cd->size+cd->comment_len+EOCDLEN) ? */
364 	if (zip_source_tell(za->src) != (zip_int64_t)cd->offset) {
365             zip_error_set(error, ZIP_ER_NOZIP, 0);
366 	    _zip_cdir_free(cd);
367 	    return NULL;
368 	}
369     }
370 
371     left = (zip_uint64_t)cd->size;
372     i=0;
373     while (i<cd->nentry && left > 0) {
374         zip_int64_t entry_size;
375 	if ((cd->entry[i].orig=_zip_dirent_new()) == NULL || (entry_size = _zip_dirent_read(cd->entry[i].orig, za->src, cd_buffer, false, error)) < 0) {
376 	    _zip_cdir_free(cd);
377             _zip_buffer_free(cd_buffer);
378 	    return NULL;
379 	}
380 	i++;
381         left -= (zip_uint64_t)entry_size;
382     }
383 
384     if (i != cd->nentry) {
385         zip_error_set(error, ZIP_ER_INCONS, 0);
386         _zip_buffer_free(cd_buffer);
387         _zip_cdir_free(cd);
388         return NULL;
389     }
390 
391     if (za->open_flags & ZIP_CHECKCONS) {
392         bool ok;
393 
394         if (cd_buffer) {
395             ok = _zip_buffer_eof(cd_buffer);
396         }
397         else {
398             zip_int64_t offset = zip_source_tell(za->src);
399 
400             if (offset < 0) {
401                 _zip_error_set_from_source(error, za->src);
402                 _zip_buffer_free(cd_buffer);
403                 _zip_cdir_free(cd);
404                 return NULL;
405             }
406             ok = ((zip_uint64_t)offset == cd->offset + cd->size);
407         }
408 
409         if (!ok) {
410             zip_error_set(error, ZIP_ER_INCONS, 0);
411             _zip_buffer_free(cd_buffer);
412             _zip_cdir_free(cd);
413             return NULL;
414         }
415     }
416 
417     _zip_buffer_free(cd_buffer);
418     return cd;
419 }
420 
421 
422 /* _zip_checkcons:
423    Checks the consistency of the central directory by comparing central
424    directory entries with local headers and checking for plausible
425    file and header offsets. Returns -1 if not plausible, else the
426    difference between the lowest and the highest fileposition reached */
427 
428 static zip_int64_t
_zip_checkcons(zip_t * za,zip_cdir_t * cd,zip_error_t * error)429 _zip_checkcons(zip_t *za, zip_cdir_t *cd, zip_error_t *error)
430 {
431     zip_uint64_t i;
432     zip_uint64_t min, max, j;
433     struct zip_dirent temp;
434 
435     _zip_dirent_init(&temp);
436     if (cd->nentry) {
437 	max = cd->entry[0].orig->offset;
438 	min = cd->entry[0].orig->offset;
439     }
440     else
441 	min = max = 0;
442 
443     for (i=0; i<cd->nentry; i++) {
444 	if (cd->entry[i].orig->offset < min)
445 	    min = cd->entry[i].orig->offset;
446 	if (min > (zip_uint64_t)cd->offset) {
447 	    zip_error_set(error, ZIP_ER_NOZIP, 0);
448 	    return -1;
449 	}
450 
451 	j = cd->entry[i].orig->offset + cd->entry[i].orig->comp_size
452 	    + _zip_string_length(cd->entry[i].orig->filename) + LENTRYSIZE;
453 	if (j > max)
454 	    max = j;
455 	if (max > (zip_uint64_t)cd->offset) {
456 	    zip_error_set(error, ZIP_ER_NOZIP, 0);
457 	    return -1;
458 	}
459 
460         if (zip_source_seek(za->src, (zip_int64_t)cd->entry[i].orig->offset, SEEK_SET) < 0) {
461             _zip_error_set_from_source(error, za->src);
462             return -1;
463 	}
464 
465 	if (_zip_dirent_read(&temp, za->src, NULL, true, error) == -1) {
466 	    _zip_dirent_finalize(&temp);
467 	    return -1;
468 	}
469 
470 	if (_zip_headercomp(cd->entry[i].orig, &temp) != 0) {
471 	    zip_error_set(error, ZIP_ER_INCONS, 0);
472 	    _zip_dirent_finalize(&temp);
473 	    return -1;
474 	}
475 
476 	cd->entry[i].orig->extra_fields = _zip_ef_merge(cd->entry[i].orig->extra_fields, temp.extra_fields);
477 	cd->entry[i].orig->local_extra_fields_read = 1;
478 	temp.extra_fields = NULL;
479 
480 	_zip_dirent_finalize(&temp);
481     }
482 
483     return (max-min) < ZIP_INT64_MAX ? (zip_int64_t)(max-min) : ZIP_INT64_MAX;
484 }
485 
486 
487 /* _zip_headercomp:
488    compares a central directory entry and a local file header
489    Return 0 if they are consistent, -1 if not. */
490 
491 static int
_zip_headercomp(const zip_dirent_t * central,const zip_dirent_t * local)492 _zip_headercomp(const zip_dirent_t *central, const zip_dirent_t *local)
493 {
494     if ((central->version_needed != local->version_needed)
495 #if 0
496 	/* some zip-files have different values in local
497 	   and global headers for the bitflags */
498 	|| (central->bitflags != local->bitflags)
499 #endif
500 	|| (central->comp_method != local->comp_method)
501 	|| (central->last_mod != local->last_mod)
502 	|| !_zip_string_equal(central->filename, local->filename))
503 	return -1;
504 
505     if ((central->crc != local->crc) || (central->comp_size != local->comp_size)
506 	|| (central->uncomp_size != local->uncomp_size)) {
507 	/* InfoZip stores valid values in local header even when data descriptor is used.
508 	   This is in violation of the appnote. */
509 	if (((local->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) == 0
510 	     || local->crc != 0 || local->comp_size != 0 || local->uncomp_size != 0))
511 	    return -1;
512     }
513 
514     return 0;
515 }
516 
517 
518 static zip_t *
_zip_allocate_new(zip_source_t * src,unsigned int flags,zip_error_t * error)519 _zip_allocate_new(zip_source_t *src, unsigned int flags, zip_error_t *error)
520 {
521     zip_t *za;
522 
523     if ((za = _zip_new(error)) == NULL) {
524 	return NULL;
525     }
526 
527     za->src = src;
528     za->open_flags = flags;
529     if (flags & ZIP_RDONLY) {
530         za->flags |= ZIP_AFL_RDONLY;
531         za->ch_flags |= ZIP_AFL_RDONLY;
532     }
533     return za;
534 }
535 
536 
537 /*
538  * tests for file existence
539  */
540 static exists_t
_zip_file_exists(zip_source_t * src,zip_error_t * error)541 _zip_file_exists(zip_source_t *src, zip_error_t *error)
542 {
543     struct zip_stat st;
544 
545     zip_stat_init(&st);
546     if (zip_source_stat(src, &st) != 0) {
547         zip_error_t *src_error = zip_source_error(src);
548         if (zip_error_code_zip(src_error) == ZIP_ER_READ && zip_error_code_system(src_error) == ENOENT) {
549 	    return EXISTS_NOT;
550 	}
551 	_zip_error_copy(error, src_error);
552 	return EXISTS_ERROR;
553     }
554 
555     return (st.valid & ZIP_STAT_SIZE) && st.size == 0 ? EXISTS_EMPTY : EXISTS_NONEMPTY;
556 }
557 
558 
559 static zip_cdir_t *
_zip_find_central_dir(zip_t * za,zip_uint64_t len)560 _zip_find_central_dir(zip_t *za, zip_uint64_t len)
561 {
562     zip_cdir_t *cdir, *cdirnew;
563     zip_uint8_t *match;
564     zip_int64_t buf_offset;
565     zip_uint64_t buflen;
566     zip_int64_t a;
567     zip_int64_t best;
568     zip_error_t error;
569     zip_buffer_t *buffer;
570 
571     if (len < EOCDLEN) {
572 	zip_error_set(&za->error, ZIP_ER_NOZIP, 0);
573         return NULL;
574     }
575 
576     buflen = (len < CDBUFSIZE ? len : CDBUFSIZE);
577     if (zip_source_seek(za->src, -(zip_int64_t)buflen, SEEK_END) < 0) {
578 	zip_error_t *src_error = zip_source_error(za->src);
579 	if (zip_error_code_zip(src_error) != ZIP_ER_SEEK || zip_error_code_system(src_error) != EFBIG) {
580 	    /* seek before start of file on my machine */
581 	    _zip_error_copy(&za->error, src_error);
582 	    return NULL;
583 	}
584     }
585     if ((buf_offset = zip_source_tell(za->src)) < 0) {
586         _zip_error_set_from_source(&za->error, za->src);
587         return NULL;
588     }
589 
590     if ((buffer = _zip_buffer_new_from_source(za->src, buflen, NULL, &za->error)) == NULL) {
591         return NULL;
592     }
593 
594     best = -1;
595     cdir = NULL;
596     if (buflen >= CDBUFSIZE) {
597         /* EOCD64 locator is before EOCD, so leave place for it */
598         _zip_buffer_set_offset(buffer, EOCD64LOCLEN);
599     }
600     zip_error_set(&error, ZIP_ER_NOZIP, 0);
601 
602     match = _zip_buffer_get(buffer, 0);
603     while ((match=_zip_memmem(match, _zip_buffer_left(buffer)-(EOCDLEN-4), (const unsigned char *)EOCD_MAGIC, 4)) != NULL) {
604         _zip_buffer_set_offset(buffer, (zip_uint64_t)(match - _zip_buffer_data(buffer)));
605         if ((cdirnew = _zip_read_cdir(za, buffer, (zip_uint64_t)buf_offset, &error)) != NULL) {
606             if (cdir) {
607                 if (best <= 0) {
608                     best = _zip_checkcons(za, cdir, &error);
609                 }
610 
611                 a = _zip_checkcons(za, cdirnew, &error);
612                 if (best < a) {
613                     _zip_cdir_free(cdir);
614                     cdir = cdirnew;
615                     best = a;
616                 }
617                 else {
618                     _zip_cdir_free(cdirnew);
619                 }
620             }
621             else {
622                 cdir = cdirnew;
623                 if (za->open_flags & ZIP_CHECKCONS)
624                     best = _zip_checkcons(za, cdir, &error);
625                 else {
626                     best = 0;
627                 }
628             }
629             cdirnew = NULL;
630         }
631 
632         match++;
633         _zip_buffer_set_offset(buffer, (zip_uint64_t)(match - _zip_buffer_data(buffer)));
634     }
635 
636     _zip_buffer_free(buffer);
637 
638     if (best < 0) {
639         _zip_error_copy(&za->error, &error);
640         _zip_cdir_free(cdir);
641         return NULL;
642     }
643 
644     return cdir;
645 }
646 
647 
648 static unsigned char *
_zip_memmem(const unsigned char * big,size_t biglen,const unsigned char * little,size_t littlelen)649 _zip_memmem(const unsigned char *big, size_t biglen, const unsigned char *little, size_t littlelen)
650 {
651     const unsigned char *p;
652 
653     if ((biglen < littlelen) || (littlelen == 0))
654 	return NULL;
655     p = big-1;
656     while ((p=(const unsigned char *)
657 	        memchr(p+1, little[0], (size_t)(big-(p+1))+(size_t)(biglen-littlelen)+1)) != NULL) {
658 	if (memcmp(p+1, little+1, littlelen-1)==0)
659 	    return (unsigned char *)p;
660     }
661 
662     return NULL;
663 }
664 
665 
666 static zip_cdir_t *
_zip_read_eocd(zip_buffer_t * buffer,zip_uint64_t buf_offset,unsigned int flags,zip_error_t * error)667 _zip_read_eocd(zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error)
668 {
669     zip_cdir_t *cd;
670     zip_uint64_t i, nentry, size, offset, eocd_offset;
671 
672     if (_zip_buffer_left(buffer) < EOCDLEN) {
673 	zip_error_set(error, ZIP_ER_INCONS, 0);
674 	return NULL;
675     }
676 
677     eocd_offset = _zip_buffer_offset(buffer);
678 
679     _zip_buffer_get(buffer, 4); /* magic already verified */
680 
681     if (_zip_buffer_get_32(buffer) != 0) {
682 	zip_error_set(error, ZIP_ER_MULTIDISK, 0);
683 	return NULL;
684     }
685 
686     /* number of cdir-entries on this disk */
687     i = _zip_buffer_get_16(buffer);
688     /* number of cdir-entries */
689     nentry = _zip_buffer_get_16(buffer);
690 
691     if (nentry != i) {
692 	zip_error_set(error, ZIP_ER_NOZIP, 0);
693 	return NULL;
694     }
695 
696     size = _zip_buffer_get_32(buffer);
697     offset = _zip_buffer_get_32(buffer);
698 
699     if (offset+size < offset) {
700         zip_error_set(error, ZIP_ER_SEEK, EFBIG);
701         return NULL;
702     }
703 
704     if (offset+size > buf_offset + eocd_offset) {
705 	/* cdir spans past EOCD record */
706 	zip_error_set(error, ZIP_ER_INCONS, 0);
707 	return NULL;
708     }
709 
710     if ((flags & ZIP_CHECKCONS) && offset+size != buf_offset + eocd_offset) {
711 	zip_error_set(error, ZIP_ER_INCONS, 0);
712 	return NULL;
713     }
714 
715     if ((cd=_zip_cdir_new(nentry, error)) == NULL)
716 	return NULL;
717 
718     cd->size = size;
719     cd->offset = offset;
720 
721     return cd;
722 }
723 
724 
725 static zip_cdir_t *
_zip_read_eocd64(zip_source_t * src,zip_buffer_t * buffer,zip_uint64_t buf_offset,unsigned int flags,zip_error_t * error)726 _zip_read_eocd64(zip_source_t *src, zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error)
727 {
728     zip_cdir_t *cd;
729     zip_uint64_t offset;
730     zip_uint8_t eocd[EOCD64LEN];
731     zip_uint64_t eocd_offset;
732     zip_uint64_t size, nentry, i, eocdloc_offset;
733     bool free_buffer;
734     zip_uint32_t num_disks, num_disks64, eocd_disk, eocd_disk64;
735 
736     eocdloc_offset = _zip_buffer_offset(buffer);
737 
738     _zip_buffer_get(buffer, 4); /* magic already verified */
739 
740     num_disks = _zip_buffer_get_16(buffer);
741     eocd_disk = _zip_buffer_get_16(buffer);
742     eocd_offset = _zip_buffer_get_64(buffer);
743 
744     if (eocd_offset > ZIP_INT64_MAX || eocd_offset + EOCD64LEN < eocd_offset) {
745         zip_error_set(error, ZIP_ER_SEEK, EFBIG);
746         return NULL;
747     }
748 
749     if (eocd_offset + EOCD64LEN > eocdloc_offset + buf_offset) {
750 	zip_error_set(error, ZIP_ER_INCONS, 0);
751 	return NULL;
752     }
753 
754     if (eocd_offset >= buf_offset && eocd_offset + EOCD64LEN <= buf_offset + _zip_buffer_size(buffer)) {
755         _zip_buffer_set_offset(buffer, eocd_offset - buf_offset);
756         free_buffer = false;
757     }
758     else {
759         if (zip_source_seek(src, (zip_int64_t)eocd_offset, SEEK_SET) < 0) {
760             _zip_error_set_from_source(error, src);
761             return NULL;
762         }
763         if ((buffer = _zip_buffer_new_from_source(src, EOCD64LEN, eocd, error)) == NULL) {
764             return NULL;
765         }
766         free_buffer = true;
767     }
768 
769     if (memcmp(_zip_buffer_get(buffer, 4), EOCD64_MAGIC, 4) != 0) {
770 	zip_error_set(error, ZIP_ER_INCONS, 0);
771         if (free_buffer) {
772             _zip_buffer_free(buffer);
773         }
774 	return NULL;
775     }
776 
777     size = _zip_buffer_get_64(buffer);
778 
779     if ((flags & ZIP_CHECKCONS) && size + eocd_offset + 12 != buf_offset + eocdloc_offset) {
780 	zip_error_set(error, ZIP_ER_INCONS, 0);
781         if (free_buffer) {
782             _zip_buffer_free(buffer);
783         }
784         return NULL;
785     }
786 
787     _zip_buffer_get(buffer, 4); /* skip version made by/needed */
788 
789     num_disks64 = _zip_buffer_get_32(buffer);
790     eocd_disk64 = _zip_buffer_get_32(buffer);
791 
792     /* if eocd values are 0xffff, we have to use eocd64 values.
793        otherwise, if the values are not the same, it's inconsistent;
794        in any case, if the value is not 0, we don't support it */
795     if (num_disks == 0xffff) {
796 	num_disks = num_disks64;
797     }
798     if (eocd_disk == 0xffff) {
799 	eocd_disk = eocd_disk64;
800     }
801     if ((flags & ZIP_CHECKCONS) && (eocd_disk != eocd_disk64 || num_disks != num_disks64)) {
802 	zip_error_set(error, ZIP_ER_INCONS, 0);
803 	return NULL;
804     }
805     if (num_disks != 0 || eocd_disk != 0) {
806 	zip_error_set(error, ZIP_ER_MULTIDISK, 0);
807 	return NULL;
808     }
809 
810     nentry = _zip_buffer_get_64(buffer);
811     i = _zip_buffer_get_64(buffer);
812 
813     if (nentry != i) {
814 	zip_error_set(error, ZIP_ER_MULTIDISK, 0);
815         if (free_buffer) {
816             _zip_buffer_free(buffer);
817         }
818 	return NULL;
819     }
820 
821     size = _zip_buffer_get_64(buffer);
822     offset = _zip_buffer_get_64(buffer);
823 
824     if (!_zip_buffer_ok(buffer)) {
825         zip_error_set(error, ZIP_ER_INTERNAL, 0);
826         if (free_buffer) {
827             _zip_buffer_free(buffer);
828         }
829         return NULL;
830     }
831 
832     if (free_buffer) {
833         _zip_buffer_free(buffer);
834     }
835 
836     if (offset > ZIP_INT64_MAX || offset+size < offset) {
837         zip_error_set(error, ZIP_ER_SEEK, EFBIG);
838         return NULL;
839     }
840     if (offset+size > buf_offset + eocd_offset) {
841 	/* cdir spans past EOCD record */
842 	zip_error_set(error, ZIP_ER_INCONS, 0);
843 	return NULL;
844     }
845     if ((flags & ZIP_CHECKCONS) && offset+size != buf_offset + eocd_offset) {
846 	zip_error_set(error, ZIP_ER_INCONS, 0);
847 	return NULL;
848     }
849 
850     if ((cd=_zip_cdir_new(nentry, error)) == NULL)
851 	return NULL;
852 
853 
854     cd->size = size;
855     cd->offset = offset;
856 
857     return cd;
858 }
859