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