[ Index ] |
|
Code source de Serendipity 1.2 |
1 <?php # $Id: functions_config.inc.php 1860 2007-08-21 10:26:07Z garvinhicking $ 2 # Copyright (c) 2003-2005, Jannis Hermanns (on behalf the Serendipity Developer Team) 3 # All rights reserved. See LICENSE file for licensing details 4 5 if (IN_serendipity !== true) { 6 die ("Don't hack!"); 7 } 8 9 if (defined('S9Y_FRAMEWORK_CONFIG')) { 10 return; 11 } 12 @define('S9Y_FRAMEWORK_CONFIG', true); 13 14 /** 15 * Adds a new author account 16 * 17 * @access public 18 * @param string New username 19 * @param string New password 20 * @param string The realname of the user 21 * @param string The email address of the user 22 * @param int The userlevel of a user 23 * @return int The new user ID of the added author 24 */ 25 function serendipity_addAuthor($username, $password, $realname, $email, $userlevel=0) { 26 global $serendipity; 27 $password = md5($password); 28 $query = "INSERT INTO {$serendipity['dbPrefix']}authors (username, password, realname, email, userlevel) 29 VALUES ('" . serendipity_db_escape_string($username) . "', 30 '" . serendipity_db_escape_String($password) . "', 31 '" . serendipity_db_escape_String($realname) . "', 32 '" . serendipity_db_escape_String($email) . "', 33 '" . serendipity_db_escape_String($userlevel) . "')"; 34 serendipity_db_query($query); 35 $cid = serendipity_db_insert_id('authors', 'authorid'); 36 37 $data = array( 38 'authorid' => $cid, 39 'username' => $username, 40 'realname' => $realname, 41 'email' => $email 42 ); 43 44 serendipity_insertPermalink($data, 'author'); 45 return $cid; 46 } 47 48 /** 49 * Delete an author account 50 * 51 * (Note, this function does not delete entries by an author) 52 * 53 * @access public 54 * @param int The author ID to delete 55 * @return boolean True on success, false on error or unsufficient privileges 56 */ 57 function serendipity_deleteAuthor($authorid) { 58 global $serendipity; 59 60 if (!serendipity_checkPermission('adminUsersDelete')) { 61 return false; 62 } 63 64 if (serendipity_db_query("DELETE FROM {$serendipity['dbPrefix']}authors WHERE authorid=" . (int)$authorid)) { 65 serendipity_db_query("DELETE FROM {$serendipity['dbPrefix']}permalinks WHERE entry_id=" . (int)$authorid ." and type='author'"); 66 } 67 return true; 68 } 69 70 /** 71 * Removes a configuration value from the Serendipity Configuration 72 * 73 * Global config items have the authorid 0, author-specific configuration items have the corresponding authorid. 74 * 75 * @access public 76 * @param string The name of the configuration value 77 * @param int The ID of the owner of the config value (0: global) 78 * @return null 79 */ 80 function serendipity_remove_config_var($name, $authorid = 0) { 81 global $serendipity; 82 serendipity_db_query("DELETE FROM {$serendipity['dbPrefix']}config where name='" . serendipity_db_escape_string($name) . "' AND authorid = " . (int)$authorid); 83 } 84 85 /** 86 * Sets a configuration value for the Serendipity Configuration 87 * 88 * Global config items have the authorid 0, author-specific configuration items have the corresponding authorid. 89 * 90 * @access public 91 * @param string The name of the configuration value 92 * @param string The value of the configuration item 93 * @param int The ID of the owner of the config value (0: global) 94 * @return null 95 */ 96 function serendipity_set_config_var($name, $val, $authorid = 0) { 97 global $serendipity; 98 99 serendipity_db_query("DELETE FROM {$serendipity['dbPrefix']}config where name='" . serendipity_db_escape_string($name) . "' AND authorid = " . (int)$authorid); 100 101 if ($name == 'password' || $name == 'check_password') { 102 return; 103 } 104 105 $r = serendipity_db_insert('config', array('name' => $name, 'value' => $val, 'authorid' => $authorid)); 106 107 if ($authorid === 0 || $authorid === $serendipity['authorid']) { 108 if ($val === 'false') { 109 $serendipity[$name] = false; 110 } else { 111 $serendipity[$name] = $val; 112 } 113 } 114 115 if (is_string($r)) { 116 echo $r; 117 } 118 } 119 120 /** 121 * Retrieve a global configuration value for a specific item of the current Serendipity Configuration 122 * 123 * @access public 124 * @param string The name of the configuration value 125 * @param string The default value of a configuration item, if not found in the Database 126 * @param boolean If set to true, the default value of a configuration item will be returned if the item is set, but empty. If false, an empty configuration value will be returned empty. This is required for getting default values if you do not want to store/allow empty config values. 127 * @return string The configuration value content 128 */ 129 function serendipity_get_config_var($name, $defval = false, $empty = false) { 130 global $serendipity; 131 if (isset($serendipity[$name])) { 132 if ($empty && gettype($serendipity[$name]) == 'string' && $serendipity[$name] === '') { 133 return $defval; 134 } else { 135 return $serendipity[$name]; 136 } 137 } else { 138 return $defval; 139 } 140 } 141 142 /** 143 * Retrieve an author-specific configuration value for an item of the Serendipity Configuration stored in the DB 144 * 145 * Despite the serendipity_get_config_var() function, this will retrieve author-specific values straight from the Database. 146 * 147 * @access public 148 * @param string The name of the configuration value 149 * @param int The ID of the owner of the config value (0: global) 150 * @param string The default value of a configuration option, if not set in the DB 151 * @return string The configuration value content 152 */ 153 function serendipity_get_user_config_var($name, $authorid, $default = '') { 154 global $serendipity; 155 156 $author_sql = ''; 157 if (!empty($authorid)) { 158 $author_sql = "authorid = " . (int)$authorid . " AND "; 159 } elseif (isset($serendipity[$name])) { 160 return $serendipity[$name]; 161 } 162 163 $r = serendipity_db_query("SELECT value FROM {$serendipity['dbPrefix']}config WHERE $author_sql name = '" . $name . "' LIMIT 1", true); 164 165 if (is_array($r)) { 166 return $r[0]; 167 } else { 168 return $default; 169 } 170 } 171 172 /** 173 * Retrieves an author-specific account value 174 * 175 * This retrieves specific account data from the user configuration, not from the serendipity configuration. 176 * 177 * @access public 178 * @param string The name of the configuration value 179 * @param int The ID of the author to fetch the configuration for 180 * @param string The default value of a configuration option, if not set in the DB 181 * @return string The configuration value content 182 */ 183 function serendipity_get_user_var($name, $authorid, $default) { 184 global $serendipity; 185 186 $r = serendipity_db_query("SELECT $name FROM {$serendipity['dbPrefix']}authors WHERE authorid = " . (int)$authorid, true); 187 188 if (is_array($r)) { 189 return $r[0]; 190 } else { 191 return $default; 192 } 193 } 194 195 /** 196 * Updates data from the author-specific account 197 * 198 * This sets the personal account data of a serendipity user within the 'authors' DB table 199 * 200 * @access public 201 * @param string The name of the configuration value 202 * @param string The content of the configuration value 203 * @param int The ID of the author to set the configuration for 204 * @param boolean If set to true, the stored config value will be imported to the Session/current config of the user. This is applied for example when you change your own user's preferences and want it to be immediately reflected in the interface. 205 * @return null 206 */ 207 function serendipity_set_user_var($name, $val, $authorid, $copy_to_s9y = true) { 208 global $serendipity; 209 210 // When inserting a DB value, this array maps the new values to the corresponding s9y variables 211 static $user_map_array = array( 212 'username' => 'serendipityUser', 213 'email' => 'serendipityEmail', 214 'userlevel' => 'serendipityUserlevel' 215 ); 216 217 // Special case for inserting a password 218 switch($name) { 219 case 'check_password': 220 //Skip this field. It doesn't need to be stored. 221 return; 222 case 'password': 223 if (empty($val)) { 224 return; 225 } 226 227 $val = md5($val); 228 $copy_to_s9y = false; 229 break; 230 231 case 'right_publish': 232 case 'mail_comments': 233 case 'mail_trackbacks': 234 $val = (serendipity_db_bool($val) ? 1 : '0'); 235 break; 236 } 237 238 serendipity_db_query("UPDATE {$serendipity['dbPrefix']}authors SET $name = '" . serendipity_db_escape_string($val) . "' WHERE authorid = " . (int)$authorid); 239 240 if ($copy_to_s9y) { 241 if (isset($user_map_array[$name])) { 242 $key = $user_map_array[$name]; 243 } else { 244 $key = 'serendipity' . ucfirst($name); 245 } 246 247 $_SESSION[$key] = $serendipity[$key] = $val; 248 } 249 } 250 251 /** 252 * Gets the full filename and path of a template/style/theme file 253 * 254 * The returned full path is depending on the second parameter, where you can either fetch a HTTP path, or a realpath. 255 * The file is searched in the current template, and if it is not found there, it is returned from the default template. 256 * 257 * @access public 258 * @param string The filename to search for in the selected template 259 * @param string The path selector that tells whether to return a HTTP or realpath 260 * @return string The full path+filename to the requested file 261 */ 262 function serendipity_getTemplateFile($file, $key = 'serendipityHTTPPath') { 263 global $serendipity; 264 265 $directories = array(); 266 267 $directories[] = isset($serendipity['template']) ? $serendipity['template'] . '/' : ''; 268 if (isset($serendipity['template_engine']) && (stristr($file, 'admin/') === false || $serendipity['template_engine'] != 'default')) { 269 $directories[] = $serendipity['template_engine'] . '/'; 270 } 271 272 $directories[] = $serendipity['defaultTemplate'] .'/'; 273 $directories[] = 'default/'; 274 275 foreach ($directories as $directory) { 276 $templateFile = $serendipity['templatePath'] . $directory . $file; 277 if (file_exists($serendipity['serendipityPath'] . $templateFile)) { 278 return $serendipity[$key] . $templateFile; 279 } 280 } 281 282 if (preg_match('@\.(tpl|css|php)@i', $file) && !stristr($file, 'plugin')) { 283 return $file; 284 } 285 286 return false; 287 } 288 289 /** 290 * Loads all configuration values and imports them to the $serendipity array 291 * 292 * This function may be called twice - once for the global config and once for 293 * user-specific config 294 * 295 * @access public 296 * @param int The Authorid to fetch the configuration from (0: global) 297 * @return null 298 */ 299 function serendipity_load_configuration($author = null) { 300 global $serendipity; 301 static $config_loaded = array(); 302 303 if (isset($config_loaded[$author])) { 304 return true; 305 } 306 307 if (!empty($author)) { 308 // Replace default configuration directives with user-relevant data 309 $rows =& serendipity_db_query("SELECT name,value 310 FROM {$serendipity['dbPrefix']}config 311 WHERE authorid = '". (int)$author ."'"); 312 } else { 313 // Only get default variables, user-independent (frontend) 314 $rows =& serendipity_db_query("SELECT name, value 315 FROM {$serendipity['dbPrefix']}config 316 WHERE authorid = 0"); 317 } 318 319 if (is_array($rows)) { 320 foreach ($rows as $row) { 321 // Convert 'true' and 'false' into booleans 322 $serendipity[$row['name']] = serendipity_get_bool($row['value']); 323 } 324 } 325 $config_loaded[$author] = true; 326 327 // Store default language 328 $serendipity['default_lang'] = $serendipity['lang']; 329 } 330 331 /** 332 * Perform logout functions (destroys session data) 333 * 334 * @access public 335 * @return null 336 */ 337 function serendipity_logout() { 338 $_SESSION['serendipityAuthedUser'] = false; 339 serendipity_session_destroy(); 340 serendipity_deleteCookie('author_information'); 341 serendipity_deleteCookie('author_token'); 342 } 343 344 /** 345 * Destroys a session, keeps important stuff intact. 346 * @access public 347 * @return null 348 */ 349 function serendipity_session_destroy() { 350 $no_smarty = $_SESSION['no_smarty']; 351 @session_destroy(); 352 session_regenerate_id(); 353 session_start(); 354 355 $_SESSION['SERVER_GENERATED_SID'] = true; 356 $_SESSION['no_smarty'] = $no_smarty; 357 } 358 359 /** 360 * Perform login to Serendipity 361 * 362 * @access public 363 * @param boolean If set to true, external plugins will be queried for getting a login 364 * @return boolean Return true, if the user is logged in. False if not. 365 */ 366 function serendipity_login($use_external = true) { 367 global $serendipity; 368 369 if (serendipity_authenticate_author('', '', false, $use_external)) { 370 #The session has this data already 371 #we previously just checked the value of $_SESSION['serendipityAuthedUser'] but 372 #we need the authorid still, so call serendipity_authenticate_author with blank 373 #params 374 return true; 375 } 376 377 // First try login via POST data. If true, the userinformation will be stored in a cookie (optionally) 378 if (serendipity_authenticate_author($serendipity['POST']['user'], $serendipity['POST']['pass'], false, $use_external)) { 379 if (empty($serendipity['POST']['auto'])) { 380 serendipity_deleteCookie('author_information'); 381 serendipity_deleteCookie('author_information_iv'); 382 return false; 383 } else { 384 serendipity_issueAutologin( 385 array('username' => $serendipity['POST']['user'], 386 'password' => $serendipity['POST']['pass'] 387 ) 388 ); 389 return true; 390 } 391 // Now try login via COOKIE data 392 } elseif (isset($serendipity['COOKIE']['author_information'])) { 393 $cookie = serendipity_checkAutologin($serendipity['COOKIE']['author_information'], $serendipity['COOKIE']['author_information_iv']); 394 395 if (is_array($cookie) && serendipity_authenticate_author($cookie['username'], $cookie['password'], false, $use_external)) { 396 return true; 397 } else { 398 serendipity_deleteCookie('author_information'); 399 serendipity_deleteCookie('author_information_iv'); 400 return false; 401 } 402 } 403 } 404 405 /** 406 * Issue a new auto login cookie 407 * @param array The input data 408 */ 409 function serendipity_issueAutologin($array) { 410 global $serendipity; 411 412 $package = serialize($array); 413 414 if (function_exists('mcrypt_encrypt')) { 415 // Secure the package data when being stored inside the Database 416 $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC), MCRYPT_RAND); 417 $key = base64_encode($iv); 418 $package = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $package, MCRYPT_MODE_CBC, $iv); 419 serendipity_setCookie('author_information_iv', $key); 420 } 421 $package = base64_encode($package); 422 423 $rnd = md5(uniqid(time(), true) . $_SERVER['REMOTE_ADDR']); 424 425 // Delete possible current cookie. Also delete any autologin keys that smell like 3-week-old, dead fish. 426 serendipity_db_query("DELETE FROM {$serendipity['dbPrefix']}options 427 WHERE okey = 'l_" . serendipity_db_escape_string($serendipity['COOKIE']['author_information']) . "' 428 OR (okey LIKE 'l_%' AND name < " . (time() - 1814400) . ")"); 429 430 // Issue new autologin cookie 431 serendipity_db_query("INSERT INTO {$serendipity['dbPrefix']}options (name, value, okey) VALUES ('" . time() . "', '" . serendipity_db_escape_string($package) . "', 'l_" . $rnd . "')"); 432 serendipity_setCookie('author_information', $rnd); 433 } 434 435 /** 436 * Checks a new auto login cookie 437 * @param array The input data 438 */ 439 function serendipity_checkAutologin($ident, $iv) { 440 global $serendipity; 441 442 // Fetch login data from DB 443 $autologin =& serendipity_db_query("SELECT * FROM {$serendipity['dbPrefix']}options WHERE okey = 'l_" . serendipity_db_escape_string($ident) . "' LIMIT 1", true, 'assoc'); 444 if (!is_array($autologin)) { 445 return false; 446 } 447 448 if (function_exists('mcrypt_decrypt') && !empty($iv)) { 449 $key = $iv; 450 $iv = base64_decode($iv); 451 $cookie = unserialize(mcrypt_decrypt(MCRYPT_BLOWFISH, $key, base64_decode($autologin['value']), MCRYPT_MODE_CBC, $iv)); 452 } else { 453 $cookie = unserialize(base64_decode($autologin['value'])); 454 } 455 456 if ($autologin['name'] < (time()-86400)) { 457 // Issued autologin cookie has been issued more than 1 day ago. Re-Issue new cookie, invalidate old one to prevent abuse 458 if ($serendipity['expose_s9y']) serendipity_header('X-ReIssue-Cookie: +' . (time() - $autologin['name']) . 's'); 459 serendipity_issueAutologin($cookie); 460 } 461 462 return $cookie; 463 } 464 465 /** 466 * Set a session cookie which can identify a user accross http/https boundaries 467 */ 468 function serendipity_setAuthorToken() { 469 $hash = sha1(uniqid(rand(), true)); 470 serendipity_setCookie('author_token', $hash); 471 $_SESSION['author_token'] = $hash; 472 } 473 474 /** 475 * Perform user authentication routine 476 * 477 * If a user is already authenticated via session data, this bypasses some routines. 478 * After a user has ben authenticated, several SESSION variables ar set. 479 * If the authentication fails, the session is destroyed. 480 * 481 * @access public 482 * @param string The username to check 483 * @param string The password to check (may contain plaintext or MD5 hash) 484 * @param boolean Indicates whether the input password is already in MD5 format (TRUE) or not (FALSE). 485 * @param boolean Indicates whether to query external plugins for authentication 486 * @return boolean True on success, False on error 487 */ 488 function serendipity_authenticate_author($username = '', $password = '', $is_md5 = false, $use_external = true) { 489 global $serendipity; 490 491 if (isset($_SESSION['serendipityUser']) && isset($_SESSION['serendipityPassword']) && isset($_SESSION['serendipityAuthedUser']) && $_SESSION['serendipityAuthedUser'] == true) { 492 $username = $_SESSION['serendipityUser']; 493 $password = $_SESSION['serendipityPassword']; 494 // For safety reasons when multiple blogs are installed on the same host, we need to check the current author each time to not let him log into a different blog with the same sessiondata 495 $is_md5 = true; 496 } 497 498 $is_authenticated = false; 499 serendipity_plugin_api::hook_event('backend_login', $is_authenticated, NULL); 500 if ($is_authenticated) { 501 return true; 502 } 503 504 if ($username != '') { 505 if ($use_external) { 506 serendipity_plugin_api::hook_event('backend_auth', $is_md5, array('username' => $username, 'password' => $password)); 507 } 508 509 if ($is_md5 === false && !empty($password)) { 510 $password = md5($password); 511 } 512 513 $query = "SELECT DISTINCT 514 email, realname, authorid, userlevel, right_publish 515 FROM 516 {$serendipity['dbPrefix']}authors 517 WHERE 518 username = '" . serendipity_db_escape_string($username) . "' 519 AND password = '" . serendipity_db_escape_string($password) . "'"; 520 $row =& serendipity_db_query($query, true, 'assoc'); 521 522 if (is_array($row)) { 523 serendipity_setCookie('old_session', session_id(), false); 524 if (!$is_md5) { 525 serendipity_setAuthorToken(); 526 } 527 $_SESSION['serendipityUser'] = $serendipity['serendipityUser'] = $username; 528 $_SESSION['serendipityRealname'] = $serendipity['serendipityRealname'] = $row['realname']; 529 $_SESSION['serendipityPassword'] = $serendipity['serendipityPassword'] = $password; 530 $_SESSION['serendipityEmail'] = $serendipity['serendipityEmail'] = $row['email']; 531 $_SESSION['serendipityAuthorid'] = $serendipity['authorid'] = $row['authorid']; 532 $_SESSION['serendipityUserlevel'] = $serendipity['serendipityUserlevel'] = $row['userlevel']; 533 $_SESSION['serendipityAuthedUser'] = $serendipity['serendipityAuthedUser'] = true; 534 $_SESSION['serendipityRightPublish']= $serendipity['serendipityRightPublish'] = $row['right_publish']; 535 serendipity_load_configuration($serendipity['authorid']); 536 serendipity_setCookie('userDefLang', $serendipity['lang'], false); 537 return true; 538 } else { 539 $_SESSION['serendipityAuthedUser'] = false; 540 serendipity_session_destroy(); 541 } 542 } 543 544 return false; 545 } 546 547 /** 548 * Check if a user is logged in 549 * 550 * @access public 551 * @return boolean TRUE when logged in, FALSE when not. 552 */ 553 function serendipity_userLoggedIn() { 554 if ($_SESSION['serendipityAuthedUser'] === true && IS_installed) { 555 return true; 556 } else { 557 return false; 558 } 559 } 560 561 /** 562 * A clone of an ifsetor() function to set a variable conditional on if the target already exists 563 * 564 * The function sets the contents of $source into the $target variable, but only if $target is not yet set. Eases up some if...else logic or multiple ternary operators 565 * 566 * @access public 567 * @param mixed Source variable that should be set into the target variable (reference call!) 568 * @param mixed Target variable, that should get the contents of the source variable (reference call!) 569 * @return boolean True, when $target was not yet set and has been altered. False when no changes where made. 570 */ 571 function serendipity_restoreVar(&$source, &$target) { 572 global $serendipity; 573 574 if (isset($source) && !isset($target)) { 575 $target = $source; 576 return true; 577 } 578 579 return false; 580 } 581 582 /** 583 * Echo Javascript code to set a cookie variable 584 * 585 * This function is useful if your HTTP headers were already sent, but you still want to set a cookie 586 * Note that contents are echo'd, not return'd. 587 * 588 * @access public 589 * @param string The name of the cookie variable 590 * @param string The contents of the cookie variable 591 * @return null 592 */ 593 function serendipity_JSsetCookie($name, $value) { 594 $name = htmlentities($name); 595 $value = urlencode($value); 596 597 echo '<script type="text/javascript">SetCookie("' . $name . '", unescape("' . $value . '"))</script>' . "\n"; 598 } 599 600 /** 601 * Set a Cookie via HTTP calls, and update $_COOKIE plus $serendipity['COOKIE'] array. 602 * 603 * @access public 604 * @param string The name of the cookie variable 605 * @param string The contents of the cookie variable 606 * @return null 607 */ 608 function serendipity_setCookie($name, $value, $securebyprot = true) { 609 global $serendipity; 610 611 $host = $_SERVER['HTTP_HOST']; 612 if ($securebyprot) { 613 $secure = (strtolower($_SERVER['HTTPS']) == 'on') ? true : false; 614 if ($pos = strpos($host, ":")) { 615 $host = substr($host, 0, $pos); 616 } 617 } else { 618 $secure = false; 619 } 620 621 // If HTTP-Hosts like "localhost" are used, current browsers reject cookies. 622 // In this case, we disregard the HTTP host to be able to set that cookie. 623 if (substr_count($host, '.') < 2) { 624 $host = ''; 625 } 626 627 setcookie("serendipity[$name]", $value, time()+60*60*24*30, $serendipity['serendipityHTTPPath'], $host, $secure); 628 $_COOKIE[$name] = $value; 629 $serendipity['COOKIE'][$name] = $value; 630 } 631 632 /** 633 * Deletes an existing cookie value 634 * 635 * LONG 636 * 637 * @access public 638 * @param string Name of the cookie to delete 639 * @return 640 */ 641 function serendipity_deleteCookie($name) { 642 global $serendipity; 643 644 $host = $_SERVER['HTTP_HOST']; 645 if ($pos = strpos($host, ":")) { 646 $host = substr($host, 0, $pos); 647 } 648 649 setcookie("serendipity[$name]", '', time()-4000, $serendipity['serendipityHTTPPath'], $host); 650 unset($_COOKIE[$name]); 651 unset($serendipity['COOKIE'][$name]); 652 } 653 654 /** 655 * Performs a check whether an iframe for the admin section shall be emitted 656 * 657 * The iframe is used for previewing an entry with the stylesheet of the frontend. 658 * It fetches its data from the session input data. 659 * 660 * @access private 661 * @return boolean True, if iframe was requested, false if not. 662 */ 663 function serendipity_is_iframe() { 664 global $serendipity; 665 666 if ($serendipity['GET']['is_iframe'] && is_array($_SESSION['save_entry'])) { 667 include_once S9Y_INCLUDE_PATH . 'include/functions_entries_admin.inc.php'; 668 // An iframe may NOT contain <html> and </html> tags, that's why we emit different headers here than on serendipity_admin.php 669 670 // We need to restore GET/POST variables to that depending plugins inside the iframe 671 // can still fetch all that variables; and we also tighten security by not allowing 672 // to pass any different GET/POST variables to our iframe. 673 $iframe_mode = $serendipity['GET']['iframe_mode']; 674 $serendipity['POST'] = &$_SESSION['save_entry_POST']; 675 $serendipity['GET'] = &$_SESSION['save_entry_POST']; // GET-Vars are the same as POST to ensure compatibility. 676 ignore_user_abort(true); 677 serendipity_iframe($_SESSION['save_entry'], $iframe_mode, true); 678 return true; 679 } 680 return false; 681 } 682 683 /** 684 * Prints the content of the iframe. 685 * 686 * Called by serendipity_is_iframe, when preview is requested. Fetches data from session. 687 * An iframe is used so that a single s9y page must not timeout on intensive operations, 688 * and so that the frontend stylesheet can be embedded without screwing up the backend. 689 * 690 * @access private 691 * @see serendipity_is_iframe() 692 * @param mixed The entry array (comes from session variable) 693 * @param string Indicates whether an entry is previewed or saved. Save performs XML-RPC calls. 694 * @param boolean Use smarty templating? 695 * @return boolean Indicates whether iframe data was printed 696 */ 697 function serendipity_iframe(&$entry, $mode = null, $use_smarty = true) { 698 global $serendipity; 699 700 if (empty($mode) || !is_array($entry)) { 701 return false; 702 } 703 704 if ($use_smarty) { 705 $serendipity['smarty_raw_mode'] = true; // Force output of Smarty stuff in the backend 706 $serendipity['smarty_preview'] = true; 707 serendipity_smarty_init(); 708 $serendipity['smarty']->assign('is_preview', true); 709 ob_start(); 710 } 711 712 $show = false; 713 switch ($mode) { 714 case 'save': 715 echo '<div style="float: left; height: 75px"></div>'; 716 $res = serendipity_updertEntry($entry); 717 718 if (is_string($res)) { 719 echo '<div class="serendipity_msg_error">' . ERROR . ': <b>' . $res . '</b></div>'; 720 } else { 721 if (!empty($serendipity['lastSavedEntry'])) { 722 // Last saved entry must be propagated to entry form so that if the user re-edits it, 723 // it needs to be stored with the new ID. 724 echo '<script type="text/javascript">parent.document.forms[\'serendipityEntry\'][\'serendipity[id]\'].value = "' . $serendipity['lastSavedEntry'] . '";</script>'; 725 } 726 $entrylink = serendipity_archiveURL($res, $entry['title'], 'serendipityHTTPPath', true, array('timestamp' => $entry['timestamp'])); 727 echo '<div class="serendipityAdminMsgSuccess"><img style="height: 22px; width: 22px; border: 0px; padding-right: 4px; vertical-align: middle" src="' . serendipity_getTemplateFile('admin/img/admin_msg_success.png') . '" alt="" />' . ENTRY_SAVED . ' (<a href="' . $entrylink . '" target="_blank">' . VIEW . '</a>)</div>'; 728 } 729 echo '<br style="clear: both" />'; 730 731 $show = true; 732 break; 733 734 case 'preview': 735 echo '<div style="float: left; height: 225px"></div>'; 736 serendipity_printEntries(array($entry), ($entry['extended'] != '' ? 1 : 0), true); 737 echo '<br style="clear: both" />'; 738 739 $show = true; 740 break; 741 } 742 743 if ($use_smarty) { 744 $preview = ob_get_contents(); 745 ob_end_clean(); 746 $serendipity['smarty']->assign_by_ref('preview', $preview); 747 $serendipity['smarty']->display(serendipity_getTemplateFile('preview_iframe.tpl', 'serendipityPath')); 748 } 749 750 return $show; 751 } 752 753 /** 754 * Creates the necessary session data to be used by later iframe calls 755 * 756 * This function emits the actual <iframe> call. 757 * 758 * @access private 759 * @see serendipity_is_iframe() 760 * @param string Indicates whether an entry is previewed or saved. Save performs XML-RPC calls. 761 * @param mixed The entry array (comes from HTTP POST request) 762 * @return boolean Indicates whether iframe data was stored 763 */ 764 function serendipity_iframe_create($mode, &$entry) { 765 global $serendipity; 766 767 if (!empty($serendipity['POST']['no_save'])) { 768 return true; 769 } 770 771 $_SESSION['save_entry'] = $entry; 772 $_SESSION['save_entry_POST'] = $serendipity['POST']; 773 774 $attr = ''; 775 switch($mode) { 776 case 'save': 777 $attr = ' height="100" '; 778 break; 779 780 case 'preview': 781 $attr = ' height="300" '; 782 break; 783 } 784 785 echo '<iframe src="serendipity_admin.php?serendipity[is_iframe]=true&serendipity[iframe_mode]=' . $mode . '" id="serendipity_iframe" name="serendipity_iframe" ' . $attr . ' width="100%" frameborder="0" marginwidth="0" marginheight="0" scrolling="auto" title="Serendipity">' 786 . IFRAME_WARNING 787 . '</iframe><br /><br />'; 788 } 789 790 /** 791 * Pre-Checks certain server environments to indicate available options when installing Serendipity 792 * 793 * @access public 794 * @param string The name of the configuration option that needs to be checked for environmental data. 795 * @return array Returns the array of available options for the requested config option 796 */ 797 function serendipity_probeInstallation($item) { 798 global $serendipity; 799 $res = NULL; 800 801 switch ( $item ) { 802 case 'dbType' : 803 $res = array(); 804 if (extension_loaded('mysql')) { 805 $res['mysql'] = 'MySQL'; 806 } 807 if (extension_loaded('PDO') && 808 in_array('pgsql', PDO::getAvailableDrivers())) { 809 $res['pdo-postgres'] = 'PDO::PostgreSQL'; 810 } 811 if (extension_loaded('pgsql')) { 812 $res['postgres'] = 'PostgreSQL'; 813 } 814 if (extension_loaded('mysqli')) { 815 $res['mysqli'] = 'MySQLi'; 816 } 817 if (extension_loaded('sqlite')) { 818 $res['sqlite'] = 'SQLite'; 819 } 820 if (extension_loaded('SQLITE3')) { 821 $res['sqlite3'] = 'SQLite3'; 822 } 823 break; 824 825 case 'rewrite' : 826 $res = array(); 827 $res['none'] = 'Disable URL Rewriting'; 828 $res['errordocs'] = 'Use Apache errorhandling'; 829 if( !function_exists('apache_get_modules') || in_array('mod_rewrite', apache_get_modules()) ) { 830 $res['rewrite'] = 'Use Apache mod_rewrite'; 831 } 832 break; 833 } 834 835 return $res; 836 } 837 838 /** 839 * Sets a HTTP header 840 * 841 * @access public 842 * @param string The HTTP headre to set 843 * @return null 844 */ 845 function serendipity_header($header) { 846 if (!headers_sent()) { 847 header($header); 848 } 849 } 850 851 /** 852 * Gets the currently selected language. Either from the browser, or the personal configuration, or the global configuration. 853 * 854 * This function also sets HTTP Headers and cookies to contain the language for follow-up requests 855 * TODO: 856 * This previously was handled inside a plugin with an event hook, but caching 857 * the event plugins that early in sequence created trouble with plugins not 858 * having loaded the right language. 859 * Find a way to let plugins hook into that sequence :-) 860 * 861 * @access public 862 * @return string Returns the name of the selected language. 863 */ 864 function serendipity_getSessionLanguage() { 865 global $serendipity; 866 867 // DISABLE THIS! 868 /* 869 if ($_SESSION['serendipityAuthedUser']) { 870 serendipity_header('X-Serendipity-InterfaceLangSource: Database'); 871 return $serendipity['lang']; 872 } 873 */ 874 875 if (isset($_REQUEST['user_language']) && (!empty($serendipity['languages'][$_REQUEST['user_language']])) && !headers_sent()) { 876 serendipity_setCookie('serendipityLanguage', $_REQUEST['user_language'], false); 877 } 878 879 if (isset($serendipity['COOKIE']['serendipityLanguage'])) { 880 if ($serendipity['expose_s9y']) serendipity_header('X-Serendipity-InterfaceLangSource: Cookie'); 881 $lang = $serendipity['COOKIE']['serendipityLanguage']; 882 } elseif (!empty($serendipity['languages'][$serendipity['GET']['lang_selected']])) { 883 if ($serendipity['expose_s9y']) serendipity_header('X-Serendipity-InterfaceLangSource: GET'); 884 $lang = $serendipity['GET']['lang_selected']; 885 } elseif (serendipity_db_bool($serendipity['lang_content_negotiation'])) { 886 if ($serendipity['expose_s9y']) serendipity_header('X-Serendipity-InterfaceLangSource: Content-Negotiation'); 887 $lang = serendipity_detectLang(); 888 } 889 890 if (isset($lang)) { 891 $serendipity['detected_lang'] = $lang; 892 } else { 893 if (! empty($_SESSION['serendipityLanguage'])) { 894 $lang = $_SESSION['serendipityLanguage']; 895 } else { 896 if (isset($serendipity['COOKIE']['userDefLang']) && ! empty($serendipity['COOKIE']['userDefLang'])) { 897 $lang = $serendipity['COOKIE']['userDefLang']; 898 } else { 899 $lang = $serendipity['lang']; 900 } 901 } 902 $serendipity['detected_lang'] = null; 903 } 904 905 if (!isset($serendipity['languages'][$lang])) { 906 $serendipity['detected_lang'] = null; 907 return $serendipity['lang']; 908 } else { 909 $_SESSION['serendipityLanguage'] = $lang; 910 if (!is_null($serendipity['detected_lang'])) { 911 if ($serendipity['expose_s9y']) serendipity_header('X-Serendipity-InterfaceLang: ' . $lang); 912 } 913 } 914 915 return $lang; 916 } 917 918 /** 919 * Gets the selected language from personal configuration if needed 920 * 921 * This function also sets HTTP Headers and cookies to contain the language for follow-up requests 922 * 923 * @access public 924 * @return string Returns the name of the selected language. 925 */ 926 function serendipity_getPostAuthSessionLanguage() { 927 global $serendipity; 928 929 if (! is_null($serendipity['detected_lang'])) { 930 return $serendipity['detected_lang']; 931 } 932 933 if ($_SESSION['serendipityAuthedUser']) { 934 if ($serendipity['expose_s9y']) serendipity_header('X-Serendipity-InterfaceLangSource: Database'); 935 $lang = $serendipity['lang']; 936 } else { 937 $lang = (isset($_SESSION['serendipityLanguage']))?$_SESSION['serendipityLanguage']:$serendipity['lang']; 938 } 939 940 if (!isset($serendipity['languages'][$lang])) { 941 $lang = $serendipity['lang']; 942 } 943 944 $_SESSION['serendipityLanguage'] = $lang; 945 946 if ($serendipity['expose_s9y']) serendipity_header('X-Serendipity-InterfaceLang: ' . $lang); 947 948 if ($lang != $serendipity['lang']) { 949 $serendipity['content_lang'] = $lang; 950 } 951 952 return $lang; 953 } 954 955 /** 956 * Retrieves an array of applying permissions to an author 957 * 958 * The privileges of each group an author is a member of are aggreated 959 * and stored in a larger array. So both memberships and all aplying 960 * privileges are returned. 961 * 962 * @access public 963 * @param int The ID of the author to fetch permissions/group memberships for 964 * @return array Multi-dimensional associative array which holds a 'membership' and permission name data 965 */ 966 function &serendipity_getPermissions($authorid) { 967 global $serendipity; 968 969 // Get group information 970 $groups =& serendipity_db_query("SELECT ag.groupid, g.name, gc.property, gc.value 971 FROM {$serendipity['dbPrefix']}authorgroups AS ag 972 LEFT OUTER JOIN {$serendipity['dbPrefix']}groups AS g 973 ON ag.groupid = g.id 974 LEFT OUTER JOIN {$serendipity['dbPrefix']}groupconfig AS gc 975 ON gc.id = g.id 976 WHERE ag.authorid = " . (int)$authorid); 977 $perm = array('membership' => array()); 978 if (is_array($groups)) { 979 foreach($groups AS $group) { 980 $perm['membership'][$group['groupid']] = $group['groupid']; 981 $perm[$group['groupid']][$group['property']] = $group['value']; 982 } 983 } 984 return $perm; 985 } 986 987 /** 988 * Returns the list of available internal Serendipity permission field names 989 * 990 * This function also mapps which function was available to which userleves in older 991 * Serendipity versions. Thus if an author does not have a certain privilege he should 992 * have because of his userlevel, this can be reverse-mapped. 993 * 994 * @access public 995 * @return array Multi-dimensional associative array which the list of all permission items plus their userlevel associations 996 */ 997 function serendipity_getPermissionNames() { 998 return array( 999 'personalConfiguration' 1000 => array(USERLEVEL_ADMIN, USERLEVEL_CHIEF, USERLEVEL_EDITOR), 1001 'personalConfigurationUserlevel' 1002 => array(USERLEVEL_ADMIN, USERLEVEL_CHIEF), 1003 'personalConfigurationNoCreate' 1004 => array(USERLEVEL_ADMIN, USERLEVEL_CHIEF), 1005 'personalConfigurationRightPublish' 1006 => array(USERLEVEL_ADMIN, USERLEVEL_CHIEF), 1007 'siteConfiguration' 1008 => array(USERLEVEL_ADMIN), 1009 'blogConfiguration' 1010 => array(USERLEVEL_ADMIN, USERLEVEL_CHIEF), 1011 1012 'adminEntries' 1013 => array(USERLEVEL_ADMIN, USERLEVEL_CHIEF, USERLEVEL_EDITOR), 1014 'adminEntriesMaintainOthers' 1015 => array(USERLEVEL_ADMIN, USERLEVEL_CHIEF), 1016 1017 'adminImport' 1018 => array(USERLEVEL_ADMIN, USERLEVEL_CHIEF), 1019 1020 'adminCategories' 1021 => array(USERLEVEL_ADMIN, USERLEVEL_CHIEF, USERLEVEL_EDITOR), 1022 'adminCategoriesMaintainOthers' 1023 => array(USERLEVEL_ADMIN, USERLEVEL_CHIEF), 1024 'adminCategoriesDelete' 1025 => array(USERLEVEL_ADMIN, USERLEVEL_CHIEF), 1026 1027 'adminUsers' 1028 => array(USERLEVEL_ADMIN, USERLEVEL_CHIEF), 1029 'adminUsersDelete' 1030 => array(USERLEVEL_ADMIN, USERLEVEL_CHIEF), 1031 'adminUsersEditUserlevel' 1032 => array(USERLEVEL_ADMIN, USERLEVEL_CHIEF), 1033 'adminUsersMaintainSame' 1034 => array(USERLEVEL_ADMIN, USERLEVEL_CHIEF), 1035 'adminUsersMaintainOthers' 1036 => array(USERLEVEL_ADMIN), 1037 'adminUsersCreateNew' 1038 => array(USERLEVEL_ADMIN, USERLEVEL_CHIEF), 1039 'adminUsersGroups' 1040 => array(USERLEVEL_ADMIN, USERLEVEL_CHIEF), 1041 1042 'adminPlugins' 1043 => array(USERLEVEL_ADMIN, USERLEVEL_CHIEF), 1044 'adminPluginsMaintainOthers' 1045 => array(USERLEVEL_ADMIN), 1046 1047 'adminImages' 1048 => array(USERLEVEL_ADMIN, USERLEVEL_CHIEF, USERLEVEL_EDITOR), 1049 'adminImagesDirectories' 1050 => array(USERLEVEL_ADMIN, USERLEVEL_CHIEF), 1051 'adminImagesAdd' 1052 => array(USERLEVEL_ADMIN, USERLEVEL_CHIEF, USERLEVEL_EDITOR), 1053 'adminImagesDelete' 1054 => array(USERLEVEL_ADMIN, USERLEVEL_CHIEF, USERLEVEL_EDITOR), 1055 'adminImagesMaintainOthers' 1056 => array(USERLEVEL_ADMIN, USERLEVEL_CHIEF), 1057 'adminImagesViewOthers' 1058 => array(USERLEVEL_ADMIN, USERLEVEL_CHIEF, USERLEVEL_EDITOR), 1059 'adminImagesView' 1060 => array(USERLEVEL_ADMIN, USERLEVEL_CHIEF, USERLEVEL_EDITOR), 1061 'adminImagesSync' 1062 => array(USERLEVEL_ADMIN, USERLEVEL_CHIEF), 1063 1064 'adminComments' 1065 => array(USERLEVEL_ADMIN, USERLEVEL_CHIEF), 1066 1067 'adminTemplates' 1068 => array(USERLEVEL_ADMIN, USERLEVEL_CHIEF), 1069 ); 1070 } 1071 1072 /** 1073 * Checks if a permission is granted to a specific author 1074 * 1075 * This function caches all permission chacks in static function variables to not 1076 * fetch all permissions time and again. 1077 * The permission checks are performed agains the values of each group. If a privilege 1078 * is set in one of the groups the author is a user of, the function returns true. 1079 * If a privilege is not set, the userlevel of an author is checked to act for backwards-compatibility. 1080 * 1081 * @access public 1082 * @see serendipity_getPermissionNames() 1083 * @param string The name of the permission to check 1084 * @param int The authorid for which the permission check should be performed 1085 * @param boolean If set to true, all groups that the requested author is a user of will be returned. This bypasses the permission check and mainly acts as a mean to return cached permissions, since those variables are only available within this function. 1086 * @return mixed Either returns true if a permission check is performed, or return an array of group memberships. Depends on the $returnMyGroups variable. 1087 */ 1088 function serendipity_checkPermission($permName, $authorid = null, $returnMyGroups = false) { 1089 global $serendipity; 1090 1091 // Define old serendipity permissions 1092 static $permissions = null; 1093 static $group = null; 1094 1095 if (IS_installed !== true) { 1096 return true; 1097 } 1098 1099 if ($permissions === null) { 1100 $permissions = serendipity_getPermissionNames(); 1101 } 1102 1103 if ($group === null) { 1104 $group = array(); 1105 } 1106 1107 if ($authorid === null) { 1108 $authorid = $serendipity['authorid']; 1109 } 1110 1111 if (!isset($group[$authorid])) { 1112 $group[$authorid] = serendipity_getPermissions($authorid); 1113 } 1114 1115 if ($returnMyGroups) { 1116 if ($returnMyGroups === 'all') { 1117 return $group[$authorid]; 1118 } else { 1119 return $group[$authorid]['membership']; 1120 } 1121 } 1122 1123 if ($authorid == $serendipity['authorid'] && $serendipity['no_create']) { 1124 // This no_create user privilege overrides other permissions. 1125 return false; 1126 } 1127 1128 $return = true; 1129 1130 foreach($group[$authorid] AS $item) { 1131 if (!isset($item[$permName])) { 1132 continue; 1133 } 1134 1135 if ($item[$permName] === 'true') { 1136 return true; 1137 } else { 1138 $return = false; 1139 } 1140 } 1141 1142 // If the function did not yet return it means there's a check for a permission which is not defined anywhere. 1143 // Let's use a backwards compatible way. 1144 if ($return && isset($permissions[$permName]) && in_array($serendipity['serendipityUserlevel'], $permissions[$permName])) { 1145 return true; 1146 } 1147 1148 return false; 1149 } 1150 1151 /** 1152 * Update author group membership(s) 1153 * 1154 * @access public 1155 * @param array The array of groups the author should be a member of. All memberships that were present before and not contained in this array will be removed. 1156 * @param int The ID of the author to update 1157 * @param boolean If set to true, the groups can only be updated if the user has the adminUsersMaintainOthers privilege. If set to false, group memberships will be changable for any user. 1158 * @return 1159 */ 1160 function serendipity_updateGroups($groups, $authorid, $apply_acl = true) { 1161 global $serendipity; 1162 1163 if ($apply_acl && !serendipity_checkPermission('adminUsersMaintainOthers')) { 1164 return false; 1165 } 1166 1167 serendipity_db_query("DELETE FROM {$serendipity['dbPrefix']}authorgroups WHERE authorid = " . (int)$authorid); 1168 1169 foreach($groups AS $group) { 1170 serendipity_db_query("INSERT INTO {$serendipity['dbPrefix']}authorgroups (authorid, groupid) VALUES (" . (int)$authorid . ", " . (int)$group . ")"); 1171 } 1172 return true; 1173 } 1174 1175 /** 1176 * Returns all authorgroups that are available 1177 * 1178 * If a groupname is prefixed with "USERLEVEL_" then the constant of that name is used to 1179 * return the name of the group. This allows inserting the special groups Chief Editor, Editor 1180 * and admin and still being able to use multilingual names for these groups. 1181 * 1182 * @access public 1183 * @param int If set to an author ID value, only groups are fetched that this author is a member of. If set to false, all groups are returned, also those that the current user has no access to. 1184 * @return array An associative array of group names. 1185 */ 1186 function &serendipity_getAllGroups($apply_ACL_user = false) { 1187 global $serendipity; 1188 1189 if ($apply_ACL_user) { 1190 $groups =& serendipity_db_query("SELECT g.id AS confkey, 1191 g.name AS confvalue, 1192 g.id AS id, 1193 g.name AS name 1194 FROM {$serendipity['dbPrefix']}authorgroups AS ag 1195 LEFT OUTER JOIN {$serendipity['dbPrefix']}groups AS g 1196 ON g.id = ag.groupid 1197 WHERE ag.authorid = " . (int)$apply_ACL_user . " 1198 ORDER BY g.name", false, 'assoc'); 1199 } else { 1200 $groups =& serendipity_db_query("SELECT g.id AS confkey, 1201 g.name AS confvalue, 1202 g.id AS id, 1203 g.name AS name 1204 FROM {$serendipity['dbPrefix']}groups AS g 1205 ORDER BY g.name", false, 'assoc'); 1206 } 1207 if (is_array($groups)) { 1208 foreach ($groups as $k => $v) { 1209 if ('USERLEVEL_' == substr($v['confvalue'], 0, 10)) { 1210 $groups[$k]['confvalue'] = $groups[$k]['name'] = constant($v['confvalue']); 1211 } 1212 } 1213 } 1214 return $groups; 1215 } 1216 1217 /** 1218 * Fetch the permissions of a certain group 1219 * 1220 * @access public 1221 * @param int The ID of the group that the permissions are fetched for 1222 * @return array The associative array of permissions of a group. 1223 */ 1224 function &serendipity_fetchGroup($groupid) { 1225 global $serendipity; 1226 1227 $conf = array(); 1228 $groups =& serendipity_db_query("SELECT g.id AS confkey, 1229 g.name AS confvalue, 1230 g.id AS id, 1231 g.name AS name, 1232 1233 gc.property AS property, 1234 gc.value AS value 1235 FROM {$serendipity['dbPrefix']}groups AS g 1236 LEFT OUTER JOIN {$serendipity['dbPrefix']}groupconfig AS gc 1237 ON g.id = gc.id 1238 WHERE g.id = " . (int)$groupid, false, 'assoc'); 1239 1240 if (is_array($groups)) { 1241 foreach($groups AS $group) { 1242 $conf[$group['property']] = $group['value']; 1243 } 1244 } 1245 1246 // The following are unique 1247 $conf['name'] = $groups[0]['name']; 1248 $conf['id'] = $groups[0]['id']; 1249 $conf['confkey'] = $groups[0]['confkey']; 1250 $conf['confvalue'] = $groups[0]['confvalue']; 1251 1252 return $conf; 1253 } 1254 1255 /** 1256 * Gets all groups a user is a member of 1257 * 1258 * @access public 1259 * @param int The authorid to fetch groups for 1260 * @param boolean Indicate whether the original multi-dimensional DB result array shall be returned (FALSE) or if the array shall be flattened to be 1-dimensional (TRUE). 1261 * @return 1262 */ 1263 function &serendipity_getGroups($authorid, $sequence = false) { 1264 global $serendipity; 1265 1266 $_groups =& serendipity_db_query("SELECT g.id AS confkey, 1267 g.name AS confvalue, 1268 g.id AS id, 1269 g.name AS name 1270 FROM {$serendipity['dbPrefix']}authorgroups AS ag 1271 LEFT OUTER JOIN {$serendipity['dbPrefix']}groups AS g 1272 ON g.id = ag.groupid 1273 WHERE ag.authorid = " . (int)$authorid, false, 'assoc'); 1274 if (!is_array($_groups)) { 1275 $groups = array(); 1276 } else { 1277 $groups =& $_groups; 1278 } 1279 1280 if ($sequence) { 1281 $rgroups = array(); 1282 foreach($groups AS $grouprow) { 1283 $rgroups[] = $grouprow['confkey']; 1284 } 1285 } else { 1286 $rgroups =& $groups; 1287 } 1288 1289 return $rgroups; 1290 } 1291 1292 /** 1293 * Gets all author IDs of a specific group 1294 * 1295 * @access public 1296 * @param int The ID of the group to fetch the authors of 1297 * @return array The assotiative array of author IDs and names 1298 */ 1299 function &serendipity_getGroupUsers($groupid) { 1300 global $serendipity; 1301 1302 $groups =& serendipity_db_query("SELECT g.name AS name, 1303 a.realname AS author, 1304 a.authorid AS id 1305 FROM {$serendipity['dbPrefix']}authorgroups AS ag 1306 LEFT OUTER JOIN {$serendipity['dbPrefix']}groups AS g 1307 ON g.id = ag.groupid 1308 LEFT OUTER JOIN {$serendipity['dbPrefix']}authors AS a 1309 ON ag.authorid = a.authorid 1310 WHERE ag.groupid = " . (int)$groupid, false, 'assoc'); 1311 return $groups; 1312 } 1313 1314 /** 1315 * Deletes a specific author group by ID 1316 * 1317 * @access public 1318 * @param int The group ID to delete 1319 * @return boolean Return true if group could be deleted, false if unsufficient privileges. 1320 */ 1321 function serendipity_deleteGroup($groupid) { 1322 global $serendipity; 1323 1324 if (!serendipity_checkPermission('adminUsersGroups')) { 1325 return false; 1326 } 1327 1328 if (!serendipity_checkPermission('adminUsersMaintainOthers')) { 1329 // Only groups should be accessible where a user has access rights. 1330 $my_groups =& serendipity_getGroups($serendipity['authorid'], true); 1331 if (!in_array($groupid, $my_groups)) { 1332 return false; 1333 } 1334 } 1335 1336 serendipity_db_query("DELETE FROM {$serendipity['dbPrefix']}groups WHERE id = " . (int)$groupid); 1337 serendipity_db_query("DELETE FROM {$serendipity['dbPrefix']}authorgroups WHERE groupid = " . (int)$groupid); 1338 1339 return true; 1340 } 1341 1342 /** 1343 * Creates a new author group 1344 * 1345 * @access public 1346 * @param string The name of the new group 1347 * @return int The id of the created group 1348 */ 1349 function serendipity_addGroup($name) { 1350 global $serendipity; 1351 1352 serendipity_db_query("INSERT INTO {$serendipity['dbPrefix']}groups (name) VALUES ('" . serendipity_db_escape_string($name) . "')"); 1353 $gid = serendipity_db_insert_id('groups', 'id'); 1354 1355 return $gid; 1356 } 1357 1358 /** 1359 * Returns a list of all existing permission names. 1360 * 1361 * Additional plugins might insert specific properties into the groupconfig database to 1362 * handle their own privileges. This call returns an array of all available permission names 1363 * so that it can be intersected with the list of internal permission names (serendipity_getPermissionNames()) 1364 * and the be distincted. 1365 * 1366 * @access public 1367 * @see serendipity_getPermissionNames() 1368 * @return array associative array of all available permission names 1369 */ 1370 function &serendipity_getDBPermissionNames() { 1371 global $serendipity; 1372 1373 $config =& serendipity_db_query("SELECT property FROM {$serendipity['dbPrefix']}groupconfig GROUP BY property ORDER BY property", false, 'assoc'); 1374 1375 return $config; 1376 } 1377 1378 /** 1379 * Gets the list of all Permissions and merges the two arrays 1380 * 1381 * The first call will fetch all existing permission names of the database. Then it will 1382 * fetch the list of defined internal permission names, which has an array with extra information 1383 * (like userlevel). This array will be merged with those permission names only found in the 1384 * database. The returned array will then hold as much information about permission names as is 1385 * available. 1386 * TODO Might need further pushing and/or an event hook so that external plugins using the 1387 * permission system can inject specific information into the array 1388 * 1389 * @access public 1390 * @see serendipity_getPermissionNames() 1391 * @see serendipity_getDBPermissionNames() 1392 * @return array Returns the array with all information about all permission names 1393 */ 1394 function &serendipity_getAllPermissionNames() { 1395 global $serendipity; 1396 1397 $DBperms =& serendipity_getDBPermissionNames(); 1398 $perms =& serendipity_getPermissionNames(); 1399 1400 foreach($DBperms AS $perm) { 1401 if (!isset($perms[$perm['property']])) { 1402 $perms[$perm['property']] = array(); 1403 } 1404 } 1405 1406 return $perms; 1407 } 1408 1409 /** 1410 * Checks if two users are members of the same group 1411 * 1412 * This function will retrieve all group memeberships of a 1413 * foreign user ($checkuser) and yourself ($myself). Then it 1414 * will check if there is any group membership that those 1415 * two users have in common. 1416 * It can be used for detecting if a different author should 1417 * be allowed to access your entries, because he's in the same 1418 * group, for example. 1419 * 1420 * @access public 1421 * @param int ID of the first author to check group memberships 1422 * @param int ID of the second author to check group memberships 1423 * @return boolea True if a membership intersects, false if not 1424 */ 1425 function serendipity_intersectGroup($checkuser = null, $myself = null) { 1426 global $serendipity; 1427 1428 if ($myself === null) { 1429 $myself = $serendipity['authorid']; 1430 } 1431 1432 $my_groups =& serendipity_getGroups($myself, true); 1433 $his_groups =& serendipity_getGroups($checkuser, true); 1434 1435 foreach($his_groups AS $his_group) { 1436 if (in_array($his_group, $my_groups)) { 1437 return true; 1438 } 1439 } 1440 1441 return false; 1442 } 1443 1444 /** 1445 * Updates the configuration of permissions of a specific group 1446 * 1447 * This function ensures that a group can only be updated from users that have permissions to do so. 1448 * @access public 1449 * @param int The ID of the group to update 1450 * @param array The associative array of permission names 1451 * @param array The associative array of new values for the permissions. Needs the same associative keys like the $perms array. 1452 * @param bool Indicates if an all new privilege should be inserted (true) or if an existing privilege is going to be checked 1453 * @param array The associative array of plugin permission names 1454 * @param array The associative array of plugin permission hooks 1455 * @return true 1456 */ 1457 function serendipity_updateGroupConfig($groupid, &$perms, &$values, $isNewPriv = false, $forbidden_plugins = null, $forbidden_hooks = null) { 1458 global $serendipity; 1459 1460 if (!serendipity_checkPermission('adminUsersGroups')) { 1461 return false; 1462 } 1463 1464 if (!serendipity_checkPermission('adminUsersMaintainOthers')) { 1465 // Only groups should be accessible where a user has access rights. 1466 $my_groups =& serendipity_getGroups($serendipity['authorid'], true); 1467 if (!in_array($groupid, $my_groups)) { 1468 return false; 1469 } 1470 } 1471 1472 $storage =& serendipity_fetchGroup($groupid); 1473 1474 serendipity_db_query("DELETE FROM {$serendipity['dbPrefix']}groupconfig WHERE id = " . (int)$groupid); 1475 foreach ($perms AS $perm => $userlevels) { 1476 if (substr($perm, 0, 2) == 'f_') { 1477 continue; 1478 } 1479 1480 if (isset($values[$perm]) && $values[$perm] == 'true') { 1481 $value = 'true'; 1482 } elseif (isset($values[$perm]) && $values[$perm] === 'false') { 1483 $value = 'false'; 1484 } elseif (isset($values[$perm])) { 1485 $value = $values[$perm]; 1486 } else { 1487 $value = 'false'; 1488 } 1489 1490 if ($isNewPriv == false && !serendipity_checkPermission($perm)) { 1491 if (!isset($storage[$perm])) { 1492 $value = 'false'; 1493 } else { 1494 $value = $storage[$perm]; 1495 } 1496 } 1497 1498 serendipity_db_query( 1499 sprintf("INSERT INTO {$serendipity['dbPrefix']}groupconfig (id, property, value) VALUES (%d, '%s', '%s')", 1500 (int)$groupid, 1501 serendipity_db_escape_string($perm), 1502 serendipity_db_escape_string($value) 1503 ) 1504 ); 1505 } 1506 1507 if (is_array($forbidden_plugins)) { 1508 foreach($forbidden_plugins AS $plugid) { 1509 serendipity_db_query( 1510 sprintf("INSERT INTO {$serendipity['dbPrefix']}groupconfig (id, property, value) VALUES (%d, '%s', 'true')", 1511 (int)$groupid, 1512 serendipity_db_escape_string('f_' . urldecode($plugid)) 1513 ) 1514 ); 1515 } 1516 } 1517 1518 if (is_array($forbidden_hooks)) { 1519 foreach($forbidden_hooks AS $hook) { 1520 serendipity_db_query( 1521 sprintf("INSERT INTO {$serendipity['dbPrefix']}groupconfig (id, property, value) VALUES (%d, '%s', 'true')", 1522 (int)$groupid, 1523 serendipity_db_escape_string('f_' . urldecode($hook)) 1524 ) 1525 ); 1526 } 1527 } 1528 1529 serendipity_db_query("UPDATE {$serendipity['dbPrefix']}groups SET name = '" . serendipity_db_escape_string($values['name']) . "' WHERE id = " . (int)$groupid); 1530 1531 if (is_array($values['members'])) { 1532 serendipity_db_query("DELETE FROM {$serendipity['dbPrefix']}authorgroups WHERE groupid = " . (int)$groupid); 1533 foreach($values['members'] AS $member) { 1534 serendipity_db_query( 1535 sprintf("INSERT INTO {$serendipity['dbPrefix']}authorgroups (groupid, authorid) VALUES (%d, %d)", 1536 (int)$groupid, 1537 (int)$member 1538 ) 1539 ); 1540 } 1541 } 1542 1543 return true; 1544 } 1545 1546 /** 1547 * Adds a default internal group (Editor, Chief Editor, Admin) 1548 * 1549 * @access public 1550 * @param string The name of the group to insert 1551 * @param int The userlevel that represents this group (0|1|255 for Editor/Chief/Admin). 1552 * @return true 1553 */ 1554 function serendipity_addDefaultGroup($name, $level) { 1555 global $serendipity; 1556 1557 static $perms = null; 1558 if ($perms === null) { 1559 $perms = serendipity_getPermissionNames(); 1560 } 1561 1562 serendipity_db_query("INSERT INTO {$serendipity['dbPrefix']}groups (name) VALUES ('" . serendipity_db_escape_string($name) . "')"); 1563 $gid = (int)serendipity_db_insert_id('groups', 'id'); 1564 serendipity_db_query("INSERT INTO {$serendipity['dbPrefix']}groupconfig (id, property, value) VALUES ($gid, 'userlevel', '" . (int)$level . "')"); 1565 1566 $authors = serendipity_db_query("SELECT * FROM {$serendipity['dbPrefix']}authors WHERE userlevel = " . (int)$level); 1567 1568 if (is_array($authors)) { 1569 foreach($authors AS $author) { 1570 serendipity_db_query("INSERT INTO {$serendipity['dbPrefix']}authorgroups (authorid, groupid) VALUES ('{$author['authorid']}', '$gid')"); 1571 } 1572 } 1573 1574 foreach($perms AS $permName => $permArray) { 1575 if (in_array($level, $permArray)) { 1576 serendipity_db_query("INSERT INTO {$serendipity['dbPrefix']}groupconfig (id, property, value) VALUES ($gid, '" . serendipity_db_escape_string($permName) . "', 'true')"); 1577 } else { 1578 serendipity_db_query("INSERT INTO {$serendipity['dbPrefix']}groupconfig (id, property, value) VALUES ($gid, '" . serendipity_db_escape_string($permName) . "', 'false')"); 1579 } 1580 } 1581 1582 return true; 1583 } 1584 1585 /** 1586 * Allow access to a specific item (category or entry) for a specific usergroup 1587 * 1588 * ACL are Access Control Lists. They indicate which read/write permissions a 1589 * specific item has for specific usergroups. 1590 * An artifact in terms of Serendipity can be either a category or an entry, or 1591 * anything beyond that for future compatibility. 1592 * This function sets up the ACLs. 1593 * 1594 * @access public 1595 * @param int The ID of the artifact to set the access 1596 * @param string The type of an artifact (category|entry) 1597 * @param string The type of access to grant (read|write) 1598 * @param array The ID of the group to grant access to 1599 * @param string A variable option for an artifact 1600 * @return boolean True if ACL was applied, false if not. 1601 */ 1602 function serendipity_ACLGrant($artifact_id, $artifact_type, $artifact_mode, $groups, $artifact_index = '') { 1603 global $serendipity; 1604 1605 if (empty($groups) || !is_array($groups)) { 1606 return false; 1607 } 1608 1609 // Delete all old existing relations. 1610 serendipity_db_query("DELETE FROM {$serendipity['dbPrefix']}access 1611 WHERE artifact_id = " . (int)$artifact_id . " 1612 AND artifact_type = '" . serendipity_db_escape_string($artifact_type) . "' 1613 AND artifact_mode = '" . serendipity_db_escape_string($artifact_mode) . "' 1614 AND artifact_index = '" . serendipity_db_escape_string($artifact_index) . "'"); 1615 1616 $data = array( 1617 'artifact_id' => (int)$artifact_id, 1618 'artifact_type' => $artifact_type, 1619 'artifact_mode' => $artifact_mode, 1620 'artifact_index' => $artifact_index 1621 ); 1622 1623 if (count($data) < 1) { 1624 return true; 1625 } 1626 1627 foreach($groups AS $group) { 1628 $data['groupid'] = $group; 1629 serendipity_db_insert('access', $data); 1630 } 1631 1632 return true; 1633 } 1634 1635 /** 1636 * Checks if a specific item (category or entry) can be accessed by a specific usergroup 1637 * 1638 * ACL are Access Control Lists. They indicate which read/write permissions a 1639 * specific item has for specific usergroups. 1640 * An artifact in terms of Serendipity can be either a category or an entry, or 1641 * anything beyond that for future compatibility. 1642 * This function retrieves the ACLs. 1643 * 1644 * @access public 1645 * @param int The ID of the artifact to set the access 1646 * @param string The type of an artifact (category|entry) 1647 * @param string The type of access to check for (read|write) 1648 * @param string A variable option for an artifact 1649 * @return array Returns an array of all groups that are allowed for this kind of access. You can then check if you are the member of any of the groups returned here. 1650 */ 1651 function serendipity_ACLGet($artifact_id, $artifact_type, $artifact_mode, $artifact_index = '') { 1652 global $serendipity; 1653 1654 $sql = "SELECT groupid, artifact_index FROM {$serendipity['dbPrefix']}access 1655 WHERE artifact_type = '" . serendipity_db_escape_string($artifact_type) . "' 1656 AND artifact_id = '" . (int)$artifact_id . "' 1657 AND artifact_mode = '" . serendipity_db_escape_string($artifact_mode) . "' 1658 AND artifact_index = '" . serendipity_db_escape_string($artifact_index) . "'"; 1659 $rows =& serendipity_db_query($sql, false, 'assoc'); 1660 1661 if (!is_array($rows)) { 1662 return false; 1663 } 1664 1665 $acl = array(); 1666 foreach($rows AS $row) { 1667 $acl[$row['groupid']] = $row['artifact_index']; 1668 } 1669 1670 return $acl; 1671 } 1672 1673 /** 1674 * Checks if a specific item (category or entry) can be accessed by a specific Author 1675 * 1676 * ACL are Access Control Lists. They indicate which read/write permissions a 1677 * specific item has for specific usergroups. 1678 * An artifact in terms of Serendipity can be either a category or an entry, or 1679 * anything beyond that for future compatibility. 1680 * This function retrieves the ACLs for a specific user. 1681 * 1682 * @access public 1683 * @param int The ID of the author to check against. 1684 * @param int The ID of the artifact to set the access 1685 * @param string The type of an artifact ('category', more to come) 1686 * @param string The type of access to check for (read|write) 1687 * @return boolean Returns true, if the author has access to this artifact. False if not. 1688 */ 1689 function serendipity_ACLCheck($authorid, $artifact_id, $artifact_type, $artifact_mode) { 1690 global $serendipity; 1691 1692 $artifact_sql = array(); 1693 1694 // TODO: If more artifact_types are available, the JOIN needs to be edited so that the first AND portion is not required, and the join is fully made on that conditiion. 1695 switch($artifact_type) { 1696 default: 1697 case 'category': 1698 $artifact_sql['unique']= "atf.categoryid"; 1699 $artifact_sql['cond'] = "atf.categoryid = " . (int)$artifact_id; 1700 $artifact_sql['where'] = " ag.groupid = a.groupid 1701 OR a.groupid = 0 1702 OR (a.artifact_type IS NULL AND (atf.authorid = " . (int)$authorid . " OR atf.authorid = 0 OR atf.authorid IS NULL))"; 1703 $artifact_sql['table'] = 'category'; 1704 } 1705 1706 $sql = "SELECT {$artifact_sql['unique']} AS result 1707 FROM {$serendipity['dbPrefix']}{$artifact_sql['table']} AS atf 1708 LEFT OUTER JOIN {$serendipity['dbPrefix']}authorgroups AS ag 1709 ON ag.authorid = ". (int)$authorid . " 1710 LEFT OUTER JOIN {$serendipity['dbPrefix']}access AS a 1711 ON ( a.artifact_type = '" . serendipity_db_escape_string($artifact_type) . "' 1712 AND a.artifact_id = " . (int)$artifact_id . " 1713 AND a.artifact_mode = '" . serendipity_db_escape_string($artifact_mode) . "' 1714 ) 1715 1716 WHERE {$artifact_sql['cond']} 1717 AND ( {$artifact_sql['where']} ) 1718 GROUP BY result"; 1719 1720 $res =& serendipity_db_query($sql, true, 'assoc'); 1721 if (is_array($res) && !empty($res['result'])) { 1722 return true; 1723 } 1724 1725 return false; 1726 } 1727 1728 /** 1729 * Prepares a SQL statement to be used in queries that should be ACL restricted. 1730 * 1731 * ACL are Access Control Lists. They indicate which read/write permissions a 1732 * specific item has for specific usergroups. 1733 * An artifact in terms of Serendipity can be either a category or an entry, or 1734 * anything beyond that for future compatibility. 1735 * This function evaluates and applies the SQL statements required. 1736 * It is currently only written for retrieving Category ACLs. 1737 * All of the SQL code that will be used in serendipity_fetchEntries will be stored 1738 * within the referenced $cond array. 1739 * 1740 * @access private 1741 * @param array Associative array that holds the SQL part array to be used in other functions like serendipity_fetchEntries() 1742 * @param boolean Some queries do not need to joins categories. When ACLs need to be applied, this column is required, so if $append_category is set to true it will perform this missing JOIN. 1743 * @param string The ACL type ('category', 'directory') 1744 * @param string ACL mode 1745 * @return true True if ACLs were applied, false if not. 1746 */ 1747 function serendipity_ACL_SQL(&$cond, $append_category = false, $type = 'category', $mode = 'read') { 1748 global $serendipity; 1749 1750 // A global configuration item controls whether the blog should apply ACLs or not! 1751 if (!isset($serendipity['enableACL']) || $serendipity['enableACL'] == true) { 1752 1753 // If the user is logged in, we retrieve his authorid for the upcoming checks 1754 if ($_SESSION['serendipityAuthedUser'] === true) { 1755 $read_id = (int)$serendipity['authorid']; 1756 $read_id_sql = 'acl_a.groupid OR acl_acc.groupid = 0'; 1757 } else { 1758 // "0" as category property counts as "anonymous viewers" 1759 $read_id = 0; 1760 $read_id_sql = 0; 1761 } 1762 1763 if ($append_category) { 1764 if ($append_category !== 'limited') { 1765 $cond['joins'] .= " LEFT JOIN {$serendipity['dbPrefix']}entrycat ec 1766 ON e.id = ec.entryid"; 1767 } 1768 1769 $cond['joins'] .= " LEFT JOIN {$serendipity['dbPrefix']}category c 1770 ON ec.categoryid = c.categoryid"; 1771 } 1772 1773 switch($type) { 1774 case 'directory': 1775 $sql_artifact_column = 'i.path IS NULL OR 1776 acl_acc.groupid IS NULL'; 1777 $sql_artifact = 'AND acl_acc.artifact_index = i.path'; 1778 break; 1779 1780 case 'category': 1781 $sql_artifact_column = 'c.categoryid IS NULL'; 1782 $sql_artifact = 'AND acl_acc.artifact_id = c.categoryid'; 1783 break; 1784 } 1785 1786 $cond['joins'] .= " LEFT JOIN {$serendipity['dbPrefix']}authorgroups AS acl_a 1787 ON acl_a.authorid = " . $read_id . " 1788 LEFT JOIN {$serendipity['dbPrefix']}access AS acl_acc 1789 ON ( acl_acc.artifact_mode = '" . $mode . "' 1790 AND acl_acc.artifact_type = '" . $type . "' 1791 " . $sql_artifact . " 1792 )"; 1793 1794 if (empty($cond['and'])) { 1795 $cond['and'] .= ' WHERE '; 1796 } else { 1797 $cond['and'] .= ' AND '; 1798 } 1799 1800 // When in Admin-Mode, apply readership permissions. 1801 $cond['and'] .= " ( 1802 " . $sql_artifact_column . " 1803 OR ( acl_acc.groupid = " . $read_id_sql . ") 1804 OR ( acl_acc.artifact_id IS NULL 1805 " . (isset($serendipity['GET']['adminModule']) && 1806 $serendipity['GET']['adminModule'] == 'entries' && 1807 !serendipity_checkPermission('adminEntriesMaintainOthers') 1808 ? "AND (c.authorid IS NULL OR c.authorid = 0 OR c.authorid = " . $read_id . ")" 1809 : "") . " 1810 ) 1811 )"; 1812 return true; 1813 } 1814 1815 return false; 1816 } 1817 1818 /** 1819 * Check for Cross-Site-Request-Forgery attacks because of missing HTTP Referer 1820 * 1821 * http://de.wikipedia.org/wiki/XSRF 1822 * This function checks the HTTP referer, and if it is part of the current Admin panel. 1823 * 1824 * @access public 1825 * @return Returns true if XSRF was detected, false if not. The script should abort, if TRUE is returned. 1826 */ 1827 function serendipity_checkXSRF() { 1828 global $serendipity; 1829 1830 // If no module was requested, the user has just logged in and no action will be performed. 1831 if (empty($serendipity['GET']['adminModule'])) { 1832 return false; 1833 } 1834 1835 // The referrer was empty. Deny access. 1836 if (empty($_SERVER['HTTP_REFERER'])) { 1837 echo serendipity_reportXSRF(1, true, true); 1838 return false; 1839 } 1840 1841 // Parse the Referrer host. Abort if not parseable. 1842 $hostinfo = @parse_url($_SERVER['HTTP_REFERER']); 1843 if (!is_array($hostinfo)) { 1844 echo serendipity_reportXSRF(2, true, true); 1845 return true; 1846 } 1847 1848 // Get the server against we will perform the XSRF check. 1849 $server = ''; 1850 if (empty($_SERVER['HTTP_HOST'])) { 1851 $myhost = @parse_url($serendipity['baseURL']); 1852 if (is_array($myhost)) { 1853 $server = $myhost['host']; 1854 } 1855 } else { 1856 $server = $_SERVER['HTTP_HOST']; 1857 } 1858 1859 // If the current server is different than the referred server, deny access. 1860 if ($hostinfo['host'] != $server) { 1861 echo serendipity_reportXSRF(3, true, true); 1862 return true; 1863 } 1864 1865 return false; 1866 } 1867 1868 /** 1869 * Report a XSRF attempt to the Serendipity Interface 1870 * 1871 * http://de.wikipedia.org/wiki/XSRF 1872 * 1873 * LONG 1874 * 1875 * @access public 1876 * @see serendipity_checkXSRF() 1877 * @param string The type of XSRF check that got hit. Used for CSS formatting. 1878 * @param boolean If true, the XSRF error should be fatal 1879 * @param boolean If true, tell Serendipity to check the $serendipity['referrerXSRF'] config option to decide if an error should be reported or not. 1880 * @return string Returns the HTML error report 1881 */ 1882 function serendipity_reportXSRF($type = 0, $reset = true, $use_config = false) { 1883 global $serendipity; 1884 1885 // Set this in your serendipity_config_local.inc.php if you want HTTP Referrer blocking: 1886 // $serendipity['referrerXSRF'] = true; 1887 1888 $string = '<div class="serendipityAdminMsgError XSRF_' . $type . '"><img style="width: 22px; height: 22px; border: 0px; padding-right: 4px; vertical-align: middle" src="' . serendipity_getTemplateFile('admin/img/admin_msg_error.png') . '" alt="" />' . ERROR_XSRF . '</div>'; 1889 if ($reset) { 1890 // Config key "referrerXSRF" can be set to enable blocking based on HTTP Referrer. Recommended for Paranoia. 1891 if (($use_config && isset($serendipity['referrerXSRF']) && $serendipity['referrerXSRF']) || $use_config === false) { 1892 $serendipity['GET']['adminModule'] = ''; 1893 } else { 1894 // Paranoia not enabled. Do not report XSRF. 1895 $string = ''; 1896 } 1897 } 1898 return $string; 1899 } 1900 1901 /** 1902 * Prevent XSRF attacks by checking for a form token 1903 * 1904 * http://de.wikipedia.org/wiki/XSRF 1905 * 1906 * This function checks, if a valid Form token was posted to the site. 1907 * 1908 * @access public 1909 * @see serendipity_setFormToken() 1910 * @return boolean Returns true, if XSRF attempt was found and the token was missing 1911 */ 1912 function serendipity_checkFormToken($output = true) { 1913 global $serendipity; 1914 1915 $token = ''; 1916 if (!empty($serendipity['POST']['token'])) { 1917 $token = $serendipity['POST']['token']; 1918 } elseif (!empty($serendipity['GET']['token'])) { 1919 $token = $serendipity['GET']['token']; 1920 } 1921 1922 if (empty($token)) { 1923 if ($output) echo serendipity_reportXSRF('token', false); 1924 return false; 1925 } 1926 1927 if ($token != md5(session_id()) && 1928 $token != md5($serendipity['COOKIE']['old_session'])) { 1929 if ($output) echo serendipity_reportXSRF('token', false); 1930 return false; 1931 } 1932 1933 return true; 1934 } 1935 1936 /** 1937 * Prevent XSRF attacks by setting a form token within HTTP Forms 1938 * 1939 * http://de.wikipedia.org/wiki/XSRF 1940 * 1941 * By inserting a unique Form token that holds the session id, all requests 1942 * to serendipity HTTP forms can only be processed if the token is present. 1943 * This effectively makes XSRF attacks impossible. Only bundled with XSS 1944 * attacks it can be bypassed. 1945 * 1946 * 'form' type tokens can be embedded within the <form> script. 1947 * 'url' type token can be embedded within HTTP GET calls. 1948 * 1949 * @access public 1950 * @param string The type of token to return (form|url|plain) 1951 * @return string Returns the form token to be used in your functions 1952 */ 1953 function serendipity_setFormToken($type = 'form') { 1954 global $serendipity; 1955 1956 if ($type == 'form') { 1957 return '<input type="hidden" name="serendipity[token]" value="' . md5(session_id()) . '" />'; 1958 } elseif ($type == 'url') { 1959 return 'serendipity[token]=' . md5(session_id()); 1960 } else { 1961 return md5(session_id()); 1962 } 1963 } 1964 1965 /** 1966 * Load available/configured options for a specific theme (through config.inc.php of a template directory) 1967 * into an array. 1968 * 1969 * @param array Referenced variable coming from the config.inc.php file, where the config values will be stored in 1970 * @return array Final return array with default values 1971 */ 1972 function &serendipity_loadThemeOptions(&$template_config, $okey = '') { 1973 global $serendipity; 1974 1975 if (empty($okey)) { 1976 $okey = $serendipity['template']; 1977 } 1978 1979 $_template_vars =& serendipity_db_query("SELECT name, value FROM {$serendipity['dbPrefix']}options 1980 WHERE okey = 't_" . serendipity_db_escape_string($okey) . "'", false, 'assoc', false, 'name', 'value'); 1981 if (!is_array($_template_vars)) { 1982 $template_vars = array(); 1983 } else { 1984 $template_vars =& $_template_vars; 1985 } 1986 1987 foreach($template_config AS $key => $item) { 1988 if (!isset($template_vars[$item['var']])) { 1989 $template_vars[$item['var']] = $item['default']; 1990 } 1991 } 1992 1993 return $template_vars; 1994 } 1995 1996 /** 1997 * Check if a member of a group has permissions to execute a plugin 1998 * 1999 * @param string Pluginname 2000 * @param int ID of the group of which the members should be checked 2001 * @return boolean 2002 */ 2003 function serendipity_hasPluginPermissions($plugin, $groupid = null) { 2004 static $forbidden = null; 2005 global $serendipity; 2006 2007 if (empty($serendipity['authorid'])) { 2008 return true; 2009 } 2010 2011 if ($forbidden === null || ($groupid !== null && !isset($forbidden[$groupid]))) { 2012 $forbidden = array(); 2013 2014 if ($groupid === null) { 2015 $groups =& serendipity_checkPermission(null, null, 'all'); 2016 } else { 2017 $groups = array($groupid => serendipity_fetchGroup($groupid)); 2018 } 2019 2020 foreach($groups AS $idx => $group) { 2021 if ($idx == 'membership') { 2022 continue; 2023 } 2024 foreach($group AS $key => $val) { 2025 if (substr($key, 0, 2) == 'f_') { 2026 $forbidden[$groupid][$key] = true; 2027 } 2028 } 2029 } 2030 } 2031 2032 if (isset($forbidden[$groupid]['f_' . $plugin])) { 2033 return false; 2034 } else { 2035 return true; 2036 } 2037 } 2038 2039 /* vim: set sts=4 ts=4 expandtab : */
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sat Nov 24 09:00:37 2007 | par Balluche grâce à PHPXref 0.7 |
![]() |