/**
  * Actually action the permission changes they want.
  */
 public function action_perms_save()
 {
     global $context, $txt, $time_start, $package_ftp;
     umask(0);
     $timeout_limit = 5;
     $context['method'] = $_POST['method'] === 'individual' ? 'individual' : 'predefined';
     $context['back_look_data'] = isset($_POST['back_look']) ? $_POST['back_look'] : array();
     // Skipping use of FTP?
     if (empty($package_ftp)) {
         $context['skip_ftp'] = true;
     }
     // We'll start off in a good place, security. Make sure that if we're dealing with individual files that they seem in the right place.
     if ($context['method'] === 'individual') {
         // Only these path roots are legal.
         $legal_roots = array_keys($context['file_tree']);
         $context['custom_value'] = (int) $_POST['custom_value'];
         // Continuing?
         if (isset($_POST['toProcess'])) {
             $_POST['permStatus'] = unserialize(base64_decode($_POST['toProcess']));
         }
         if (isset($_POST['permStatus'])) {
             $context['to_process'] = array();
             $validate_custom = false;
             foreach ($_POST['permStatus'] as $path => $status) {
                 // Nothing to see here?
                 if ($status === 'no_change') {
                     continue;
                 }
                 $legal = false;
                 foreach ($legal_roots as $root) {
                     if (substr($path, 0, strlen($root)) == $root) {
                         $legal = true;
                     }
                 }
                 if (!$legal) {
                     continue;
                 }
                 // Check it exists.
                 if (!file_exists($path)) {
                     continue;
                 }
                 if ($status === 'custom') {
                     $validate_custom = true;
                 }
                 // Now add it.
                 $context['to_process'][$path] = $status;
             }
             $context['total_items'] = isset($_POST['totalItems']) ? (int) $_POST['totalItems'] : count($context['to_process']);
             // Make sure the chmod status is valid?
             if ($validate_custom) {
                 if (preg_match('~^[4567][4567][4567]$~', $context['custom_value']) == false) {
                     fatal_error($txt['chmod_value_invalid']);
                 }
             }
             // Nothing to do?
             if (empty($context['to_process'])) {
                 redirectexit('action=admin;area=packages;sa=perms' . (!empty($context['back_look_data']) ? ';back_look=' . base64_encode(serialize($context['back_look_data'])) : '') . ';' . $context['session_var'] . '=' . $context['session_id']);
             }
         } else {
             fatal_lang_error('no_access', false);
         }
         // Setup the custom value.
         $custom_value = octdec('0' . $context['custom_value']);
         // Start processing items.
         foreach ($context['to_process'] as $path => $status) {
             if (in_array($status, array('execute', 'writable', 'read'))) {
                 package_chmod($path, $status);
             } elseif ($status == 'custom' && !empty($custom_value)) {
                 // Use FTP if we have it.
                 if (!empty($package_ftp) && !empty($_SESSION['pack_ftp'])) {
                     $ftp_file = strtr($path, array($_SESSION['pack_ftp']['root'] => ''));
                     $package_ftp->chmod($ftp_file, $custom_value);
                 } else {
                     @chmod($path, $custom_value);
                 }
             }
             // This fish is fried...
             unset($context['to_process'][$path]);
             // See if we're out of time?
             if (time() - array_sum(explode(' ', $time_start)) > $timeout_limit) {
                 pausePermsSave();
             }
         }
     } else {
         $context['predefined_type'] = isset($_POST['predefined']) ? $_POST['predefined'] : 'restricted';
         $context['total_items'] = isset($_POST['totalItems']) ? (int) $_POST['totalItems'] : 0;
         $context['directory_list'] = isset($_POST['dirList']) ? unserialize(base64_decode($_POST['dirList'])) : array();
         $context['file_offset'] = isset($_POST['fileOffset']) ? (int) $_POST['fileOffset'] : 0;
         // Haven't counted the items yet?
         if (empty($context['total_items'])) {
             foreach ($context['file_tree'] as $path => $data) {
                 if (is_dir($path)) {
                     $context['directory_list'][$path] = 1;
                     $context['total_items'] += $this->count_directories__recursive($path);
                     $context['total_items']++;
                 }
             }
         }
         // Have we built up our list of special files?
         if (!isset($_POST['specialFiles']) && $context['predefined_type'] != 'free') {
             $context['special_files'] = array();
             foreach ($context['file_tree'] as $path => $data) {
                 $this->build_special_files__recursive($path, $data);
             }
         } elseif ($context['predefined_type'] === 'free') {
             $context['special_files'] = array();
         } else {
             $context['special_files'] = unserialize(base64_decode($_POST['specialFiles']));
         }
         // Now we definitely know where we are, we need to go through again doing the chmod!
         foreach ($context['directory_list'] as $path => $dummy) {
             // Do the contents of the directory first.
             $dh = @opendir($path);
             $file_count = 0;
             $dont_chmod = false;
             while ($entry = readdir($dh)) {
                 $file_count++;
                 // Actually process this file?
                 if (!$dont_chmod && !is_dir($path . '/' . $entry) && (empty($context['file_offset']) || $context['file_offset'] < $file_count)) {
                     $status = $context['predefined_type'] === 'free' || isset($context['special_files'][$path . '/' . $entry]) ? 'writable' : 'execute';
                     package_chmod($path . '/' . $entry, $status);
                 }
                 // See if we're out of time?
                 if (!$dont_chmod && time() - array_sum(explode(' ', $time_start)) > $timeout_limit) {
                     $dont_chmod = true;
                     // Make note of how far we have come so we restart at the right point
                     $context['file_offset'] = $file_count;
                     break;
                 }
             }
             closedir($dh);
             // If this is set it means we timed out half way through.
             if ($dont_chmod) {
                 $context['total_files'] = $file_count;
                 pausePermsSave();
             }
             // Do the actual directory.
             $status = $context['predefined_type'] === 'free' || isset($context['special_files'][$path]) ? 'writable' : 'execute';
             package_chmod($path, $status);
             // We've finished the directory so no file offset, and no record.
             $context['file_offset'] = 0;
             unset($context['directory_list'][$path]);
             // See if we're out of time?
             if (time() - array_sum(explode(' ', $time_start)) > $timeout_limit) {
                 pausePermsSave();
             }
         }
     }
     // If we're here we are done!
     redirectexit('action=admin;area=packages;sa=perms' . (!empty($context['back_look_data']) ? ';back_look=' . base64_encode(serialize($context['back_look_data'])) : '') . ';' . $context['session_var'] . '=' . $context['session_id']);
 }
Exemple #2
0
function package_create_backup($id = 'backup')
{
    global $sourcedir, $boarddir, $smcFunc;
    $files = array();
    $base_files = array('index.php', 'SSI.php', 'agreement.txt', 'ssi_examples.php', 'ssi_examples.shtml');
    foreach ($base_files as $file) {
        if (file_exists($boarddir . '/' . $file)) {
            $files[realpath($boarddir . '/' . $file)] = array(empty($_REQUEST['use_full_paths']) ? $file : $boarddir . '/' . $file, stat($boarddir . '/' . $file));
        }
    }
    $dirs = array($sourcedir => empty($_REQUEST['use_full_paths']) ? 'Sources/' : strtr($sourcedir . '/', '\\', '/'));
    $request = smf_db_query('
		SELECT value
		FROM {db_prefix}themes
		WHERE id_member = {int:no_member}
			AND variable = {string:theme_dir}', array('no_member' => 0, 'theme_dir' => 'theme_dir'));
    while ($row = mysql_fetch_assoc($request)) {
        $dirs[$row['value']] = empty($_REQUEST['use_full_paths']) ? 'Themes/' . basename($row['value']) . '/' : strtr($row['value'] . '/', '\\', '/');
    }
    mysql_free_result($request);
    while (!empty($dirs)) {
        list($dir, $dest) = each($dirs);
        unset($dirs[$dir]);
        $listing = @dir($dir);
        if (!$listing) {
            continue;
        }
        while ($entry = $listing->read()) {
            if (preg_match('~^(\\.{1,2}|CVS|backup.*|help|images|.*\\~)$~', $entry) != 0) {
                continue;
            }
            $filepath = realpath($dir . '/' . $entry);
            if (isset($files[$filepath])) {
                continue;
            }
            $stat = stat($dir . '/' . $entry);
            if ($stat['mode'] & 040000) {
                $files[$filepath] = array($dest . $entry . '/', $stat);
                $dirs[$dir . '/' . $entry] = $dest . $entry . '/';
            } else {
                $files[$filepath] = array($dest . $entry, $stat);
            }
        }
        $listing->close();
    }
    if (!file_exists($boarddir . '/Packages/backups')) {
        mktree($boarddir . '/Packages/backups', 0777);
    }
    if (!is_writable($boarddir . '/Packages/backups')) {
        package_chmod($boarddir . '/Packages/backups');
    }
    $output_file = $boarddir . '/Packages/backups/' . strftime('%Y-%m-%d_') . preg_replace('~[$\\\\/:<>|?*"\']~', '', $id);
    $output_ext = '.tar' . (function_exists('gzopen') ? '.gz' : '');
    if (file_exists($output_file . $output_ext)) {
        $i = 2;
        while (file_exists($output_file . '_' . $i . $output_ext)) {
            $i++;
        }
        $output_file = $output_file . '_' . $i . $output_ext;
    } else {
        $output_file .= $output_ext;
    }
    @set_time_limit(300);
    if (function_exists('apache_reset_timeout')) {
        @apache_reset_timeout();
    }
    if (function_exists('gzopen')) {
        $fwrite = 'gzwrite';
        $fclose = 'gzclose';
        $output = gzopen($output_file, 'wb');
    } else {
        $fwrite = 'fwrite';
        $fclose = 'fclose';
        $output = fopen($output_file, 'wb');
    }
    foreach ($files as $real_file => $file) {
        if (!file_exists($real_file)) {
            continue;
        }
        $stat = $file[1];
        if (substr($file[0], -1) == '/') {
            $stat['size'] = 0;
        }
        $current = pack('a100a8a8a8a12a12a8a1a100a6a2a32a32a8a8a155a12', $file[0], decoct($stat['mode']), sprintf('%06d', decoct($stat['uid'])), sprintf('%06d', decoct($stat['gid'])), decoct($stat['size']), decoct($stat['mtime']), '', 0, '', '', '', '', '', '', '', '', '');
        $checksum = 256;
        for ($i = 0; $i < 512; $i++) {
            $checksum += ord($current[$i]);
        }
        $fwrite($output, substr($current, 0, 148) . pack('a8', decoct($checksum)) . substr($current, 156, 511));
        if ($stat['size'] == 0) {
            continue;
        }
        $fp = fopen($real_file, 'rb');
        while (!feof($fp)) {
            $fwrite($output, fread($fp, 16384));
        }
        fclose($fp);
        $fwrite($output, pack('a' . (512 - $stat['size'] % 512), ''));
    }
    $fwrite($output, pack('a1024', ''));
    $fclose($output);
}
Exemple #3
0
/**
 * Creates a site backup before installing a package just in case things don't go
 * as planned.
 *
 * @package Packages
 * @param string $id
 */
function package_create_backup($id = 'backup')
{
    $db = database();
    $files = array();
    // The files that reside outside of sources, in the base, we add manually
    $base_files = array('index.php', 'SSI.php', 'agreement.txt', 'ssi_examples.php', 'ssi_examples.shtml', 'subscriptions.php', 'email_imap_cron.php', 'emailpost.php', 'emailtopic.php');
    foreach ($base_files as $file) {
        if (file_exists(BOARDDIR . '/' . $file)) {
            $files[realpath(BOARDDIR . '/' . $file)] = array(empty($_REQUEST['use_full_paths']) ? $file : BOARDDIR . '/' . $file, stat(BOARDDIR . '/' . $file));
        }
    }
    // Root directory where most of our files reside
    $dirs = array(SOURCEDIR => empty($_REQUEST['use_full_paths']) ? 'sources/' : strtr(SOURCEDIR . '/', '\\', '/'));
    // Find all installed theme directories
    $request = $db->query('', '
		SELECT value
		FROM {db_prefix}themes
		WHERE id_member = {int:no_member}
			AND variable = {string:theme_dir}', array('no_member' => 0, 'theme_dir' => 'theme_dir'));
    while ($row = $db->fetch_assoc($request)) {
        $dirs[$row['value']] = empty($_REQUEST['use_full_paths']) ? 'themes/' . basename($row['value']) . '/' : strtr($row['value'] . '/', '\\', '/');
    }
    $db->free_result($request);
    // While we have directorys to check
    while (!empty($dirs)) {
        list($dir, $dest) = each($dirs);
        unset($dirs[$dir]);
        // Get the file listing for this directory
        $listing = @dir($dir);
        if (!$listing) {
            continue;
        }
        while ($entry = $listing->read()) {
            if (preg_match('~^(\\.{1,2}|CVS|backup.*|help|images|.*\\~)$~', $entry) != 0) {
                continue;
            }
            $filepath = realpath($dir . '/' . $entry);
            if (isset($files[$filepath])) {
                continue;
            }
            $stat = stat($dir . '/' . $entry);
            // If this is a directory, add it to the dir stack for processing
            if ($stat['mode'] & 040000) {
                $files[$filepath] = array($dest . $entry . '/', $stat);
                $dirs[$dir . '/' . $entry] = $dest . $entry . '/';
            } else {
                $files[$filepath] = array($dest . $entry, $stat);
            }
        }
        $listing->close();
    }
    // Make sure we have a backup directory and its writable
    if (!file_exists(BOARDDIR . '/packages/backups')) {
        mktree(BOARDDIR . '/packages/backups', 0777);
    }
    if (!is_writable(BOARDDIR . '/packages/backups')) {
        package_chmod(BOARDDIR . '/packages/backups');
    }
    // Name the output file, yyyy-mm-dd_before_package_name.tar.gz
    $output_file = BOARDDIR . '/packages/backups/' . strftime('%Y-%m-%d_') . preg_replace('~[$\\\\/:<>|?*"\']~', '', $id);
    $output_ext = '.tar' . (function_exists('gzopen') ? '.gz' : '');
    if (file_exists($output_file . $output_ext)) {
        $i = 2;
        while (file_exists($output_file . '_' . $i . $output_ext)) {
            $i++;
        }
        $output_file = $output_file . '_' . $i . $output_ext;
    } else {
        $output_file .= $output_ext;
    }
    // Buy some more time so we have enough to create this archive
    @set_time_limit(300);
    if (function_exists('apache_reset_timeout')) {
        @apache_reset_timeout();
    }
    // Set up the file output handle, try gzip first to save space
    if (function_exists('gzopen')) {
        $fwrite = 'gzwrite';
        $fclose = 'gzclose';
        $output = gzopen($output_file, 'wb');
    } else {
        $fwrite = 'fwrite';
        $fclose = 'fclose';
        $output = fopen($output_file, 'wb');
    }
    // For each file we found in the directory, we add them to a TAR archive
    foreach ($files as $real_file => $file) {
        if (!file_exists($real_file)) {
            continue;
        }
        // Check if its a directory
        $stat = $file[1];
        if (substr($file[0], -1) == '/') {
            $stat['size'] = 0;
        }
        // Create a tar file header, pack the details in to the fields
        $current = pack('a100a8a8a8a12a12a8a1a100a6a2a32a32a8a8a155a12', $file[0], decoct($stat['mode']), sprintf('%06d', decoct($stat['uid'])), sprintf('%06d', decoct($stat['gid'])), decoct($stat['size']), decoct($stat['mtime']), '', 0, '', '', '', '', '', '', '', '', '');
        // Create the header checksum
        $checksum = 256;
        for ($i = 0; $i < 512; $i++) {
            $checksum += ord($current[$i]);
        }
        // Write out the file header (insert the checksum we just computed)
        $fwrite($output, substr($current, 0, 148) . pack('a8', decoct($checksum)) . substr($current, 156, 511));
        // If this is a directory entry all thats needed is the header
        if ($stat['size'] == 0) {
            continue;
        }
        // Write the actual file contents to the backup file
        $fp = fopen($real_file, 'rb');
        while (!feof($fp)) {
            $fwrite($output, fread($fp, 16384));
        }
        fclose($fp);
        // Pad the output so its on 512 boundarys
        $fwrite($output, pack('a' . (512 - $stat['size'] % 512), ''));
    }
    $fwrite($output, pack('a1024', ''));
    $fclose($output);
}