PluginProbe
phpinfo() WP – Site Health, PHP Compatibility & Server Audit / 7.2.5
phpinfo() WP – Site Health, PHP Compatibility & Server Audit v7.2.5
7.2.7 7.2.6 7.2.5 7.2.4 7.2.3 7.2.0 7.2.1 7.2.2 7.1.0 7.0.3 7.0.4 7.0.5 trunk 6.0 7.0.0 7.0.1 7.0.2
phpinfo-wp / includes / class-permissions.php

class-permissions.php in phpinfo() WP – Site Health, PHP Compatibility & Server Audit 7.2.5, at includes/class-permissions.php

105 lines 3.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 defined('ABSPATH') or die('Unauthorized Access');
3
4 class Phpinfo_WP_Permissions {
5
6 public static function register(): void {
7 // No background hooks needed. This is an on-demand auditing tool.
8 }
9
10 public static function get_php_user(): string {
11 if (function_exists('posix_getpwuid') && function_exists('posix_geteuid')) {
12 $user = posix_getpwuid(posix_geteuid());
13 return $user['name'] ?? get_current_user();
14 }
15 return get_current_user();
16 }
17
18 public static function scan(): array {
19 if (!Phpinfo_WP_License::is_valid()) return [];
20
21 $php_uid = function_exists('posix_geteuid') ? posix_geteuid() : getmyuid();
22
23 $results = [
24 'dangerous' => [],
25 'mismatch' => [],
26 'scanned' => 0,
27 'wp_config' => null,
28 'php_uid' => $php_uid,
29 'php_user' => self::get_php_user(),
30 ];
31
32 // 1. Check wp-config.php specifically
33 $wp_config_path = self::get_wp_config_path();
34 if ($wp_config_path && file_exists($wp_config_path)) {
35 $perms = fileperms($wp_config_path) & 0777;
36 $owner = fileowner($wp_config_path);
37
38 $results['wp_config'] = [
39 'path' => $wp_config_path,
40 'perms' => sprintf('%04o', $perms),
41 'owner' => function_exists('posix_getpwuid') ? (posix_getpwuid($owner)['name'] ?? $owner) : $owner,
42 'is_dangerous' => ($perms === 0666 || $perms === 0777),
43 ];
44 $results['scanned']++;
45 }
46
47 // 2. Targeted scan
48 $targets = [
49 ABSPATH . WPINC,
50 ABSPATH . 'wp-admin',
51 WP_PLUGIN_DIR,
52 get_theme_root(),
53 ];
54
55 $limit = 5000;
56
57 foreach ($targets as $dir) {
58 if (!is_dir($dir)) continue;
59
60 $iterator = new RecursiveIteratorIterator(
61 new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
62 RecursiveIteratorIterator::SELF_FIRST
63 );
64
65 foreach ($iterator as $file) {
66 if ($results['scanned'] >= $limit) break 2;
67
68 $results['scanned']++;
69 $path = $file->getPathname();
70 $is_dir = $file->isDir();
71 $perms = $file->getPerms() & 0777;
72 $owner = $file->getOwner();
73
74 // Dangerous permissions: 777 on dirs, 666/777 on files
75 if ($is_dir && $perms === 0777) {
76 $results['dangerous'][] = ['path' => $path, 'perms' => '0777', 'type' => 'dir'];
77 } elseif (!$is_dir && ($perms === 0666 || $perms === 0777)) {
78 $results['dangerous'][] = ['path' => $path, 'perms' => sprintf('%04o', $perms), 'type' => 'file'];
79 }
80
81 // Ownership mismatch: File owner doesn't match PHP executor UID
82 if ($owner !== $php_uid) {
83 $owner_name = function_exists('posix_getpwuid') ? (posix_getpwuid($owner)['name'] ?? $owner) : $owner;
84 // Cap mismatch results to 20 to prevent memory exhaustion,
85 // since one wrong `chown` causes thousands of mismatches.
86 if (count($results['mismatch']) < 20) {
87 $results['mismatch'][] = ['path' => $path, 'owner' => $owner_name, 'type' => $is_dir ? 'dir' : 'file'];
88 }
89 }
90 }
91 }
92
93 return $results;
94 }
95
96 private static function get_wp_config_path(): ?string {
97 if (file_exists(ABSPATH . 'wp-config.php')) {
98 return ABSPATH . 'wp-config.php';
99 } elseif (file_exists(dirname(ABSPATH) . '/wp-config.php') && !file_exists(dirname(ABSPATH) . '/wp-settings.php')) {
100 return dirname(ABSPATH) . '/wp-config.php';
101 }
102 return null;
103 }
104 }
105