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