1 /*
2 +----------------------------------------------------------------------+
3 | phar php single-file executable PHP extension |
4 | utility functions |
5 +----------------------------------------------------------------------+
6 | Copyright (c) 2005-2015 The PHP Group |
7 +----------------------------------------------------------------------+
8 | This source file is subject to version 3.01 of the PHP license, |
9 | that is bundled with this package in the file LICENSE, and is |
10 | available through the world-wide-web at the following url: |
11 | http://www.php.net/license/3_01.txt. |
12 | If you did not receive a copy of the PHP license and are unable to |
13 | obtain it through the world-wide-web, please send a note to |
14 | license@php.net so we can mail you a copy immediately. |
15 +----------------------------------------------------------------------+
16 | Authors: Gregory Beaver <cellog@php.net> |
17 | Marcus Boerger <helly@php.net> |
18 +----------------------------------------------------------------------+
19 */
20
21 /* $Id$ */
22
23 #include "phar_internal.h"
24 #ifdef PHAR_HASH_OK
25 #include "ext/hash/php_hash_sha.h"
26 #endif
27
28 #ifdef PHAR_HAVE_OPENSSL
29 /* OpenSSL includes */
30 #include <openssl/evp.h>
31 #include <openssl/x509.h>
32 #include <openssl/x509v3.h>
33 #include <openssl/crypto.h>
34 #include <openssl/pem.h>
35 #include <openssl/err.h>
36 #include <openssl/conf.h>
37 #include <openssl/rand.h>
38 #include <openssl/ssl.h>
39 #include <openssl/pkcs12.h>
40 #else
41 static int phar_call_openssl_signverify(int is_sign, php_stream *fp, off_t end, char *key, int key_len, char **signature, int *signature_len TSRMLS_DC);
42 #endif
43
44 /* for links to relative location, prepend cwd of the entry */
phar_get_link_location(phar_entry_info * entry TSRMLS_DC)45 static char *phar_get_link_location(phar_entry_info *entry TSRMLS_DC) /* {{{ */
46 {
47 char *p, *ret = NULL;
48 if (!entry->link) {
49 return NULL;
50 }
51 if (entry->link[0] == '/') {
52 return estrdup(entry->link + 1);
53 }
54 p = strrchr(entry->filename, '/');
55 if (p) {
56 *p = '\0';
57 spprintf(&ret, 0, "%s/%s", entry->filename, entry->link);
58 return ret;
59 }
60 return entry->link;
61 }
62 /* }}} */
63
phar_get_link_source(phar_entry_info * entry TSRMLS_DC)64 phar_entry_info *phar_get_link_source(phar_entry_info *entry TSRMLS_DC) /* {{{ */
65 {
66 phar_entry_info *link_entry;
67 char *link;
68
69 if (!entry->link) {
70 return entry;
71 }
72
73 link = phar_get_link_location(entry TSRMLS_CC);
74 if (SUCCESS == zend_hash_find(&(entry->phar->manifest), entry->link, strlen(entry->link), (void **)&link_entry) ||
75 SUCCESS == zend_hash_find(&(entry->phar->manifest), link, strlen(link), (void **)&link_entry)) {
76 if (link != entry->link) {
77 efree(link);
78 }
79 return phar_get_link_source(link_entry TSRMLS_CC);
80 } else {
81 if (link != entry->link) {
82 efree(link);
83 }
84 return NULL;
85 }
86 }
87 /* }}} */
88
89 /* retrieve a phar_entry_info's current file pointer for reading contents */
phar_get_efp(phar_entry_info * entry,int follow_links TSRMLS_DC)90 php_stream *phar_get_efp(phar_entry_info *entry, int follow_links TSRMLS_DC) /* {{{ */
91 {
92 if (follow_links && entry->link) {
93 phar_entry_info *link_entry = phar_get_link_source(entry TSRMLS_CC);
94
95 if (link_entry && link_entry != entry) {
96 return phar_get_efp(link_entry, 1 TSRMLS_CC);
97 }
98 }
99
100 if (phar_get_fp_type(entry TSRMLS_CC) == PHAR_FP) {
101 if (!phar_get_entrypfp(entry TSRMLS_CC)) {
102 /* re-open just in time for cases where our refcount reached 0 on the phar archive */
103 phar_open_archive_fp(entry->phar TSRMLS_CC);
104 }
105 return phar_get_entrypfp(entry TSRMLS_CC);
106 } else if (phar_get_fp_type(entry TSRMLS_CC) == PHAR_UFP) {
107 return phar_get_entrypufp(entry TSRMLS_CC);
108 } else if (entry->fp_type == PHAR_MOD) {
109 return entry->fp;
110 } else {
111 /* temporary manifest entry */
112 if (!entry->fp) {
113 entry->fp = php_stream_open_wrapper(entry->tmp, "rb", STREAM_MUST_SEEK|0, NULL);
114 }
115 return entry->fp;
116 }
117 }
118 /* }}} */
119
phar_seek_efp(phar_entry_info * entry,off_t offset,int whence,off_t position,int follow_links TSRMLS_DC)120 int phar_seek_efp(phar_entry_info *entry, off_t offset, int whence, off_t position, int follow_links TSRMLS_DC) /* {{{ */
121 {
122 php_stream *fp = phar_get_efp(entry, follow_links TSRMLS_CC);
123 off_t temp, eoffset;
124
125 if (!fp) {
126 return -1;
127 }
128
129 if (follow_links) {
130 phar_entry_info *t;
131 t = phar_get_link_source(entry TSRMLS_CC);
132 if (t) {
133 entry = t;
134 }
135 }
136
137 if (entry->is_dir) {
138 return 0;
139 }
140
141 eoffset = phar_get_fp_offset(entry TSRMLS_CC);
142
143 switch (whence) {
144 case SEEK_END:
145 temp = eoffset + entry->uncompressed_filesize + offset;
146 break;
147 case SEEK_CUR:
148 temp = eoffset + position + offset;
149 break;
150 case SEEK_SET:
151 temp = eoffset + offset;
152 break;
153 default:
154 temp = 0;
155 }
156
157 if (temp > eoffset + (off_t) entry->uncompressed_filesize) {
158 return -1;
159 }
160
161 if (temp < eoffset) {
162 return -1;
163 }
164
165 return php_stream_seek(fp, temp, SEEK_SET);
166 }
167 /* }}} */
168
169 /* mount an absolute path or uri to a path internal to the phar archive */
phar_mount_entry(phar_archive_data * phar,char * filename,int filename_len,char * path,int path_len TSRMLS_DC)170 int phar_mount_entry(phar_archive_data *phar, char *filename, int filename_len, char *path, int path_len TSRMLS_DC) /* {{{ */
171 {
172 phar_entry_info entry = {0};
173 php_stream_statbuf ssb;
174 int is_phar;
175 const char *err;
176
177 if (phar_path_check(&path, &path_len, &err) > pcr_is_ok) {
178 return FAILURE;
179 }
180
181 if (path_len >= sizeof(".phar")-1 && !memcmp(path, ".phar", sizeof(".phar")-1)) {
182 /* no creating magic phar files by mounting them */
183 return FAILURE;
184 }
185
186 is_phar = (filename_len > 7 && !memcmp(filename, "phar://", 7));
187
188 entry.phar = phar;
189 entry.filename = estrndup(path, path_len);
190 #ifdef PHP_WIN32
191 phar_unixify_path_separators(entry.filename, path_len);
192 #endif
193 entry.filename_len = path_len;
194 if (is_phar) {
195 entry.tmp = estrndup(filename, filename_len);
196 } else {
197 entry.tmp = expand_filepath(filename, NULL TSRMLS_CC);
198 if (!entry.tmp) {
199 entry.tmp = estrndup(filename, filename_len);
200 }
201 }
202 #if PHP_API_VERSION < 20100412
203 if (PG(safe_mode) && !is_phar && (!php_checkuid(entry.tmp, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
204 efree(entry.tmp);
205 efree(entry.filename);
206 return FAILURE;
207 }
208 #endif
209 filename = entry.tmp;
210
211 /* only check openbasedir for files, not for phar streams */
212 if (!is_phar && php_check_open_basedir(filename TSRMLS_CC)) {
213 efree(entry.tmp);
214 efree(entry.filename);
215 return FAILURE;
216 }
217
218 entry.is_mounted = 1;
219 entry.is_crc_checked = 1;
220 entry.fp_type = PHAR_TMP;
221
222 if (SUCCESS != php_stream_stat_path(filename, &ssb)) {
223 efree(entry.tmp);
224 efree(entry.filename);
225 return FAILURE;
226 }
227
228 if (ssb.sb.st_mode & S_IFDIR) {
229 entry.is_dir = 1;
230 if (SUCCESS != zend_hash_add(&phar->mounted_dirs, entry.filename, path_len, (void *)&(entry.filename), sizeof(char *), NULL)) {
231 /* directory already mounted */
232 efree(entry.tmp);
233 efree(entry.filename);
234 return FAILURE;
235 }
236 } else {
237 entry.is_dir = 0;
238 entry.uncompressed_filesize = entry.compressed_filesize = ssb.sb.st_size;
239 }
240
241 entry.flags = ssb.sb.st_mode;
242
243 if (SUCCESS == zend_hash_add(&phar->manifest, entry.filename, path_len, (void*)&entry, sizeof(phar_entry_info), NULL)) {
244 return SUCCESS;
245 }
246
247 efree(entry.tmp);
248 efree(entry.filename);
249 return FAILURE;
250 }
251 /* }}} */
252
phar_find_in_include_path(char * filename,int filename_len,phar_archive_data ** pphar TSRMLS_DC)253 char *phar_find_in_include_path(char *filename, int filename_len, phar_archive_data **pphar TSRMLS_DC) /* {{{ */
254 {
255 char *path, *fname, *arch, *entry, *ret, *test;
256 int arch_len, entry_len, fname_len, ret_len;
257 phar_archive_data *phar;
258
259 if (pphar) {
260 *pphar = NULL;
261 } else {
262 pphar = &phar;
263 }
264
265 if (!zend_is_executing(TSRMLS_C) || !PHAR_G(cwd)) {
266 return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
267 }
268
269 fname = (char*)zend_get_executed_filename(TSRMLS_C);
270 fname_len = strlen(fname);
271
272 if (PHAR_G(last_phar) && !memcmp(fname, "phar://", 7) && fname_len - 7 >= PHAR_G(last_phar_name_len) && !memcmp(fname + 7, PHAR_G(last_phar_name), PHAR_G(last_phar_name_len))) {
273 arch = estrndup(PHAR_G(last_phar_name), PHAR_G(last_phar_name_len));
274 arch_len = PHAR_G(last_phar_name_len);
275 phar = PHAR_G(last_phar);
276 goto splitted;
277 }
278
279 if (fname_len < 7 || memcmp(fname, "phar://", 7) || SUCCESS != phar_split_fname(fname, strlen(fname), &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
280 return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
281 }
282
283 efree(entry);
284
285 if (*filename == '.') {
286 int try_len;
287
288 if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
289 efree(arch);
290 return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
291 }
292 splitted:
293 if (pphar) {
294 *pphar = phar;
295 }
296
297 try_len = filename_len;
298 test = phar_fix_filepath(estrndup(filename, filename_len), &try_len, 1 TSRMLS_CC);
299
300 if (*test == '/') {
301 if (zend_hash_exists(&(phar->manifest), test + 1, try_len - 1)) {
302 spprintf(&ret, 0, "phar://%s%s", arch, test);
303 efree(arch);
304 efree(test);
305 return ret;
306 }
307 } else {
308 if (zend_hash_exists(&(phar->manifest), test, try_len)) {
309 spprintf(&ret, 0, "phar://%s/%s", arch, test);
310 efree(arch);
311 efree(test);
312 return ret;
313 }
314 }
315 efree(test);
316 }
317
318 spprintf(&path, MAXPATHLEN, "phar://%s/%s%c%s", arch, PHAR_G(cwd), DEFAULT_DIR_SEPARATOR, PG(include_path));
319 efree(arch);
320 ret = php_resolve_path(filename, filename_len, path TSRMLS_CC);
321 efree(path);
322
323 if (ret && strlen(ret) > 8 && !strncmp(ret, "phar://", 7)) {
324 ret_len = strlen(ret);
325 /* found phar:// */
326
327 if (SUCCESS != phar_split_fname(ret, ret_len, &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
328 return ret;
329 }
330
331 zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar);
332
333 if (!pphar && PHAR_G(manifest_cached)) {
334 zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar);
335 }
336
337 efree(arch);
338 efree(entry);
339 }
340
341 return ret;
342 }
343 /* }}} */
344
345 /**
346 * Retrieve a copy of the file information on a single file within a phar, or null.
347 * This also transfers the open file pointer, if any, to the entry.
348 *
349 * If the file does not already exist, this will fail. Pre-existing files can be
350 * appended, truncated, or read. For read, if the entry is marked unmodified, it is
351 * assumed that the file pointer, if present, is opened for reading
352 */
phar_get_entry_data(phar_entry_data ** ret,char * fname,int fname_len,char * path,int path_len,char * mode,char allow_dir,char ** error,int security TSRMLS_DC)353 int phar_get_entry_data(phar_entry_data **ret, char *fname, int fname_len, char *path, int path_len, char *mode, char allow_dir, char **error, int security TSRMLS_DC) /* {{{ */
354 {
355 phar_archive_data *phar;
356 phar_entry_info *entry;
357 int for_write = mode[0] != 'r' || mode[1] == '+';
358 int for_append = mode[0] == 'a';
359 int for_create = mode[0] != 'r';
360 int for_trunc = mode[0] == 'w';
361
362 if (!ret) {
363 return FAILURE;
364 }
365
366 *ret = NULL;
367
368 if (error) {
369 *error = NULL;
370 }
371
372 if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error TSRMLS_CC)) {
373 return FAILURE;
374 }
375
376 if (for_write && PHAR_G(readonly) && !phar->is_data) {
377 if (error) {
378 spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, disabled by ini setting", path, fname);
379 }
380 return FAILURE;
381 }
382
383 if (!path_len) {
384 if (error) {
385 spprintf(error, 4096, "phar error: file \"\" in phar \"%s\" cannot be empty", fname);
386 }
387 return FAILURE;
388 }
389 really_get_entry:
390 if (allow_dir) {
391 if ((entry = phar_get_entry_info_dir(phar, path, path_len, allow_dir, for_create && !PHAR_G(readonly) && !phar->is_data ? NULL : error, security TSRMLS_CC)) == NULL) {
392 if (for_create && (!PHAR_G(readonly) || phar->is_data)) {
393 return SUCCESS;
394 }
395 return FAILURE;
396 }
397 } else {
398 if ((entry = phar_get_entry_info(phar, path, path_len, for_create && !PHAR_G(readonly) && !phar->is_data ? NULL : error, security TSRMLS_CC)) == NULL) {
399 if (for_create && (!PHAR_G(readonly) || phar->is_data)) {
400 return SUCCESS;
401 }
402 return FAILURE;
403 }
404 }
405
406 if (for_write && phar->is_persistent) {
407 if (FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
408 if (error) {
409 spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, could not make cached phar writeable", path, fname);
410 }
411 return FAILURE;
412 } else {
413 goto really_get_entry;
414 }
415 }
416
417 if (entry->is_modified && !for_write) {
418 if (error) {
419 spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for reading, writable file pointers are open", path, fname);
420 }
421 return FAILURE;
422 }
423
424 if (entry->fp_refcount && for_write) {
425 if (error) {
426 spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, readable file pointers are open", path, fname);
427 }
428 return FAILURE;
429 }
430
431 if (entry->is_deleted) {
432 if (!for_create) {
433 return FAILURE;
434 }
435 entry->is_deleted = 0;
436 }
437
438 if (entry->is_dir) {
439 *ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
440 (*ret)->position = 0;
441 (*ret)->fp = NULL;
442 (*ret)->phar = phar;
443 (*ret)->for_write = for_write;
444 (*ret)->internal_file = entry;
445 (*ret)->is_zip = entry->is_zip;
446 (*ret)->is_tar = entry->is_tar;
447
448 if (!phar->is_persistent) {
449 ++(entry->phar->refcount);
450 ++(entry->fp_refcount);
451 }
452
453 return SUCCESS;
454 }
455
456 if (entry->fp_type == PHAR_MOD) {
457 if (for_trunc) {
458 if (FAILURE == phar_create_writeable_entry(phar, entry, error TSRMLS_CC)) {
459 return FAILURE;
460 }
461 } else if (for_append) {
462 phar_seek_efp(entry, 0, SEEK_END, 0, 0 TSRMLS_CC);
463 }
464 } else {
465 if (for_write) {
466 if (entry->link) {
467 efree(entry->link);
468 entry->link = NULL;
469 entry->tar_type = (entry->is_tar ? TAR_FILE : '\0');
470 }
471
472 if (for_trunc) {
473 if (FAILURE == phar_create_writeable_entry(phar, entry, error TSRMLS_CC)) {
474 return FAILURE;
475 }
476 } else {
477 if (FAILURE == phar_separate_entry_fp(entry, error TSRMLS_CC)) {
478 return FAILURE;
479 }
480 }
481 } else {
482 if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
483 return FAILURE;
484 }
485 }
486 }
487
488 *ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
489 (*ret)->position = 0;
490 (*ret)->phar = phar;
491 (*ret)->for_write = for_write;
492 (*ret)->internal_file = entry;
493 (*ret)->is_zip = entry->is_zip;
494 (*ret)->is_tar = entry->is_tar;
495 (*ret)->fp = phar_get_efp(entry, 1 TSRMLS_CC);
496 if (entry->link) {
497 phar_entry_info *link = phar_get_link_source(entry TSRMLS_CC);
498 if(!link) {
499 efree(*ret);
500 return FAILURE;
501 }
502 (*ret)->zero = phar_get_fp_offset(link TSRMLS_CC);
503 } else {
504 (*ret)->zero = phar_get_fp_offset(entry TSRMLS_CC);
505 }
506
507 if (!phar->is_persistent) {
508 ++(entry->fp_refcount);
509 ++(entry->phar->refcount);
510 }
511
512 return SUCCESS;
513 }
514 /* }}} */
515
516 /**
517 * Create a new dummy file slot within a writeable phar for a newly created file
518 */
phar_get_or_create_entry_data(char * fname,int fname_len,char * path,int path_len,char * mode,char allow_dir,char ** error,int security TSRMLS_DC)519 phar_entry_data *phar_get_or_create_entry_data(char *fname, int fname_len, char *path, int path_len, char *mode, char allow_dir, char **error, int security TSRMLS_DC) /* {{{ */
520 {
521 phar_archive_data *phar;
522 phar_entry_info *entry, etemp;
523 phar_entry_data *ret;
524 const char *pcr_error;
525 char is_dir;
526
527 #ifdef PHP_WIN32
528 phar_unixify_path_separators(path, path_len);
529 #endif
530
531 is_dir = (path_len && path[path_len - 1] == '/') ? 1 : 0;
532
533 if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error TSRMLS_CC)) {
534 return NULL;
535 }
536
537 if (FAILURE == phar_get_entry_data(&ret, fname, fname_len, path, path_len, mode, allow_dir, error, security TSRMLS_CC)) {
538 return NULL;
539 } else if (ret) {
540 return ret;
541 }
542
543 if (phar_path_check(&path, &path_len, &pcr_error) > pcr_is_ok) {
544 if (error) {
545 spprintf(error, 0, "phar error: invalid path \"%s\" contains %s", path, pcr_error);
546 }
547 return NULL;
548 }
549
550 if (phar->is_persistent && FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
551 if (error) {
552 spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be created, could not make cached phar writeable", path, fname);
553 }
554 return NULL;
555 }
556
557 /* create a new phar data holder */
558 ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
559
560 /* create an entry, this is a new file */
561 memset(&etemp, 0, sizeof(phar_entry_info));
562 etemp.filename_len = path_len;
563 etemp.fp_type = PHAR_MOD;
564 etemp.fp = php_stream_fopen_tmpfile();
565
566 if (!etemp.fp) {
567 if (error) {
568 spprintf(error, 0, "phar error: unable to create temporary file");
569 }
570 efree(ret);
571 return NULL;
572 }
573
574 etemp.fp_refcount = 1;
575
576 if (allow_dir == 2) {
577 etemp.is_dir = 1;
578 etemp.flags = etemp.old_flags = PHAR_ENT_PERM_DEF_DIR;
579 } else {
580 etemp.flags = etemp.old_flags = PHAR_ENT_PERM_DEF_FILE;
581 }
582 if (is_dir) {
583 etemp.filename_len--; /* strip trailing / */
584 path_len--;
585 }
586
587 phar_add_virtual_dirs(phar, path, path_len TSRMLS_CC);
588 etemp.is_modified = 1;
589 etemp.timestamp = time(0);
590 etemp.is_crc_checked = 1;
591 etemp.phar = phar;
592 etemp.filename = estrndup(path, path_len);
593 etemp.is_zip = phar->is_zip;
594
595 if (phar->is_tar) {
596 etemp.is_tar = phar->is_tar;
597 etemp.tar_type = etemp.is_dir ? TAR_DIR : TAR_FILE;
598 }
599
600 if (FAILURE == zend_hash_add(&phar->manifest, etemp.filename, path_len, (void*)&etemp, sizeof(phar_entry_info), (void **) &entry)) {
601 php_stream_close(etemp.fp);
602 if (error) {
603 spprintf(error, 0, "phar error: unable to add new entry \"%s\" to phar \"%s\"", etemp.filename, phar->fname);
604 }
605 efree(ret);
606 efree(etemp.filename);
607 return NULL;
608 }
609
610 if (!entry) {
611 php_stream_close(etemp.fp);
612 efree(etemp.filename);
613 efree(ret);
614 return NULL;
615 }
616
617 ++(phar->refcount);
618 ret->phar = phar;
619 ret->fp = entry->fp;
620 ret->position = ret->zero = 0;
621 ret->for_write = 1;
622 ret->is_zip = entry->is_zip;
623 ret->is_tar = entry->is_tar;
624 ret->internal_file = entry;
625
626 return ret;
627 }
628 /* }}} */
629
630 /* initialize a phar_archive_data's read-only fp for existing phar data */
phar_open_archive_fp(phar_archive_data * phar TSRMLS_DC)631 int phar_open_archive_fp(phar_archive_data *phar TSRMLS_DC) /* {{{ */
632 {
633 if (phar_get_pharfp(phar TSRMLS_CC)) {
634 return SUCCESS;
635 }
636
637 if (php_check_open_basedir(phar->fname TSRMLS_CC)) {
638 return FAILURE;
639 }
640
641 phar_set_pharfp(phar, php_stream_open_wrapper(phar->fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|0, NULL) TSRMLS_CC);
642
643 if (!phar_get_pharfp(phar TSRMLS_CC)) {
644 return FAILURE;
645 }
646
647 return SUCCESS;
648 }
649 /* }}} */
650
651 /* copy file data from an existing to a new phar_entry_info that is not in the manifest */
phar_copy_entry_fp(phar_entry_info * source,phar_entry_info * dest,char ** error TSRMLS_DC)652 int phar_copy_entry_fp(phar_entry_info *source, phar_entry_info *dest, char **error TSRMLS_DC) /* {{{ */
653 {
654 phar_entry_info *link;
655
656 if (FAILURE == phar_open_entry_fp(source, error, 1 TSRMLS_CC)) {
657 return FAILURE;
658 }
659
660 if (dest->link) {
661 efree(dest->link);
662 dest->link = NULL;
663 dest->tar_type = (dest->is_tar ? TAR_FILE : '\0');
664 }
665
666 dest->fp_type = PHAR_MOD;
667 dest->offset = 0;
668 dest->is_modified = 1;
669 dest->fp = php_stream_fopen_tmpfile();
670 if (dest->fp == NULL) {
671 spprintf(error, 0, "phar error: unable to create temporary file");
672 return EOF;
673 }
674 phar_seek_efp(source, 0, SEEK_SET, 0, 1 TSRMLS_CC);
675 link = phar_get_link_source(source TSRMLS_CC);
676
677 if (!link) {
678 link = source;
679 }
680
681 if (SUCCESS != phar_stream_copy_to_stream(phar_get_efp(link, 0 TSRMLS_CC), dest->fp, link->uncompressed_filesize, NULL)) {
682 php_stream_close(dest->fp);
683 dest->fp_type = PHAR_FP;
684 if (error) {
685 spprintf(error, 4096, "phar error: unable to copy contents of file \"%s\" to \"%s\" in phar archive \"%s\"", source->filename, dest->filename, source->phar->fname);
686 }
687 return FAILURE;
688 }
689
690 return SUCCESS;
691 }
692 /* }}} */
693
694 /* open and decompress a compressed phar entry
695 */
phar_open_entry_fp(phar_entry_info * entry,char ** error,int follow_links TSRMLS_DC)696 int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TSRMLS_DC) /* {{{ */
697 {
698 php_stream_filter *filter;
699 phar_archive_data *phar = entry->phar;
700 char *filtername;
701 off_t loc;
702 php_stream *ufp;
703 phar_entry_data dummy;
704
705 if (follow_links && entry->link) {
706 phar_entry_info *link_entry = phar_get_link_source(entry TSRMLS_CC);
707 if (link_entry && link_entry != entry) {
708 return phar_open_entry_fp(link_entry, error, 1 TSRMLS_CC);
709 }
710 }
711
712 if (entry->is_modified) {
713 return SUCCESS;
714 }
715
716 if (entry->fp_type == PHAR_TMP) {
717 if (!entry->fp) {
718 entry->fp = php_stream_open_wrapper(entry->tmp, "rb", STREAM_MUST_SEEK|0, NULL);
719 }
720 return SUCCESS;
721 }
722
723 if (entry->fp_type != PHAR_FP) {
724 /* either newly created or already modified */
725 return SUCCESS;
726 }
727
728 if (!phar_get_pharfp(phar TSRMLS_CC)) {
729 if (FAILURE == phar_open_archive_fp(phar TSRMLS_CC)) {
730 spprintf(error, 4096, "phar error: Cannot open phar archive \"%s\" for reading", phar->fname);
731 return FAILURE;
732 }
733 }
734
735 if ((entry->old_flags && !(entry->old_flags & PHAR_ENT_COMPRESSION_MASK)) || !(entry->flags & PHAR_ENT_COMPRESSION_MASK)) {
736 dummy.internal_file = entry;
737 dummy.phar = phar;
738 dummy.zero = entry->offset;
739 dummy.fp = phar_get_pharfp(phar TSRMLS_CC);
740 if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 1 TSRMLS_CC)) {
741 return FAILURE;
742 }
743 return SUCCESS;
744 }
745
746 if (!phar_get_entrypufp(entry TSRMLS_CC)) {
747 phar_set_entrypufp(entry, php_stream_fopen_tmpfile() TSRMLS_CC);
748 if (!phar_get_entrypufp(entry TSRMLS_CC)) {
749 spprintf(error, 4096, "phar error: Cannot open temporary file for decompressing phar archive \"%s\" file \"%s\"", phar->fname, entry->filename);
750 return FAILURE;
751 }
752 }
753
754 dummy.internal_file = entry;
755 dummy.phar = phar;
756 dummy.zero = entry->offset;
757 dummy.fp = phar_get_pharfp(phar TSRMLS_CC);
758 if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 1 TSRMLS_CC)) {
759 return FAILURE;
760 }
761
762 ufp = phar_get_entrypufp(entry TSRMLS_CC);
763
764 if ((filtername = phar_decompress_filter(entry, 0)) != NULL) {
765 filter = php_stream_filter_create(filtername, NULL, 0 TSRMLS_CC);
766 } else {
767 filter = NULL;
768 }
769
770 if (!filter) {
771 spprintf(error, 4096, "phar error: unable to read phar \"%s\" (cannot create %s filter while decompressing file \"%s\")", phar->fname, phar_decompress_filter(entry, 1), entry->filename);
772 return FAILURE;
773 }
774
775 /* now we can safely use proper decompression */
776 /* save the new offset location within ufp */
777 php_stream_seek(ufp, 0, SEEK_END);
778 loc = php_stream_tell(ufp);
779 php_stream_filter_append(&ufp->writefilters, filter);
780 php_stream_seek(phar_get_entrypfp(entry TSRMLS_CC), phar_get_fp_offset(entry TSRMLS_CC), SEEK_SET);
781
782 if (entry->uncompressed_filesize) {
783 if (SUCCESS != phar_stream_copy_to_stream(phar_get_entrypfp(entry TSRMLS_CC), ufp, entry->compressed_filesize, NULL)) {
784 spprintf(error, 4096, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", phar->fname, entry->filename);
785 php_stream_filter_remove(filter, 1 TSRMLS_CC);
786 return FAILURE;
787 }
788 }
789
790 php_stream_filter_flush(filter, 1);
791 php_stream_flush(ufp);
792 php_stream_filter_remove(filter, 1 TSRMLS_CC);
793
794 if (php_stream_tell(ufp) - loc != (off_t) entry->uncompressed_filesize) {
795 spprintf(error, 4096, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", phar->fname, entry->filename);
796 return FAILURE;
797 }
798
799 entry->old_flags = entry->flags;
800
801 /* this is now the new location of the file contents within this fp */
802 phar_set_fp_type(entry, PHAR_UFP, loc TSRMLS_CC);
803 dummy.zero = entry->offset;
804 dummy.fp = ufp;
805 if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 0 TSRMLS_CC)) {
806 return FAILURE;
807 }
808 return SUCCESS;
809 }
810 /* }}} */
811
phar_create_writeable_entry(phar_archive_data * phar,phar_entry_info * entry,char ** error TSRMLS_DC)812 int phar_create_writeable_entry(phar_archive_data *phar, phar_entry_info *entry, char **error TSRMLS_DC) /* {{{ */
813 {
814 if (entry->fp_type == PHAR_MOD) {
815 /* already newly created, truncate */
816 php_stream_truncate_set_size(entry->fp, 0);
817
818 entry->old_flags = entry->flags;
819 entry->is_modified = 1;
820 phar->is_modified = 1;
821 /* reset file size */
822 entry->uncompressed_filesize = 0;
823 entry->compressed_filesize = 0;
824 entry->crc32 = 0;
825 entry->flags = PHAR_ENT_PERM_DEF_FILE;
826 entry->fp_type = PHAR_MOD;
827 entry->offset = 0;
828 return SUCCESS;
829 }
830
831 if (error) {
832 *error = NULL;
833 }
834
835 /* open a new temp file for writing */
836 if (entry->link) {
837 efree(entry->link);
838 entry->link = NULL;
839 entry->tar_type = (entry->is_tar ? TAR_FILE : '\0');
840 }
841
842 entry->fp = php_stream_fopen_tmpfile();
843
844 if (!entry->fp) {
845 if (error) {
846 spprintf(error, 0, "phar error: unable to create temporary file");
847 }
848 return FAILURE;
849 }
850
851 entry->old_flags = entry->flags;
852 entry->is_modified = 1;
853 phar->is_modified = 1;
854 /* reset file size */
855 entry->uncompressed_filesize = 0;
856 entry->compressed_filesize = 0;
857 entry->crc32 = 0;
858 entry->flags = PHAR_ENT_PERM_DEF_FILE;
859 entry->fp_type = PHAR_MOD;
860 entry->offset = 0;
861 return SUCCESS;
862 }
863 /* }}} */
864
phar_separate_entry_fp(phar_entry_info * entry,char ** error TSRMLS_DC)865 int phar_separate_entry_fp(phar_entry_info *entry, char **error TSRMLS_DC) /* {{{ */
866 {
867 php_stream *fp;
868 phar_entry_info *link;
869
870 if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
871 return FAILURE;
872 }
873
874 if (entry->fp_type == PHAR_MOD) {
875 return SUCCESS;
876 }
877
878 fp = php_stream_fopen_tmpfile();
879 if (fp == NULL) {
880 spprintf(error, 0, "phar error: unable to create temporary file");
881 return FAILURE;
882 }
883 phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC);
884 link = phar_get_link_source(entry TSRMLS_CC);
885
886 if (!link) {
887 link = entry;
888 }
889
890 if (SUCCESS != phar_stream_copy_to_stream(phar_get_efp(link, 0 TSRMLS_CC), fp, link->uncompressed_filesize, NULL)) {
891 if (error) {
892 spprintf(error, 4096, "phar error: cannot separate entry file \"%s\" contents in phar archive \"%s\" for write access", entry->filename, entry->phar->fname);
893 }
894 return FAILURE;
895 }
896
897 if (entry->link) {
898 efree(entry->link);
899 entry->link = NULL;
900 entry->tar_type = (entry->is_tar ? TAR_FILE : '\0');
901 }
902
903 entry->offset = 0;
904 entry->fp = fp;
905 entry->fp_type = PHAR_MOD;
906 entry->is_modified = 1;
907 return SUCCESS;
908 }
909 /* }}} */
910
911 /**
912 * helper function to open an internal file's fp just-in-time
913 */
phar_open_jit(phar_archive_data * phar,phar_entry_info * entry,char ** error TSRMLS_DC)914 phar_entry_info * phar_open_jit(phar_archive_data *phar, phar_entry_info *entry, char **error TSRMLS_DC) /* {{{ */
915 {
916 if (error) {
917 *error = NULL;
918 }
919 /* seek to start of internal file and read it */
920 if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
921 return NULL;
922 }
923 if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC)) {
924 spprintf(error, 4096, "phar error: cannot seek to start of file \"%s\" in phar \"%s\"", entry->filename, phar->fname);
925 return NULL;
926 }
927 return entry;
928 }
929 /* }}} */
930
phar_resolve_alias(char * alias,int alias_len,char ** filename,int * filename_len TSRMLS_DC)931 PHP_PHAR_API int phar_resolve_alias(char *alias, int alias_len, char **filename, int *filename_len TSRMLS_DC) /* {{{ */ {
932 phar_archive_data **fd_ptr;
933 if (PHAR_GLOBALS->phar_alias_map.arBuckets
934 && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void**)&fd_ptr)) {
935 *filename = (*fd_ptr)->fname;
936 *filename_len = (*fd_ptr)->fname_len;
937 return SUCCESS;
938 }
939 return FAILURE;
940 }
941 /* }}} */
942
phar_free_alias(phar_archive_data * phar,char * alias,int alias_len TSRMLS_DC)943 int phar_free_alias(phar_archive_data *phar, char *alias, int alias_len TSRMLS_DC) /* {{{ */
944 {
945 if (phar->refcount || phar->is_persistent) {
946 return FAILURE;
947 }
948
949 /* this archive has no open references, so emit an E_STRICT and remove it */
950 if (zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), phar->fname, phar->fname_len) != SUCCESS) {
951 return FAILURE;
952 }
953
954 /* invalidate phar cache */
955 PHAR_G(last_phar) = NULL;
956 PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
957
958 return SUCCESS;
959 }
960 /* }}} */
961
962 /**
963 * Looks up a phar archive in the filename map, connecting it to the alias
964 * (if any) or returns null
965 */
phar_get_archive(phar_archive_data ** archive,char * fname,int fname_len,char * alias,int alias_len,char ** error TSRMLS_DC)966 int phar_get_archive(phar_archive_data **archive, char *fname, int fname_len, char *alias, int alias_len, char **error TSRMLS_DC) /* {{{ */
967 {
968 phar_archive_data *fd, **fd_ptr;
969 char *my_realpath, *save;
970 int save_len;
971 ulong fhash, ahash = 0;
972
973 phar_request_initialize(TSRMLS_C);
974
975 if (error) {
976 *error = NULL;
977 }
978
979 *archive = NULL;
980
981 if (PHAR_G(last_phar) && fname_len == PHAR_G(last_phar_name_len) && !memcmp(fname, PHAR_G(last_phar_name), fname_len)) {
982 *archive = PHAR_G(last_phar);
983 if (alias && alias_len) {
984
985 if (!PHAR_G(last_phar)->is_temporary_alias && (alias_len != PHAR_G(last_phar)->alias_len || memcmp(PHAR_G(last_phar)->alias, alias, alias_len))) {
986 if (error) {
987 spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, PHAR_G(last_phar)->fname, fname);
988 }
989 *archive = NULL;
990 return FAILURE;
991 }
992
993 if (PHAR_G(last_phar)->alias_len && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), PHAR_G(last_phar)->alias, PHAR_G(last_phar)->alias_len, (void**)&fd_ptr)) {
994 zend_hash_del(&(PHAR_GLOBALS->phar_alias_map), PHAR_G(last_phar)->alias, PHAR_G(last_phar)->alias_len);
995 }
996
997 zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&(*archive), sizeof(phar_archive_data*), NULL);
998 PHAR_G(last_alias) = alias;
999 PHAR_G(last_alias_len) = alias_len;
1000 }
1001
1002 return SUCCESS;
1003 }
1004
1005 if (alias && alias_len && PHAR_G(last_phar) && alias_len == PHAR_G(last_alias_len) && !memcmp(alias, PHAR_G(last_alias), alias_len)) {
1006 fd = PHAR_G(last_phar);
1007 fd_ptr = &fd;
1008 goto alias_success;
1009 }
1010
1011 if (alias && alias_len) {
1012 ahash = zend_inline_hash_func(alias, alias_len);
1013 if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void**)&fd_ptr)) {
1014 alias_success:
1015 if (fname && (fname_len != (*fd_ptr)->fname_len || strncmp(fname, (*fd_ptr)->fname, fname_len))) {
1016 if (error) {
1017 spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
1018 }
1019 if (SUCCESS == phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
1020 if (error) {
1021 efree(*error);
1022 *error = NULL;
1023 }
1024 }
1025 return FAILURE;
1026 }
1027
1028 *archive = *fd_ptr;
1029 fd = *fd_ptr;
1030 PHAR_G(last_phar) = fd;
1031 PHAR_G(last_phar_name) = fd->fname;
1032 PHAR_G(last_phar_name_len) = fd->fname_len;
1033 PHAR_G(last_alias) = alias;
1034 PHAR_G(last_alias_len) = alias_len;
1035
1036 return SUCCESS;
1037 }
1038
1039 if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_alias, alias, alias_len, ahash, (void **)&fd_ptr)) {
1040 goto alias_success;
1041 }
1042 }
1043
1044 fhash = zend_inline_hash_func(fname, fname_len);
1045 my_realpath = NULL;
1046 save = fname;
1047 save_len = fname_len;
1048
1049 if (fname && fname_len) {
1050 if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, fhash, (void**)&fd_ptr)) {
1051 *archive = *fd_ptr;
1052 fd = *fd_ptr;
1053
1054 if (alias && alias_len) {
1055 if (!fd->is_temporary_alias && (alias_len != fd->alias_len || memcmp(fd->alias, alias, alias_len))) {
1056 if (error) {
1057 spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
1058 }
1059 return FAILURE;
1060 }
1061
1062 if (fd->alias_len && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), fd->alias, fd->alias_len, (void**)&fd_ptr)) {
1063 zend_hash_del(&(PHAR_GLOBALS->phar_alias_map), fd->alias, fd->alias_len);
1064 }
1065
1066 zend_hash_quick_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void*)&fd, sizeof(phar_archive_data*), NULL);
1067 }
1068
1069 PHAR_G(last_phar) = fd;
1070 PHAR_G(last_phar_name) = fd->fname;
1071 PHAR_G(last_phar_name_len) = fd->fname_len;
1072 PHAR_G(last_alias) = fd->alias;
1073 PHAR_G(last_alias_len) = fd->alias_len;
1074
1075 return SUCCESS;
1076 }
1077
1078 if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_phars, fname, fname_len, fhash, (void**)&fd_ptr)) {
1079 *archive = *fd_ptr;
1080 fd = *fd_ptr;
1081
1082 /* this could be problematic - alias should never be different from manifest alias
1083 for cached phars */
1084 if (!fd->is_temporary_alias && alias && alias_len) {
1085 if (alias_len != fd->alias_len || memcmp(fd->alias, alias, alias_len)) {
1086 if (error) {
1087 spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
1088 }
1089 return FAILURE;
1090 }
1091 }
1092
1093 PHAR_G(last_phar) = fd;
1094 PHAR_G(last_phar_name) = fd->fname;
1095 PHAR_G(last_phar_name_len) = fd->fname_len;
1096 PHAR_G(last_alias) = fd->alias;
1097 PHAR_G(last_alias_len) = fd->alias_len;
1098
1099 return SUCCESS;
1100 }
1101
1102 if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_alias_map), save, save_len, fhash, (void**)&fd_ptr)) {
1103 fd = *archive = *fd_ptr;
1104
1105 PHAR_G(last_phar) = fd;
1106 PHAR_G(last_phar_name) = fd->fname;
1107 PHAR_G(last_phar_name_len) = fd->fname_len;
1108 PHAR_G(last_alias) = fd->alias;
1109 PHAR_G(last_alias_len) = fd->alias_len;
1110
1111 return SUCCESS;
1112 }
1113
1114 if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_alias, save, save_len, fhash, (void**)&fd_ptr)) {
1115 fd = *archive = *fd_ptr;
1116
1117 PHAR_G(last_phar) = fd;
1118 PHAR_G(last_phar_name) = fd->fname;
1119 PHAR_G(last_phar_name_len) = fd->fname_len;
1120 PHAR_G(last_alias) = fd->alias;
1121 PHAR_G(last_alias_len) = fd->alias_len;
1122
1123 return SUCCESS;
1124 }
1125
1126 /* not found, try converting \ to / */
1127 my_realpath = expand_filepath(fname, my_realpath TSRMLS_CC);
1128
1129 if (my_realpath) {
1130 fname_len = strlen(my_realpath);
1131 fname = my_realpath;
1132 } else {
1133 return FAILURE;
1134 }
1135 #ifdef PHP_WIN32
1136 phar_unixify_path_separators(fname, fname_len);
1137 #endif
1138 fhash = zend_inline_hash_func(fname, fname_len);
1139
1140 if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, fhash, (void**)&fd_ptr)) {
1141 realpath_success:
1142 *archive = *fd_ptr;
1143 fd = *fd_ptr;
1144
1145 if (alias && alias_len) {
1146 zend_hash_quick_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void*)&fd, sizeof(phar_archive_data*), NULL);
1147 }
1148
1149 efree(my_realpath);
1150
1151 PHAR_G(last_phar) = fd;
1152 PHAR_G(last_phar_name) = fd->fname;
1153 PHAR_G(last_phar_name_len) = fd->fname_len;
1154 PHAR_G(last_alias) = fd->alias;
1155 PHAR_G(last_alias_len) = fd->alias_len;
1156
1157 return SUCCESS;
1158 }
1159
1160 if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_phars, fname, fname_len, fhash, (void**)&fd_ptr)) {
1161 goto realpath_success;
1162 }
1163
1164 efree(my_realpath);
1165 }
1166
1167 return FAILURE;
1168 }
1169 /* }}} */
1170
1171 /**
1172 * Determine which stream compression filter (if any) we need to read this file
1173 */
phar_compress_filter(phar_entry_info * entry,int return_unknown)1174 char * phar_compress_filter(phar_entry_info * entry, int return_unknown) /* {{{ */
1175 {
1176 switch (entry->flags & PHAR_ENT_COMPRESSION_MASK) {
1177 case PHAR_ENT_COMPRESSED_GZ:
1178 return "zlib.deflate";
1179 case PHAR_ENT_COMPRESSED_BZ2:
1180 return "bzip2.compress";
1181 default:
1182 return return_unknown ? "unknown" : NULL;
1183 }
1184 }
1185 /* }}} */
1186
1187 /**
1188 * Determine which stream decompression filter (if any) we need to read this file
1189 */
phar_decompress_filter(phar_entry_info * entry,int return_unknown)1190 char * phar_decompress_filter(phar_entry_info * entry, int return_unknown) /* {{{ */
1191 {
1192 php_uint32 flags;
1193
1194 if (entry->is_modified) {
1195 flags = entry->old_flags;
1196 } else {
1197 flags = entry->flags;
1198 }
1199
1200 switch (flags & PHAR_ENT_COMPRESSION_MASK) {
1201 case PHAR_ENT_COMPRESSED_GZ:
1202 return "zlib.inflate";
1203 case PHAR_ENT_COMPRESSED_BZ2:
1204 return "bzip2.decompress";
1205 default:
1206 return return_unknown ? "unknown" : NULL;
1207 }
1208 }
1209 /* }}} */
1210
1211 /**
1212 * retrieve information on a file contained within a phar, or null if it ain't there
1213 */
phar_get_entry_info(phar_archive_data * phar,char * path,int path_len,char ** error,int security TSRMLS_DC)1214 phar_entry_info *phar_get_entry_info(phar_archive_data *phar, char *path, int path_len, char **error, int security TSRMLS_DC) /* {{{ */
1215 {
1216 return phar_get_entry_info_dir(phar, path, path_len, 0, error, security TSRMLS_CC);
1217 }
1218 /* }}} */
1219 /**
1220 * retrieve information on a file or directory contained within a phar, or null if none found
1221 * allow_dir is 0 for none, 1 for both empty directories in the phar and temp directories, and 2 for only
1222 * valid pre-existing empty directory entries
1223 */
phar_get_entry_info_dir(phar_archive_data * phar,char * path,int path_len,char dir,char ** error,int security TSRMLS_DC)1224 phar_entry_info *phar_get_entry_info_dir(phar_archive_data *phar, char *path, int path_len, char dir, char **error, int security TSRMLS_DC) /* {{{ */
1225 {
1226 const char *pcr_error;
1227 phar_entry_info *entry;
1228 int is_dir;
1229
1230 #ifdef PHP_WIN32
1231 phar_unixify_path_separators(path, path_len);
1232 #endif
1233
1234 is_dir = (path_len && (path[path_len - 1] == '/')) ? 1 : 0;
1235
1236 if (error) {
1237 *error = NULL;
1238 }
1239
1240 if (security && path_len >= sizeof(".phar")-1 && !memcmp(path, ".phar", sizeof(".phar")-1)) {
1241 if (error) {
1242 spprintf(error, 4096, "phar error: cannot directly access magic \".phar\" directory or files within it");
1243 }
1244 return NULL;
1245 }
1246
1247 if (!path_len && !dir) {
1248 if (error) {
1249 spprintf(error, 4096, "phar error: invalid path \"%s\" must not be empty", path);
1250 }
1251 return NULL;
1252 }
1253
1254 if (phar_path_check(&path, &path_len, &pcr_error) > pcr_is_ok) {
1255 if (error) {
1256 spprintf(error, 4096, "phar error: invalid path \"%s\" contains %s", path, pcr_error);
1257 }
1258 return NULL;
1259 }
1260
1261 if (!phar->manifest.arBuckets) {
1262 return NULL;
1263 }
1264
1265 if (is_dir) {
1266 if (!path_len || path_len == 1) {
1267 return NULL;
1268 }
1269 path_len--;
1270 }
1271
1272 if (SUCCESS == zend_hash_find(&phar->manifest, path, path_len, (void**)&entry)) {
1273 if (entry->is_deleted) {
1274 /* entry is deleted, but has not been flushed to disk yet */
1275 return NULL;
1276 }
1277 if (entry->is_dir && !dir) {
1278 if (error) {
1279 spprintf(error, 4096, "phar error: path \"%s\" is a directory", path);
1280 }
1281 return NULL;
1282 }
1283 if (!entry->is_dir && dir == 2) {
1284 /* user requested a directory, we must return one */
1285 if (error) {
1286 spprintf(error, 4096, "phar error: path \"%s\" exists and is a not a directory", path);
1287 }
1288 return NULL;
1289 }
1290 return entry;
1291 }
1292
1293 if (dir) {
1294 if (zend_hash_exists(&phar->virtual_dirs, path, path_len)) {
1295 /* a file or directory exists in a sub-directory of this path */
1296 entry = (phar_entry_info *) ecalloc(1, sizeof(phar_entry_info));
1297 /* this next line tells PharFileInfo->__destruct() to efree the filename */
1298 entry->is_temp_dir = entry->is_dir = 1;
1299 entry->filename = (char *) estrndup(path, path_len + 1);
1300 entry->filename_len = path_len;
1301 entry->phar = phar;
1302 return entry;
1303 }
1304 }
1305
1306 if (phar->mounted_dirs.arBuckets && zend_hash_num_elements(&phar->mounted_dirs)) {
1307 phar_zstr key;
1308 char *str_key;
1309 ulong unused;
1310 uint keylen;
1311
1312 zend_hash_internal_pointer_reset(&phar->mounted_dirs);
1313 while (FAILURE != zend_hash_has_more_elements(&phar->mounted_dirs)) {
1314 if (HASH_KEY_NON_EXISTENT == zend_hash_get_current_key_ex(&phar->mounted_dirs, &key, &keylen, &unused, 0, NULL)) {
1315 break;
1316 }
1317
1318 PHAR_STR(key, str_key);
1319
1320 if ((int)keylen >= path_len || strncmp(str_key, path, keylen)) {
1321 PHAR_STR_FREE(str_key);
1322 continue;
1323 } else {
1324 char *test;
1325 int test_len;
1326 php_stream_statbuf ssb;
1327
1328 if (SUCCESS != zend_hash_find(&phar->manifest, str_key, keylen, (void **) &entry)) {
1329 if (error) {
1330 spprintf(error, 4096, "phar internal error: mounted path \"%s\" could not be retrieved from manifest", str_key);
1331 }
1332 PHAR_STR_FREE(str_key);
1333 return NULL;
1334 }
1335
1336 if (!entry->tmp || !entry->is_mounted) {
1337 if (error) {
1338 spprintf(error, 4096, "phar internal error: mounted path \"%s\" is not properly initialized as a mounted path", str_key);
1339 }
1340 PHAR_STR_FREE(str_key);
1341 return NULL;
1342 }
1343 PHAR_STR_FREE(str_key);
1344
1345 test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->tmp, path + keylen);
1346
1347 if (SUCCESS != php_stream_stat_path(test, &ssb)) {
1348 efree(test);
1349 return NULL;
1350 }
1351
1352 if (ssb.sb.st_mode & S_IFDIR && !dir) {
1353 efree(test);
1354 if (error) {
1355 spprintf(error, 4096, "phar error: path \"%s\" is a directory", path);
1356 }
1357 return NULL;
1358 }
1359
1360 if ((ssb.sb.st_mode & S_IFDIR) == 0 && dir) {
1361 efree(test);
1362 /* user requested a directory, we must return one */
1363 if (error) {
1364 spprintf(error, 4096, "phar error: path \"%s\" exists and is a not a directory", path);
1365 }
1366 return NULL;
1367 }
1368
1369 /* mount the file just in time */
1370 if (SUCCESS != phar_mount_entry(phar, test, test_len, path, path_len TSRMLS_CC)) {
1371 efree(test);
1372 if (error) {
1373 spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be mounted", path, test);
1374 }
1375 return NULL;
1376 }
1377
1378 efree(test);
1379
1380 if (SUCCESS != zend_hash_find(&phar->manifest, path, path_len, (void**)&entry)) {
1381 if (error) {
1382 spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be retrieved after being mounted", path, test);
1383 }
1384 return NULL;
1385 }
1386 return entry;
1387 }
1388 }
1389 }
1390
1391 return NULL;
1392 }
1393 /* }}} */
1394
1395 static const char hexChars[] = "0123456789ABCDEF";
1396
phar_hex_str(const char * digest,size_t digest_len,char ** signature TSRMLS_DC)1397 static int phar_hex_str(const char *digest, size_t digest_len, char **signature TSRMLS_DC) /* {{{ */
1398 {
1399 int pos = -1;
1400 size_t len = 0;
1401
1402 *signature = (char*)safe_pemalloc(digest_len, 2, 1, PHAR_G(persist));
1403
1404 for (; len < digest_len; ++len) {
1405 (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] >> 4];
1406 (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] & 0x0F];
1407 }
1408 (*signature)[++pos] = '\0';
1409 return pos;
1410 }
1411 /* }}} */
1412
1413 #ifndef PHAR_HAVE_OPENSSL
phar_call_openssl_signverify(int is_sign,php_stream * fp,off_t end,char * key,int key_len,char ** signature,int * signature_len TSRMLS_DC)1414 static int phar_call_openssl_signverify(int is_sign, php_stream *fp, off_t end, char *key, int key_len, char **signature, int *signature_len TSRMLS_DC) /* {{{ */
1415 {
1416 zend_fcall_info fci;
1417 zend_fcall_info_cache fcc;
1418 zval *zdata, *zsig, *zkey, *retval_ptr, **zp[3], *openssl;
1419
1420 MAKE_STD_ZVAL(zdata);
1421 MAKE_STD_ZVAL(openssl);
1422 ZVAL_STRINGL(openssl, is_sign ? "openssl_sign" : "openssl_verify", is_sign ? sizeof("openssl_sign")-1 : sizeof("openssl_verify")-1, 1);
1423 MAKE_STD_ZVAL(zsig);
1424 ZVAL_STRINGL(zsig, *signature, *signature_len, 1);
1425 MAKE_STD_ZVAL(zkey);
1426 ZVAL_STRINGL(zkey, key, key_len, 1);
1427 zp[0] = &zdata;
1428 zp[1] = &zsig;
1429 zp[2] = &zkey;
1430
1431 php_stream_rewind(fp);
1432 Z_TYPE_P(zdata) = IS_STRING;
1433 Z_STRLEN_P(zdata) = end;
1434
1435 if (end != (off_t) php_stream_copy_to_mem(fp, &(Z_STRVAL_P(zdata)), (size_t) end, 0)) {
1436 zval_dtor(zdata);
1437 zval_dtor(zsig);
1438 zval_dtor(zkey);
1439 zval_dtor(openssl);
1440 efree(openssl);
1441 efree(zdata);
1442 efree(zkey);
1443 efree(zsig);
1444 return FAILURE;
1445 }
1446
1447 if (FAILURE == zend_fcall_info_init(openssl, 0, &fci, &fcc, NULL, NULL TSRMLS_CC)) {
1448 zval_dtor(zdata);
1449 zval_dtor(zsig);
1450 zval_dtor(zkey);
1451 zval_dtor(openssl);
1452 efree(openssl);
1453 efree(zdata);
1454 efree(zkey);
1455 efree(zsig);
1456 return FAILURE;
1457 }
1458
1459 fci.param_count = 3;
1460 fci.params = zp;
1461 Z_ADDREF_P(zdata);
1462 if (is_sign) {
1463 Z_SET_ISREF_P(zsig);
1464 } else {
1465 Z_ADDREF_P(zsig);
1466 }
1467 Z_ADDREF_P(zkey);
1468
1469 fci.retval_ptr_ptr = &retval_ptr;
1470
1471 if (FAILURE == zend_call_function(&fci, &fcc TSRMLS_CC)) {
1472 zval_dtor(zdata);
1473 zval_dtor(zsig);
1474 zval_dtor(zkey);
1475 zval_dtor(openssl);
1476 efree(openssl);
1477 efree(zdata);
1478 efree(zkey);
1479 efree(zsig);
1480 return FAILURE;
1481 }
1482
1483 zval_dtor(openssl);
1484 efree(openssl);
1485 Z_DELREF_P(zdata);
1486
1487 if (is_sign) {
1488 Z_UNSET_ISREF_P(zsig);
1489 } else {
1490 Z_DELREF_P(zsig);
1491 }
1492 Z_DELREF_P(zkey);
1493
1494 zval_dtor(zdata);
1495 efree(zdata);
1496 zval_dtor(zkey);
1497 efree(zkey);
1498
1499 switch (Z_TYPE_P(retval_ptr)) {
1500 default:
1501 case IS_LONG:
1502 zval_dtor(zsig);
1503 efree(zsig);
1504 if (1 == Z_LVAL_P(retval_ptr)) {
1505 efree(retval_ptr);
1506 return SUCCESS;
1507 }
1508 efree(retval_ptr);
1509 return FAILURE;
1510 case IS_BOOL:
1511 efree(retval_ptr);
1512 if (Z_BVAL_P(retval_ptr)) {
1513 *signature = estrndup(Z_STRVAL_P(zsig), Z_STRLEN_P(zsig));
1514 *signature_len = Z_STRLEN_P(zsig);
1515 zval_dtor(zsig);
1516 efree(zsig);
1517 return SUCCESS;
1518 }
1519 zval_dtor(zsig);
1520 efree(zsig);
1521 return FAILURE;
1522 }
1523 }
1524 /* }}} */
1525 #endif /* #ifndef PHAR_HAVE_OPENSSL */
1526
phar_verify_signature(php_stream * fp,size_t end_of_phar,php_uint32 sig_type,char * sig,int sig_len,char * fname,char ** signature,int * signature_len,char ** error TSRMLS_DC)1527 int phar_verify_signature(php_stream *fp, size_t end_of_phar, php_uint32 sig_type, char *sig, int sig_len, char *fname, char **signature, int *signature_len, char **error TSRMLS_DC) /* {{{ */
1528 {
1529 int read_size, len;
1530 off_t read_len;
1531 unsigned char buf[1024];
1532
1533 php_stream_rewind(fp);
1534
1535 switch (sig_type) {
1536 case PHAR_SIG_OPENSSL: {
1537 #ifdef PHAR_HAVE_OPENSSL
1538 BIO *in;
1539 EVP_PKEY *key;
1540 EVP_MD *mdtype = (EVP_MD *) EVP_sha1();
1541 EVP_MD_CTX md_ctx;
1542 #else
1543 int tempsig;
1544 #endif
1545 php_uint32 pubkey_len;
1546 char *pubkey = NULL, *pfile;
1547 php_stream *pfp;
1548 #ifndef PHAR_HAVE_OPENSSL
1549 if (!zend_hash_exists(&module_registry, "openssl", sizeof("openssl"))) {
1550 if (error) {
1551 spprintf(error, 0, "openssl not loaded");
1552 }
1553 return FAILURE;
1554 }
1555 #endif
1556 /* use __FILE__ . '.pubkey' for public key file */
1557 spprintf(&pfile, 0, "%s.pubkey", fname);
1558 pfp = php_stream_open_wrapper(pfile, "rb", 0, NULL);
1559 efree(pfile);
1560
1561 #if PHP_MAJOR_VERSION > 5
1562 if (!pfp || !(pubkey_len = php_stream_copy_to_mem(pfp, (void **) &pubkey, PHP_STREAM_COPY_ALL, 0)) || !pubkey) {
1563 #else
1564 if (!pfp || !(pubkey_len = php_stream_copy_to_mem(pfp, &pubkey, PHP_STREAM_COPY_ALL, 0)) || !pubkey) {
1565 #endif
1566 if (pfp) {
1567 php_stream_close(pfp);
1568 }
1569 if (error) {
1570 spprintf(error, 0, "openssl public key could not be read");
1571 }
1572 return FAILURE;
1573 }
1574
1575 php_stream_close(pfp);
1576 #ifndef PHAR_HAVE_OPENSSL
1577 tempsig = sig_len;
1578
1579 if (FAILURE == phar_call_openssl_signverify(0, fp, end_of_phar, pubkey, pubkey_len, &sig, &tempsig TSRMLS_CC)) {
1580 if (pubkey) {
1581 efree(pubkey);
1582 }
1583
1584 if (error) {
1585 spprintf(error, 0, "openssl signature could not be verified");
1586 }
1587
1588 return FAILURE;
1589 }
1590
1591 if (pubkey) {
1592 efree(pubkey);
1593 }
1594
1595 sig_len = tempsig;
1596 #else
1597 in = BIO_new_mem_buf(pubkey, pubkey_len);
1598
1599 if (NULL == in) {
1600 efree(pubkey);
1601 if (error) {
1602 spprintf(error, 0, "openssl signature could not be processed");
1603 }
1604 return FAILURE;
1605 }
1606
1607 key = PEM_read_bio_PUBKEY(in, NULL,NULL, NULL);
1608 BIO_free(in);
1609 efree(pubkey);
1610
1611 if (NULL == key) {
1612 if (error) {
1613 spprintf(error, 0, "openssl signature could not be processed");
1614 }
1615 return FAILURE;
1616 }
1617
1618 EVP_VerifyInit(&md_ctx, mdtype);
1619 read_len = end_of_phar;
1620
1621 if (read_len > sizeof(buf)) {
1622 read_size = sizeof(buf);
1623 } else {
1624 read_size = (int)read_len;
1625 }
1626
1627 php_stream_seek(fp, 0, SEEK_SET);
1628
1629 while (read_size && (len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
1630 EVP_VerifyUpdate (&md_ctx, buf, len);
1631 read_len -= (off_t)len;
1632
1633 if (read_len < read_size) {
1634 read_size = (int)read_len;
1635 }
1636 }
1637
1638 if (EVP_VerifyFinal(&md_ctx, (unsigned char *)sig, sig_len, key) != 1) {
1639 /* 1: signature verified, 0: signature does not match, -1: failed signature operation */
1640 EVP_MD_CTX_cleanup(&md_ctx);
1641
1642 if (error) {
1643 spprintf(error, 0, "broken openssl signature");
1644 }
1645
1646 return FAILURE;
1647 }
1648
1649 EVP_MD_CTX_cleanup(&md_ctx);
1650 #endif
1651
1652 *signature_len = phar_hex_str((const char*)sig, sig_len, signature TSRMLS_CC);
1653 }
1654 break;
1655 #ifdef PHAR_HASH_OK
1656 case PHAR_SIG_SHA512: {
1657 unsigned char digest[64];
1658 PHP_SHA512_CTX context;
1659
1660 PHP_SHA512Init(&context);
1661 read_len = end_of_phar;
1662
1663 if (read_len > sizeof(buf)) {
1664 read_size = sizeof(buf);
1665 } else {
1666 read_size = (int)read_len;
1667 }
1668
1669 while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
1670 PHP_SHA512Update(&context, buf, len);
1671 read_len -= (off_t)len;
1672 if (read_len < read_size) {
1673 read_size = (int)read_len;
1674 }
1675 }
1676
1677 PHP_SHA512Final(digest, &context);
1678
1679 if (memcmp(digest, sig, sizeof(digest))) {
1680 if (error) {
1681 spprintf(error, 0, "broken signature");
1682 }
1683 return FAILURE;
1684 }
1685
1686 *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
1687 break;
1688 }
1689 case PHAR_SIG_SHA256: {
1690 unsigned char digest[32];
1691 PHP_SHA256_CTX context;
1692
1693 PHP_SHA256Init(&context);
1694 read_len = end_of_phar;
1695
1696 if (read_len > sizeof(buf)) {
1697 read_size = sizeof(buf);
1698 } else {
1699 read_size = (int)read_len;
1700 }
1701
1702 while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
1703 PHP_SHA256Update(&context, buf, len);
1704 read_len -= (off_t)len;
1705 if (read_len < read_size) {
1706 read_size = (int)read_len;
1707 }
1708 }
1709
1710 PHP_SHA256Final(digest, &context);
1711
1712 if (memcmp(digest, sig, sizeof(digest))) {
1713 if (error) {
1714 spprintf(error, 0, "broken signature");
1715 }
1716 return FAILURE;
1717 }
1718
1719 *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
1720 break;
1721 }
1722 #else
1723 case PHAR_SIG_SHA512:
1724 case PHAR_SIG_SHA256:
1725 if (error) {
1726 spprintf(error, 0, "unsupported signature");
1727 }
1728 return FAILURE;
1729 #endif
1730 case PHAR_SIG_SHA1: {
1731 unsigned char digest[20];
1732 PHP_SHA1_CTX context;
1733
1734 PHP_SHA1Init(&context);
1735 read_len = end_of_phar;
1736
1737 if (read_len > sizeof(buf)) {
1738 read_size = sizeof(buf);
1739 } else {
1740 read_size = (int)read_len;
1741 }
1742
1743 while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
1744 PHP_SHA1Update(&context, buf, len);
1745 read_len -= (off_t)len;
1746 if (read_len < read_size) {
1747 read_size = (int)read_len;
1748 }
1749 }
1750
1751 PHP_SHA1Final(digest, &context);
1752
1753 if (memcmp(digest, sig, sizeof(digest))) {
1754 if (error) {
1755 spprintf(error, 0, "broken signature");
1756 }
1757 return FAILURE;
1758 }
1759
1760 *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
1761 break;
1762 }
1763 case PHAR_SIG_MD5: {
1764 unsigned char digest[16];
1765 PHP_MD5_CTX context;
1766
1767 PHP_MD5Init(&context);
1768 read_len = end_of_phar;
1769
1770 if (read_len > sizeof(buf)) {
1771 read_size = sizeof(buf);
1772 } else {
1773 read_size = (int)read_len;
1774 }
1775
1776 while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
1777 PHP_MD5Update(&context, buf, len);
1778 read_len -= (off_t)len;
1779 if (read_len < read_size) {
1780 read_size = (int)read_len;
1781 }
1782 }
1783
1784 PHP_MD5Final(digest, &context);
1785
1786 if (memcmp(digest, sig, sizeof(digest))) {
1787 if (error) {
1788 spprintf(error, 0, "broken signature");
1789 }
1790 return FAILURE;
1791 }
1792
1793 *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
1794 break;
1795 }
1796 default:
1797 if (error) {
1798 spprintf(error, 0, "broken or unsupported signature");
1799 }
1800 return FAILURE;
1801 }
1802 return SUCCESS;
1803 }
1804 /* }}} */
1805
1806 int phar_create_signature(phar_archive_data *phar, php_stream *fp, char **signature, int *signature_length, char **error TSRMLS_DC) /* {{{ */
1807 {
1808 unsigned char buf[1024];
1809 int sig_len;
1810
1811 php_stream_rewind(fp);
1812
1813 if (phar->signature) {
1814 efree(phar->signature);
1815 phar->signature = NULL;
1816 }
1817
1818 switch(phar->sig_flags) {
1819 #ifdef PHAR_HASH_OK
1820 case PHAR_SIG_SHA512: {
1821 unsigned char digest[64];
1822 PHP_SHA512_CTX context;
1823
1824 PHP_SHA512Init(&context);
1825
1826 while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
1827 PHP_SHA512Update(&context, buf, sig_len);
1828 }
1829
1830 PHP_SHA512Final(digest, &context);
1831 *signature = estrndup((char *) digest, 64);
1832 *signature_length = 64;
1833 break;
1834 }
1835 case PHAR_SIG_SHA256: {
1836 unsigned char digest[32];
1837 PHP_SHA256_CTX context;
1838
1839 PHP_SHA256Init(&context);
1840
1841 while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
1842 PHP_SHA256Update(&context, buf, sig_len);
1843 }
1844
1845 PHP_SHA256Final(digest, &context);
1846 *signature = estrndup((char *) digest, 32);
1847 *signature_length = 32;
1848 break;
1849 }
1850 #else
1851 case PHAR_SIG_SHA512:
1852 case PHAR_SIG_SHA256:
1853 if (error) {
1854 spprintf(error, 0, "unable to write to phar \"%s\" with requested hash type", phar->fname);
1855 }
1856
1857 return FAILURE;
1858 #endif
1859 case PHAR_SIG_OPENSSL: {
1860 int siglen;
1861 unsigned char *sigbuf;
1862 #ifdef PHAR_HAVE_OPENSSL
1863 BIO *in;
1864 EVP_PKEY *key;
1865 EVP_MD_CTX *md_ctx;
1866
1867 in = BIO_new_mem_buf(PHAR_G(openssl_privatekey), PHAR_G(openssl_privatekey_len));
1868
1869 if (in == NULL) {
1870 if (error) {
1871 spprintf(error, 0, "unable to write to phar \"%s\" with requested openssl signature", phar->fname);
1872 }
1873 return FAILURE;
1874 }
1875
1876 key = PEM_read_bio_PrivateKey(in, NULL,NULL, "");
1877 BIO_free(in);
1878
1879 if (!key) {
1880 if (error) {
1881 spprintf(error, 0, "unable to process private key");
1882 }
1883 return FAILURE;
1884 }
1885
1886 md_ctx = EVP_MD_CTX_create();
1887
1888 siglen = EVP_PKEY_size(key);
1889 sigbuf = emalloc(siglen + 1);
1890
1891 if (!EVP_SignInit(md_ctx, EVP_sha1())) {
1892 efree(sigbuf);
1893 if (error) {
1894 spprintf(error, 0, "unable to initialize openssl signature for phar \"%s\"", phar->fname);
1895 }
1896 return FAILURE;
1897 }
1898
1899 while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
1900 if (!EVP_SignUpdate(md_ctx, buf, sig_len)) {
1901 efree(sigbuf);
1902 if (error) {
1903 spprintf(error, 0, "unable to update the openssl signature for phar \"%s\"", phar->fname);
1904 }
1905 return FAILURE;
1906 }
1907 }
1908
1909 if (!EVP_SignFinal (md_ctx, sigbuf,(unsigned int *)&siglen, key)) {
1910 efree(sigbuf);
1911 if (error) {
1912 spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname);
1913 }
1914 return FAILURE;
1915 }
1916
1917 sigbuf[siglen] = '\0';
1918 EVP_MD_CTX_destroy(md_ctx);
1919 #else
1920 sigbuf = NULL;
1921 siglen = 0;
1922 php_stream_seek(fp, 0, SEEK_END);
1923
1924 if (FAILURE == phar_call_openssl_signverify(1, fp, php_stream_tell(fp), PHAR_G(openssl_privatekey), PHAR_G(openssl_privatekey_len), (char **)&sigbuf, &siglen TSRMLS_CC)) {
1925 if (error) {
1926 spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname);
1927 }
1928 return FAILURE;
1929 }
1930 #endif
1931 *signature = (char *) sigbuf;
1932 *signature_length = siglen;
1933 }
1934 break;
1935 default:
1936 phar->sig_flags = PHAR_SIG_SHA1;
1937 case PHAR_SIG_SHA1: {
1938 unsigned char digest[20];
1939 PHP_SHA1_CTX context;
1940
1941 PHP_SHA1Init(&context);
1942
1943 while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
1944 PHP_SHA1Update(&context, buf, sig_len);
1945 }
1946
1947 PHP_SHA1Final(digest, &context);
1948 *signature = estrndup((char *) digest, 20);
1949 *signature_length = 20;
1950 break;
1951 }
1952 case PHAR_SIG_MD5: {
1953 unsigned char digest[16];
1954 PHP_MD5_CTX context;
1955
1956 PHP_MD5Init(&context);
1957
1958 while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
1959 PHP_MD5Update(&context, buf, sig_len);
1960 }
1961
1962 PHP_MD5Final(digest, &context);
1963 *signature = estrndup((char *) digest, 16);
1964 *signature_length = 16;
1965 break;
1966 }
1967 }
1968
1969 phar->sig_len = phar_hex_str((const char *)*signature, *signature_length, &phar->signature TSRMLS_CC);
1970 return SUCCESS;
1971 }
1972 /* }}} */
1973
1974 void phar_add_virtual_dirs(phar_archive_data *phar, char *filename, int filename_len TSRMLS_DC) /* {{{ */
1975 {
1976 const char *s;
1977
1978 while ((s = zend_memrchr(filename, '/', filename_len))) {
1979 filename_len = s - filename;
1980 if (!filename_len || FAILURE == zend_hash_add_empty_element(&phar->virtual_dirs, filename, filename_len)) {
1981 break;
1982 }
1983 }
1984 }
1985 /* }}} */
1986
1987 static int phar_update_cached_entry(void *data, void *argument) /* {{{ */
1988 {
1989 phar_entry_info *entry = (phar_entry_info *)data;
1990 TSRMLS_FETCH();
1991
1992 entry->phar = (phar_archive_data *)argument;
1993
1994 if (entry->link) {
1995 entry->link = estrdup(entry->link);
1996 }
1997
1998 if (entry->tmp) {
1999 entry->tmp = estrdup(entry->tmp);
2000 }
2001
2002 entry->metadata_str.c = 0;
2003 entry->filename = estrndup(entry->filename, entry->filename_len);
2004 entry->is_persistent = 0;
2005
2006 if (entry->metadata) {
2007 if (entry->metadata_len) {
2008 char *buf = estrndup((char *) entry->metadata, entry->metadata_len);
2009 /* assume success, we would have failed before */
2010 phar_parse_metadata((char **) &buf, &entry->metadata, entry->metadata_len TSRMLS_CC);
2011 efree(buf);
2012 } else {
2013 zval *t;
2014
2015 t = entry->metadata;
2016 ALLOC_ZVAL(entry->metadata);
2017 *entry->metadata = *t;
2018 zval_copy_ctor(entry->metadata);
2019 Z_SET_REFCOUNT_P(entry->metadata, 1);
2020 entry->metadata_str.c = NULL;
2021 entry->metadata_str.len = 0;
2022 }
2023 }
2024 return ZEND_HASH_APPLY_KEEP;
2025 }
2026 /* }}} */
2027
2028 static void phar_copy_cached_phar(phar_archive_data **pphar TSRMLS_DC) /* {{{ */
2029 {
2030 phar_archive_data *phar;
2031 HashTable newmanifest;
2032 char *fname;
2033 phar_archive_object **objphar;
2034
2035 phar = (phar_archive_data *) emalloc(sizeof(phar_archive_data));
2036 *phar = **pphar;
2037 phar->is_persistent = 0;
2038 fname = phar->fname;
2039 phar->fname = estrndup(phar->fname, phar->fname_len);
2040 phar->ext = phar->fname + (phar->ext - fname);
2041
2042 if (phar->alias) {
2043 phar->alias = estrndup(phar->alias, phar->alias_len);
2044 }
2045
2046 if (phar->signature) {
2047 phar->signature = estrdup(phar->signature);
2048 }
2049
2050 if (phar->metadata) {
2051 /* assume success, we would have failed before */
2052 if (phar->metadata_len) {
2053 char *buf = estrndup((char *) phar->metadata, phar->metadata_len);
2054 phar_parse_metadata(&buf, &phar->metadata, phar->metadata_len TSRMLS_CC);
2055 efree(buf);
2056 } else {
2057 zval *t;
2058
2059 t = phar->metadata;
2060 ALLOC_ZVAL(phar->metadata);
2061 *phar->metadata = *t;
2062 zval_copy_ctor(phar->metadata);
2063 Z_SET_REFCOUNT_P(phar->metadata, 1);
2064 }
2065 }
2066
2067 zend_hash_init(&newmanifest, sizeof(phar_entry_info),
2068 zend_get_hash_value, destroy_phar_manifest_entry, 0);
2069 zend_hash_copy(&newmanifest, &(*pphar)->manifest, NULL, NULL, sizeof(phar_entry_info));
2070 zend_hash_apply_with_argument(&newmanifest, (apply_func_arg_t) phar_update_cached_entry, (void *)phar TSRMLS_CC);
2071 phar->manifest = newmanifest;
2072 zend_hash_init(&phar->mounted_dirs, sizeof(char *),
2073 zend_get_hash_value, NULL, 0);
2074 zend_hash_init(&phar->virtual_dirs, sizeof(char *),
2075 zend_get_hash_value, NULL, 0);
2076 zend_hash_copy(&phar->virtual_dirs, &(*pphar)->virtual_dirs, NULL, NULL, sizeof(void *));
2077 *pphar = phar;
2078
2079 /* now, scan the list of persistent Phar objects referencing this phar and update the pointers */
2080 for (zend_hash_internal_pointer_reset(&PHAR_GLOBALS->phar_persist_map);
2081 SUCCESS == zend_hash_get_current_data(&PHAR_GLOBALS->phar_persist_map, (void **) &objphar);
2082 zend_hash_move_forward(&PHAR_GLOBALS->phar_persist_map)) {
2083 if (objphar[0]->arc.archive->fname_len == phar->fname_len && !memcmp(objphar[0]->arc.archive->fname, phar->fname, phar->fname_len)) {
2084 objphar[0]->arc.archive = phar;
2085 }
2086 }
2087 }
2088 /* }}} */
2089
2090 int phar_copy_on_write(phar_archive_data **pphar TSRMLS_DC) /* {{{ */
2091 {
2092 phar_archive_data **newpphar, *newphar = NULL;
2093
2094 if (SUCCESS != zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), (*pphar)->fname, (*pphar)->fname_len, (void *)&newphar, sizeof(phar_archive_data *), (void **)&newpphar)) {
2095 return FAILURE;
2096 }
2097
2098 *newpphar = *pphar;
2099 phar_copy_cached_phar(newpphar TSRMLS_CC);
2100 /* invalidate phar cache */
2101 PHAR_G(last_phar) = NULL;
2102 PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
2103
2104 if (newpphar[0]->alias_len && FAILURE == zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), newpphar[0]->alias, newpphar[0]->alias_len, (void*)newpphar, sizeof(phar_archive_data*), NULL)) {
2105 zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), (*pphar)->fname, (*pphar)->fname_len);
2106 return FAILURE;
2107 }
2108
2109 *pphar = *newpphar;
2110 return SUCCESS;
2111 }
2112 /* }}} */
2113
2114 /*
2115 * Local variables:
2116 * tab-width: 4
2117 * c-basic-offset: 4
2118 * End:
2119 * vim600: noet sw=4 ts=4 fdm=marker
2120 * vim<600: noet sw=4 ts=4
2121 */
2122