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