Verzeichnisstruktur phpBB-3.1.0


Veröffentlicht
27.10.2014

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

auth.php

Zuletzt modifiziert: 09.10.2024, 12:51 - Dateigröße: 30.42 KiB


0001  <?php
0002  /**
0003  *
0004  * This file is part of the phpBB Forum Software package.
0005  *
0006  * @copyright (c) phpBB Limited <https://www.phpbb.com>
0007  * @license GNU General Public License, version 2 (GPL-2.0)
0008  *
0009  * For full copyright and license information, please see
0010  * the docs/CREDITS.txt file.
0011  *
0012  */
0013   
0014  namespace phpbb\auth;
0015   
0016  /**
0017  * Permission/Auth class
0018  */
0019  class auth
0020  {
0021      var $acl = array();
0022      var $cache = array();
0023      var $acl_options = array();
0024      var $acl_forum_ids = false;
0025   
0026      /**
0027      * Init permissions
0028      */
0029      function acl(&$userdata)
0030      {
0031          global $db, $cache;
0032   
0033          $this->acl = $this->cache = $this->acl_options = array();
0034          $this->acl_forum_ids = false;
0035   
0036          if (($this->acl_options = $cache->get('_acl_options')) === false)
0037          {
0038              $sql = 'SELECT auth_option_id, auth_option, is_global, is_local
0039                  FROM ' . ACL_OPTIONS_TABLE . '
0040                  ORDER BY auth_option_id';
0041              $result = $db->sql_query($sql);
0042   
0043              $global = $local = 0;
0044              $this->acl_options = array();
0045              while ($row = $db->sql_fetchrow($result))
0046              {
0047                  if ($row['is_global'])
0048                  {
0049                      $this->acl_options['global'][$row['auth_option']] = $global++;
0050                  }
0051   
0052                  if ($row['is_local'])
0053                  {
0054                      $this->acl_options['local'][$row['auth_option']] = $local++;
0055                  }
0056   
0057                  $this->acl_options['id'][$row['auth_option']] = (int) $row['auth_option_id'];
0058                  $this->acl_options['option'][(int) $row['auth_option_id']] = $row['auth_option'];
0059              }
0060              $db->sql_freeresult($result);
0061   
0062              $cache->put('_acl_options', $this->acl_options);
0063          }
0064   
0065          if (!trim($userdata['user_permissions']))
0066          {
0067              $this->acl_cache($userdata);
0068          }
0069   
0070          // Fill ACL array
0071          $this->_fill_acl($userdata['user_permissions']);
0072   
0073          // Verify bitstring length with options provided...
0074          $renew = false;
0075          $global_length = sizeof($this->acl_options['global']);
0076          $local_length = sizeof($this->acl_options['local']);
0077   
0078          // Specify comparing length (bitstring is padded to 31 bits)
0079          $global_length = ($global_length % 31) ? ($global_length - ($global_length % 31) + 31) : $global_length;
0080          $local_length = ($local_length % 31) ? ($local_length - ($local_length % 31) + 31) : $local_length;
0081   
0082          // You thought we are finished now? Noooo... now compare them.
0083          foreach ($this->acl as $forum_id => $bitstring)
0084          {
0085              if (($forum_id && strlen($bitstring) != $local_length) || (!$forum_id && strlen($bitstring) != $global_length))
0086              {
0087                  $renew = true;
0088                  break;
0089              }
0090          }
0091   
0092          // If a bitstring within the list does not match the options, we have a user with incorrect permissions set and need to renew them
0093          if ($renew)
0094          {
0095              $this->acl_cache($userdata);
0096              $this->_fill_acl($userdata['user_permissions']);
0097          }
0098   
0099          return;
0100      }
0101   
0102      /**
0103      * Retrieves data wanted by acl function from the database for the
0104      * specified user.
0105      *
0106      * @param int $user_id User ID
0107      * @return array User attributes
0108      */
0109      public function obtain_user_data($user_id)
0110      {
0111          global $db;
0112   
0113          $sql = 'SELECT user_id, username, user_permissions, user_type
0114              FROM ' . USERS_TABLE . '
0115              WHERE user_id = ' . $user_id;
0116          $result = $db->sql_query($sql);
0117          $user_data = $db->sql_fetchrow($result);
0118          $db->sql_freeresult($result);
0119          return $user_data;
0120      }
0121   
0122      /**
0123      * Fill ACL array with relevant bitstrings from user_permissions column
0124      * @access private
0125      */
0126      function _fill_acl($user_permissions)
0127      {
0128          $seq_cache = array();
0129          $this->acl = array();
0130          $user_permissions = explode("\n", $user_permissions);
0131   
0132          foreach ($user_permissions as $f => $seq)
0133          {
0134              if ($seq)
0135              {
0136                  $i = 0;
0137   
0138                  if (!isset($this->acl[$f]))
0139                  {
0140                      $this->acl[$f] = '';
0141                  }
0142   
0143                  while ($subseq = substr($seq, $i, 6))
0144                  {
0145                      if (isset($seq_cache[$subseq]))
0146                      {
0147                          $converted = $seq_cache[$subseq];
0148                      }
0149                      else
0150                      {
0151                          $converted = $seq_cache[$subseq] = str_pad(base_convert($subseq, 36, 2), 31, 0, STR_PAD_LEFT);
0152                      }
0153   
0154                      // We put the original bitstring into the acl array
0155                      $this->acl[$f] .= $converted;
0156                      $i += 6;
0157                  }
0158              }
0159          }
0160      }
0161   
0162      /**
0163      * Look up an option
0164      * if the option is prefixed with !, then the result becomes negated
0165      *
0166      * If a forum id is specified the local option will be combined with a global option if one exist.
0167      * If a forum id is not specified, only the global option will be checked.
0168      */
0169      function acl_get($opt, $f = 0)
0170      {
0171          $negate = false;
0172   
0173          if (strpos($opt, '!') === 0)
0174          {
0175              $negate = true;
0176              $opt = substr($opt, 1);
0177          }
0178   
0179          if (!isset($this->cache[$f][$opt]))
0180          {
0181              // We combine the global/local option with an OR because some options are global and local.
0182              // If the user has the global permission the local one is true too and vice versa
0183              $this->cache[$f][$opt] = false;
0184   
0185              // Is this option a global permission setting?
0186              if (isset($this->acl_options['global'][$opt]))
0187              {
0188                  if (isset($this->acl[0]))
0189                  {
0190                      $this->cache[$f][$opt] = $this->acl[0][$this->acl_options['global'][$opt]];
0191                  }
0192              }
0193   
0194              // Is this option a local permission setting?
0195              // But if we check for a global option only, we won't combine the options...
0196              if ($f != 0 && isset($this->acl_options['local'][$opt]))
0197              {
0198                  if (isset($this->acl[$f]) && isset($this->acl[$f][$this->acl_options['local'][$opt]]))
0199                  {
0200                      $this->cache[$f][$opt] |= $this->acl[$f][$this->acl_options['local'][$opt]];
0201                  }
0202              }
0203          }
0204   
0205          // Founder always has all global options set to true...
0206          return ($negate) ? !$this->cache[$f][$opt] : $this->cache[$f][$opt];
0207      }
0208   
0209      /**
0210      * Get forums with the specified permission setting
0211      *
0212      * @param string $opt The permission name to lookup. If prefixed with !, the result is negated.
0213      * @param bool    $clean set to true if only values needs to be returned which are set/unset
0214      *
0215      * @return array Contains the forum ids with the specified permission set to true.
0216                      This is a nested array: array => forum_id => permission => true
0217      */
0218      function acl_getf($opt, $clean = false)
0219      {
0220          $acl_f = array();
0221          $negate = false;
0222   
0223          if (strpos($opt, '!') === 0)
0224          {
0225              $negate = true;
0226              $opt = substr($opt, 1);
0227          }
0228   
0229          // If we retrieve a list of forums not having permissions in, we need to get every forum_id
0230          if ($negate)
0231          {
0232              if ($this->acl_forum_ids === false)
0233              {
0234                  global $db;
0235   
0236                  $sql = 'SELECT forum_id
0237                      FROM ' . FORUMS_TABLE;
0238   
0239                  if (sizeof($this->acl))
0240                  {
0241                      $sql .= ' WHERE ' . $db->sql_in_set('forum_id', array_keys($this->acl), true);
0242                  }
0243                  $result = $db->sql_query($sql);
0244   
0245                  $this->acl_forum_ids = array();
0246                  while ($row = $db->sql_fetchrow($result))
0247                  {
0248                      $this->acl_forum_ids[] = $row['forum_id'];
0249                  }
0250                  $db->sql_freeresult($result);
0251              }
0252          }
0253   
0254          if (isset($this->acl_options['local'][$opt]))
0255          {
0256              foreach ($this->acl as $f => $bitstring)
0257              {
0258                  // Skip global settings
0259                  if (!$f)
0260                  {
0261                      continue;
0262                  }
0263   
0264                  $allowed = (!isset($this->cache[$f][$opt])) ? $this->acl_get($opt, $f) : $this->cache[$f][$opt];
0265   
0266                  if (!$clean)
0267                  {
0268                      $acl_f[$f][$opt] = ($negate) ? !$allowed : $allowed;
0269                  }
0270                  else
0271                  {
0272                      if (($negate && !$allowed) || (!$negate && $allowed))
0273                      {
0274                          $acl_f[$f][$opt] = 1;
0275                      }
0276                  }
0277              }
0278          }
0279   
0280          // If we get forum_ids not having this permission, we need to fill the remaining parts
0281          if ($negate && sizeof($this->acl_forum_ids))
0282          {
0283              foreach ($this->acl_forum_ids as $f)
0284              {
0285                  $acl_f[$f][$opt] = 1;
0286              }
0287          }
0288   
0289          return $acl_f;
0290      }
0291   
0292      /**
0293      * Get local permission state for any forum.
0294      *
0295      * Returns true if user has the permission in one or more forums, false if in no forum.
0296      * If global option is checked it returns the global state (same as acl_get($opt))
0297      * Local option has precedence...
0298      */
0299      function acl_getf_global($opt)
0300      {
0301          if (is_array($opt))
0302          {
0303              // evaluates to true as soon as acl_getf_global is true for one option
0304              foreach ($opt as $check_option)
0305              {
0306                  if ($this->acl_getf_global($check_option))
0307                  {
0308                      return true;
0309                  }
0310              }
0311   
0312              return false;
0313          }
0314   
0315          if (isset($this->acl_options['local'][$opt]))
0316          {
0317              foreach ($this->acl as $f => $bitstring)
0318              {
0319                  // Skip global settings
0320                  if (!$f)
0321                  {
0322                      continue;
0323                  }
0324   
0325                  // as soon as the user has any permission we're done so return true
0326                  if ((!isset($this->cache[$f][$opt])) ? $this->acl_get($opt, $f) : $this->cache[$f][$opt])
0327                  {
0328                      return true;
0329                  }
0330              }
0331          }
0332          else if (isset($this->acl_options['global'][$opt]))
0333          {
0334              return $this->acl_get($opt);
0335          }
0336   
0337          return false;
0338      }
0339   
0340      /**
0341      * Get permission settings (more than one)
0342      */
0343      function acl_gets()
0344      {
0345          $args = func_get_args();
0346          $f = array_pop($args);
0347   
0348          if (!is_numeric($f))
0349          {
0350              $args[] = $f;
0351              $f = 0;
0352          }
0353   
0354          // alternate syntax: acl_gets(array('m_', 'a_'), $forum_id)
0355          if (is_array($args[0]))
0356          {
0357              $args = $args[0];
0358          }
0359   
0360          $acl = 0;
0361          foreach ($args as $opt)
0362          {
0363              $acl |= $this->acl_get($opt, $f);
0364          }
0365   
0366          return $acl;
0367      }
0368   
0369      /**
0370      * Get permission listing based on user_id/options/forum_ids
0371      *
0372      * Be careful when using this function with permissions a_, m_, u_ and f_ !
0373      * It may not work correctly. When a user group grants an a_* permission,
0374      * e.g. a_foo, but the user's a_foo permission is set to "Never", then
0375      * the user does not in fact have the a_ permission.
0376      * But the user will still be listed as having the a_ permission.
0377      *
0378      * For more information see: http://tracker.phpbb.com/browse/PHPBB3-10252
0379      */
0380      function acl_get_list($user_id = false, $opts = false, $forum_id = false)
0381      {
0382          if ($user_id !== false && !is_array($user_id) && $opts === false && $forum_id === false)
0383          {
0384              $hold_ary = array($user_id => $this->acl_raw_data_single_user($user_id));
0385          }
0386          else
0387          {
0388              $hold_ary = $this->acl_raw_data($user_id, $opts, $forum_id);
0389          }
0390   
0391          $auth_ary = array();
0392          foreach ($hold_ary as $user_id => $forum_ary)
0393          {
0394              foreach ($forum_ary as $forum_id => $auth_option_ary)
0395              {
0396                  foreach ($auth_option_ary as $auth_option => $auth_setting)
0397                  {
0398                      if ($auth_setting)
0399                      {
0400                          $auth_ary[$forum_id][$auth_option][] = $user_id;
0401                      }
0402                  }
0403              }
0404          }
0405   
0406          return $auth_ary;
0407      }
0408   
0409      /**
0410      * Cache data to user_permissions row
0411      */
0412      function acl_cache(&$userdata)
0413      {
0414          global $db;
0415   
0416          // Empty user_permissions
0417          $userdata['user_permissions'] = '';
0418   
0419          $hold_ary = $this->acl_raw_data_single_user($userdata['user_id']);
0420   
0421          // Key 0 in $hold_ary are global options, all others are forum_ids
0422   
0423          // If this user is founder we're going to force fill the admin options ...
0424          if ($userdata['user_type'] == USER_FOUNDER)
0425          {
0426              foreach ($this->acl_options['global'] as $opt => $id)
0427              {
0428                  if (strpos($opt, 'a_') === 0)
0429                  {
0430                      $hold_ary[0][$this->acl_options['id'][$opt]] = ACL_YES;
0431                  }
0432              }
0433          }
0434   
0435          $hold_str = $this->build_bitstring($hold_ary);
0436   
0437          if ($hold_str)
0438          {
0439              $userdata['user_permissions'] = $hold_str;
0440   
0441              $sql = 'UPDATE ' . USERS_TABLE . "
0442                  SET user_permissions = '" . $db->sql_escape($userdata['user_permissions']) . "',
0443                      user_perm_from = 0
0444                  WHERE user_id = " . $userdata['user_id'];
0445              $db->sql_query($sql);
0446          }
0447   
0448          return;
0449      }
0450   
0451      /**
0452      * Build bitstring from permission set
0453      */
0454      function build_bitstring(&$hold_ary)
0455      {
0456          $hold_str = '';
0457   
0458          if (sizeof($hold_ary))
0459          {
0460              ksort($hold_ary);
0461   
0462              $last_f = 0;
0463   
0464              foreach ($hold_ary as $f => $auth_ary)
0465              {
0466                  $ary_key = (!$f) ? 'global' : 'local';
0467   
0468                  $bitstring = array();
0469                  foreach ($this->acl_options[$ary_key] as $opt => $id)
0470                  {
0471                      if (isset($auth_ary[$this->acl_options['id'][$opt]]))
0472                      {
0473                          $bitstring[$id] = $auth_ary[$this->acl_options['id'][$opt]];
0474   
0475                          $option_key = substr($opt, 0, strpos($opt, '_') + 1);
0476   
0477                          // If one option is allowed, the global permission for this option has to be allowed too
0478                          // example: if the user has the a_ permission this means he has one or more a_* permissions
0479                          if ($auth_ary[$this->acl_options['id'][$opt]] == ACL_YES && (!isset($bitstring[$this->acl_options[$ary_key][$option_key]]) || $bitstring[$this->acl_options[$ary_key][$option_key]] == ACL_NEVER))
0480                          {
0481                              $bitstring[$this->acl_options[$ary_key][$option_key]] = ACL_YES;
0482                          }
0483                      }
0484                      else
0485                      {
0486                          $bitstring[$id] = ACL_NEVER;
0487                      }
0488                  }
0489   
0490                  // Now this bitstring defines the permission setting for the current forum $f (or global setting)
0491                  $bitstring = implode('', $bitstring);
0492   
0493                  // The line number indicates the id, therefore we have to add empty lines for those ids not present
0494                  $hold_str .= str_repeat("\n", $f - $last_f);
0495   
0496                  // Convert bitstring for storage - we do not use binary/bytes because PHP's string functions are not fully binary safe
0497                  for ($i = 0, $bit_length = strlen($bitstring); $i < $bit_length; $i += 31)
0498                  {
0499                      $hold_str .= str_pad(base_convert(str_pad(substr($bitstring, $i, 31), 31, 0, STR_PAD_RIGHT), 2, 36), 6, 0, STR_PAD_LEFT);
0500                  }
0501   
0502                  $last_f = $f;
0503              }
0504              unset($bitstring);
0505   
0506              $hold_str = rtrim($hold_str);
0507          }
0508   
0509          return $hold_str;
0510      }
0511   
0512      /**
0513      * Clear one or all users cached permission settings
0514      */
0515      function acl_clear_prefetch($user_id = false)
0516      {
0517          global $db, $cache;
0518   
0519          // Rebuild options cache
0520          $cache->destroy('_role_cache');
0521   
0522          $sql = 'SELECT *
0523              FROM ' . ACL_ROLES_DATA_TABLE . '
0524              ORDER BY role_id ASC';
0525          $result = $db->sql_query($sql);
0526   
0527          $this->role_cache = array();
0528          while ($row = $db->sql_fetchrow($result))
0529          {
0530              $this->role_cache[$row['role_id']][$row['auth_option_id']] = (int) $row['auth_setting'];
0531          }
0532          $db->sql_freeresult($result);
0533   
0534          foreach ($this->role_cache as $role_id => $role_options)
0535          {
0536              $this->role_cache[$role_id] = serialize($role_options);
0537          }
0538   
0539          $cache->put('_role_cache', $this->role_cache);
0540   
0541          // Now empty user permissions
0542          $where_sql = '';
0543   
0544          if ($user_id !== false)
0545          {
0546              $user_id = (!is_array($user_id)) ? $user_id = array((int) $user_id) : array_map('intval', $user_id);
0547              $where_sql = ' WHERE ' . $db->sql_in_set('user_id', $user_id);
0548          }
0549   
0550          $sql = 'UPDATE ' . USERS_TABLE . "
0551              SET user_permissions = '',
0552                  user_perm_from = 0
0553              $where_sql";
0554          $db->sql_query($sql);
0555   
0556          return;
0557      }
0558   
0559      /**
0560      * Get assigned roles
0561      */
0562      function acl_role_data($user_type, $role_type, $ug_id = false, $forum_id = false)
0563      {
0564          global $db;
0565   
0566          $roles = array();
0567   
0568          $sql_id = ($user_type == 'user') ? 'user_id' : 'group_id';
0569   
0570          $sql_ug = ($ug_id !== false) ? ((!is_array($ug_id)) ? "AND a.$sql_id = $ug_id" : 'AND ' . $db->sql_in_set("a.$sql_id", $ug_id)) : '';
0571          $sql_forum = ($forum_id !== false) ? ((!is_array($forum_id)) ? "AND a.forum_id = $forum_id" : 'AND ' . $db->sql_in_set('a.forum_id', $forum_id)) : '';
0572   
0573          // Grab assigned roles...
0574          $sql = 'SELECT a.auth_role_id, a.' . $sql_id . ', a.forum_id
0575              FROM ' . (($user_type == 'user') ? ACL_USERS_TABLE : ACL_GROUPS_TABLE) . ' a, ' . ACL_ROLES_TABLE . " r
0576              WHERE a.auth_role_id = r.role_id
0577                  AND r.role_type = '" . $db->sql_escape($role_type) . "'
0578                  $sql_ug
0579                  $sql_forum
0580              ORDER BY r.role_order ASC";
0581          $result = $db->sql_query($sql);
0582   
0583          while ($row = $db->sql_fetchrow($result))
0584          {
0585              $roles[$row[$sql_id]][$row['forum_id']] = $row['auth_role_id'];
0586          }
0587          $db->sql_freeresult($result);
0588   
0589          return $roles;
0590      }
0591   
0592      /**
0593      * Get raw acl data based on user/option/forum
0594      */
0595      function acl_raw_data($user_id = false, $opts = false, $forum_id = false)
0596      {
0597          global $db;
0598   
0599          $sql_user = ($user_id !== false) ? ((!is_array($user_id)) ? 'user_id = ' . (int) $user_id : $db->sql_in_set('user_id', array_map('intval', $user_id))) : '';
0600          $sql_forum = ($forum_id !== false) ? ((!is_array($forum_id)) ? 'AND a.forum_id = ' . (int) $forum_id : 'AND ' . $db->sql_in_set('a.forum_id', array_map('intval', $forum_id))) : '';
0601   
0602          $sql_opts = $sql_opts_select = $sql_opts_from = '';
0603          $hold_ary = array();
0604   
0605          if ($opts !== false)
0606          {
0607              $sql_opts_select = ', ao.auth_option';
0608              $sql_opts_from = ', ' . ACL_OPTIONS_TABLE . ' ao';
0609              $this->build_auth_option_statement('ao.auth_option', $opts, $sql_opts);
0610          }
0611   
0612          $sql_ary = array();
0613   
0614          // Grab non-role settings - user-specific
0615          $sql_ary[] = 'SELECT a.user_id, a.forum_id, a.auth_setting, a.auth_option_id' . $sql_opts_select . '
0616              FROM ' . ACL_USERS_TABLE . ' a' . $sql_opts_from . '
0617              WHERE a.auth_role_id = 0 ' .
0618                  (($sql_opts_from) ? 'AND a.auth_option_id = ao.auth_option_id ' : '') .
0619                  (($sql_user) ? 'AND a.' . $sql_user : '') . "
0620                  $sql_forum
0621                  $sql_opts";
0622   
0623          // Now the role settings - user-specific
0624          $sql_ary[] = 'SELECT a.user_id, a.forum_id, r.auth_option_id, r.auth_setting, r.auth_option_id' . $sql_opts_select . '
0625              FROM ' . ACL_USERS_TABLE . ' a, ' . ACL_ROLES_DATA_TABLE . ' r' . $sql_opts_from . '
0626              WHERE a.auth_role_id = r.role_id ' .
0627                  (($sql_opts_from) ? 'AND r.auth_option_id = ao.auth_option_id ' : '') .
0628                  (($sql_user) ? 'AND a.' . $sql_user : '') . "
0629                  $sql_forum
0630                  $sql_opts";
0631   
0632          foreach ($sql_ary as $sql)
0633          {
0634              $result = $db->sql_query($sql);
0635   
0636              while ($row = $db->sql_fetchrow($result))
0637              {
0638                  $option = ($sql_opts_select) ? $row['auth_option'] : $this->acl_options['option'][$row['auth_option_id']];
0639                  $hold_ary[$row['user_id']][$row['forum_id']][$option] = $row['auth_setting'];
0640              }
0641              $db->sql_freeresult($result);
0642          }
0643   
0644          $sql_ary = array();
0645   
0646          // Now grab group settings - non-role specific...
0647          $sql_ary[] = 'SELECT ug.user_id, a.forum_id, a.auth_setting, a.auth_option_id' . $sql_opts_select . '
0648              FROM ' . ACL_GROUPS_TABLE . ' a, ' . USER_GROUP_TABLE . ' ug, ' . GROUPS_TABLE . ' g' . $sql_opts_from . '
0649              WHERE a.auth_role_id = 0 ' .
0650                  (($sql_opts_from) ? 'AND a.auth_option_id = ao.auth_option_id ' : '') . '
0651                  AND a.group_id = ug.group_id
0652                  AND g.group_id = ug.group_id
0653                  AND ug.user_pending = 0
0654                  AND NOT (ug.group_leader = 1 AND g.group_skip_auth = 1)
0655                  ' . (($sql_user) ? 'AND ug.' . $sql_user : '') . "
0656                  $sql_forum
0657                  $sql_opts";
0658   
0659          // Now grab group settings - role specific...
0660          $sql_ary[] = 'SELECT ug.user_id, a.forum_id, r.auth_setting, r.auth_option_id' . $sql_opts_select . '
0661              FROM ' . ACL_GROUPS_TABLE . ' a, ' . USER_GROUP_TABLE . ' ug, ' . GROUPS_TABLE . ' g, ' . ACL_ROLES_DATA_TABLE . ' r' . $sql_opts_from . '
0662              WHERE a.auth_role_id = r.role_id ' .
0663                  (($sql_opts_from) ? 'AND r.auth_option_id = ao.auth_option_id ' : '') . '
0664                  AND a.group_id = ug.group_id
0665                  AND g.group_id = ug.group_id
0666                  AND ug.user_pending = 0
0667                  AND NOT (ug.group_leader = 1 AND g.group_skip_auth = 1)
0668                  ' . (($sql_user) ? 'AND ug.' . $sql_user : '') . "
0669                  $sql_forum
0670                  $sql_opts";
0671   
0672          foreach ($sql_ary as $sql)
0673          {
0674              $result = $db->sql_query($sql);
0675   
0676              while ($row = $db->sql_fetchrow($result))
0677              {
0678                  $option = ($sql_opts_select) ? $row['auth_option'] : $this->acl_options['option'][$row['auth_option_id']];
0679   
0680                  if (!isset($hold_ary[$row['user_id']][$row['forum_id']][$option]) || (isset($hold_ary[$row['user_id']][$row['forum_id']][$option]) && $hold_ary[$row['user_id']][$row['forum_id']][$option] != ACL_NEVER))
0681                  {
0682                      $hold_ary[$row['user_id']][$row['forum_id']][$option] = $row['auth_setting'];
0683   
0684                      // If we detect ACL_NEVER, we will unset the flag option (within building the bitstring it is correctly set again)
0685                      if ($row['auth_setting'] == ACL_NEVER)
0686                      {
0687                          $flag = substr($option, 0, strpos($option, '_') + 1);
0688   
0689                          if (isset($hold_ary[$row['user_id']][$row['forum_id']][$flag]) && $hold_ary[$row['user_id']][$row['forum_id']][$flag] == ACL_YES)
0690                          {
0691                              unset($hold_ary[$row['user_id']][$row['forum_id']][$flag]);
0692   
0693  /*                            if (in_array(ACL_YES, $hold_ary[$row['user_id']][$row['forum_id']]))
0694                              {
0695                                  $hold_ary[$row['user_id']][$row['forum_id']][$flag] = ACL_YES;
0696                              }
0697  */
0698                          }
0699                      }
0700                  }
0701              }
0702              $db->sql_freeresult($result);
0703          }
0704   
0705          return $hold_ary;
0706      }
0707   
0708      /**
0709      * Get raw user based permission settings
0710      */
0711      function acl_user_raw_data($user_id = false, $opts = false, $forum_id = false)
0712      {
0713          global $db;
0714   
0715          $sql_user = ($user_id !== false) ? ((!is_array($user_id)) ? 'user_id = ' . (int) $user_id : $db->sql_in_set('user_id', array_map('intval', $user_id))) : '';
0716          $sql_forum = ($forum_id !== false) ? ((!is_array($forum_id)) ? 'AND a.forum_id = ' . (int) $forum_id : 'AND ' . $db->sql_in_set('a.forum_id', array_map('intval', $forum_id))) : '';
0717   
0718          $sql_opts = '';
0719          $hold_ary = $sql_ary = array();
0720   
0721          if ($opts !== false)
0722          {
0723              $this->build_auth_option_statement('ao.auth_option', $opts, $sql_opts);
0724          }
0725   
0726          // Grab user settings - non-role specific...
0727          $sql_ary[] = 'SELECT a.user_id, a.forum_id, a.auth_setting, a.auth_option_id, ao.auth_option
0728              FROM ' . ACL_USERS_TABLE . ' a, ' . ACL_OPTIONS_TABLE . ' ao
0729              WHERE a.auth_role_id = 0
0730                  AND a.auth_option_id = ao.auth_option_id ' .
0731                  (($sql_user) ? 'AND a.' . $sql_user : '') . "
0732                  $sql_forum
0733                  $sql_opts
0734              ORDER BY a.forum_id, ao.auth_option";
0735   
0736          // Now the role settings - user-specific
0737          $sql_ary[] = 'SELECT a.user_id, a.forum_id, r.auth_option_id, r.auth_setting, r.auth_option_id, ao.auth_option
0738              FROM ' . ACL_USERS_TABLE . ' a, ' . ACL_ROLES_DATA_TABLE . ' r, ' . ACL_OPTIONS_TABLE . ' ao
0739              WHERE a.auth_role_id = r.role_id
0740                  AND r.auth_option_id = ao.auth_option_id ' .
0741                  (($sql_user) ? 'AND a.' . $sql_user : '') . "
0742                  $sql_forum
0743                  $sql_opts
0744              ORDER BY a.forum_id, ao.auth_option";
0745   
0746          foreach ($sql_ary as $sql)
0747          {
0748              $result = $db->sql_query($sql);
0749   
0750              while ($row = $db->sql_fetchrow($result))
0751              {
0752                  $hold_ary[$row['user_id']][$row['forum_id']][$row['auth_option']] = $row['auth_setting'];
0753              }
0754              $db->sql_freeresult($result);
0755          }
0756   
0757          return $hold_ary;
0758      }
0759   
0760      /**
0761      * Get raw group based permission settings
0762      */
0763      function acl_group_raw_data($group_id = false, $opts = false, $forum_id = false)
0764      {
0765          global $db;
0766   
0767          $sql_group = ($group_id !== false) ? ((!is_array($group_id)) ? 'group_id = ' . (int) $group_id : $db->sql_in_set('group_id', array_map('intval', $group_id))) : '';
0768          $sql_forum = ($forum_id !== false) ? ((!is_array($forum_id)) ? 'AND a.forum_id = ' . (int) $forum_id : 'AND ' . $db->sql_in_set('a.forum_id', array_map('intval', $forum_id))) : '';
0769   
0770          $sql_opts = '';
0771          $hold_ary = $sql_ary = array();
0772   
0773          if ($opts !== false)
0774          {
0775              $this->build_auth_option_statement('ao.auth_option', $opts, $sql_opts);
0776          }
0777   
0778          // Grab group settings - non-role specific...
0779          $sql_ary[] = 'SELECT a.group_id, a.forum_id, a.auth_setting, a.auth_option_id, ao.auth_option
0780              FROM ' . ACL_GROUPS_TABLE . ' a, ' . ACL_OPTIONS_TABLE . ' ao
0781              WHERE a.auth_role_id = 0
0782                  AND a.auth_option_id = ao.auth_option_id ' .
0783                  (($sql_group) ? 'AND a.' . $sql_group : '') . "
0784                  $sql_forum
0785                  $sql_opts
0786              ORDER BY a.forum_id, ao.auth_option";
0787   
0788          // Now grab group settings - role specific...
0789          $sql_ary[] = 'SELECT a.group_id, a.forum_id, r.auth_setting, r.auth_option_id, ao.auth_option
0790              FROM ' . ACL_GROUPS_TABLE . ' a, ' . ACL_ROLES_DATA_TABLE . ' r, ' . ACL_OPTIONS_TABLE . ' ao
0791              WHERE a.auth_role_id = r.role_id
0792                  AND r.auth_option_id = ao.auth_option_id ' .
0793                  (($sql_group) ? 'AND a.' . $sql_group : '') . "
0794                  $sql_forum
0795                  $sql_opts
0796              ORDER BY a.forum_id, ao.auth_option";
0797   
0798          foreach ($sql_ary as $sql)
0799          {
0800              $result = $db->sql_query($sql);
0801   
0802              while ($row = $db->sql_fetchrow($result))
0803              {
0804                  $hold_ary[$row['group_id']][$row['forum_id']][$row['auth_option']] = $row['auth_setting'];
0805              }
0806              $db->sql_freeresult($result);
0807          }
0808   
0809          return $hold_ary;
0810      }
0811   
0812      /**
0813      * Get raw acl data based on user for caching user_permissions
0814      * This function returns the same data as acl_raw_data(), but without the user id as the first key within the array.
0815      */
0816      function acl_raw_data_single_user($user_id)
0817      {
0818          global $db, $cache;
0819   
0820          // Check if the role-cache is there
0821          if (($this->role_cache = $cache->get('_role_cache')) === false)
0822          {
0823              $this->role_cache = array();
0824   
0825              // We pre-fetch roles
0826              $sql = 'SELECT *
0827                  FROM ' . ACL_ROLES_DATA_TABLE . '
0828                  ORDER BY role_id ASC';
0829              $result = $db->sql_query($sql);
0830   
0831              while ($row = $db->sql_fetchrow($result))
0832              {
0833                  $this->role_cache[$row['role_id']][$row['auth_option_id']] = (int) $row['auth_setting'];
0834              }
0835              $db->sql_freeresult($result);
0836   
0837              foreach ($this->role_cache as $role_id => $role_options)
0838              {
0839                  $this->role_cache[$role_id] = serialize($role_options);
0840              }
0841   
0842              $cache->put('_role_cache', $this->role_cache);
0843          }
0844   
0845          $hold_ary = array();
0846   
0847          // Grab user-specific permission settings
0848          $sql = 'SELECT forum_id, auth_option_id, auth_role_id, auth_setting
0849              FROM ' . ACL_USERS_TABLE . '
0850              WHERE user_id = ' . $user_id;
0851          $result = $db->sql_query($sql);
0852   
0853          while ($row = $db->sql_fetchrow($result))
0854          {
0855              // If a role is assigned, assign all options included within this role. Else, only set this one option.
0856              if ($row['auth_role_id'])
0857              {
0858                  $hold_ary[$row['forum_id']] = (empty($hold_ary[$row['forum_id']])) ? unserialize($this->role_cache[$row['auth_role_id']]) : $hold_ary[$row['forum_id']] + unserialize($this->role_cache[$row['auth_role_id']]);
0859              }
0860              else
0861              {
0862                  $hold_ary[$row['forum_id']][$row['auth_option_id']] = $row['auth_setting'];
0863              }
0864          }
0865          $db->sql_freeresult($result);
0866   
0867          // Now grab group-specific permission settings
0868          $sql = 'SELECT a.forum_id, a.auth_option_id, a.auth_role_id, a.auth_setting
0869              FROM ' . ACL_GROUPS_TABLE . ' a, ' . USER_GROUP_TABLE . ' ug, ' . GROUPS_TABLE . ' g
0870              WHERE a.group_id = ug.group_id
0871                  AND g.group_id = ug.group_id
0872                  AND ug.user_pending = 0
0873                  AND NOT (ug.group_leader = 1 AND g.group_skip_auth = 1)
0874                  AND ug.user_id = ' . $user_id;
0875          $result = $db->sql_query($sql);
0876   
0877          while ($row = $db->sql_fetchrow($result))
0878          {
0879              if (!$row['auth_role_id'])
0880              {
0881                  $this->_set_group_hold_ary($hold_ary[$row['forum_id']], $row['auth_option_id'], $row['auth_setting']);
0882              }
0883              else if (!empty($this->role_cache[$row['auth_role_id']]))
0884              {
0885                  foreach (unserialize($this->role_cache[$row['auth_role_id']]) as $option_id => $setting)
0886                  {
0887                      $this->_set_group_hold_ary($hold_ary[$row['forum_id']], $option_id, $setting);
0888                  }
0889              }
0890          }
0891          $db->sql_freeresult($result);
0892   
0893          return $hold_ary;
0894      }
0895   
0896      /**
0897      * Private function snippet for setting a specific piece of the hold_ary
0898      */
0899      function _set_group_hold_ary(&$hold_ary, $option_id, $setting)
0900      {
0901          if (!isset($hold_ary[$option_id]) || (isset($hold_ary[$option_id]) && $hold_ary[$option_id] != ACL_NEVER))
0902          {
0903              $hold_ary[$option_id] = $setting;
0904   
0905              // If we detect ACL_NEVER, we will unset the flag option (within building the bitstring it is correctly set again)
0906              if ($setting == ACL_NEVER)
0907              {
0908                  $flag = substr($this->acl_options['option'][$option_id], 0, strpos($this->acl_options['option'][$option_id], '_') + 1);
0909                  $flag = (int) $this->acl_options['id'][$flag];
0910   
0911                  if (isset($hold_ary[$flag]) && $hold_ary[$flag] == ACL_YES)
0912                  {
0913                      unset($hold_ary[$flag]);
0914   
0915  /*                    This is uncommented, because i suspect this being slightly wrong due to mixed permission classes being possible
0916                      if (in_array(ACL_YES, $hold_ary))
0917                      {
0918                          $hold_ary[$flag] = ACL_YES;
0919                      }*/
0920                  }
0921              }
0922          }
0923      }
0924   
0925      /**
0926      * Authentication plug-ins is largely down to Sergey Kanareykin, our thanks to him.
0927      */
0928      function login($username, $password, $autologin = false, $viewonline = 1, $admin = 0)
0929      {
0930          global $config, $db, $user, $phpbb_root_path, $phpEx, $phpbb_container;
0931   
0932          $method = trim(basename($config['auth_method']));
0933   
0934          $provider = $phpbb_container->get('auth.provider.' . $method);
0935          if ($provider)
0936          {
0937              $login = $provider->login($username, $password);
0938   
0939              // If the auth module wants us to create an empty profile do so and then treat the status as LOGIN_SUCCESS
0940              if ($login['status'] == LOGIN_SUCCESS_CREATE_PROFILE)
0941              {
0942                  // we are going to use the user_add function so include functions_user.php if it wasn't defined yet
0943                  if (!function_exists('user_add'))
0944                  {
0945                      include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
0946                  }
0947   
0948                  user_add($login['user_row'], (isset($login['cp_data'])) ? $login['cp_data'] : false);
0949   
0950                  $sql = 'SELECT user_id, username, user_password, user_passchg, user_email, user_type
0951                      FROM ' . USERS_TABLE . "
0952                      WHERE username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'";
0953                  $result = $db->sql_query($sql);
0954                  $row = $db->sql_fetchrow($result);
0955                  $db->sql_freeresult($result);
0956   
0957                  if (!$row)
0958                  {
0959                      return array(
0960                          'status'        => LOGIN_ERROR_EXTERNAL_AUTH,
0961                          'error_msg'        => 'AUTH_NO_PROFILE_CREATED',
0962                          'user_row'        => array('user_id' => ANONYMOUS),
0963                      );
0964                  }
0965   
0966                  $login = array(
0967                      'status'    => LOGIN_SUCCESS,
0968                      'error_msg'    => false,
0969                      'user_row'    => $row,
0970                  );
0971              }
0972   
0973              // If the auth provider wants us to link an empty account do so and redirect
0974              if ($login['status'] == LOGIN_SUCCESS_LINK_PROFILE)
0975              {
0976                  // If this status exists a fourth field is in the $login array called 'redirect_data'
0977                  // This data is passed along as GET data to the next page allow the account to be linked
0978   
0979                  $params = array('mode' => 'login_link');
0980                  $url = append_sid($phpbb_root_path . 'ucp.' . $phpEx, array_merge($params, $login['redirect_data']));
0981   
0982                  redirect($url);
0983              }
0984   
0985              // If login succeeded, we will log the user in... else we pass the login array through...
0986              if ($login['status'] == LOGIN_SUCCESS)
0987              {
0988                  $old_session_id = $user->session_id;
0989   
0990                  if ($admin)
0991                  {
0992                      global $SID, $_SID;
0993   
0994                      $cookie_expire = time() - 31536000;
0995                      $user->set_cookie('u', '', $cookie_expire);
0996                      $user->set_cookie('sid', '', $cookie_expire);
0997                      unset($cookie_expire);
0998   
0999                      $SID = '?sid=';
1000                      $user->session_id = $_SID = '';
1001                  }
1002   
1003                  $result = $user->session_create($login['user_row']['user_id'], $admin, $autologin, $viewonline);
1004   
1005                  // Successful session creation
1006                  if ($result === true)
1007                  {
1008                      // If admin re-authentication we remove the old session entry because a new one has been created...
1009                      if ($admin)
1010                      {
1011                          // the login array is used because the user ids do not differ for re-authentication
1012                          $sql = 'DELETE FROM ' . SESSIONS_TABLE . "
1013                              WHERE session_id = '" . $db->sql_escape($old_session_id) . "'
1014                              AND session_user_id = {$login['user_row']['user_id']}";
1015                          $db->sql_query($sql);
1016                      }
1017   
1018                      return array(
1019                          'status'        => LOGIN_SUCCESS,
1020                          'error_msg'        => false,
1021                          'user_row'        => $login['user_row'],
1022                      );
1023                  }
1024   
1025                  return array(
1026                      'status'        => LOGIN_BREAK,
1027                      'error_msg'        => $result,
1028                      'user_row'        => $login['user_row'],
1029                  );
1030              }
1031   
1032              return $login;
1033          }
1034   
1035          trigger_error('Authentication method not found', E_USER_ERROR);
1036      }
1037   
1038      /**
1039      * Fill auth_option statement for later querying based on the supplied options
1040      */
1041      function build_auth_option_statement($key, $auth_options, &$sql_opts)
1042      {
1043          global $db;
1044   
1045          if (!is_array($auth_options))
1046          {
1047              if (strpos($auth_options, '%') !== false)
1048              {
1049                  $sql_opts = "AND $key " . $db->sql_like_expression(str_replace('%', $db->get_any_char(), $auth_options));
1050              }
1051              else
1052              {
1053                  $sql_opts = "AND $key = '" . $db->sql_escape($auth_options) . "'";
1054              }
1055          }
1056          else
1057          {
1058              $is_like_expression = false;
1059   
1060              foreach ($auth_options as $option)
1061              {
1062                  if (strpos($option, '%') !== false)
1063                  {
1064                      $is_like_expression = true;
1065                  }
1066              }
1067   
1068              if (!$is_like_expression)
1069              {
1070                  $sql_opts = 'AND ' . $db->sql_in_set($key, $auth_options);
1071              }
1072              else
1073              {
1074                  $sql = array();
1075   
1076                  foreach ($auth_options as $option)
1077                  {
1078                      if (strpos($option, '%') !== false)
1079                      {
1080                          $sql[] = $key . ' ' . $db->sql_like_expression(str_replace('%', $db->get_any_char(), $option));
1081                      }
1082                      else
1083                      {
1084                          $sql[] = $key . " = '" . $db->sql_escape($option) . "'";
1085                      }
1086                  }
1087   
1088                  $sql_opts = 'AND (' . implode(' OR ', $sql) . ')';
1089              }
1090          }
1091      }
1092  }
1093