aboutsummaryrefslogtreecommitdiffstats
path: root/phpBB/includes/core/system.php
blob: 5bb42e9ed46d6572b2edd5ce1e170c1f7652e5fe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
<?php
/**
*
* @package core
* @version $Id$
* @copyright (c) 2008 phpBB Group
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
*
*/

/**
* @ignore
*/
if (!defined('IN_PHPBB'))
{
	exit();
}

/**
* System-specific methods. For example chmod(), unlink()...
*
* @package core
*/
class phpbb_system extends phpbb_plugin_support
{
	/**
	* @var array required phpBB objects
	*/
	public $phpbb_required = array();

	/**
	* @var array Optional phpBB objects
	*/
	public $phpbb_optional = array();

	/**
	* @var array Holding some information for chmod()
	*/
	private $chmod_info = array();

	/**
	* Method for chmodding directories and files for internal use.
	*
	* This function determines owner and group whom the file belongs to and user and group of PHP and then set safest possible file permissions.
	* The function determines owner and group from common.php file and sets the same to the provided file.
	* The function uses bit fields to build the permissions.
	* The function sets the appropiate execute bit on directories.
	*
	* Supported constants representing bit fields are:
	*
	* phpbb::CHMOD_ALL - all permissions (7)
	* phpbb::CHMOD_READ - read permission (4)
	* phpbb::CHMOD_WRITE - write permission (2)
	* phpbb::CHMOD_EXECUTE - execute permission (1)
	*
	* NOTE: The function uses POSIX extension and fileowner()/filegroup() functions. If any of them is disabled, this function tries to build proper permissions, by calling is_readable() and is_writable() functions.
	*
	* @param string	$filename	The file/directory to be chmodded
	* @param int	$perms		Permissions to set
	*
	* @return bool	true on success, otherwise false
	* @author faw, phpBB Group
	* @access public
	*/
	public function chmod($filename, $perms = phpbb::CHMOD_READ)
	{
		// Return if the file no longer exists.
		if (!file_exists($filename))
		{
			return false;
		}

		// Determine some common vars
		if (empty($this->chmod_info))
		{
			if (!function_exists('fileowner') || !function_exists('filegroup'))
			{
				// No need to further determine owner/group - it is unknown
				$this->chmod_info['process'] = false;
			}
			else
			{
				// Determine owner/group of common.php file and the filename we want to change here
				$common_php_owner = fileowner(PHPBB_ROOT_PATH . 'common.' . PHP_EXT);
				$common_php_group = filegroup(PHPBB_ROOT_PATH . 'common.' . PHP_EXT);

				// And the owner and the groups PHP is running under.
				$php_uid = (function_exists('posix_getuid')) ? @posix_getuid() : false;
				$php_gids = (function_exists('posix_getgroups')) ? @posix_getgroups() : false;

				if (!$php_uid || empty($php_gids) || !$common_php_owner || !$common_php_group)
				{
					$this->chmod_info['process'] = false;
				}
				else
				{
					$this->chmod_info = array(
						'process'		=> true,
						'common_owner'	=> $common_php_owner,
						'common_group'	=> $common_php_group,
						'php_uid'		=> $php_uid,
						'php_gids'		=> $php_gids,
					);
				}
			}
		}

		if ($this->chmod_info['process'])
		{
			$file_uid = fileowner($filename);
			$file_gid = filegroup($filename);

			// Change owner
			if (@chown($filename, $this->chmod_info['common_owner']))
			{
				clearstatcache();
				$file_uid = fileowner($filename);
			}

			// Change group
			if (@chgrp($filename, $this->chmod_info['common_group']))
			{
				clearstatcache();
				$file_gid = filegroup($filename);
			}

			// If the file_uid/gid now match the one from common.php we can process further, else we are not able to change something
			if ($file_uid != $this->chmod_info['common_owner'] || $file_gid != $this->chmod_info['common_group'])
			{
				$this->chmod_info['process'] = false;
			}
		}

		// Still able to process?
		if ($this->chmod_info['process'])
		{
			if ($file_uid == $this->chmod_info['php_uid'])
			{
				$php = 'owner';
			}
			else if (in_array($file_gid, $this->chmod_info['php_gids']))
			{
				$php = 'group';
			}
			else
			{
				// Since we are setting the everyone bit anyway, no need to do expensive operations
				$this->chmod_info['process'] = false;
			}
		}

		// We are not able to determine or change something
		if (!$this->chmod_info['process'])
		{
			$php = 'other';
		}

		// Owner always has read/write permission
		$owner = phpbb::CHMOD_READ | phpbb::CHMOD_WRITE;
		if (is_dir($filename))
		{
			$owner |= phpbb::CHMOD_EXECUTE;

			// Only add execute bit to the permission if the dir needs to be readable
			if ($perms & phpbb::CHMOD_READ)
			{
				$perms |= phpbb::CHMOD_EXECUTE;
			}
		}

		switch ($php)
		{
			case 'owner':
				$result = @chmod($filename, ($owner << 6) + (0 << 3) + (0 << 0));

				clearstatcache();

				if (!is_null($php) || (is_readable($filename) && is_writable($filename)))
				{
					break;
				}

			case 'group':
				$result = @chmod($filename, ($owner << 6) + ($perms << 3) + (0 << 0));

				clearstatcache();

				if (!is_null($php) || ((!($perms & phpbb::CHMOD_READ) || is_readable($filename)) && (!($perms & phpbb::CHMOD_WRITE) || is_writable($filename))))
				{
					break;
				}

			case 'other':
				$result = @chmod($filename, ($owner << 6) + ($perms << 3) + ($perms << 0));

				clearstatcache();

				if (!is_null($php) || ((!($perms & phpbb::CHMOD_READ) || is_readable($filename)) && (!($perms & phpbb::CHMOD_WRITE) || is_writable($filename))))
				{
					break;
				}

			default:
				return false;
			break;
		}

		return $result;
	}

}

?>