1 /*
2 +----------------------------------------------------------------------+
3 | phar php single-file executable PHP extension |
4 | utility functions |
5 +----------------------------------------------------------------------+
6 | Copyright (c) 2005-2016 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,const 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, const 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,const 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, const 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 != php_stream_copy_to_stream_ex(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 != php_stream_copy_to_stream_ex(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 != php_stream_copy_to_stream_ex(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 char *str_key;
1308 ulong unused;
1309 uint keylen;
1310
1311 zend_hash_internal_pointer_reset(&phar->mounted_dirs);
1312 while (FAILURE != zend_hash_has_more_elements(&phar->mounted_dirs)) {
1313 if (HASH_KEY_NON_EXISTENT == zend_hash_get_current_key_ex(&phar->mounted_dirs, &str_key, &keylen, &unused, 0, NULL)) {
1314 break;
1315 }
1316
1317 if ((int)keylen >= path_len || strncmp(str_key, path, keylen)) {
1318 continue;
1319 } else {
1320 char *test;
1321 int test_len;
1322 php_stream_statbuf ssb;
1323
1324 if (SUCCESS != zend_hash_find(&phar->manifest, str_key, keylen, (void **) &entry)) {
1325 if (error) {
1326 spprintf(error, 4096, "phar internal error: mounted path \"%s\" could not be retrieved from manifest", str_key);
1327 }
1328 return NULL;
1329 }
1330
1331 if (!entry->tmp || !entry->is_mounted) {
1332 if (error) {
1333 spprintf(error, 4096, "phar internal error: mounted path \"%s\" is not properly initialized as a mounted path", str_key);
1334 }
1335 return NULL;
1336 }
1337
1338 test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->tmp, path + keylen);
1339
1340 if (SUCCESS != php_stream_stat_path(test, &ssb)) {
1341 efree(test);
1342 return NULL;
1343 }
1344
1345 if (ssb.sb.st_mode & S_IFDIR && !dir) {
1346 efree(test);
1347 if (error) {
1348 spprintf(error, 4096, "phar error: path \"%s\" is a directory", path);
1349 }
1350 return NULL;
1351 }
1352
1353 if ((ssb.sb.st_mode & S_IFDIR) == 0 && dir) {
1354 efree(test);
1355 /* user requested a directory, we must return one */
1356 if (error) {
1357 spprintf(error, 4096, "phar error: path \"%s\" exists and is a not a directory", path);
1358 }
1359 return NULL;
1360 }
1361
1362 /* mount the file just in time */
1363 if (SUCCESS != phar_mount_entry(phar, test, test_len, path, path_len TSRMLS_CC)) {
1364 efree(test);
1365 if (error) {
1366 spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be mounted", path, test);
1367 }
1368 return NULL;
1369 }
1370
1371 efree(test);
1372
1373 if (SUCCESS != zend_hash_find(&phar->manifest, path, path_len, (void**)&entry)) {
1374 if (error) {
1375 spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be retrieved after being mounted", path, test);
1376 }
1377 return NULL;
1378 }
1379 return entry;
1380 }
1381 }
1382 }
1383
1384 return NULL;
1385 }
1386 /* }}} */
1387
1388 static const char hexChars[] = "0123456789ABCDEF";
1389
phar_hex_str(const char * digest,size_t digest_len,char ** signature TSRMLS_DC)1390 static int phar_hex_str(const char *digest, size_t digest_len, char **signature TSRMLS_DC) /* {{{ */
1391 {
1392 int pos = -1;
1393 size_t len = 0;
1394
1395 *signature = (char*)safe_pemalloc(digest_len, 2, 1, PHAR_G(persist));
1396
1397 for (; len < digest_len; ++len) {
1398 (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] >> 4];
1399 (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] & 0x0F];
1400 }
1401 (*signature)[++pos] = '\0';
1402 return pos;
1403 }
1404 /* }}} */
1405
1406 #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)1407 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) /* {{{ */
1408 {
1409 zend_fcall_info fci;
1410 zend_fcall_info_cache fcc;
1411 zval *zdata, *zsig, *zkey, *retval_ptr, **zp[3], *openssl;
1412
1413 MAKE_STD_ZVAL(zdata);
1414 MAKE_STD_ZVAL(openssl);
1415 ZVAL_STRINGL(openssl, is_sign ? "openssl_sign" : "openssl_verify", is_sign ? sizeof("openssl_sign")-1 : sizeof("openssl_verify")-1, 1);
1416 MAKE_STD_ZVAL(zsig);
1417 ZVAL_STRINGL(zsig, *signature, *signature_len, 1);
1418 MAKE_STD_ZVAL(zkey);
1419 ZVAL_STRINGL(zkey, key, key_len, 1);
1420 zp[0] = &zdata;
1421 zp[1] = &zsig;
1422 zp[2] = &zkey;
1423
1424 php_stream_rewind(fp);
1425 Z_TYPE_P(zdata) = IS_STRING;
1426 Z_STRLEN_P(zdata) = end;
1427
1428 if (end != (off_t) php_stream_copy_to_mem(fp, &(Z_STRVAL_P(zdata)), (size_t) end, 0)) {
1429 zval_dtor(zdata);
1430 zval_dtor(zsig);
1431 zval_dtor(zkey);
1432 zval_dtor(openssl);
1433 efree(openssl);
1434 efree(zdata);
1435 efree(zkey);
1436 efree(zsig);
1437 return FAILURE;
1438 }
1439
1440 if (FAILURE == zend_fcall_info_init(openssl, 0, &fci, &fcc, NULL, NULL TSRMLS_CC)) {
1441 zval_dtor(zdata);
1442 zval_dtor(zsig);
1443 zval_dtor(zkey);
1444 zval_dtor(openssl);
1445 efree(openssl);
1446 efree(zdata);
1447 efree(zkey);
1448 efree(zsig);
1449 return FAILURE;
1450 }
1451
1452 fci.param_count = 3;
1453 fci.params = zp;
1454 Z_ADDREF_P(zdata);
1455 if (is_sign) {
1456 Z_SET_ISREF_P(zsig);
1457 } else {
1458 Z_ADDREF_P(zsig);
1459 }
1460 Z_ADDREF_P(zkey);
1461
1462 fci.retval_ptr_ptr = &retval_ptr;
1463
1464 if (FAILURE == zend_call_function(&fci, &fcc TSRMLS_CC)) {
1465 zval_dtor(zdata);
1466 zval_dtor(zsig);
1467 zval_dtor(zkey);
1468 zval_dtor(openssl);
1469 efree(openssl);
1470 efree(zdata);
1471 efree(zkey);
1472 efree(zsig);
1473 return FAILURE;
1474 }
1475
1476 zval_dtor(openssl);
1477 efree(openssl);
1478 Z_DELREF_P(zdata);
1479
1480 if (is_sign) {
1481 Z_UNSET_ISREF_P(zsig);
1482 } else {
1483 Z_DELREF_P(zsig);
1484 }
1485 Z_DELREF_P(zkey);
1486
1487 zval_dtor(zdata);
1488 efree(zdata);
1489 zval_dtor(zkey);
1490 efree(zkey);
1491
1492 switch (Z_TYPE_P(retval_ptr)) {
1493 default:
1494 case IS_LONG:
1495 zval_dtor(zsig);
1496 efree(zsig);
1497 if (1 == Z_LVAL_P(retval_ptr)) {
1498 efree(retval_ptr);
1499 return SUCCESS;
1500 }
1501 efree(retval_ptr);
1502 return FAILURE;
1503 case IS_BOOL:
1504 efree(retval_ptr);
1505 if (Z_BVAL_P(retval_ptr)) {
1506 *signature = estrndup(Z_STRVAL_P(zsig), Z_STRLEN_P(zsig));
1507 *signature_len = Z_STRLEN_P(zsig);
1508 zval_dtor(zsig);
1509 efree(zsig);
1510 return SUCCESS;
1511 }
1512 zval_dtor(zsig);
1513 efree(zsig);
1514 return FAILURE;
1515 }
1516 }
1517 /* }}} */
1518 #endif /* #ifndef PHAR_HAVE_OPENSSL */
1519
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)1520 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) /* {{{ */
1521 {
1522 int read_size, len;
1523 off_t read_len;
1524 unsigned char buf[1024];
1525
1526 php_stream_rewind(fp);
1527
1528 switch (sig_type) {
1529 case PHAR_SIG_OPENSSL: {
1530 #ifdef PHAR_HAVE_OPENSSL
1531 BIO *in;
1532 EVP_PKEY *key;
1533 EVP_MD *mdtype = (EVP_MD *) EVP_sha1();
1534 EVP_MD_CTX md_ctx;
1535 #else
1536 int tempsig;
1537 #endif
1538 php_uint32 pubkey_len;
1539 char *pubkey = NULL, *pfile;
1540 php_stream *pfp;
1541 #ifndef PHAR_HAVE_OPENSSL
1542 if (!zend_hash_exists(&module_registry, "openssl", sizeof("openssl"))) {
1543 if (error) {
1544 spprintf(error, 0, "openssl not loaded");
1545 }
1546 return FAILURE;
1547 }
1548 #endif
1549 /* use __FILE__ . '.pubkey' for public key file */
1550 spprintf(&pfile, 0, "%s.pubkey", fname);
1551 pfp = php_stream_open_wrapper(pfile, "rb", 0, NULL);
1552 efree(pfile);
1553
1554 #if PHP_MAJOR_VERSION > 5
1555 if (!pfp || !(pubkey_len = php_stream_copy_to_mem(pfp, (void **) &pubkey, PHP_STREAM_COPY_ALL, 0)) || !pubkey) {
1556 #else
1557 if (!pfp || !(pubkey_len = php_stream_copy_to_mem(pfp, &pubkey, PHP_STREAM_COPY_ALL, 0)) || !pubkey) {
1558 #endif
1559 if (pfp) {
1560 php_stream_close(pfp);
1561 }
1562 if (error) {
1563 spprintf(error, 0, "openssl public key could not be read");
1564 }
1565 return FAILURE;
1566 }
1567
1568 php_stream_close(pfp);
1569 #ifndef PHAR_HAVE_OPENSSL
1570 tempsig = sig_len;
1571
1572 if (FAILURE == phar_call_openssl_signverify(0, fp, end_of_phar, pubkey, pubkey_len, &sig, &tempsig TSRMLS_CC)) {
1573 if (pubkey) {
1574 efree(pubkey);
1575 }
1576
1577 if (error) {
1578 spprintf(error, 0, "openssl signature could not be verified");
1579 }
1580
1581 return FAILURE;
1582 }
1583
1584 if (pubkey) {
1585 efree(pubkey);
1586 }
1587
1588 sig_len = tempsig;
1589 #else
1590 in = BIO_new_mem_buf(pubkey, pubkey_len);
1591
1592 if (NULL == in) {
1593 efree(pubkey);
1594 if (error) {
1595 spprintf(error, 0, "openssl signature could not be processed");
1596 }
1597 return FAILURE;
1598 }
1599
1600 key = PEM_read_bio_PUBKEY(in, NULL,NULL, NULL);
1601 BIO_free(in);
1602 efree(pubkey);
1603
1604 if (NULL == key) {
1605 if (error) {
1606 spprintf(error, 0, "openssl signature could not be processed");
1607 }
1608 return FAILURE;
1609 }
1610
1611 EVP_VerifyInit(&md_ctx, mdtype);
1612 read_len = end_of_phar;
1613
1614 if (read_len > sizeof(buf)) {
1615 read_size = sizeof(buf);
1616 } else {
1617 read_size = (int)read_len;
1618 }
1619
1620 php_stream_seek(fp, 0, SEEK_SET);
1621
1622 while (read_size && (len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
1623 EVP_VerifyUpdate (&md_ctx, buf, len);
1624 read_len -= (off_t)len;
1625
1626 if (read_len < read_size) {
1627 read_size = (int)read_len;
1628 }
1629 }
1630
1631 if (EVP_VerifyFinal(&md_ctx, (unsigned char *)sig, sig_len, key) != 1) {
1632 /* 1: signature verified, 0: signature does not match, -1: failed signature operation */
1633 EVP_MD_CTX_cleanup(&md_ctx);
1634
1635 if (error) {
1636 spprintf(error, 0, "broken openssl signature");
1637 }
1638
1639 return FAILURE;
1640 }
1641
1642 EVP_MD_CTX_cleanup(&md_ctx);
1643 #endif
1644
1645 *signature_len = phar_hex_str((const char*)sig, sig_len, signature TSRMLS_CC);
1646 }
1647 break;
1648 #ifdef PHAR_HASH_OK
1649 case PHAR_SIG_SHA512: {
1650 unsigned char digest[64];
1651 PHP_SHA512_CTX context;
1652
1653 if (sig_len < sizeof(digest)) {
1654 if (error) {
1655 spprintf(error, 0, "broken signature");
1656 }
1657 return FAILURE;
1658 }
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 if (sig_len < sizeof(digest)) {
1694 if (error) {
1695 spprintf(error, 0, "broken signature");
1696 }
1697 return FAILURE;
1698 }
1699
1700 PHP_SHA256Init(&context);
1701 read_len = end_of_phar;
1702
1703 if (read_len > sizeof(buf)) {
1704 read_size = sizeof(buf);
1705 } else {
1706 read_size = (int)read_len;
1707 }
1708
1709 while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
1710 PHP_SHA256Update(&context, buf, len);
1711 read_len -= (off_t)len;
1712 if (read_len < read_size) {
1713 read_size = (int)read_len;
1714 }
1715 }
1716
1717 PHP_SHA256Final(digest, &context);
1718
1719 if (memcmp(digest, sig, sizeof(digest))) {
1720 if (error) {
1721 spprintf(error, 0, "broken signature");
1722 }
1723 return FAILURE;
1724 }
1725
1726 *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
1727 break;
1728 }
1729 #else
1730 case PHAR_SIG_SHA512:
1731 case PHAR_SIG_SHA256:
1732 if (error) {
1733 spprintf(error, 0, "unsupported signature");
1734 }
1735 return FAILURE;
1736 #endif
1737 case PHAR_SIG_SHA1: {
1738 unsigned char digest[20];
1739 PHP_SHA1_CTX context;
1740
1741 if (sig_len < sizeof(digest)) {
1742 if (error) {
1743 spprintf(error, 0, "broken signature");
1744 }
1745 return FAILURE;
1746 }
1747
1748 PHP_SHA1Init(&context);
1749 read_len = end_of_phar;
1750
1751 if (read_len > sizeof(buf)) {
1752 read_size = sizeof(buf);
1753 } else {
1754 read_size = (int)read_len;
1755 }
1756
1757 while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
1758 PHP_SHA1Update(&context, buf, len);
1759 read_len -= (off_t)len;
1760 if (read_len < read_size) {
1761 read_size = (int)read_len;
1762 }
1763 }
1764
1765 PHP_SHA1Final(digest, &context);
1766
1767 if (memcmp(digest, sig, sizeof(digest))) {
1768 if (error) {
1769 spprintf(error, 0, "broken signature");
1770 }
1771 return FAILURE;
1772 }
1773
1774 *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
1775 break;
1776 }
1777 case PHAR_SIG_MD5: {
1778 unsigned char digest[16];
1779 PHP_MD5_CTX context;
1780
1781 if (sig_len < sizeof(digest)) {
1782 if (error) {
1783 spprintf(error, 0, "broken signature");
1784 }
1785 return FAILURE;
1786 }
1787
1788 PHP_MD5Init(&context);
1789 read_len = end_of_phar;
1790
1791 if (read_len > sizeof(buf)) {
1792 read_size = sizeof(buf);
1793 } else {
1794 read_size = (int)read_len;
1795 }
1796
1797 while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
1798 PHP_MD5Update(&context, buf, len);
1799 read_len -= (off_t)len;
1800 if (read_len < read_size) {
1801 read_size = (int)read_len;
1802 }
1803 }
1804
1805 PHP_MD5Final(digest, &context);
1806
1807 if (memcmp(digest, sig, sizeof(digest))) {
1808 if (error) {
1809 spprintf(error, 0, "broken signature");
1810 }
1811 return FAILURE;
1812 }
1813
1814 *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
1815 break;
1816 }
1817 default:
1818 if (error) {
1819 spprintf(error, 0, "broken or unsupported signature");
1820 }
1821 return FAILURE;
1822 }
1823 return SUCCESS;
1824 }
1825 /* }}} */
1826
1827 int phar_create_signature(phar_archive_data *phar, php_stream *fp, char **signature, int *signature_length, char **error TSRMLS_DC) /* {{{ */
1828 {
1829 unsigned char buf[1024];
1830 int sig_len;
1831
1832 php_stream_rewind(fp);
1833
1834 if (phar->signature) {
1835 efree(phar->signature);
1836 phar->signature = NULL;
1837 }
1838
1839 switch(phar->sig_flags) {
1840 #ifdef PHAR_HASH_OK
1841 case PHAR_SIG_SHA512: {
1842 unsigned char digest[64];
1843 PHP_SHA512_CTX context;
1844
1845 PHP_SHA512Init(&context);
1846
1847 while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
1848 PHP_SHA512Update(&context, buf, sig_len);
1849 }
1850
1851 PHP_SHA512Final(digest, &context);
1852 *signature = estrndup((char *) digest, 64);
1853 *signature_length = 64;
1854 break;
1855 }
1856 case PHAR_SIG_SHA256: {
1857 unsigned char digest[32];
1858 PHP_SHA256_CTX context;
1859
1860 PHP_SHA256Init(&context);
1861
1862 while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
1863 PHP_SHA256Update(&context, buf, sig_len);
1864 }
1865
1866 PHP_SHA256Final(digest, &context);
1867 *signature = estrndup((char *) digest, 32);
1868 *signature_length = 32;
1869 break;
1870 }
1871 #else
1872 case PHAR_SIG_SHA512:
1873 case PHAR_SIG_SHA256:
1874 if (error) {
1875 spprintf(error, 0, "unable to write to phar \"%s\" with requested hash type", phar->fname);
1876 }
1877
1878 return FAILURE;
1879 #endif
1880 case PHAR_SIG_OPENSSL: {
1881 int siglen;
1882 unsigned char *sigbuf;
1883 #ifdef PHAR_HAVE_OPENSSL
1884 BIO *in;
1885 EVP_PKEY *key;
1886 EVP_MD_CTX *md_ctx;
1887
1888 in = BIO_new_mem_buf(PHAR_G(openssl_privatekey), PHAR_G(openssl_privatekey_len));
1889
1890 if (in == NULL) {
1891 if (error) {
1892 spprintf(error, 0, "unable to write to phar \"%s\" with requested openssl signature", phar->fname);
1893 }
1894 return FAILURE;
1895 }
1896
1897 key = PEM_read_bio_PrivateKey(in, NULL,NULL, "");
1898 BIO_free(in);
1899
1900 if (!key) {
1901 if (error) {
1902 spprintf(error, 0, "unable to process private key");
1903 }
1904 return FAILURE;
1905 }
1906
1907 md_ctx = EVP_MD_CTX_create();
1908
1909 siglen = EVP_PKEY_size(key);
1910 sigbuf = emalloc(siglen + 1);
1911
1912 if (!EVP_SignInit(md_ctx, EVP_sha1())) {
1913 efree(sigbuf);
1914 if (error) {
1915 spprintf(error, 0, "unable to initialize openssl signature for phar \"%s\"", phar->fname);
1916 }
1917 return FAILURE;
1918 }
1919
1920 while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
1921 if (!EVP_SignUpdate(md_ctx, buf, sig_len)) {
1922 efree(sigbuf);
1923 if (error) {
1924 spprintf(error, 0, "unable to update the openssl signature for phar \"%s\"", phar->fname);
1925 }
1926 return FAILURE;
1927 }
1928 }
1929
1930 if (!EVP_SignFinal (md_ctx, sigbuf,(unsigned int *)&siglen, key)) {
1931 efree(sigbuf);
1932 if (error) {
1933 spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname);
1934 }
1935 return FAILURE;
1936 }
1937
1938 sigbuf[siglen] = '\0';
1939 EVP_MD_CTX_destroy(md_ctx);
1940 #else
1941 sigbuf = NULL;
1942 siglen = 0;
1943 php_stream_seek(fp, 0, SEEK_END);
1944
1945 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)) {
1946 if (error) {
1947 spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname);
1948 }
1949 return FAILURE;
1950 }
1951 #endif
1952 *signature = (char *) sigbuf;
1953 *signature_length = siglen;
1954 }
1955 break;
1956 default:
1957 phar->sig_flags = PHAR_SIG_SHA1;
1958 case PHAR_SIG_SHA1: {
1959 unsigned char digest[20];
1960 PHP_SHA1_CTX context;
1961
1962 PHP_SHA1Init(&context);
1963
1964 while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
1965 PHP_SHA1Update(&context, buf, sig_len);
1966 }
1967
1968 PHP_SHA1Final(digest, &context);
1969 *signature = estrndup((char *) digest, 20);
1970 *signature_length = 20;
1971 break;
1972 }
1973 case PHAR_SIG_MD5: {
1974 unsigned char digest[16];
1975 PHP_MD5_CTX context;
1976
1977 PHP_MD5Init(&context);
1978
1979 while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
1980 PHP_MD5Update(&context, buf, sig_len);
1981 }
1982
1983 PHP_MD5Final(digest, &context);
1984 *signature = estrndup((char *) digest, 16);
1985 *signature_length = 16;
1986 break;
1987 }
1988 }
1989
1990 phar->sig_len = phar_hex_str((const char *)*signature, *signature_length, &phar->signature TSRMLS_CC);
1991 return SUCCESS;
1992 }
1993 /* }}} */
1994
1995 void phar_add_virtual_dirs(phar_archive_data *phar, char *filename, int filename_len TSRMLS_DC) /* {{{ */
1996 {
1997 const char *s;
1998
1999 while ((s = zend_memrchr(filename, '/', filename_len))) {
2000 filename_len = s - filename;
2001 if (!filename_len || FAILURE == zend_hash_add_empty_element(&phar->virtual_dirs, filename, filename_len)) {
2002 break;
2003 }
2004 }
2005 }
2006 /* }}} */
2007
2008 static int phar_update_cached_entry(void *data, void *argument) /* {{{ */
2009 {
2010 phar_entry_info *entry = (phar_entry_info *)data;
2011 TSRMLS_FETCH();
2012
2013 entry->phar = (phar_archive_data *)argument;
2014
2015 if (entry->link) {
2016 entry->link = estrdup(entry->link);
2017 }
2018
2019 if (entry->tmp) {
2020 entry->tmp = estrdup(entry->tmp);
2021 }
2022
2023 entry->metadata_str.c = 0;
2024 entry->filename = estrndup(entry->filename, entry->filename_len);
2025 entry->is_persistent = 0;
2026
2027 if (entry->metadata) {
2028 if (entry->metadata_len) {
2029 char *buf = estrndup((char *) entry->metadata, entry->metadata_len);
2030 /* assume success, we would have failed before */
2031 phar_parse_metadata((char **) &buf, &entry->metadata, entry->metadata_len TSRMLS_CC);
2032 efree(buf);
2033 } else {
2034 zval *t;
2035
2036 t = entry->metadata;
2037 ALLOC_ZVAL(entry->metadata);
2038 *entry->metadata = *t;
2039 zval_copy_ctor(entry->metadata);
2040 Z_SET_REFCOUNT_P(entry->metadata, 1);
2041 entry->metadata_str.c = NULL;
2042 entry->metadata_str.len = 0;
2043 }
2044 }
2045 return ZEND_HASH_APPLY_KEEP;
2046 }
2047 /* }}} */
2048
2049 static void phar_copy_cached_phar(phar_archive_data **pphar TSRMLS_DC) /* {{{ */
2050 {
2051 phar_archive_data *phar;
2052 HashTable newmanifest;
2053 char *fname;
2054 phar_archive_object **objphar;
2055
2056 phar = (phar_archive_data *) emalloc(sizeof(phar_archive_data));
2057 *phar = **pphar;
2058 phar->is_persistent = 0;
2059 fname = phar->fname;
2060 phar->fname = estrndup(phar->fname, phar->fname_len);
2061 phar->ext = phar->fname + (phar->ext - fname);
2062
2063 if (phar->alias) {
2064 phar->alias = estrndup(phar->alias, phar->alias_len);
2065 }
2066
2067 if (phar->signature) {
2068 phar->signature = estrdup(phar->signature);
2069 }
2070
2071 if (phar->metadata) {
2072 /* assume success, we would have failed before */
2073 if (phar->metadata_len) {
2074 char *buf = estrndup((char *) phar->metadata, phar->metadata_len);
2075 phar_parse_metadata(&buf, &phar->metadata, phar->metadata_len TSRMLS_CC);
2076 efree(buf);
2077 } else {
2078 zval *t;
2079
2080 t = phar->metadata;
2081 ALLOC_ZVAL(phar->metadata);
2082 *phar->metadata = *t;
2083 zval_copy_ctor(phar->metadata);
2084 Z_SET_REFCOUNT_P(phar->metadata, 1);
2085 }
2086 }
2087
2088 zend_hash_init(&newmanifest, sizeof(phar_entry_info),
2089 zend_get_hash_value, destroy_phar_manifest_entry, 0);
2090 zend_hash_copy(&newmanifest, &(*pphar)->manifest, NULL, NULL, sizeof(phar_entry_info));
2091 zend_hash_apply_with_argument(&newmanifest, (apply_func_arg_t) phar_update_cached_entry, (void *)phar TSRMLS_CC);
2092 phar->manifest = newmanifest;
2093 zend_hash_init(&phar->mounted_dirs, sizeof(char *),
2094 zend_get_hash_value, NULL, 0);
2095 zend_hash_init(&phar->virtual_dirs, sizeof(char *),
2096 zend_get_hash_value, NULL, 0);
2097 zend_hash_copy(&phar->virtual_dirs, &(*pphar)->virtual_dirs, NULL, NULL, sizeof(void *));
2098 *pphar = phar;
2099
2100 /* now, scan the list of persistent Phar objects referencing this phar and update the pointers */
2101 for (zend_hash_internal_pointer_reset(&PHAR_GLOBALS->phar_persist_map);
2102 SUCCESS == zend_hash_get_current_data(&PHAR_GLOBALS->phar_persist_map, (void **) &objphar);
2103 zend_hash_move_forward(&PHAR_GLOBALS->phar_persist_map)) {
2104 if (objphar[0]->arc.archive->fname_len == phar->fname_len && !memcmp(objphar[0]->arc.archive->fname, phar->fname, phar->fname_len)) {
2105 objphar[0]->arc.archive = phar;
2106 }
2107 }
2108 }
2109 /* }}} */
2110
2111 int phar_copy_on_write(phar_archive_data **pphar TSRMLS_DC) /* {{{ */
2112 {
2113 phar_archive_data **newpphar, *newphar = NULL;
2114
2115 if (SUCCESS != zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), (*pphar)->fname, (*pphar)->fname_len, (void *)&newphar, sizeof(phar_archive_data *), (void **)&newpphar)) {
2116 return FAILURE;
2117 }
2118
2119 *newpphar = *pphar;
2120 phar_copy_cached_phar(newpphar TSRMLS_CC);
2121 /* invalidate phar cache */
2122 PHAR_G(last_phar) = NULL;
2123 PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
2124
2125 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)) {
2126 zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), (*pphar)->fname, (*pphar)->fname_len);
2127 return FAILURE;
2128 }
2129
2130 *pphar = *newpphar;
2131 return SUCCESS;
2132 }
2133 /* }}} */
2134
2135 /*
2136 * Local variables:
2137 * tab-width: 4
2138 * c-basic-offset: 4
2139 * End:
2140 * vim600: noet sw=4 ts=4 fdm=marker
2141 * vim<600: noet sw=4 ts=4
2142 */
2143