diff options
Diffstat (limited to 'phpBB/includes/auth.php')
-rw-r--r-- | phpBB/includes/auth.php | 473 |
1 files changed, 473 insertions, 0 deletions
diff --git a/phpBB/includes/auth.php b/phpBB/includes/auth.php new file mode 100644 index 0000000000..ef8245d58c --- /dev/null +++ b/phpBB/includes/auth.php @@ -0,0 +1,473 @@ +<?php +/** +* +* @package phpBB3 +* @version $Id$ +* @copyright (c) 2005 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +/** +* @package phpBB3 +* Permission/Auth class +*/ +class auth +{ + var $acl = array(); + var $acl_options = array(); + + /** + * Init permissions + */ + function acl(&$userdata) + { + global $db, $cache; + + $this->acl = array(); + + if (!($this->acl_options = $cache->get('acl_options'))) + { + $sql = 'SELECT auth_option, is_global, is_local + FROM ' . ACL_OPTIONS_TABLE . ' + ORDER BY auth_option_id'; + $result = $db->sql_query($sql); + + $global = $local = 0; + while ($row = $db->sql_fetchrow($result)) + { + if ($row['is_global']) + { + $this->acl_options['global'][$row['auth_option']] = $global++; + } + + if ($row['is_local']) + { + $this->acl_options['local'][$row['auth_option']] = $local++; + } + } + $db->sql_freeresult($result); + + $cache->put('acl_options', $this->acl_options); + $this->acl_clear_prefetch(); + $this->acl_cache($userdata); + } + else if (!trim($userdata['user_permissions'])) + { + $this->acl_cache($userdata); + } + + $user_permissions = explode("\n", $userdata['user_permissions']); + + foreach ($user_permissions as $f => $seq) + { + if ($seq) + { + $i = 0; + + while ($subseq = substr($seq, $i, 6)) + { + if (!isset($this->acl[$f])) + { + $this->acl[$f] = ''; + } + + // We put the original bitstring into the acl array + $this->acl[$f] .= str_pad(base_convert($subseq, 36, 2), 31, 0, STR_PAD_LEFT); + $i += 6; + } + } + } + + return; + } + + /** + * Look up an option + * if the option is prefixed with !, then the result becomes nagated + */ + function acl_get($opt, $f = 0) + { + static $cache; + + if (!isset($cache)) + { + $cache = array(); + } + + $negate = false; + + if (strpos($opt, '!') === 0) + { + $negate = true; + $opt = substr($opt, 1); + } + + if (!isset($cache[$f][$opt])) + { + // We combine the global/local option with an OR because some options are global and local. + // If the user has the global permission the local one is true too and vice versa + $cache[$f][$opt] = false; + + // Is this option a global permission setting? + if (isset($this->acl_options['global'][$opt])) + { + if (isset($this->acl[0])) + { + $cache[$f][$opt] = $this->acl[0]{$this->acl_options['global'][$opt]}; + } + } + + // Is this option a local permission setting? + if (isset($this->acl_options['local'][$opt])) + { + if (isset($this->acl[$f])) + { + $cache[$f][$opt] |= $this->acl[$f]{$this->acl_options['local'][$opt]}; + } + } + } + + // Founder always has all global options set to true... + return ($negate) ? !$cache[$f][$opt] : $cache[$f][$opt]; + } + + /** + * Get forums with the specified permission setting + * if the option is prefixed with !, then the result becomes nagated + * + * @param clean true|false set to true if only values needs to be returned which are set/unset + */ + function acl_getf($opt, $clean = false) + { + static $cache; + + $acl_f = array(); + + if (!isset($cache)) + { + $cache = array(); + } + + $negate = false; + + if (strpos($opt, '!') === 0) + { + $negate = true; + $opt = substr($opt, 1); + } + + if (isset($this->acl_options['local'][$opt])) + { + foreach ($this->acl as $f => $bitstring) + { + // Skip global settings + if (!$f) + { + continue; + } + + $allowed = (!isset($cache[$f][$opt])) ? $this->acl_get($opt, $f) : $cache[$f][$opt]; + + if (!$clean) + { + $acl_f[$f][$opt] = ($negate) ? !$allowed : $allowed; + } + else + { + if (($negate && !$allowed) || (!$negate && $allowed)) + { + $acl_f[$f][$opt] = 1; + } + } + } + } + + return $acl_f; + } + + /** + * Get permission settings (more than one) + */ + function acl_gets() + { + $args = func_get_args(); + $f = array_pop($args); + + if (!is_numeric($f)) + { + $args[] = $f; + $f = 0; + } + + // alternate syntax: acl_gets(array('m_', 'a_'), $forum_id) + if (is_array($args[0])) + { + $args = $args[0]; + } + + $acl = 0; + foreach ($args as $opt) + { + $acl |= $this->acl_get($opt, $f); + } + + return $acl; + } + + /** + * Get permission listing based on user_id/options/forum_ids + */ + function acl_get_list($user_id = false, $opts = false, $forum_id = false) + { + $hold_ary = $this->acl_raw_data($user_id, $opts, $forum_id); + + $auth_ary = array(); + foreach ($hold_ary as $user_id => $forum_ary) + { + foreach ($forum_ary as $forum_id => $auth_option_ary) + { + foreach ($auth_option_ary as $auth_option => $auth_setting) + { + if ($auth_setting) + { + $auth_ary[$forum_id][$auth_option][] = $user_id; + } + } + } + } + + return $auth_ary; + } + + /** + * Get raw group based permission settings + function acl_group_raw_data($group_id = false, $opts = false, $forum_id = false) + { + global $db; + + $sql_group = ($group_id !== false) ? ((!is_array($group_id)) ? "group_id = $group_id" : 'group_id IN (' . implode(', ', $group_id) . ')') : ''; + $sql_forum = ($forum_id !== false) ? ((!is_array($forum_id)) ? "AND a.forum_id = $forum_id" : 'AND a.forum_id IN (' . implode(', ', $forum_id) . ')') : ''; + $sql_opts = ($opts !== false) ? ((!is_array($opts)) ? "AND ao.auth_option = '$opts'" : 'AND ao.auth_option IN (' . implode(', ', preg_replace('#^\s*(.*)\s*$#e', "\"'\" . \$db->sql_escape('\\1') . \"'\"", $opts)) . ')') : ''; + + $hold_ary = array(); + + // Grab group settings... + $sql = 'SELECT a.group_id, ao.auth_option, a.forum_id, a.auth_setting + FROM ' . ACL_OPTIONS_TABLE . ' ao, ' . ACL_GROUPS_TABLE . ' a + WHERE ao.auth_option_id = a.auth_option_id + ' . (($sql_group) ? 'AND a.' . $sql_group : '') . " + $sql_forum + $sql_opts + ORDER BY a.forum_id, ao.auth_option"; + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + $hold_ary[$row['group_id']][$row['forum_id']][$row['auth_option']] = $row['auth_setting']; + } + $db->sql_freeresult($result); + + return $hold_ary; + } +*/ + + /** + * Cache data to user_permissions row + */ + function acl_cache(&$userdata) + { + global $db; + + // Empty user_permissions + $userdata['user_permissions'] = ''; + + $hold_ary = $this->acl_raw_data($userdata['user_id'], false, false); + + if (isset($hold_ary[$userdata['user_id']])) + { + $hold_ary = $hold_ary[$userdata['user_id']]; + } + + // Key 0 in $hold_ary are global options, all others are forum_ids + + // If this user is founder we're going to force fill the admin options ... + if ($userdata['user_type'] == USER_FOUNDER) + { + foreach ($this->acl_options['global'] as $opt => $id) + { + if (strpos($opt, 'a_') === 0) + { + $hold_ary[0][$opt] = 1; + } + } + } + + $hold_str = ''; + if (sizeof($hold_ary)) + { + ksort($hold_ary); + + $last_f = 0; + + foreach ($hold_ary as $f => $auth_ary) + { + $ary_key = (!$f) ? 'global' : 'local'; + + $bitstring = array(); + foreach ($this->acl_options[$ary_key] as $opt => $id) + { + if (isset($auth_ary[$opt])) + { + $bitstring[$id] = 1; + + $option_key = substr($opt, 0, strpos($opt, '_') + 1); + + // If one option is allowed, the global permission for this option has to be allowed too + // example: if the user has the a_ permission this means he has one or more a_* permissions + if (!isset($bitstring[$this->acl_options[$ary_key][$option_key]]) || !$bitstring[$this->acl_options[$ary_key][$option_key]]) + { + $bitstring[$this->acl_options[$ary_key][$option_key]] = 1; + } + } + else + { + $bitstring[$id] = 0; + } + } + + // Now this bitstring defines the permission setting for the current forum $f (or global setting) + $bitstring = implode('', $bitstring); + + // The line number indicates the id, therefore we have to add empty lines for those ids not present + $hold_str .= str_repeat("\n", $f - $last_f); + + // Convert bitstring for storage - we do not use binary/bytes because PHP's string functions are not fully binary safe + for ($i = 0; $i < strlen($bitstring); $i += 31) + { + $hold_str .= str_pad(base_convert(str_pad(substr($bitstring, $i, 31), 31, 0, STR_PAD_RIGHT), 2, 36), 6, 0, STR_PAD_LEFT); + } + + $last_f = $f; + } + unset($bitstring); + + $userdata['user_permissions'] = rtrim($hold_str); + + $sql = 'UPDATE ' . USERS_TABLE . " + SET user_permissions = '" . $db->sql_escape($userdata['user_permissions']) . "' + WHERE user_id = " . $userdata['user_id']; + $db->sql_query($sql); + } + unset($hold_ary); + + return; + } + + /** + * Clear one or all users cached permission settings + */ + function acl_clear_prefetch($user_id = false) + { + global $db; + + $where_sql = ($user_id !== false) ? ' WHERE user_id ' . ((is_array($user_id)) ? ' IN (' . implode(', ', array_map('intval', $user_id)) . ')' : " = $user_id") : ''; + + $sql = 'UPDATE ' . USERS_TABLE . " + SET user_permissions = '' + $where_sql"; + $db->sql_query($sql); + + return; + } + + /** + * Get raw acl data based on user/option/forum + */ + function acl_raw_data($user_id = false, $opts = false, $forum_id = false) + { + global $db; + + $sql_user = ($user_id !== false) ? ((!is_array($user_id)) ? "user_id = $user_id" : 'user_id IN (' . implode(', ', $user_id) . ')') : ''; + $sql_forum = ($forum_id !== false) ? ((!is_array($forum_id)) ? "AND a.forum_id = $forum_id" : 'AND a.forum_id IN (' . implode(', ', $forum_id) . ')') : ''; + $sql_opts = ($opts !== false) ? ((!is_array($opts)) ? "AND ao.auth_option = '$opts'" : 'AND ao.auth_option IN (' . implode(', ', preg_replace('#^\s*(.*)\s*$#e', "\"'\" . \$db->sql_escape('\\1') . \"'\"", $opts)) . ')') : ''; + + $hold_ary = array(); + + // First grab user settings ... each user has only one setting for each + // option ... so we shouldn't need any ACL_NO checks ... he says ... + $sql = 'SELECT ao.auth_option, a.user_id, a.forum_id, a.auth_setting + FROM ' . ACL_OPTIONS_TABLE . ' ao, ' . ACL_USERS_TABLE . ' a + WHERE ao.auth_option_id = a.auth_option_id + ' . (($sql_user) ? 'AND a.' . $sql_user : '') . " + $sql_forum + $sql_opts + ORDER BY a.forum_id, ao.auth_option"; + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + $hold_ary[$row['user_id']][$row['forum_id']][$row['auth_option']] = $row['auth_setting']; + } + $db->sql_freeresult($result); + + // Now grab group settings ... ACL_NO overrides ACL_YES so act appropriatley + $sql = 'SELECT ug.user_id, ao.auth_option, a.forum_id, a.auth_setting + FROM ' . USER_GROUP_TABLE . ' ug, ' . ACL_OPTIONS_TABLE . ' ao, ' . ACL_GROUPS_TABLE . ' a + WHERE ao.auth_option_id = a.auth_option_id + AND a.group_id = ug.group_id + ' . (($sql_user) ? 'AND ug.' . $sql_user : '') . " + $sql_forum + $sql_opts + ORDER BY a.forum_id, ao.auth_option"; + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + if (!isset($hold_ary[$row['user_id']][$row['forum_id']][$row['auth_option']]) || (isset($hold_ary[$row['user_id']][$row['forum_id']][$row['auth_option']]) && $hold_ary[$row['user_id']][$row['forum_id']][$row['auth_option']] != ACL_NO)) + { + $hold_ary[$row['user_id']][$row['forum_id']][$row['auth_option']] = $row['auth_setting']; + } + } + $db->sql_freeresult($result); + + return $hold_ary; + } + + /** + * Authentication plug-ins is largely down to Sergey Kanareykin, our thanks to him. + * @todo replace this with a new system + */ + function login($username, $password, $autologin = false, $viewonline = 1, $admin = 0) + { + global $config, $db, $user, $phpbb_root_path, $phpEx; + + $method = trim($config['auth_method']); + + if (file_exists($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx)) + { + include_once($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx); + + $method = 'login_' . $method; + if (function_exists($method)) + { + $login = $method($username, $password); + + // If login returned anything other than an array there was an error + if (!is_array($login)) + { + /** + * @todo Login Attempt++ + */ + return $login; + } + + return $user->session_create($login['user_id'], $admin, $autologin, $viewonline); + } + } + + trigger_error('Authentication method not found', E_USER_ERROR); + } +} + +?>
\ No newline at end of file |