Annotation of embedaddon/php/ext/phar/util.c, revision 1.1.1.4
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | phar php single-file executable PHP extension |
4: | utility functions |
5: +----------------------------------------------------------------------+
1.1.1.4 ! misho 6: | Copyright (c) 2005-2014 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)) {
1.1.1.4 ! misho 1265: if (error) {
! 1266: efree(*error);
! 1267: *error = NULL;
! 1268: }
1.1 misho 1269: }
1270: return FAILURE;
1271: }
1272:
1273: *archive = *fd_ptr;
1274: fd = *fd_ptr;
1275: PHAR_G(last_phar) = fd;
1276: PHAR_G(last_phar_name) = fd->fname;
1277: PHAR_G(last_phar_name_len) = fd->fname_len;
1278: PHAR_G(last_alias) = alias;
1279: PHAR_G(last_alias_len) = alias_len;
1280:
1281: return SUCCESS;
1282: }
1283:
1284: if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_alias, alias, alias_len, ahash, (void **)&fd_ptr)) {
1285: goto alias_success;
1286: }
1287: }
1288:
1289: fhash = zend_inline_hash_func(fname, fname_len);
1290: my_realpath = NULL;
1291: save = fname;
1292: save_len = fname_len;
1293:
1294: if (fname && fname_len) {
1295: if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, fhash, (void**)&fd_ptr)) {
1296: *archive = *fd_ptr;
1297: fd = *fd_ptr;
1298:
1299: if (alias && alias_len) {
1300: if (!fd->is_temporary_alias && (alias_len != fd->alias_len || memcmp(fd->alias, alias, alias_len))) {
1301: if (error) {
1302: spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
1303: }
1304: return FAILURE;
1305: }
1306:
1307: if (fd->alias_len && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), fd->alias, fd->alias_len, (void**)&fd_ptr)) {
1308: zend_hash_del(&(PHAR_GLOBALS->phar_alias_map), fd->alias, fd->alias_len);
1309: }
1310:
1311: zend_hash_quick_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void*)&fd, sizeof(phar_archive_data*), NULL);
1312: }
1313:
1314: PHAR_G(last_phar) = fd;
1315: PHAR_G(last_phar_name) = fd->fname;
1316: PHAR_G(last_phar_name_len) = fd->fname_len;
1317: PHAR_G(last_alias) = fd->alias;
1318: PHAR_G(last_alias_len) = fd->alias_len;
1319:
1320: return SUCCESS;
1321: }
1322:
1323: if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_phars, fname, fname_len, fhash, (void**)&fd_ptr)) {
1324: *archive = *fd_ptr;
1325: fd = *fd_ptr;
1326:
1327: /* this could be problematic - alias should never be different from manifest alias
1328: for cached phars */
1329: if (!fd->is_temporary_alias && alias && alias_len) {
1330: if (alias_len != fd->alias_len || memcmp(fd->alias, alias, alias_len)) {
1331: if (error) {
1332: spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
1333: }
1334: return FAILURE;
1335: }
1336: }
1337:
1338: PHAR_G(last_phar) = fd;
1339: PHAR_G(last_phar_name) = fd->fname;
1340: PHAR_G(last_phar_name_len) = fd->fname_len;
1341: PHAR_G(last_alias) = fd->alias;
1342: PHAR_G(last_alias_len) = fd->alias_len;
1343:
1344: return SUCCESS;
1345: }
1346:
1347: if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_alias_map), save, save_len, fhash, (void**)&fd_ptr)) {
1348: fd = *archive = *fd_ptr;
1349:
1350: PHAR_G(last_phar) = fd;
1351: PHAR_G(last_phar_name) = fd->fname;
1352: PHAR_G(last_phar_name_len) = fd->fname_len;
1353: PHAR_G(last_alias) = fd->alias;
1354: PHAR_G(last_alias_len) = fd->alias_len;
1355:
1356: return SUCCESS;
1357: }
1358:
1359: if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_alias, save, save_len, fhash, (void**)&fd_ptr)) {
1360: fd = *archive = *fd_ptr;
1361:
1362: PHAR_G(last_phar) = fd;
1363: PHAR_G(last_phar_name) = fd->fname;
1364: PHAR_G(last_phar_name_len) = fd->fname_len;
1365: PHAR_G(last_alias) = fd->alias;
1366: PHAR_G(last_alias_len) = fd->alias_len;
1367:
1368: return SUCCESS;
1369: }
1370:
1371: /* not found, try converting \ to / */
1372: my_realpath = expand_filepath(fname, my_realpath TSRMLS_CC);
1373:
1374: if (my_realpath) {
1375: fname_len = strlen(my_realpath);
1376: fname = my_realpath;
1377: } else {
1378: return FAILURE;
1379: }
1380: #ifdef PHP_WIN32
1381: phar_unixify_path_separators(fname, fname_len);
1382: #endif
1383: fhash = zend_inline_hash_func(fname, fname_len);
1384:
1385: if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, fhash, (void**)&fd_ptr)) {
1386: realpath_success:
1387: *archive = *fd_ptr;
1388: fd = *fd_ptr;
1389:
1390: if (alias && alias_len) {
1391: zend_hash_quick_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void*)&fd, sizeof(phar_archive_data*), NULL);
1392: }
1393:
1394: efree(my_realpath);
1395:
1396: PHAR_G(last_phar) = fd;
1397: PHAR_G(last_phar_name) = fd->fname;
1398: PHAR_G(last_phar_name_len) = fd->fname_len;
1399: PHAR_G(last_alias) = fd->alias;
1400: PHAR_G(last_alias_len) = fd->alias_len;
1401:
1402: return SUCCESS;
1403: }
1404:
1405: if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_phars, fname, fname_len, fhash, (void**)&fd_ptr)) {
1406: goto realpath_success;
1407: }
1408:
1409: efree(my_realpath);
1410: }
1411:
1412: return FAILURE;
1413: }
1414: /* }}} */
1415:
1416: /**
1417: * Determine which stream compression filter (if any) we need to read this file
1418: */
1419: char * phar_compress_filter(phar_entry_info * entry, int return_unknown) /* {{{ */
1420: {
1421: switch (entry->flags & PHAR_ENT_COMPRESSION_MASK) {
1422: case PHAR_ENT_COMPRESSED_GZ:
1423: return "zlib.deflate";
1424: case PHAR_ENT_COMPRESSED_BZ2:
1425: return "bzip2.compress";
1426: default:
1427: return return_unknown ? "unknown" : NULL;
1428: }
1429: }
1430: /* }}} */
1431:
1432: /**
1433: * Determine which stream decompression filter (if any) we need to read this file
1434: */
1435: char * phar_decompress_filter(phar_entry_info * entry, int return_unknown) /* {{{ */
1436: {
1437: php_uint32 flags;
1438:
1439: if (entry->is_modified) {
1440: flags = entry->old_flags;
1441: } else {
1442: flags = entry->flags;
1443: }
1444:
1445: switch (flags & PHAR_ENT_COMPRESSION_MASK) {
1446: case PHAR_ENT_COMPRESSED_GZ:
1447: return "zlib.inflate";
1448: case PHAR_ENT_COMPRESSED_BZ2:
1449: return "bzip2.decompress";
1450: default:
1451: return return_unknown ? "unknown" : NULL;
1452: }
1453: }
1454: /* }}} */
1455:
1456: /**
1457: * retrieve information on a file contained within a phar, or null if it ain't there
1458: */
1459: phar_entry_info *phar_get_entry_info(phar_archive_data *phar, char *path, int path_len, char **error, int security TSRMLS_DC) /* {{{ */
1460: {
1461: return phar_get_entry_info_dir(phar, path, path_len, 0, error, security TSRMLS_CC);
1462: }
1463: /* }}} */
1464: /**
1465: * retrieve information on a file or directory contained within a phar, or null if none found
1466: * allow_dir is 0 for none, 1 for both empty directories in the phar and temp directories, and 2 for only
1467: * valid pre-existing empty directory entries
1468: */
1469: 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) /* {{{ */
1470: {
1471: const char *pcr_error;
1472: phar_entry_info *entry;
1473: int is_dir;
1474:
1475: #ifdef PHP_WIN32
1476: phar_unixify_path_separators(path, path_len);
1477: #endif
1478:
1479: is_dir = (path_len && (path[path_len - 1] == '/')) ? 1 : 0;
1480:
1481: if (error) {
1482: *error = NULL;
1483: }
1484:
1485: if (security && path_len >= sizeof(".phar")-1 && !memcmp(path, ".phar", sizeof(".phar")-1)) {
1486: if (error) {
1487: spprintf(error, 4096, "phar error: cannot directly access magic \".phar\" directory or files within it");
1488: }
1489: return NULL;
1490: }
1491:
1492: if (!path_len && !dir) {
1493: if (error) {
1494: spprintf(error, 4096, "phar error: invalid path \"%s\" must not be empty", path);
1495: }
1496: return NULL;
1497: }
1498:
1499: if (phar_path_check(&path, &path_len, &pcr_error) > pcr_is_ok) {
1500: if (error) {
1501: spprintf(error, 4096, "phar error: invalid path \"%s\" contains %s", path, pcr_error);
1502: }
1503: return NULL;
1504: }
1505:
1506: if (!phar->manifest.arBuckets) {
1507: return NULL;
1508: }
1509:
1510: if (is_dir) {
1511: if (!path_len || path_len == 1) {
1512: return NULL;
1513: }
1514: path_len--;
1515: }
1516:
1517: if (SUCCESS == zend_hash_find(&phar->manifest, path, path_len, (void**)&entry)) {
1518: if (entry->is_deleted) {
1519: /* entry is deleted, but has not been flushed to disk yet */
1520: return NULL;
1521: }
1522: if (entry->is_dir && !dir) {
1523: if (error) {
1524: spprintf(error, 4096, "phar error: path \"%s\" is a directory", path);
1525: }
1526: return NULL;
1527: }
1528: if (!entry->is_dir && dir == 2) {
1529: /* user requested a directory, we must return one */
1530: if (error) {
1531: spprintf(error, 4096, "phar error: path \"%s\" exists and is a not a directory", path);
1532: }
1533: return NULL;
1534: }
1535: return entry;
1536: }
1537:
1538: if (dir) {
1539: if (zend_hash_exists(&phar->virtual_dirs, path, path_len)) {
1540: /* a file or directory exists in a sub-directory of this path */
1541: entry = (phar_entry_info *) ecalloc(1, sizeof(phar_entry_info));
1542: /* this next line tells PharFileInfo->__destruct() to efree the filename */
1543: entry->is_temp_dir = entry->is_dir = 1;
1544: entry->filename = (char *) estrndup(path, path_len + 1);
1545: entry->filename_len = path_len;
1546: entry->phar = phar;
1547: return entry;
1548: }
1549: }
1550:
1551: if (phar->mounted_dirs.arBuckets && zend_hash_num_elements(&phar->mounted_dirs)) {
1552: phar_zstr key;
1553: char *str_key;
1554: ulong unused;
1555: uint keylen;
1556:
1557: zend_hash_internal_pointer_reset(&phar->mounted_dirs);
1558: while (FAILURE != zend_hash_has_more_elements(&phar->mounted_dirs)) {
1559: if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&phar->mounted_dirs, &key, &keylen, &unused, 0, NULL)) {
1560: break;
1561: }
1562:
1563: PHAR_STR(key, str_key);
1564:
1565: if ((int)keylen >= path_len || strncmp(str_key, path, keylen)) {
1566: PHAR_STR_FREE(str_key);
1567: continue;
1568: } else {
1569: char *test;
1570: int test_len;
1571: php_stream_statbuf ssb;
1572:
1573: if (SUCCESS != zend_hash_find(&phar->manifest, str_key, keylen, (void **) &entry)) {
1574: if (error) {
1575: spprintf(error, 4096, "phar internal error: mounted path \"%s\" could not be retrieved from manifest", str_key);
1576: }
1577: PHAR_STR_FREE(str_key);
1578: return NULL;
1579: }
1580:
1581: if (!entry->tmp || !entry->is_mounted) {
1582: if (error) {
1583: spprintf(error, 4096, "phar internal error: mounted path \"%s\" is not properly initialized as a mounted path", str_key);
1584: }
1585: PHAR_STR_FREE(str_key);
1586: return NULL;
1587: }
1588: PHAR_STR_FREE(str_key);
1589:
1590: test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->tmp, path + keylen);
1591:
1592: if (SUCCESS != php_stream_stat_path(test, &ssb)) {
1593: efree(test);
1594: return NULL;
1595: }
1596:
1597: if (ssb.sb.st_mode & S_IFDIR && !dir) {
1598: efree(test);
1599: if (error) {
1600: spprintf(error, 4096, "phar error: path \"%s\" is a directory", path);
1601: }
1602: return NULL;
1603: }
1604:
1605: if ((ssb.sb.st_mode & S_IFDIR) == 0 && dir) {
1606: efree(test);
1607: /* user requested a directory, we must return one */
1608: if (error) {
1609: spprintf(error, 4096, "phar error: path \"%s\" exists and is a not a directory", path);
1610: }
1611: return NULL;
1612: }
1613:
1614: /* mount the file just in time */
1615: if (SUCCESS != phar_mount_entry(phar, test, test_len, path, path_len TSRMLS_CC)) {
1616: efree(test);
1617: if (error) {
1618: spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be mounted", path, test);
1619: }
1620: return NULL;
1621: }
1622:
1623: efree(test);
1624:
1625: if (SUCCESS != zend_hash_find(&phar->manifest, path, path_len, (void**)&entry)) {
1626: if (error) {
1627: spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be retrieved after being mounted", path, test);
1628: }
1629: return NULL;
1630: }
1631: return entry;
1632: }
1633: }
1634: }
1635:
1636: return NULL;
1637: }
1638: /* }}} */
1639:
1640: static const char hexChars[] = "0123456789ABCDEF";
1641:
1642: static int phar_hex_str(const char *digest, size_t digest_len, char **signature TSRMLS_DC) /* {{{ */
1643: {
1644: int pos = -1;
1645: size_t len = 0;
1646:
1647: *signature = (char*)safe_pemalloc(digest_len, 2, 1, PHAR_G(persist));
1648:
1649: for (; len < digest_len; ++len) {
1650: (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] >> 4];
1651: (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] & 0x0F];
1652: }
1653: (*signature)[++pos] = '\0';
1654: return pos;
1655: }
1656: /* }}} */
1657:
1658: #ifndef PHAR_HAVE_OPENSSL
1659: 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) /* {{{ */
1660: {
1661: zend_fcall_info fci;
1662: zend_fcall_info_cache fcc;
1663: zval *zdata, *zsig, *zkey, *retval_ptr, **zp[3], *openssl;
1664:
1665: MAKE_STD_ZVAL(zdata);
1666: MAKE_STD_ZVAL(openssl);
1667: ZVAL_STRINGL(openssl, is_sign ? "openssl_sign" : "openssl_verify", is_sign ? sizeof("openssl_sign")-1 : sizeof("openssl_verify")-1, 1);
1668: MAKE_STD_ZVAL(zsig);
1669: ZVAL_STRINGL(zsig, *signature, *signature_len, 1);
1670: MAKE_STD_ZVAL(zkey);
1671: ZVAL_STRINGL(zkey, key, key_len, 1);
1672: zp[0] = &zdata;
1673: zp[1] = &zsig;
1674: zp[2] = &zkey;
1675:
1676: php_stream_rewind(fp);
1677: Z_TYPE_P(zdata) = IS_STRING;
1678: Z_STRLEN_P(zdata) = end;
1679:
1680: #if PHP_MAJOR_VERSION > 5
1681: if (end != (off_t) php_stream_copy_to_mem(fp, (void **) &(Z_STRVAL_P(zdata)), (size_t) end, 0)) {
1682: #else
1683: if (end != (off_t) php_stream_copy_to_mem(fp, &(Z_STRVAL_P(zdata)), (size_t) end, 0)) {
1684: #endif
1685: zval_dtor(zdata);
1686: zval_dtor(zsig);
1687: zval_dtor(zkey);
1688: zval_dtor(openssl);
1689: efree(openssl);
1690: efree(zdata);
1691: efree(zkey);
1692: efree(zsig);
1693: return FAILURE;
1694: }
1695:
1696: #if PHP_VERSION_ID < 50300
1697: if (FAILURE == zend_fcall_info_init(openssl, &fci, &fcc TSRMLS_CC)) {
1698: #else
1699: if (FAILURE == zend_fcall_info_init(openssl, 0, &fci, &fcc, NULL, NULL TSRMLS_CC)) {
1700: #endif
1701: zval_dtor(zdata);
1702: zval_dtor(zsig);
1703: zval_dtor(zkey);
1704: zval_dtor(openssl);
1705: efree(openssl);
1706: efree(zdata);
1707: efree(zkey);
1708: efree(zsig);
1709: return FAILURE;
1710: }
1711:
1712: fci.param_count = 3;
1713: fci.params = zp;
1714: #if PHP_VERSION_ID < 50300
1715: ++(zdata->refcount);
1716: if (!is_sign) {
1717: ++(zsig->refcount);
1718: }
1719: ++(zkey->refcount);
1720: #else
1721: Z_ADDREF_P(zdata);
1722: if (is_sign) {
1723: Z_SET_ISREF_P(zsig);
1724: } else {
1725: Z_ADDREF_P(zsig);
1726: }
1727: Z_ADDREF_P(zkey);
1728: #endif
1729: fci.retval_ptr_ptr = &retval_ptr;
1730:
1731: if (FAILURE == zend_call_function(&fci, &fcc TSRMLS_CC)) {
1732: zval_dtor(zdata);
1733: zval_dtor(zsig);
1734: zval_dtor(zkey);
1735: zval_dtor(openssl);
1736: efree(openssl);
1737: efree(zdata);
1738: efree(zkey);
1739: efree(zsig);
1740: return FAILURE;
1741: }
1742:
1743: zval_dtor(openssl);
1744: efree(openssl);
1745: #if PHP_VERSION_ID < 50300
1746: --(zdata->refcount);
1747: if (!is_sign) {
1748: --(zsig->refcount);
1749: }
1750: --(zkey->refcount);
1751: #else
1752: Z_DELREF_P(zdata);
1753: if (is_sign) {
1754: Z_UNSET_ISREF_P(zsig);
1755: } else {
1756: Z_DELREF_P(zsig);
1757: }
1758: Z_DELREF_P(zkey);
1759: #endif
1760: zval_dtor(zdata);
1761: efree(zdata);
1762: zval_dtor(zkey);
1763: efree(zkey);
1764:
1765: switch (Z_TYPE_P(retval_ptr)) {
1766: default:
1767: case IS_LONG:
1768: zval_dtor(zsig);
1769: efree(zsig);
1770: if (1 == Z_LVAL_P(retval_ptr)) {
1771: efree(retval_ptr);
1772: return SUCCESS;
1773: }
1774: efree(retval_ptr);
1775: return FAILURE;
1776: case IS_BOOL:
1777: efree(retval_ptr);
1778: if (Z_BVAL_P(retval_ptr)) {
1779: *signature = estrndup(Z_STRVAL_P(zsig), Z_STRLEN_P(zsig));
1780: *signature_len = Z_STRLEN_P(zsig);
1781: zval_dtor(zsig);
1782: efree(zsig);
1783: return SUCCESS;
1784: }
1785: zval_dtor(zsig);
1786: efree(zsig);
1787: return FAILURE;
1788: }
1789: }
1790: /* }}} */
1791: #endif /* #ifndef PHAR_HAVE_OPENSSL */
1792:
1793: 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) /* {{{ */
1794: {
1795: int read_size, len;
1796: off_t read_len;
1797: unsigned char buf[1024];
1798:
1799: php_stream_rewind(fp);
1800:
1801: switch (sig_type) {
1802: case PHAR_SIG_OPENSSL: {
1803: #ifdef PHAR_HAVE_OPENSSL
1804: BIO *in;
1805: EVP_PKEY *key;
1806: EVP_MD *mdtype = (EVP_MD *) EVP_sha1();
1807: EVP_MD_CTX md_ctx;
1808: #else
1809: int tempsig;
1810: #endif
1811: php_uint32 pubkey_len;
1812: char *pubkey = NULL, *pfile;
1813: php_stream *pfp;
1814: #ifndef PHAR_HAVE_OPENSSL
1815: if (!zend_hash_exists(&module_registry, "openssl", sizeof("openssl"))) {
1816: if (error) {
1817: spprintf(error, 0, "openssl not loaded");
1818: }
1819: return FAILURE;
1820: }
1821: #endif
1822: /* use __FILE__ . '.pubkey' for public key file */
1823: spprintf(&pfile, 0, "%s.pubkey", fname);
1824: pfp = php_stream_open_wrapper(pfile, "rb", 0, NULL);
1825: efree(pfile);
1826:
1827: #if PHP_MAJOR_VERSION > 5
1828: if (!pfp || !(pubkey_len = php_stream_copy_to_mem(pfp, (void **) &pubkey, PHP_STREAM_COPY_ALL, 0)) || !pubkey) {
1829: #else
1830: if (!pfp || !(pubkey_len = php_stream_copy_to_mem(pfp, &pubkey, PHP_STREAM_COPY_ALL, 0)) || !pubkey) {
1831: #endif
1832: if (pfp) {
1833: php_stream_close(pfp);
1834: }
1835: if (error) {
1836: spprintf(error, 0, "openssl public key could not be read");
1837: }
1838: return FAILURE;
1839: }
1840:
1841: php_stream_close(pfp);
1842: #ifndef PHAR_HAVE_OPENSSL
1843: tempsig = sig_len;
1844:
1845: if (FAILURE == phar_call_openssl_signverify(0, fp, end_of_phar, pubkey, pubkey_len, &sig, &tempsig TSRMLS_CC)) {
1846: if (pubkey) {
1847: efree(pubkey);
1848: }
1849:
1850: if (error) {
1851: spprintf(error, 0, "openssl signature could not be verified");
1852: }
1853:
1854: return FAILURE;
1855: }
1856:
1857: if (pubkey) {
1858: efree(pubkey);
1859: }
1860:
1861: sig_len = tempsig;
1862: #else
1863: in = BIO_new_mem_buf(pubkey, pubkey_len);
1864:
1865: if (NULL == in) {
1866: efree(pubkey);
1867: if (error) {
1868: spprintf(error, 0, "openssl signature could not be processed");
1869: }
1870: return FAILURE;
1871: }
1872:
1873: key = PEM_read_bio_PUBKEY(in, NULL,NULL, NULL);
1874: BIO_free(in);
1875: efree(pubkey);
1876:
1877: if (NULL == key) {
1878: if (error) {
1879: spprintf(error, 0, "openssl signature could not be processed");
1880: }
1881: return FAILURE;
1882: }
1883:
1884: EVP_VerifyInit(&md_ctx, mdtype);
1885: read_len = end_of_phar;
1886:
1887: if (read_len > sizeof(buf)) {
1888: read_size = sizeof(buf);
1889: } else {
1890: read_size = (int)read_len;
1891: }
1892:
1893: php_stream_seek(fp, 0, SEEK_SET);
1894:
1895: while (read_size && (len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
1896: EVP_VerifyUpdate (&md_ctx, buf, len);
1897: read_len -= (off_t)len;
1898:
1899: if (read_len < read_size) {
1900: read_size = (int)read_len;
1901: }
1902: }
1903:
1904: if (EVP_VerifyFinal(&md_ctx, (unsigned char *)sig, sig_len, key) != 1) {
1905: /* 1: signature verified, 0: signature does not match, -1: failed signature operation */
1906: EVP_MD_CTX_cleanup(&md_ctx);
1907:
1908: if (error) {
1909: spprintf(error, 0, "broken openssl signature");
1910: }
1911:
1912: return FAILURE;
1913: }
1914:
1915: EVP_MD_CTX_cleanup(&md_ctx);
1916: #endif
1917:
1918: *signature_len = phar_hex_str((const char*)sig, sig_len, signature TSRMLS_CC);
1919: }
1920: break;
1921: #ifdef PHAR_HASH_OK
1922: case PHAR_SIG_SHA512: {
1923: unsigned char digest[64];
1924: PHP_SHA512_CTX context;
1925:
1926: PHP_SHA512Init(&context);
1927: read_len = end_of_phar;
1928:
1929: if (read_len > sizeof(buf)) {
1930: read_size = sizeof(buf);
1931: } else {
1932: read_size = (int)read_len;
1933: }
1934:
1935: while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
1936: PHP_SHA512Update(&context, buf, len);
1937: read_len -= (off_t)len;
1938: if (read_len < read_size) {
1939: read_size = (int)read_len;
1940: }
1941: }
1942:
1943: PHP_SHA512Final(digest, &context);
1944:
1945: if (memcmp(digest, sig, sizeof(digest))) {
1946: if (error) {
1947: spprintf(error, 0, "broken signature");
1948: }
1949: return FAILURE;
1950: }
1951:
1952: *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
1953: break;
1954: }
1955: case PHAR_SIG_SHA256: {
1956: unsigned char digest[32];
1957: PHP_SHA256_CTX context;
1958:
1959: PHP_SHA256Init(&context);
1960: read_len = end_of_phar;
1961:
1962: if (read_len > sizeof(buf)) {
1963: read_size = sizeof(buf);
1964: } else {
1965: read_size = (int)read_len;
1966: }
1967:
1968: while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
1969: PHP_SHA256Update(&context, buf, len);
1970: read_len -= (off_t)len;
1971: if (read_len < read_size) {
1972: read_size = (int)read_len;
1973: }
1974: }
1975:
1976: PHP_SHA256Final(digest, &context);
1977:
1978: if (memcmp(digest, sig, sizeof(digest))) {
1979: if (error) {
1980: spprintf(error, 0, "broken signature");
1981: }
1982: return FAILURE;
1983: }
1984:
1985: *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
1986: break;
1987: }
1988: #else
1989: case PHAR_SIG_SHA512:
1990: case PHAR_SIG_SHA256:
1991: if (error) {
1992: spprintf(error, 0, "unsupported signature");
1993: }
1994: return FAILURE;
1995: #endif
1996: case PHAR_SIG_SHA1: {
1997: unsigned char digest[20];
1998: PHP_SHA1_CTX context;
1999:
2000: PHP_SHA1Init(&context);
2001: read_len = end_of_phar;
2002:
2003: if (read_len > sizeof(buf)) {
2004: read_size = sizeof(buf);
2005: } else {
2006: read_size = (int)read_len;
2007: }
2008:
2009: while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
2010: PHP_SHA1Update(&context, buf, len);
2011: read_len -= (off_t)len;
2012: if (read_len < read_size) {
2013: read_size = (int)read_len;
2014: }
2015: }
2016:
2017: PHP_SHA1Final(digest, &context);
2018:
2019: if (memcmp(digest, sig, sizeof(digest))) {
2020: if (error) {
2021: spprintf(error, 0, "broken signature");
2022: }
2023: return FAILURE;
2024: }
2025:
2026: *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
2027: break;
2028: }
2029: case PHAR_SIG_MD5: {
2030: unsigned char digest[16];
2031: PHP_MD5_CTX context;
2032:
2033: PHP_MD5Init(&context);
2034: read_len = end_of_phar;
2035:
2036: if (read_len > sizeof(buf)) {
2037: read_size = sizeof(buf);
2038: } else {
2039: read_size = (int)read_len;
2040: }
2041:
2042: while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
2043: PHP_MD5Update(&context, buf, len);
2044: read_len -= (off_t)len;
2045: if (read_len < read_size) {
2046: read_size = (int)read_len;
2047: }
2048: }
2049:
2050: PHP_MD5Final(digest, &context);
2051:
2052: if (memcmp(digest, sig, sizeof(digest))) {
2053: if (error) {
2054: spprintf(error, 0, "broken signature");
2055: }
2056: return FAILURE;
2057: }
2058:
2059: *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
2060: break;
2061: }
2062: default:
2063: if (error) {
2064: spprintf(error, 0, "broken or unsupported signature");
2065: }
2066: return FAILURE;
2067: }
2068: return SUCCESS;
2069: }
2070: /* }}} */
2071:
2072: int phar_create_signature(phar_archive_data *phar, php_stream *fp, char **signature, int *signature_length, char **error TSRMLS_DC) /* {{{ */
2073: {
2074: unsigned char buf[1024];
2075: int sig_len;
2076:
2077: php_stream_rewind(fp);
2078:
2079: if (phar->signature) {
2080: efree(phar->signature);
2081: phar->signature = NULL;
2082: }
2083:
2084: switch(phar->sig_flags) {
2085: #ifdef PHAR_HASH_OK
2086: case PHAR_SIG_SHA512: {
2087: unsigned char digest[64];
2088: PHP_SHA512_CTX context;
2089:
2090: PHP_SHA512Init(&context);
2091:
2092: while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
2093: PHP_SHA512Update(&context, buf, sig_len);
2094: }
2095:
2096: PHP_SHA512Final(digest, &context);
2097: *signature = estrndup((char *) digest, 64);
2098: *signature_length = 64;
2099: break;
2100: }
2101: case PHAR_SIG_SHA256: {
2102: unsigned char digest[32];
2103: PHP_SHA256_CTX context;
2104:
2105: PHP_SHA256Init(&context);
2106:
2107: while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
2108: PHP_SHA256Update(&context, buf, sig_len);
2109: }
2110:
2111: PHP_SHA256Final(digest, &context);
2112: *signature = estrndup((char *) digest, 32);
2113: *signature_length = 32;
2114: break;
2115: }
2116: #else
2117: case PHAR_SIG_SHA512:
2118: case PHAR_SIG_SHA256:
2119: if (error) {
2120: spprintf(error, 0, "unable to write to phar \"%s\" with requested hash type", phar->fname);
2121: }
2122:
2123: return FAILURE;
2124: #endif
2125: case PHAR_SIG_OPENSSL: {
2126: int siglen;
2127: unsigned char *sigbuf;
2128: #ifdef PHAR_HAVE_OPENSSL
2129: BIO *in;
2130: EVP_PKEY *key;
1.1.1.3 misho 2131: EVP_MD_CTX *md_ctx;
1.1 misho 2132:
2133: in = BIO_new_mem_buf(PHAR_G(openssl_privatekey), PHAR_G(openssl_privatekey_len));
2134:
2135: if (in == NULL) {
2136: if (error) {
2137: spprintf(error, 0, "unable to write to phar \"%s\" with requested openssl signature", phar->fname);
2138: }
2139: return FAILURE;
2140: }
2141:
2142: key = PEM_read_bio_PrivateKey(in, NULL,NULL, "");
2143: BIO_free(in);
2144:
2145: if (!key) {
2146: if (error) {
2147: spprintf(error, 0, "unable to process private key");
2148: }
2149: return FAILURE;
2150: }
2151:
1.1.1.3 misho 2152: md_ctx = EVP_MD_CTX_create();
2153:
1.1 misho 2154: siglen = EVP_PKEY_size(key);
2155: sigbuf = emalloc(siglen + 1);
1.1.1.3 misho 2156:
2157: if (!EVP_SignInit(md_ctx, EVP_sha1())) {
2158: efree(sigbuf);
2159: if (error) {
2160: spprintf(error, 0, "unable to initialize openssl signature for phar \"%s\"", phar->fname);
2161: }
2162: return FAILURE;
2163: }
1.1 misho 2164:
2165: while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
1.1.1.3 misho 2166: if (!EVP_SignUpdate(md_ctx, buf, sig_len)) {
2167: efree(sigbuf);
2168: if (error) {
2169: spprintf(error, 0, "unable to update the openssl signature for phar \"%s\"", phar->fname);
2170: }
2171: return FAILURE;
2172: }
1.1 misho 2173: }
2174:
1.1.1.3 misho 2175: if (!EVP_SignFinal (md_ctx, sigbuf,(unsigned int *)&siglen, key)) {
1.1 misho 2176: efree(sigbuf);
2177: if (error) {
2178: spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname);
2179: }
2180: return FAILURE;
2181: }
2182:
2183: sigbuf[siglen] = '\0';
1.1.1.3 misho 2184: EVP_MD_CTX_destroy(md_ctx);
1.1 misho 2185: #else
2186: sigbuf = NULL;
2187: siglen = 0;
2188: php_stream_seek(fp, 0, SEEK_END);
2189:
2190: 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)) {
2191: if (error) {
2192: spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname);
2193: }
2194: return FAILURE;
2195: }
2196: #endif
2197: *signature = (char *) sigbuf;
2198: *signature_length = siglen;
2199: }
2200: break;
2201: default:
2202: phar->sig_flags = PHAR_SIG_SHA1;
2203: case PHAR_SIG_SHA1: {
2204: unsigned char digest[20];
2205: PHP_SHA1_CTX context;
2206:
2207: PHP_SHA1Init(&context);
2208:
2209: while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
2210: PHP_SHA1Update(&context, buf, sig_len);
2211: }
2212:
2213: PHP_SHA1Final(digest, &context);
2214: *signature = estrndup((char *) digest, 20);
2215: *signature_length = 20;
2216: break;
2217: }
2218: case PHAR_SIG_MD5: {
2219: unsigned char digest[16];
2220: PHP_MD5_CTX context;
2221:
2222: PHP_MD5Init(&context);
2223:
2224: while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
2225: PHP_MD5Update(&context, buf, sig_len);
2226: }
2227:
2228: PHP_MD5Final(digest, &context);
2229: *signature = estrndup((char *) digest, 16);
2230: *signature_length = 16;
2231: break;
2232: }
2233: }
2234:
2235: phar->sig_len = phar_hex_str((const char *)*signature, *signature_length, &phar->signature TSRMLS_CC);
2236: return SUCCESS;
2237: }
2238: /* }}} */
2239:
2240: void phar_add_virtual_dirs(phar_archive_data *phar, char *filename, int filename_len TSRMLS_DC) /* {{{ */
2241: {
1.1.1.2 misho 2242: const char *s;
1.1 misho 2243:
2244: while ((s = zend_memrchr(filename, '/', filename_len))) {
2245: filename_len = s - filename;
2246: if (FAILURE == zend_hash_add_empty_element(&phar->virtual_dirs, filename, filename_len)) {
2247: break;
2248: }
2249: }
2250: }
2251: /* }}} */
2252:
2253: static int phar_update_cached_entry(void *data, void *argument) /* {{{ */
2254: {
2255: phar_entry_info *entry = (phar_entry_info *)data;
2256: TSRMLS_FETCH();
2257:
2258: entry->phar = (phar_archive_data *)argument;
2259:
2260: if (entry->link) {
2261: entry->link = estrdup(entry->link);
2262: }
2263:
2264: if (entry->tmp) {
2265: entry->tmp = estrdup(entry->tmp);
2266: }
2267:
2268: entry->metadata_str.c = 0;
2269: entry->filename = estrndup(entry->filename, entry->filename_len);
2270: entry->is_persistent = 0;
2271:
2272: if (entry->metadata) {
2273: if (entry->metadata_len) {
2274: char *buf = estrndup((char *) entry->metadata, entry->metadata_len);
2275: /* assume success, we would have failed before */
2276: phar_parse_metadata((char **) &buf, &entry->metadata, entry->metadata_len TSRMLS_CC);
2277: efree(buf);
2278: } else {
2279: zval *t;
2280:
2281: t = entry->metadata;
2282: ALLOC_ZVAL(entry->metadata);
2283: *entry->metadata = *t;
2284: zval_copy_ctor(entry->metadata);
2285: #if PHP_VERSION_ID < 50300
2286: entry->metadata->refcount = 1;
2287: #else
2288: Z_SET_REFCOUNT_P(entry->metadata, 1);
2289: #endif
2290: entry->metadata_str.c = NULL;
2291: entry->metadata_str.len = 0;
2292: }
2293: }
2294: return ZEND_HASH_APPLY_KEEP;
2295: }
2296: /* }}} */
2297:
2298: static void phar_copy_cached_phar(phar_archive_data **pphar TSRMLS_DC) /* {{{ */
2299: {
2300: phar_archive_data *phar;
2301: HashTable newmanifest;
2302: char *fname;
2303: phar_archive_object **objphar;
2304:
2305: phar = (phar_archive_data *) emalloc(sizeof(phar_archive_data));
2306: *phar = **pphar;
2307: phar->is_persistent = 0;
2308: fname = phar->fname;
2309: phar->fname = estrndup(phar->fname, phar->fname_len);
2310: phar->ext = phar->fname + (phar->ext - fname);
2311:
2312: if (phar->alias) {
2313: phar->alias = estrndup(phar->alias, phar->alias_len);
2314: }
2315:
2316: if (phar->signature) {
2317: phar->signature = estrdup(phar->signature);
2318: }
2319:
2320: if (phar->metadata) {
2321: /* assume success, we would have failed before */
2322: if (phar->metadata_len) {
2323: char *buf = estrndup((char *) phar->metadata, phar->metadata_len);
2324: phar_parse_metadata(&buf, &phar->metadata, phar->metadata_len TSRMLS_CC);
2325: efree(buf);
2326: } else {
2327: zval *t;
2328:
2329: t = phar->metadata;
2330: ALLOC_ZVAL(phar->metadata);
2331: *phar->metadata = *t;
2332: zval_copy_ctor(phar->metadata);
2333: #if PHP_VERSION_ID < 50300
2334: phar->metadata->refcount = 1;
2335: #else
2336: Z_SET_REFCOUNT_P(phar->metadata, 1);
2337: #endif
2338: }
2339: }
2340:
2341: zend_hash_init(&newmanifest, sizeof(phar_entry_info),
2342: zend_get_hash_value, destroy_phar_manifest_entry, 0);
2343: zend_hash_copy(&newmanifest, &(*pphar)->manifest, NULL, NULL, sizeof(phar_entry_info));
2344: zend_hash_apply_with_argument(&newmanifest, (apply_func_arg_t) phar_update_cached_entry, (void *)phar TSRMLS_CC);
2345: phar->manifest = newmanifest;
2346: zend_hash_init(&phar->mounted_dirs, sizeof(char *),
2347: zend_get_hash_value, NULL, 0);
2348: zend_hash_init(&phar->virtual_dirs, sizeof(char *),
2349: zend_get_hash_value, NULL, 0);
2350: zend_hash_copy(&phar->virtual_dirs, &(*pphar)->virtual_dirs, NULL, NULL, sizeof(void *));
2351: *pphar = phar;
2352:
2353: /* now, scan the list of persistent Phar objects referencing this phar and update the pointers */
2354: for (zend_hash_internal_pointer_reset(&PHAR_GLOBALS->phar_persist_map);
2355: SUCCESS == zend_hash_get_current_data(&PHAR_GLOBALS->phar_persist_map, (void **) &objphar);
2356: zend_hash_move_forward(&PHAR_GLOBALS->phar_persist_map)) {
2357: if (objphar[0]->arc.archive->fname_len == phar->fname_len && !memcmp(objphar[0]->arc.archive->fname, phar->fname, phar->fname_len)) {
2358: objphar[0]->arc.archive = phar;
2359: }
2360: }
2361: }
2362: /* }}} */
2363:
2364: int phar_copy_on_write(phar_archive_data **pphar TSRMLS_DC) /* {{{ */
2365: {
2366: phar_archive_data **newpphar, *newphar = NULL;
2367:
2368: if (SUCCESS != zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), (*pphar)->fname, (*pphar)->fname_len, (void *)&newphar, sizeof(phar_archive_data *), (void **)&newpphar)) {
2369: return FAILURE;
2370: }
2371:
2372: *newpphar = *pphar;
2373: phar_copy_cached_phar(newpphar TSRMLS_CC);
2374: /* invalidate phar cache */
2375: PHAR_G(last_phar) = NULL;
2376: PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
2377:
2378: 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)) {
2379: zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), (*pphar)->fname, (*pphar)->fname_len);
2380: return FAILURE;
2381: }
2382:
2383: *pphar = *newpphar;
2384: return SUCCESS;
2385: }
2386: /* }}} */
2387:
2388: /*
2389: * Local variables:
2390: * tab-width: 4
2391: * c-basic-offset: 4
2392: * End:
2393: * vim600: noet sw=4 ts=4 fdm=marker
2394: * vim<600: noet sw=4 ts=4
2395: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>