Verzeichnisstruktur phpBB-3.2.0
- Veröffentlicht
- 06.01.2017
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
manager.php
001 <?php
002 /**
003 *
004 * This file is part of the phpBB Forum Software package.
005 *
006 * @copyright (c) phpBB Limited <https://www.phpbb.com>
007 * @license GNU General Public License, version 2 (GPL-2.0)
008 *
009 * For full copyright and license information, please see
010 * the docs/CREDITS.txt file.
011 *
012 */
013
014 namespace phpbb\passwords;
015
016 class manager
017 {
018 /**
019 * Default hashing method
020 */
021 protected $type = false;
022
023 /**
024 * Hashing algorithm type map
025 * Will be used to map hash prefix to type
026 */
027 protected $type_map = false;
028
029 /**
030 * Service collection of hashing algorithms
031 * Needs to be public for passwords helper
032 */
033 public $algorithms = false;
034
035 /**
036 * Password convert flag. Signals that password should be converted
037 */
038 public $convert_flag = false;
039
040 /**
041 * Passwords helper
042 * @var \phpbb\passwords\helper
043 */
044 protected $helper;
045
046 /**
047 * phpBB configuration
048 * @var \phpbb\config\config
049 */
050 protected $config;
051
052 /**
053 * @var bool Whether or not initialized() has been called
054 */
055 private $initialized = false;
056
057 /**
058 * @var array Hashing driver service collection
059 */
060 private $hashing_algorithms;
061
062 /**
063 * @var array List of default driver types
064 */
065 private $defaults;
066
067 /**
068 * Construct a passwords object
069 *
070 * @param \phpbb\config\config $config phpBB configuration
071 * @param array $hashing_algorithms Hashing driver service collection
072 * @param \phpbb\passwords\helper $helper Passwords helper object
073 * @param array $defaults List of default driver types
074 */
075 public function __construct(\phpbb\config\config $config, $hashing_algorithms, helper $helper, $defaults)
076 {
077 $this->config = $config;
078 $this->helper = $helper;
079 $this->hashing_algorithms = $hashing_algorithms;
080 $this->defaults = $defaults;
081 }
082
083 /**
084 * Initialize the internal state
085 */
086 protected function initialize()
087 {
088 if (!$this->initialized)
089 {
090 $this->initialized = true;
091 $this->fill_type_map($this->hashing_algorithms);
092 $this->register_default_type($this->defaults);
093 }
094 }
095
096 /**
097 * Register default type
098 * Will register the first supported type from the list of default types
099 *
100 * @param array $defaults List of default types in order from first to
101 * use to last to use
102 */
103 protected function register_default_type($defaults)
104 {
105 foreach ($defaults as $type)
106 {
107 if ($this->algorithms[$type]->is_supported())
108 {
109 $this->type = $this->algorithms[$type]->get_prefix();
110 break;
111 }
112 }
113 }
114
115 /**
116 * Fill algorithm type map
117 *
118 * @param \phpbb\di\service_collection $hashing_algorithms
119 */
120 protected function fill_type_map($hashing_algorithms)
121 {
122 foreach ($hashing_algorithms as $algorithm)
123 {
124 if (!isset($this->type_map[$algorithm->get_prefix()]))
125 {
126 $this->type_map[$algorithm->get_prefix()] = $algorithm;
127 }
128 }
129 $this->algorithms = $hashing_algorithms;
130 }
131
132 /**
133 * Get the algorithm specified by a specific prefix
134 *
135 * @param string $prefix Password hash prefix
136 *
137 * @return object|bool The hash type object or false if prefix is not
138 * supported
139 */
140 protected function get_algorithm($prefix)
141 {
142 if (isset($this->type_map[$prefix]))
143 {
144 return $this->type_map[$prefix];
145 }
146 else
147 {
148 return false;
149 }
150 }
151
152 /**
153 * Detect the hash type of the supplied hash
154 *
155 * @param string $hash Password hash that should be checked
156 *
157 * @return object|bool The hash type object or false if the specified
158 * type is not supported
159 */
160 public function detect_algorithm($hash)
161 {
162 /*
163 * preg_match() will also show hashing algos like $2a\H$, which
164 * is a combination of bcrypt and phpass. Legacy algorithms
165 * like md5 will not be matched by this and need to be treated
166 * differently.
167 */
168 if (!preg_match('#^\$([a-zA-Z0-9\\\]*?)\$#', $hash, $match))
169 {
170 return false;
171 }
172
173 $this->initialize();
174
175 // Be on the lookout for multiple hashing algorithms
176 // 2 is correct: H\2a > 2, H\P > 2
177 if (strlen($match[1]) > 2 && strpos($match[1], '\\') !== false)
178 {
179 $hash_types = explode('\\', $match[1]);
180 $return_ary = array();
181 foreach ($hash_types as $type)
182 {
183 // we do not support the same hashing
184 // algorithm more than once
185 if (isset($return_ary[$type]))
186 {
187 return false;
188 }
189
190 $return_ary[$type] = $this->get_algorithm('$' . $type . '$');
191
192 if (empty($return_ary[$type]))
193 {
194 return false;
195 }
196 }
197 return $return_ary;
198 }
199
200 // get_algorithm() will automatically return false if prefix
201 // is not supported
202 return $this->get_algorithm($match[0]);
203 }
204
205 /**
206 * Hash supplied password
207 *
208 * @param string $password Password that should be hashed
209 * @param string $type Hash type. Will default to standard hash type if
210 * none is supplied
211 * @return string|bool Password hash of supplied password or false if
212 * if something went wrong during hashing
213 */
214 public function hash($password, $type = '')
215 {
216 if (strlen($password) > 4096)
217 {
218 // If the password is too huge, we will simply reject it
219 // and not let the server try to hash it.
220 return false;
221 }
222
223 $this->initialize();
224
225 // Try to retrieve algorithm by service name if type doesn't
226 // start with dollar sign
227 if (!is_array($type) && strpos($type, '$') !== 0 && isset($this->algorithms[$type]))
228 {
229 $type = $this->algorithms[$type]->get_prefix();
230 }
231
232 $type = ($type === '') ? $this->type : $type;
233
234 if (is_array($type))
235 {
236 return $this->combined_hash_password($password, $type);
237 }
238
239 if (isset($this->type_map[$type]))
240 {
241 $hashing_algorithm = $this->type_map[$type];
242 }
243 else
244 {
245 return false;
246 }
247
248 return $hashing_algorithm->hash($password);
249 }
250
251 /**
252 * Check supplied password against hash and set convert_flag if password
253 * needs to be converted to different format (preferrably newer one)
254 *
255 * @param string $password Password that should be checked
256 * @param string $hash Stored hash
257 * @param array $user_row User's row in users table
258 * @return string|bool True if password is correct, false if not
259 */
260 public function check($password, $hash, $user_row = array())
261 {
262 if (strlen($password) > 4096)
263 {
264 // If the password is too huge, we will simply reject it
265 // and not let the server try to hash it.
266 return false;
267 }
268
269 // Empty hashes can't be checked
270 if (empty($hash))
271 {
272 return false;
273 }
274
275 $this->initialize();
276
277 // First find out what kind of hash we're dealing with
278 $stored_hash_type = $this->detect_algorithm($hash);
279 if ($stored_hash_type == false)
280 {
281 // Still check MD5 hashes as that is what the installer
282 // will default to for the admin user
283 return $this->get_algorithm('$H$')->check($password, $hash);
284 }
285
286 // Multiple hash passes needed
287 if (is_array($stored_hash_type))
288 {
289 $correct = $this->check_combined_hash($password, $stored_hash_type, $hash);
290 $this->convert_flag = ($correct === true) ? true : false;
291 return $correct;
292 }
293
294 if ($stored_hash_type->get_prefix() !== $this->type)
295 {
296 $this->convert_flag = true;
297 }
298 else
299 {
300 if ($stored_hash_type instanceof driver\rehashable_driver_interface)
301 {
302 $this->convert_flag = $stored_hash_type->needs_rehash($hash);
303 }
304 else
305 {
306 $this->convert_flag = false;
307 }
308 }
309
310 // Check all legacy hash types if prefix is $CP$
311 if ($stored_hash_type->get_prefix() === '$CP$')
312 {
313 // Remove $CP$ prefix for proper checking
314 $hash = substr($hash, 4);
315
316 foreach ($this->type_map as $algorithm)
317 {
318 if ($algorithm->is_legacy() && $algorithm->check($password, $hash, $user_row) === true)
319 {
320 return true;
321 }
322 }
323 }
324
325 return $stored_hash_type->check($password, $hash);
326 }
327
328 /**
329 * Create combined hash from already hashed password
330 *
331 * @param string $password_hash Complete current password hash
332 * @param string $type Type of the hashing algorithm the password hash
333 * should be combined with
334 * @return string|bool Combined password hash if combined hashing was
335 * successful, else false
336 */
337 public function combined_hash_password($password_hash, $type)
338 {
339 $this->initialize();
340
341 $data = array(
342 'prefix' => '$',
343 'settings' => '$',
344 );
345 $hash_settings = $this->helper->get_combined_hash_settings($password_hash);
346 $hash = $hash_settings[0];
347
348 // Put settings of current hash into data array
349 $stored_hash_type = $this->detect_algorithm($password_hash);
350 $this->helper->combine_hash_output($data, 'prefix', $stored_hash_type->get_prefix());
351 $this->helper->combine_hash_output($data, 'settings', $stored_hash_type->get_settings_only($password_hash));
352
353 // Hash current hash with the defined types
354 foreach ($type as $cur_type)
355 {
356 if (isset($this->algorithms[$cur_type]))
357 {
358 $new_hash_type = $this->algorithms[$cur_type];
359 }
360 else
361 {
362 $new_hash_type = $this->get_algorithm($cur_type);
363 }
364
365 if (!$new_hash_type)
366 {
367 return false;
368 }
369
370 $new_hash = $new_hash_type->hash(str_replace($stored_hash_type->get_settings_only($password_hash), '', $hash));
371 $this->helper->combine_hash_output($data, 'prefix', $new_hash_type->get_prefix());
372 $this->helper->combine_hash_output($data, 'settings', substr(str_replace('$', '\\', $new_hash_type->get_settings_only($new_hash, true)), 0));
373 $hash = str_replace($new_hash_type->get_settings_only($new_hash), '', $this->helper->obtain_hash_only($new_hash));
374 }
375 return $this->helper->combine_hash_output($data, 'hash', $hash);
376 }
377
378 /**
379 * Check combined password hash against the supplied password
380 *
381 * @param string $password Password entered by user
382 * @param array $stored_hash_type An array containing the hash types
383 * as described by stored password hash
384 * @param string $hash Stored password hash
385 *
386 * @return bool True if password is correct, false if not
387 */
388 public function check_combined_hash($password, $stored_hash_type, $hash)
389 {
390 $i = 0;
391 $data = array(
392 'prefix' => '$',
393 'settings' => '$',
394 );
395 $hash_settings = $this->helper->get_combined_hash_settings($hash);
396 foreach ($stored_hash_type as $key => $hash_type)
397 {
398 $rebuilt_hash = $this->helper->rebuild_hash($hash_type->get_prefix(), $hash_settings[$i]);
399 $this->helper->combine_hash_output($data, 'prefix', $key);
400 $this->helper->combine_hash_output($data, 'settings', $hash_settings[$i]);
401 $cur_hash = $hash_type->hash($password, $rebuilt_hash);
402 $password = str_replace($rebuilt_hash, '', $cur_hash);
403 $i++;
404 }
405 return ($hash === $this->helper->combine_hash_output($data, 'hash', $password));
406 }
407 }
408