61d9ec71 |
1 | <?php |
2 | |
3 | /** |
0c701a88 |
4 | * global.php |
61d9ec71 |
5 | * |
62f7daa5 |
6 | * This includes code to update < 4.1.0 globals to the newer format |
242342d0 |
7 | * It also has some session register functions that work across various |
62f7daa5 |
8 | * php versions. |
61d9ec71 |
9 | * |
8ed19238 |
10 | * @copyright 1999-2019 The SquirrelMail Project Team |
4b4abf93 |
11 | * @license http://opensource.org/licenses/gpl-license.php GNU Public License |
31841a9e |
12 | * @version $Id$ |
d6c32258 |
13 | * @package squirrelmail |
61d9ec71 |
14 | */ |
15 | |
051f6245 |
16 | /** |
bce96055 |
17 | * These constants are used in the function sqgetGlobalVar(). See |
18 | * sqgetGlobalVar() for a description of what they mean. |
19 | * |
20 | * @since 1.4.0 |
2ca4c65a |
21 | */ |
7f62aaef |
22 | define('SQ_INORDER',0); |
23 | define('SQ_GET',1); |
24 | define('SQ_POST',2); |
25 | define('SQ_SESSION',3); |
26 | define('SQ_COOKIE',4); |
27 | define('SQ_SERVER',5); |
28 | define('SQ_FORM',6); |
a32985a5 |
29 | |
202bcbcc |
30 | |
62f7daa5 |
31 | /** |
32 | * returns true if current php version is at mimimum a.b.c |
33 | * |
97bdc607 |
34 | * Called: check_php_version(4,1) |
8b096f0a |
35 | * @param int a major version number |
36 | * @param int b minor version number |
37 | * @param int c release number |
38 | * @return bool |
97bdc607 |
39 | */ |
62f7daa5 |
40 | function check_php_version ($a = '0', $b = '0', $c = '0') |
9697c5ab |
41 | { |
5673cabe |
42 | return version_compare ( PHP_VERSION, "$a.$b.$c", 'ge' ); |
9697c5ab |
43 | } |
44 | |
97bdc607 |
45 | /** |
62f7daa5 |
46 | * returns true if the current internal SM version is at minimum a.b.c |
47 | * These are plain integer comparisons, as our internal version is |
97bdc607 |
48 | * constructed by us, as an array of 3 ints. |
49 | * |
50 | * Called: check_sm_version(1,3,3) |
8b096f0a |
51 | * @param int a major version number |
52 | * @param int b minor version number |
53 | * @param int c release number |
54 | * @return bool |
97bdc607 |
55 | */ |
56 | function check_sm_version($a = 0, $b = 0, $c = 0) |
57 | { |
58 | global $SQM_INTERNAL_VERSION; |
59 | if ( !isset($SQM_INTERNAL_VERSION) || |
60 | $SQM_INTERNAL_VERSION[0] < $a || |
150c28d6 |
61 | ( $SQM_INTERNAL_VERSION[0] == $a && |
62 | $SQM_INTERNAL_VERSION[1] < $b) || |
63 | ( $SQM_INTERNAL_VERSION[0] == $a && |
64 | $SQM_INTERNAL_VERSION[1] == $b && |
97bdc607 |
65 | $SQM_INTERNAL_VERSION[2] < $c ) ) { |
66 | return FALSE; |
62f7daa5 |
67 | } |
68 | return TRUE; |
97bdc607 |
69 | } |
70 | |
71 | |
8b096f0a |
72 | /** |
73 | * Recursively strip slashes from the values of an array. |
74 | * @param array array the array to strip, passed by reference |
75 | * @return void |
76 | */ |
a32985a5 |
77 | function sqstripslashes(&$array) { |
3aa17cf9 |
78 | if(count($array) > 0) { |
79 | foreach ($array as $index=>$value) { |
80 | if (is_array($array[$index])) { |
81 | sqstripslashes($array[$index]); |
82 | } |
83 | else { |
84 | $array[$index] = stripslashes($value); |
85 | } |
a32985a5 |
86 | } |
87 | } |
88 | } |
89 | |
8442ecb9 |
90 | /** |
91 | * Squelch error output to screen (only) for the given function. |
1888b1bf |
92 | * If the SquirrelMail debug mode SM_DEBUG_MODE_ADVANCED is not |
93 | * enabled, error output will not go to the log, either. |
8442ecb9 |
94 | * |
95 | * This provides an alternative to the @ error-suppression |
96 | * operator where errors will not be shown in the interface |
97 | * but will show up in the server log file (assuming the |
98 | * administrator has configured PHP logging). |
99 | * |
100 | * @since 1.4.12 and 1.5.2 |
101 | * |
102 | * @param string $function The function to be executed |
103 | * @param array $args The arguments to be passed to the function |
104 | * (OPTIONAL; default no arguments) |
105 | * NOTE: The caller must take extra action if |
106 | * the function being called is supposed |
107 | * to use any of the parameters by |
108 | * reference. In the following example, |
109 | * $x is passed by reference and $y is |
110 | * passed by value to the "my_func" |
111 | * function. |
112 | * sq_call_function_suppress_errors('my_func', array(&$x, $y)); |
113 | * |
114 | * @return mixed The return value, if any, of the function being |
115 | * executed will be returned. |
116 | * |
117 | */ |
d0e7f324 |
118 | function sq_call_function_suppress_errors($function, $args=array()) { |
1888b1bf |
119 | global $sm_debug_mode; |
120 | |
8442ecb9 |
121 | $display_errors = ini_get('display_errors'); |
122 | ini_set('display_errors', '0'); |
1888b1bf |
123 | |
124 | // if advanced debug mode isn't enabled, don't log the error, either |
125 | // |
126 | if (!($sm_debug_mode & SM_DEBUG_MODE_ADVANCED)) |
127 | $error_reporting = error_reporting(0); |
128 | |
8442ecb9 |
129 | $ret = call_user_func_array($function, $args); |
1888b1bf |
130 | |
131 | if (!($sm_debug_mode & SM_DEBUG_MODE_ADVANCED)) |
132 | error_reporting($error_reporting); |
133 | |
8442ecb9 |
134 | ini_set('display_errors', $display_errors); |
135 | return $ret; |
136 | } |
137 | |
8b096f0a |
138 | /** |
139 | * Add a variable to the session. |
140 | * @param mixed $var the variable to register |
141 | * @param string $name the name to refer to this variable |
142 | * @return void |
143 | */ |
61d9ec71 |
144 | function sqsession_register ($var, $name) { |
281c3d5b |
145 | |
146 | sqsession_is_active(); |
147 | |
04ce2477 |
148 | $_SESSION[$name] = $var; |
61d9ec71 |
149 | } |
3aa17cf9 |
150 | |
8b096f0a |
151 | /** |
152 | * Delete a variable from the session. |
153 | * @param string $name the name of the var to delete |
154 | * @return void |
155 | */ |
61d9ec71 |
156 | function sqsession_unregister ($name) { |
281c3d5b |
157 | |
158 | sqsession_is_active(); |
159 | |
abd74f7d |
160 | unset($_SESSION[$name]); |
62f7daa5 |
161 | |
f48a90ca |
162 | // starts throwing warnings in PHP 5.3.0 and is |
163 | // removed in PHP 6 and is redundant anyway |
164 | //session_unregister("$name"); |
61d9ec71 |
165 | } |
3aa17cf9 |
166 | |
8b096f0a |
167 | /** |
168 | * Checks to see if a variable has already been registered |
169 | * in the session. |
170 | * @param string $name the name of the var to check |
171 | * @return bool whether the var has been registered |
172 | */ |
d7c82551 |
173 | function sqsession_is_registered ($name) { |
174 | $test_name = &$name; |
175 | $result = false; |
62f7daa5 |
176 | |
abd74f7d |
177 | if (isset($_SESSION[$test_name])) { |
178 | $result = true; |
d7c82551 |
179 | } |
62f7daa5 |
180 | |
d7c82551 |
181 | return $result; |
182 | } |
183 | |
54ce41dd |
184 | |
185 | /** |
186 | * Retrieves a form variable, from a set of possible similarly named |
187 | * form variables, based on finding a different, single field. This |
68a7e1d6 |
188 | * is intended to allow more than one same-named inputs in a single |
189 | * <form>, where the submit button that is clicked tells us which |
54ce41dd |
190 | * input we should retrieve. An example is if we have: |
191 | * <select name="startMessage_1"> |
192 | * <select name="startMessage_2"> |
b116fd78 |
193 | * <input type="submit" name="form_submit_1" /> |
194 | * <input type="submit" name="form_submit_2" /> |
68a7e1d6 |
195 | * and we want to know which one of the select inputs should be |
54ce41dd |
196 | * returned as $startMessage (without the suffix!), this function |
197 | * decides by looking for either "form_submit_1" or "form_submit_2" |
198 | * (both should not appear). In this example, $name should be |
199 | * "startMessage" and $indicator_field should be "form_submit". |
200 | * |
201 | * NOTE that form widgets must be named with the suffix "_1", "_2", "_3" |
202 | * and so on, or this function will not work. |
203 | * |
204 | * If more than one of the indicator fields is found, the first one |
205 | * (numerically) will win. |
206 | * |
68a7e1d6 |
207 | * If an indicator field is found without a matching input ($name) |
139a4b99 |
208 | * field, FALSE is returned. |
209 | * |
68a7e1d6 |
210 | * If no indicator fields are found, a field of $name *without* any |
211 | * suffix is searched for (but only if $fallback_no_suffix is TRUE), |
139a4b99 |
212 | * and if not found, FALSE is ultimately returned. |
54ce41dd |
213 | * |
214 | * It should also be possible to use the same string for both |
215 | * $name and $indicator_field to look for the first possible |
216 | * widget with a suffix that can be found (and possibly fallback |
217 | * to a widget without a suffix). |
218 | * |
219 | * @param string name the name of the var to search |
220 | * @param mixed value the variable to return |
221 | * @param string indicator_field the name of the field upon which to base |
222 | * our decision upon (see above) |
223 | * @param int search constant defining where to look |
224 | * @param bool fallback_no_suffix whether or not to look for $name with |
225 | * no suffix when nothing else is found |
226 | * @param mixed default the value to assign to $value when nothing is found |
227 | * @param int typecast force variable to be cast to given type (please |
228 | * use SQ_TYPE_XXX constants or set to FALSE (default) |
229 | * to leave variable type unmolested) |
230 | * |
231 | * @return bool whether variable is found. |
232 | */ |
68a7e1d6 |
233 | function sqGetGlobalVarMultiple($name, &$value, $indicator_field, |
234 | $search = SQ_INORDER, |
235 | $fallback_no_suffix=TRUE, $default=NULL, |
54ce41dd |
236 | $typecast=FALSE) { |
237 | |
1793f985 |
238 | // Set arbitrary max limit -- should be much lower except on the |
239 | // search results page, if there are many (50 or more?) mailboxes |
240 | // shown, this may not be high enough. Is there some way we should |
241 | // automate this value? |
242 | // |
243 | $max_form_search = 100; |
54ce41dd |
244 | |
245 | for ($i = 1; $i <= $max_form_search; $i++) { |
246 | if (sqGetGlobalVar($indicator_field . '_' . $i, $temp, $search)) { |
247 | return sqGetGlobalVar($name . '_' . $i, $value, $search, $default, $typecast); |
248 | } |
249 | } |
250 | |
251 | |
252 | // no indicator field found; just try without suffix if allowed |
253 | // |
254 | if ($fallback_no_suffix) { |
255 | return sqGetGlobalVar($name, $value, $search, $default, $typecast); |
256 | } |
257 | |
258 | |
259 | // no dice, set default and return FALSE |
260 | // |
261 | if (!is_null($default)) { |
262 | $value = $default; |
263 | } |
264 | return FALSE; |
265 | |
266 | } |
267 | |
268 | |
4cd8ae7d |
269 | /** |
bce96055 |
270 | * Search for the variable $name in one or more of the global variables |
271 | * $_SESSION, $_POST, $_GET, $_COOKIE, and $_SERVER, and set the value of it in |
272 | * the variable $vaule. |
d1975c5b |
273 | * |
bce96055 |
274 | * $search must be one of the defined constants below. The default is |
275 | * SQ_INORDER. Both SQ_INORDER and SQ_FORM stops on the first match. |
d1975c5b |
276 | * |
bce96055 |
277 | * SQ_INORDER searches $_SESSION, then $_POST, and then $_GET. |
278 | * SQ_FORM searches $_POST and then $_GET. |
279 | * SQ_COOKIE searches $_COOKIE only. |
280 | * SQ_GET searches $_GET only. |
281 | * SQ_POST searches $_POST only. |
282 | * SQ_SERVER searches $_SERVER only. |
283 | * SQ_SESSION searches $_SESSION only. |
d1975c5b |
284 | * |
2d055f0a |
285 | * Example: |
bce96055 |
286 | * sqgetGlobalVar('username', $username, SQ_SESSION); |
287 | * // No quotes around the last parameter, it's a constant - not a string! |
d1975c5b |
288 | * |
8b096f0a |
289 | * @param string name the name of the var to search |
290 | * @param mixed value the variable to return |
291 | * @param int search constant defining where to look |
54ce41dd |
292 | * @param mixed default the value to assign to $value when nothing is found |
c2b585c5 |
293 | * @param int typecast force variable to be cast to given type (please |
294 | * use SQ_TYPE_XXX constants or set to FALSE (default) |
295 | * to leave variable type unmolested) |
54ce41dd |
296 | * |
8b096f0a |
297 | * @return bool whether variable is found. |
4cd8ae7d |
298 | */ |
bce96055 |
299 | function sqgetGlobalVar($name, &$value, $search = SQ_INORDER, $default = NULL, $typecast = FALSE) { |
300 | // The return value defaults to FALSE, i.e. the variable wasn't found. |
301 | $result = FALSE; |
f79c19a4 |
302 | |
bce96055 |
303 | // Search the global variables to find a match. |
4cd8ae7d |
304 | switch ($search) { |
bce96055 |
305 | default: |
306 | // The default needs to be first here so SQ_INORDER will be used if |
307 | // $search isn't a valid constant. |
308 | case SQ_INORDER: |
309 | // Search $_SESSION, then $_POST, and then $_GET. Stop on the first |
310 | // match. |
311 | case SQ_SESSION: |
312 | if (isset($_SESSION[$name])) { |
313 | // If a match is found, set the specified variable to the found |
314 | // value, indicate a match, and stop the search. |
315 | $value = $_SESSION[$name]; |
316 | $result = TRUE; |
317 | break; |
318 | } elseif ($search == SQ_SESSION) { |
319 | // Only stop the search if SQ_SESSION is set. SQ_INORDER will |
320 | // continue with the next clause. |
321 | break; |
322 | } |
323 | case SQ_FORM: |
324 | // Search $_POST and then $_GET. Stop on the first match. |
325 | case SQ_POST: |
326 | if (isset($_POST[$name])) { |
327 | // If a match is found, set the specified variable to the found |
328 | // value, indicate a match, and stop the search. |
329 | $value = $_POST[$name]; |
330 | $result = TRUE; |
331 | break; |
332 | } elseif ($search == SQ_POST) { |
333 | // Only stop the search if SQ_POST is set. SQ_INORDER and |
334 | // SQ_FORM will continue with the next clause. |
335 | break; |
336 | } |
337 | case SQ_GET: |
338 | if (isset($_GET[$name])) { |
339 | // If a match is found, set the specified variable to the found |
340 | // value, indicate a match, and stop the search. |
341 | $value = $_GET[$name]; |
342 | $result = TRUE; |
343 | break; |
344 | } |
345 | // Stop the search regardless of if SQ_INORDER, SQ_FORM, or SQ_GET |
346 | // is set. All three of them ends here. |
202bcbcc |
347 | break; |
bce96055 |
348 | case SQ_COOKIE: |
349 | if (isset($_COOKIE[$name])) { |
350 | // If a match is found, set the specified variable to the found |
351 | // value, indicate a match, and stop the search. |
352 | $value = $_COOKIE[$name]; |
353 | $result = TRUE; |
354 | break; |
355 | } |
356 | // Stop the search. |
202bcbcc |
357 | break; |
bce96055 |
358 | case SQ_SERVER: |
359 | if (isset($_SERVER[$name])) { |
360 | // If a match is found, set the specified variable to the found |
361 | // value, indicate a match, and stop the search. |
362 | $value = $_SERVER[$name]; |
363 | $result = TRUE; |
364 | break; |
365 | } |
366 | // Stop the search. |
202bcbcc |
367 | break; |
4cd8ae7d |
368 | } |
bce96055 |
369 | |
202bcbcc |
370 | if ($result && $typecast) { |
bce96055 |
371 | // Only typecast if it's requested and a match is found. The default is |
372 | // not to typecast, which will happen if a valid constant isn't |
373 | // specified. |
202bcbcc |
374 | switch ($typecast) { |
bce96055 |
375 | case SQ_TYPE_INT: |
376 | // Typecast the value and stop. |
377 | $value = (int) $value; |
378 | break; |
379 | case SQ_TYPE_STRING: |
380 | // Typecast the value and stop. |
381 | $value = (string) $value; |
382 | break; |
383 | case SQ_TYPE_BOOL: |
384 | // Typecast the value and stop. |
385 | $value = (bool) $value; |
386 | break; |
1c2963ab |
387 | case SQ_TYPE_BIGINT: |
bce96055 |
388 | // Typecast the value and stop. |
1c2963ab |
389 | $value = (preg_match('/^[0-9]+$/', $value) ? $value : '0'); |
390 | break; |
bce96055 |
391 | default: |
392 | // The default is to do nothing. |
393 | break; |
202bcbcc |
394 | } |
ced8272a |
395 | } else if (!$result && !is_null($default)) { |
bce96055 |
396 | // If no match is found and a default value is specified, set it. |
202bcbcc |
397 | $value = $default; |
398 | } |
bce96055 |
399 | |
400 | // Return if a match was found or not. |
202bcbcc |
401 | return $result; |
4cd8ae7d |
402 | } |
403 | |
061108dc |
404 | /** |
405 | * Get an immutable copy of a configuration variable if SquirrelMail |
406 | * is in "secured configuration" mode. This guarantees the caller |
407 | * gets a copy of the requested value as it is set in the main |
408 | * application configuration (including config_local overrides), and |
409 | * not what it might be after possibly having been modified by some |
410 | * other code (usually a plugin overriding configuration values for |
411 | * one reason or another). |
412 | * |
413 | * WARNING: Please use this function as little as possible, because |
414 | * every time it is called, it forcibly reloads the main configuration |
415 | * file(s). |
416 | * |
417 | * Caller beware that this function will do nothing if SquirrelMail |
418 | * is not in "secured configuration" mode per the $secured_config |
419 | * setting. |
420 | * |
421 | * @param string $var_name The name of the desired variable |
422 | * |
423 | * @return mixed The desired value |
424 | * |
425 | * @since 1.5.2 |
426 | * |
427 | */ |
428 | function get_secured_config_value($var_name) { |
429 | |
430 | static $return_values = array(); |
431 | |
432 | // if we can avoid it, return values that have |
433 | // already been retrieved (so we don't have to |
434 | // include the config file yet again) |
435 | // |
436 | if (isset($return_values[$var_name])) { |
437 | return $return_values[$var_name]; |
438 | } |
439 | |
440 | |
441 | // load site configuration |
442 | // |
443 | require(SM_PATH . 'config/config.php'); |
444 | |
445 | // load local configuration overrides |
446 | // |
447 | if (file_exists(SM_PATH . 'config/config_local.php')) { |
448 | require(SM_PATH . 'config/config_local.php'); |
449 | } |
450 | |
451 | // if SM isn't in "secured configuration" mode, |
452 | // just return the desired value from the global scope |
453 | // |
454 | if (!$secured_config) { |
455 | global $$var_name; |
456 | $return_values[$var_name] = $$var_name; |
457 | return $$var_name; |
458 | } |
459 | |
460 | // else we return what we got from the config file |
461 | // |
462 | $return_values[$var_name] = $$var_name; |
463 | return $$var_name; |
464 | |
465 | } |
466 | |
8b096f0a |
467 | /** |
468 | * Deletes an existing session, more advanced than the standard PHP |
469 | * session_destroy(), it explicitly deletes the cookies and global vars. |
66c7cd3f |
470 | * |
471 | * WARNING: Older PHP versions have some issues with session management. |
68a7e1d6 |
472 | * See http://bugs.php.net/11643 (warning, spammed bug tracker) and |
66c7cd3f |
473 | * http://bugs.php.net/13834. SID constant is not destroyed in PHP 4.1.2, |
68a7e1d6 |
474 | * 4.2.3 and maybe other versions. If you restart session after session |
475 | * is destroyed, affected PHP versions produce PHP notice. Bug should |
66c7cd3f |
476 | * be fixed only in 4.3.0 |
8b096f0a |
477 | */ |
513db22c |
478 | function sqsession_destroy() { |
242342d0 |
479 | |
281c3d5b |
480 | /* |
481 | * php.net says we can kill the cookie by setting just the name: |
482 | * http://www.php.net/manual/en/function.setcookie.php |
483 | * maybe this will help fix the session merging again. |
484 | * |
485 | * Changed the theory on this to kill the cookies first starting |
486 | * a new session will provide a new session for all instances of |
487 | * the browser, we don't want that, as that is what is causing the |
488 | * merging of sessions. |
489 | */ |
242342d0 |
490 | |
716cc530 |
491 | global $base_uri, $_COOKIE, $_SESSION; |
f31687f6 |
492 | |
1f80d9f5 |
493 | if (isset($_COOKIE[session_name()]) && session_name()) { |
494 | sqsetcookie(session_name(), $_COOKIE[session_name()], 1, $base_uri); |
495 | |
496 | /* |
497 | * Make sure to kill /src and /src/ cookies, just in case there are |
498 | * some left-over or malicious ones set in user's browser. |
499 | * NB: Note that an attacker could try to plant a cookie for one |
500 | * of the /plugins/* directories. Such cookies can block |
501 | * access to certain plugin pages, but they do not influence |
502 | * or fixate the $base_uri cookie, so we don't worry about |
503 | * trying to delete all of them here. |
504 | */ |
505 | sqsetcookie(session_name(), $_COOKIE[session_name()], 1, $base_uri . 'src'); |
506 | sqsetcookie(session_name(), $_COOKIE[session_name()], 1, $base_uri . 'src/'); |
507 | } |
508 | |
f6cd95a1 |
509 | if (isset($_COOKIE['key']) && $_COOKIE['key']) sqsetcookie('key','SQMTRASH',1,$base_uri); |
281c3d5b |
510 | |
1f80d9f5 |
511 | /* Make sure new session id is generated on subsequent session_start() */ |
512 | unset($_COOKIE[session_name()]); |
513 | unset($_GET[session_name()]); |
514 | unset($_POST[session_name()]); |
515 | |
281c3d5b |
516 | $sessid = session_id(); |
517 | if (!empty( $sessid )) { |
abd74f7d |
518 | $_SESSION = array(); |
21e18f59 |
519 | @session_destroy(); |
242342d0 |
520 | } |
281c3d5b |
521 | } |
242342d0 |
522 | |
8b096f0a |
523 | /** |
281c3d5b |
524 | * Function to verify a session has been started. If it hasn't |
525 | * start a session up. php.net doesn't tell you that $_SESSION |
526 | * (even though autoglobal), is not created unless a session is |
527 | * started, unlike $_POST, $_GET and such |
253ca97e |
528 | * Update: (see #1685031) the session ID is left over after the |
529 | * session is closed in some PHP setups; this function just becomes |
530 | * a passthru to sqsession_start(), but leaving old code in for |
531 | * edification. |
281c3d5b |
532 | */ |
281c3d5b |
533 | function sqsession_is_active() { |
253ca97e |
534 | //$sessid = session_id(); |
535 | //if ( empty( $sessid ) ) { |
3a1de9f1 |
536 | sqsession_start(); |
253ca97e |
537 | //} |
513db22c |
538 | } |
539 | |
3a1de9f1 |
540 | /** |
541 | * Function to start the session and store the cookie with the session_id as |
542 | * HttpOnly cookie which means that the cookie isn't accessible by javascript |
543 | * (IE6 only) |
253ca97e |
544 | * Note that as sqsession_is_active() no longer discriminates as to when |
545 | * it calls this function, session_start() has to have E_NOTICE suppression |
546 | * (thus the @ sign). |
3a1de9f1 |
547 | */ |
548 | function sqsession_start() { |
202bcbcc |
549 | global $base_uri; |
7f62aaef |
550 | |
8442ecb9 |
551 | sq_call_function_suppress_errors('session_start'); |
552 | // was: @session_start(); |
202bcbcc |
553 | $session_id = session_id(); |
554 | |
79a7fdf5 |
555 | // session_starts sets the sessionid cookie but without the httponly var |
3a1de9f1 |
556 | // setting the cookie again sets the httponly cookie attribute |
79a7fdf5 |
557 | // |
558 | // need to check if headers have been sent, since sqsession_is_active() |
559 | // has become just a passthru to this function, so the sqsetcookie() |
560 | // below is called every time, even after headers have already been sent |
561 | // |
562 | if (!headers_sent()) |
563 | sqsetcookie(session_name(),$session_id,false,$base_uri); |
3a1de9f1 |
564 | } |
565 | |
566 | |
79a7fdf5 |
567 | |
3a1de9f1 |
568 | /** |
569 | * Set a cookie |
945c733e |
570 | * |
3a1de9f1 |
571 | * @param string $sName The name of the cookie. |
572 | * @param string $sValue The value of the cookie. |
945c733e |
573 | * @param int $iExpire The time the cookie expires. This is a Unix |
574 | * timestamp so is in number of seconds since |
575 | * the epoch. |
576 | * @param string $sPath The path on the server in which the cookie |
577 | * will be available on. |
3a1de9f1 |
578 | * @param string $sDomain The domain that the cookie is available. |
945c733e |
579 | * @param boolean $bSecure Indicates that the cookie should only be |
580 | * transmitted over a secure HTTPS connection. |
3a1de9f1 |
581 | * @param boolean $bHttpOnly Disallow JS to access the cookie (IE6 only) |
945c733e |
582 | * @param boolean $bReplace Replace previous cookies with same name? |
583 | * |
3a1de9f1 |
584 | * @return void |
945c733e |
585 | * |
b80887b4 |
586 | * @since 1.4.16 and 1.5.1 |
587 | * |
3a1de9f1 |
588 | */ |
945c733e |
589 | function sqsetcookie($sName, $sValue='deleted', $iExpire=0, $sPath="", $sDomain="", |
590 | $bSecure=false, $bHttpOnly=true, $bReplace=false) { |
591 | |
c3d4275e |
592 | // some environments can get overwhelmed by an excessive |
593 | // setting of the same cookie over and over (e.g., many |
594 | // calls to this function via sqsession_is_active() result |
595 | // in repeated setting of the session cookie when $bReplace |
596 | // is FALSE, but something odd happens (during login only) |
597 | // if we change that to default TRUE) ... so we keep our own |
598 | // naive per-request name/value cache and only set the cookie |
599 | // if its value is changing (or never seen before) |
600 | static $cookies = array(); |
601 | if (isset($cookies[$sName]) && $cookies[$sName] === $sValue) |
602 | return; |
603 | else |
604 | $cookies[$sName] = $sValue; |
605 | |
606 | |
68a7e1d6 |
607 | // if we have a secure connection then limit the cookies to https only. |
8f557b94 |
608 | global $is_secure_connection; |
609 | if ($sName && $is_secure_connection) |
68a7e1d6 |
610 | $bSecure = true; |
9c0f1780 |
611 | |
612 | // admin config can override the restriction of secure-only cookies |
613 | global $only_secure_cookies; |
614 | if (!$only_secure_cookies) |
615 | $bSecure = false; |
616 | |
68a7e1d6 |
617 | if (false && check_php_version(5,2)) { |
618 | // php 5 supports the httponly attribute in setcookie, but because setcookie seems a bit |
619 | // broken we use the header function for php 5.2 as well. We might change that later. |
620 | //setcookie($sName,$sValue,(int) $iExpire,$sPath,$sDomain,$bSecure,$bHttpOnly); |
621 | } else { |
a14da8d6 |
622 | if (!empty($sDomain)) { |
68a7e1d6 |
623 | // Fix the domain to accept domains with and without 'www.'. |
a14da8d6 |
624 | if (strtolower(substr($sDomain, 0, 4)) == 'www.') $sDomain = substr($sDomain, 4); |
625 | $sDomain = '.' . $sDomain; |
68a7e1d6 |
626 | |
627 | // Remove port information. |
a14da8d6 |
628 | $Port = strpos($sDomain, ':'); |
629 | if ($Port !== false) $sDomain = substr($sDomain, 0, $Port); |
68a7e1d6 |
630 | } |
716cc530 |
631 | if (!$sValue) $sValue = 'deleted'; |
68a7e1d6 |
632 | header('Set-Cookie: ' . rawurlencode($sName) . '=' . rawurlencode($sValue) |
a14da8d6 |
633 | . (empty($iExpire) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', $iExpire) . ' GMT') |
68a7e1d6 |
634 | . (empty($sPath) ? '' : '; path=' . $sPath) |
635 | . (empty($sDomain) ? '' : '; domain=' . $sDomain) |
636 | . (!$bSecure ? '' : '; secure') |
945c733e |
637 | . (!$bHttpOnly ? '' : '; HttpOnly'), $bReplace); |
68a7e1d6 |
638 | } |
202bcbcc |
639 | } |
640 | |
945c733e |
641 | |
202bcbcc |
642 | /** |
643 | * session_regenerate_id replacement for PHP < 4.3.2 |
644 | * |
645 | * This code is borrowed from Gallery, session.php version 1.53.2.1 |
10f4b195 |
646 | FIXME: I saw this code on php.net (in the manual); that's where it comes from originally, but I don't think we need it - it's just redundant to all the hard work we already did seeding the random number generator IMO. I think we can just call to GenerateRandomString() and dump the rest. |
202bcbcc |
647 | */ |
648 | if (!function_exists('session_regenerate_id')) { |
202bcbcc |
649 | |
650 | function php_combined_lcg() { |
202bcbcc |
651 | $tv = gettimeofday(); |
652 | $lcg['s1'] = $tv['sec'] ^ (~$tv['usec']); |
653 | $lcg['s2'] = mt_rand(); |
654 | $q = (int) ($lcg['s1'] / 53668); |
655 | $lcg['s1'] = (int) (40014 * ($lcg['s1'] - 53668 * $q) - 12211 * $q); |
656 | if ($lcg['s1'] < 0) { |
657 | $lcg['s1'] += 2147483563; |
658 | } |
659 | $q = (int) ($lcg['s2'] / 52774); |
660 | $lcg['s2'] = (int) (40692 * ($lcg['s2'] - 52774 * $q) - 3791 * $q); |
661 | if ($lcg['s2'] < 0) { |
662 | $lcg['s2'] += 2147483399; |
663 | } |
664 | $z = (int) ($lcg['s1'] - $lcg['s2']); |
665 | if ($z < 1) { |
666 | $z += 2147483562; |
667 | } |
668 | return $z * 4.656613e-10; |
669 | } |
3a1de9f1 |
670 | |
202bcbcc |
671 | function session_regenerate_id() { |
672 | global $base_uri; |
673 | $tv = gettimeofday(); |
674 | sqgetGlobalVar('REMOTE_ADDR',$remote_addr,SQ_SERVER); |
675 | $buf = sprintf("%.15s%ld%ld%0.8f", $remote_addr, $tv['sec'], $tv['usec'], php_combined_lcg() * 10); |
676 | session_id(md5($buf)); |
677 | if (ini_get('session.use_cookies')) { |
73ee0267 |
678 | sqsetcookie(session_name(), session_id(), 0, $base_uri); |
202bcbcc |
679 | } |
680 | return TRUE; |
681 | } |
3a1de9f1 |
682 | } |
7f62aaef |
683 | |
202bcbcc |
684 | |
7f62aaef |
685 | /** |
686 | * php_self |
687 | * |
d930613a |
688 | * Attempts to determine the path and filename and any arguments |
689 | * for the currently executing script. This is usually found in |
690 | * $_SERVER['REQUEST_URI'], but some environments may differ, so |
691 | * this function tries to standardize this value. |
692 | * |
693 | * Note that before SquirrelMail version 1.5.1, this function was |
694 | * stored in function/strings.php. |
7f62aaef |
695 | * |
7f62aaef |
696 | * @since 1.2.3 |
d930613a |
697 | * @return string The path, filename and any arguments for the |
698 | * current script |
7f62aaef |
699 | */ |
d930613a |
700 | function php_self() { |
701 | |
702 | $request_uri = ''; |
7f62aaef |
703 | |
d930613a |
704 | // first try $_SERVER['PHP_SELF'], which seems most reliable |
705 | // (albeit it usually won't include the query string) |
706 | // |
707 | $request_uri = ''; |
708 | if (!sqgetGlobalVar('PHP_SELF', $request_uri, SQ_SERVER) |
709 | || empty($request_uri)) { |
39790db7 |
710 | |
d930613a |
711 | // well, then let's try $_SERVER['REQUEST_URI'] |
39790db7 |
712 | // |
d930613a |
713 | $request_uri = ''; |
714 | if (!sqgetGlobalVar('REQUEST_URI', $request_uri, SQ_SERVER) |
715 | || empty($request_uri)) { |
716 | |
717 | // TODO: anyone have any other ideas? maybe $_SERVER['SCRIPT_NAME']??? |
718 | // |
719 | return ''; |
39790db7 |
720 | } |
7f62aaef |
721 | |
39790db7 |
722 | } |
7f62aaef |
723 | |
d930613a |
724 | // we may or may not have any query arguments, depending on |
725 | // which environment variable was used above, and the PHP |
726 | // version, etc., so let's check for it now |
727 | // |
728 | $query_string = ''; |
729 | if (strpos($request_uri, '?') === FALSE |
730 | && sqgetGlobalVar('QUERY_STRING', $query_string, SQ_SERVER) |
731 | && !empty($query_string)) { |
39790db7 |
732 | |
d930613a |
733 | $request_uri .= '?' . $query_string; |
734 | } |
39790db7 |
735 | |
d930613a |
736 | return $request_uri; |
7f62aaef |
737 | |
7f62aaef |
738 | } |
aa201211 |
739 | |
740 | |
aa201211 |
741 | /** |
742 | * Print variable |
743 | * |
744 | * sm_print_r($some_variable, [$some_other_variable [, ...]]); |
745 | * |
746 | * Debugging function - does the same as print_r, but makes sure special |
747 | * characters are converted to htmlentities first. This will allow |
748 | * values like <some@email.address> to be displayed. |
749 | * The output is wrapped in <<pre>> and <</pre>> tags. |
750 | * Since 1.4.2 accepts unlimited number of arguments. |
751 | * @since 1.4.1 |
752 | * @return void |
753 | */ |
754 | function sm_print_r() { |
755 | ob_start(); // Buffer output |
756 | foreach(func_get_args() as $var) { |
757 | print_r($var); |
758 | echo "\n"; |
759 | // php has get_class_methods function that can print class methods |
760 | if (is_object($var)) { |
761 | // get class methods if $var is object |
762 | $aMethods=get_class_methods(get_class($var)); |
763 | // make sure that $aMethods is array and array is not empty |
764 | if (is_array($aMethods) && $aMethods!=array()) { |
765 | echo "Object methods:\n"; |
766 | foreach($aMethods as $method) { |
767 | echo '* ' . $method . "\n"; |
768 | } |
769 | } |
770 | echo "\n"; |
771 | } |
772 | } |
773 | $buffer = ob_get_contents(); // Grab the print_r output |
774 | ob_end_clean(); // Silently discard the output & stop buffering |
775 | print '<div align="left"><pre>'; |
776 | print htmlentities($buffer); |
777 | print '</pre></div>'; |
778 | } |
45ca6962 |
779 | |
780 | |
253ca97e |
781 | /** |
3047e291 |
782 | * Sanitize a value using sm_encode_html_special_chars() or similar, but also |
783 | * recursively run sm_encode_html_special_chars() (or similar) on array keys |
253ca97e |
784 | * and values. |
785 | * |
786 | * If $value is not a string or an array with strings in it, |
787 | * the value is returned as is. |
788 | * |
789 | * @param mixed $value The value to be sanitized. |
790 | * @param mixed $quote_style Either boolean or an integer. If it |
791 | * is an integer, it must be the PHP |
792 | * constant indicating if/how to escape |
793 | * quotes: ENT_QUOTES, ENT_COMPAT, or |
794 | * ENT_NOQUOTES. If it is a boolean value, |
795 | * it must be TRUE and thus indicates |
796 | * that the only sanitizing to be done |
797 | * herein is to replace single and double |
798 | * quotes with ' and ", no other |
799 | * changes are made to $value. If it is |
800 | * boolean and FALSE, behavior reverts |
801 | * to same as if the value was ENT_QUOTES |
802 | * (OPTIONAL; default is ENT_QUOTES). |
803 | * |
804 | * @return mixed The sanitized value. |
805 | * |
806 | * @since 1.5.2 |
807 | * |
808 | **/ |
809 | function sq_htmlspecialchars($value, $quote_style=ENT_QUOTES) { |
810 | |
811 | if ($quote_style === FALSE) $quote_style = ENT_QUOTES; |
812 | |
813 | // array? go recursive... |
814 | // |
815 | if (is_array($value)) { |
816 | $return_array = array(); |
817 | foreach ($value as $key => $val) { |
818 | $return_array[sq_htmlspecialchars($key, $quote_style)] |
819 | = sq_htmlspecialchars($val, $quote_style); |
820 | } |
821 | return $return_array; |
822 | |
823 | // sanitize strings only |
824 | // |
825 | } else if (is_string($value)) { |
826 | if ($quote_style === TRUE) |
827 | return str_replace(array('\'', '"'), array(''', '"'), $value); |
828 | else |
3047e291 |
829 | return sm_encode_html_special_chars($value, $quote_style); |
253ca97e |
830 | } |
831 | |
832 | // anything else gets returned with no changes |
833 | // |
834 | return $value; |
835 | |
836 | } |
67c826ce |
837 | |
838 | |
8f557b94 |
839 | /** |
840 | * Detect whether or not we have a SSL secured (HTTPS) connection |
841 | * connection to the browser |
842 | * |
843 | * It is thought to be so if you have 'SSLOptions +StdEnvVars' |
844 | * in your Apache configuration, |
845 | * OR if you have HTTPS set to a non-empty value (except "off") |
846 | * in your HTTP_SERVER_VARS, |
847 | * OR if you have HTTP_X_FORWARDED_PROTO=https in your HTTP_SERVER_VARS, |
848 | * OR if you are on port 443. |
849 | * |
850 | * Note: HTTP_X_FORWARDED_PROTO could be sent from the client and |
851 | * therefore possibly spoofed/hackable. Thus, SquirrelMail |
852 | * ignores such headers by default. The administrator |
853 | * can tell SM to use such header values by setting |
854 | * $sq_ignore_http_x_forwarded_headers to boolean FALSE |
855 | * in config/config.php or by using config/conf.pl. |
856 | * |
857 | * Note: It is possible to run SSL on a port other than 443, and |
858 | * if that is the case, the administrator should set |
859 | * $sq_https_port in config/config.php or by using config/conf.pl. |
860 | * |
861 | * @return boolean TRUE if the current connection is SSL-encrypted; |
862 | * FALSE otherwise. |
863 | * |
864 | * @since 1.4.17 and 1.5.2 |
865 | * |
866 | */ |
867 | function is_ssl_secured_connection() |
868 | { |
869 | global $sq_ignore_http_x_forwarded_headers, $sq_https_port; |
870 | $https_env_var = getenv('HTTPS'); |
871 | if ($sq_ignore_http_x_forwarded_headers |
872 | || !sqgetGlobalVar('HTTP_X_FORWARDED_PROTO', $forwarded_proto, SQ_SERVER)) |
873 | $forwarded_proto = ''; |
874 | if (empty($sq_https_port)) // won't work with port 0 (zero) |
875 | $sq_https_port = 443; |
876 | if ((isset($https_env_var) && strcasecmp($https_env_var, 'on') === 0) |
877 | || (sqgetGlobalVar('HTTPS', $https, SQ_SERVER) && !empty($https) |
878 | && strcasecmp($https, 'off') !== 0) |
879 | || (strcasecmp($forwarded_proto, 'https') === 0) |
880 | || (sqgetGlobalVar('SERVER_PORT', $server_port, SQ_SERVER) |
881 | && $server_port == $sq_https_port)) |
882 | return TRUE; |
883 | return FALSE; |
884 | } |
885 | |
886 | |
e45a534b |
887 | /** |
888 | * Endeavor to detect what user and group PHP is currently |
889 | * running as. Probably only works in non-Windows environments. |
890 | * |
891 | * @return mixed Boolean FALSE is returned if something went wrong, |
892 | * otherwise an array is returned with the following |
893 | * elements: |
894 | * uid The current process' UID (integer) |
895 | * euid The current process' effective UID (integer) |
896 | * gid The current process' GID (integer) |
897 | * egid The current process' effective GID (integer) |
898 | * name The current process' name/handle (string) |
899 | * ename The current process' effective name/handle (string) |
900 | * group The current process' group name (string) |
901 | * egroup The current process' effective group name (string) |
902 | * Note that some of these elements may have empty |
903 | * values, especially if they could not be determined. |
904 | * |
905 | * @since 1.5.2 |
906 | * |
907 | */ |
908 | function get_process_owner_info() |
909 | { |
910 | if (!function_exists('posix_getuid')) |
911 | return FALSE; |
912 | |
913 | $process_info['uid'] = posix_getuid(); |
914 | $process_info['euid'] = posix_geteuid(); |
915 | $process_info['gid'] = posix_getgid(); |
916 | $process_info['egid'] = posix_getegid(); |
917 | |
918 | $user_info = posix_getpwuid($process_info['uid']); |
919 | $euser_info = posix_getpwuid($process_info['euid']); |
920 | $group_info = posix_getgrgid($process_info['gid']); |
921 | $egroup_info = posix_getgrgid($process_info['egid']); |
922 | |
923 | $process_info['name'] = $user_info['name']; |
924 | $process_info['ename'] = $euser_info['name']; |
925 | $process_info['group'] = $user_info['name']; |
926 | $process_info['egroup'] = $euser_info['name']; |
927 | |
928 | return $process_info; |
929 | } |
930 | |
931 | |