root/ext/phar/util.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. phar_get_link_location
  2. phar_get_link_source
  3. phar_get_efp
  4. phar_seek_efp
  5. phar_mount_entry
  6. phar_find_in_include_path
  7. phar_get_entry_data
  8. phar_get_or_create_entry_data
  9. phar_open_archive_fp
  10. phar_copy_entry_fp
  11. phar_open_entry_fp
  12. phar_create_writeable_entry
  13. phar_separate_entry_fp
  14. phar_open_jit
  15. phar_resolve_alias
  16. phar_free_alias
  17. phar_get_archive
  18. phar_compress_filter
  19. phar_decompress_filter
  20. phar_get_entry_info
  21. phar_get_entry_info_dir
  22. phar_hex_str
  23. phar_call_openssl_signverify
  24. phar_verify_signature
  25. phar_create_signature
  26. phar_add_virtual_dirs
  27. phar_update_cached_entry
  28. phar_copy_cached_phar
  29. phar_copy_on_write

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

/* [<][>][^][v][top][bottom][index][help] */