Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

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: 02.04.2025, 15:02 - Dateigröße: 31.52 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 = count($this->acl_options['global']);
0076          $local_length = count($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 (count($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 && count($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 (count($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, $phpbb_dispatcher;
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          $role_cache = array();
0528          while ($row = $db->sql_fetchrow($result))
0529          {
0530              $role_cache[$row['role_id']][$row['auth_option_id']] = (int) $row['auth_setting'];
0531          }
0532          $db->sql_freeresult($result);
0533   
0534          foreach ($role_cache as $role_id => $role_options)
0535          {
0536              $role_cache[$role_id] = serialize($role_options);
0537          }
0538   
0539          $cache->put('_role_cache', $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          /**
0557          * Event is triggered after user(s) permission settings cache has been cleared
0558          *
0559          * @event core.acl_clear_prefetch_after
0560          * @var    mixed    user_id    User ID(s)
0561          * @since 3.1.11-RC1
0562          */
0563          $vars = array('user_id');
0564          extract($phpbb_dispatcher->trigger_event('core.acl_clear_prefetch_after', compact($vars)));
0565   
0566          return;
0567      }
0568   
0569      /**
0570      * Get assigned roles
0571      */
0572      function acl_role_data($user_type, $role_type, $ug_id = false, $forum_id = false)
0573      {
0574          global $db;
0575   
0576          $roles = array();
0577   
0578          $sql_id = ($user_type == 'user') ? 'user_id' : 'group_id';
0579   
0580          $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)) : '';
0581          $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)) : '';
0582   
0583          // Grab assigned roles...
0584          $sql = 'SELECT a.auth_role_id, a.' . $sql_id . ', a.forum_id
0585              FROM ' . (($user_type == 'user') ? ACL_USERS_TABLE : ACL_GROUPS_TABLE) . ' a, ' . ACL_ROLES_TABLE . " r
0586              WHERE a.auth_role_id = r.role_id
0587                  AND r.role_type = '" . $db->sql_escape($role_type) . "'
0588                  $sql_ug
0589                  $sql_forum
0590              ORDER BY r.role_order ASC";
0591          $result = $db->sql_query($sql);
0592   
0593          while ($row = $db->sql_fetchrow($result))
0594          {
0595              $roles[$row[$sql_id]][$row['forum_id']] = $row['auth_role_id'];
0596          }
0597          $db->sql_freeresult($result);
0598   
0599          return $roles;
0600      }
0601   
0602      /**
0603      * Get raw acl data based on user/option/forum
0604      */
0605      function acl_raw_data($user_id = false, $opts = false, $forum_id = false)
0606      {
0607          global $db;
0608   
0609          $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))) : '';
0610          $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))) : '';
0611   
0612          $sql_opts = $sql_opts_select = $sql_opts_from = '';
0613          $hold_ary = array();
0614   
0615          if ($opts !== false)
0616          {
0617              $sql_opts_select = ', ao.auth_option';
0618              $sql_opts_from = ', ' . ACL_OPTIONS_TABLE . ' ao';
0619              $this->build_auth_option_statement('ao.auth_option', $opts, $sql_opts);
0620          }
0621   
0622          $sql_ary = array();
0623   
0624          // Grab non-role settings - user-specific
0625          $sql_ary[] = 'SELECT a.user_id, a.forum_id, a.auth_setting, a.auth_option_id' . $sql_opts_select . '
0626              FROM ' . ACL_USERS_TABLE . ' a' . $sql_opts_from . '
0627              WHERE a.auth_role_id = 0 ' .
0628                  (($sql_opts_from) ? 'AND a.auth_option_id = ao.auth_option_id ' : '') .
0629                  (($sql_user) ? 'AND a.' . $sql_user : '') . "
0630                  $sql_forum
0631                  $sql_opts";
0632   
0633          // Now the role settings - user-specific
0634          $sql_ary[] = 'SELECT a.user_id, a.forum_id, r.auth_option_id, r.auth_setting, r.auth_option_id' . $sql_opts_select . '
0635              FROM ' . ACL_USERS_TABLE . ' a, ' . ACL_ROLES_DATA_TABLE . ' r' . $sql_opts_from . '
0636              WHERE a.auth_role_id = r.role_id ' .
0637                  (($sql_opts_from) ? 'AND r.auth_option_id = ao.auth_option_id ' : '') .
0638                  (($sql_user) ? 'AND a.' . $sql_user : '') . "
0639                  $sql_forum
0640                  $sql_opts";
0641   
0642          foreach ($sql_ary as $sql)
0643          {
0644              $result = $db->sql_query($sql);
0645   
0646              while ($row = $db->sql_fetchrow($result))
0647              {
0648                  $option = ($sql_opts_select) ? $row['auth_option'] : $this->acl_options['option'][$row['auth_option_id']];
0649                  $hold_ary[$row['user_id']][$row['forum_id']][$option] = $row['auth_setting'];
0650              }
0651              $db->sql_freeresult($result);
0652          }
0653   
0654          $sql_ary = array();
0655   
0656          // Now grab group settings - non-role specific...
0657          $sql_ary[] = 'SELECT ug.user_id, a.forum_id, a.auth_setting, a.auth_option_id' . $sql_opts_select . '
0658              FROM ' . ACL_GROUPS_TABLE . ' a, ' . USER_GROUP_TABLE . ' ug, ' . GROUPS_TABLE . ' g' . $sql_opts_from . '
0659              WHERE a.auth_role_id = 0 ' .
0660                  (($sql_opts_from) ? 'AND a.auth_option_id = ao.auth_option_id ' : '') . '
0661                  AND a.group_id = ug.group_id
0662                  AND g.group_id = ug.group_id
0663                  AND ug.user_pending = 0
0664                  AND NOT (ug.group_leader = 1 AND g.group_skip_auth = 1)
0665                  ' . (($sql_user) ? 'AND ug.' . $sql_user : '') . "
0666                  $sql_forum
0667                  $sql_opts";
0668   
0669          // Now grab group settings - role specific...
0670          $sql_ary[] = 'SELECT ug.user_id, a.forum_id, r.auth_setting, r.auth_option_id' . $sql_opts_select . '
0671              FROM ' . ACL_GROUPS_TABLE . ' a, ' . USER_GROUP_TABLE . ' ug, ' . GROUPS_TABLE . ' g, ' . ACL_ROLES_DATA_TABLE . ' r' . $sql_opts_from . '
0672              WHERE a.auth_role_id = r.role_id ' .
0673                  (($sql_opts_from) ? 'AND r.auth_option_id = ao.auth_option_id ' : '') . '
0674                  AND a.group_id = ug.group_id
0675                  AND g.group_id = ug.group_id
0676                  AND ug.user_pending = 0
0677                  AND NOT (ug.group_leader = 1 AND g.group_skip_auth = 1)
0678                  ' . (($sql_user) ? 'AND ug.' . $sql_user : '') . "
0679                  $sql_forum
0680                  $sql_opts";
0681   
0682          foreach ($sql_ary as $sql)
0683          {
0684              $result = $db->sql_query($sql);
0685   
0686              while ($row = $db->sql_fetchrow($result))
0687              {
0688                  $option = ($sql_opts_select) ? $row['auth_option'] : $this->acl_options['option'][$row['auth_option_id']];
0689   
0690                  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))
0691                  {
0692                      $hold_ary[$row['user_id']][$row['forum_id']][$option] = $row['auth_setting'];
0693   
0694                      // If we detect ACL_NEVER, we will unset the flag option (within building the bitstring it is correctly set again)
0695                      if ($row['auth_setting'] == ACL_NEVER)
0696                      {
0697                          $flag = substr($option, 0, strpos($option, '_') + 1);
0698   
0699                          if (isset($hold_ary[$row['user_id']][$row['forum_id']][$flag]) && $hold_ary[$row['user_id']][$row['forum_id']][$flag] == ACL_YES)
0700                          {
0701                              unset($hold_ary[$row['user_id']][$row['forum_id']][$flag]);
0702   
0703  /*                            if (in_array(ACL_YES, $hold_ary[$row['user_id']][$row['forum_id']]))
0704                              {
0705                                  $hold_ary[$row['user_id']][$row['forum_id']][$flag] = ACL_YES;
0706                              }
0707  */
0708                          }
0709                      }
0710                  }
0711              }
0712              $db->sql_freeresult($result);
0713          }
0714   
0715          return $hold_ary;
0716      }
0717   
0718      /**
0719      * Get raw user based permission settings
0720      */
0721      function acl_user_raw_data($user_id = false, $opts = false, $forum_id = false)
0722      {
0723          global $db;
0724   
0725          $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))) : '';
0726          $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))) : '';
0727   
0728          $sql_opts = '';
0729          $hold_ary = $sql_ary = array();
0730   
0731          if ($opts !== false)
0732          {
0733              $this->build_auth_option_statement('ao.auth_option', $opts, $sql_opts);
0734          }
0735   
0736          // Grab user settings - non-role specific...
0737          $sql_ary[] = 'SELECT a.user_id, a.forum_id, a.auth_setting, a.auth_option_id, ao.auth_option
0738              FROM ' . ACL_USERS_TABLE . ' a, ' . ACL_OPTIONS_TABLE . ' ao
0739              WHERE a.auth_role_id = 0
0740                  AND a.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          // Now the role settings - user-specific
0747          $sql_ary[] = 'SELECT a.user_id, a.forum_id, r.auth_option_id, r.auth_setting, r.auth_option_id, ao.auth_option
0748              FROM ' . ACL_USERS_TABLE . ' a, ' . ACL_ROLES_DATA_TABLE . ' r, ' . ACL_OPTIONS_TABLE . ' ao
0749              WHERE a.auth_role_id = r.role_id
0750                  AND r.auth_option_id = ao.auth_option_id ' .
0751                  (($sql_user) ? 'AND a.' . $sql_user : '') . "
0752                  $sql_forum
0753                  $sql_opts
0754              ORDER BY a.forum_id, ao.auth_option";
0755   
0756          foreach ($sql_ary as $sql)
0757          {
0758              $result = $db->sql_query($sql);
0759   
0760              while ($row = $db->sql_fetchrow($result))
0761              {
0762                  $hold_ary[$row['user_id']][$row['forum_id']][$row['auth_option']] = $row['auth_setting'];
0763              }
0764              $db->sql_freeresult($result);
0765          }
0766   
0767          return $hold_ary;
0768      }
0769   
0770      /**
0771      * Get raw group based permission settings
0772      */
0773      function acl_group_raw_data($group_id = false, $opts = false, $forum_id = false)
0774      {
0775          global $db;
0776   
0777          $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))) : '';
0778          $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))) : '';
0779          $sql_is_local = !empty($forum_id) ? 'AND ao.is_local <> 0' : '';
0780   
0781          $sql_opts = '';
0782          $hold_ary = $sql_ary = array();
0783   
0784          if ($opts !== false)
0785          {
0786              $this->build_auth_option_statement('ao.auth_option', $opts, $sql_opts);
0787          }
0788   
0789          // Grab group settings - non-role specific...
0790          $sql_ary[] = 'SELECT a.group_id, a.forum_id, a.auth_setting, a.auth_option_id, ao.auth_option
0791              FROM ' . ACL_GROUPS_TABLE . ' a, ' . ACL_OPTIONS_TABLE . " ao
0792              WHERE a.auth_role_id = 0
0793                  AND a.auth_option_id = ao.auth_option_id
0794                  $sql_is_local " .
0795                  (($sql_group) ? 'AND a.' . $sql_group : '') . "
0796                  $sql_forum
0797                  $sql_opts
0798              ORDER BY a.forum_id, ao.auth_option";
0799   
0800          // Now grab group settings - role specific...
0801          $sql_ary[] = 'SELECT a.group_id, a.forum_id, r.auth_setting, r.auth_option_id, ao.auth_option
0802              FROM ' . ACL_GROUPS_TABLE . ' a, ' . ACL_ROLES_DATA_TABLE . ' r, ' . ACL_OPTIONS_TABLE . " ao
0803              WHERE a.auth_role_id = r.role_id
0804                  $sql_is_local
0805                  AND r.auth_option_id = ao.auth_option_id " .
0806                  (($sql_group) ? 'AND a.' . $sql_group : '') . "
0807                  $sql_forum
0808                  $sql_opts
0809              ORDER BY a.forum_id, ao.auth_option";
0810   
0811          foreach ($sql_ary as $sql)
0812          {
0813              $result = $db->sql_query($sql);
0814   
0815              while ($row = $db->sql_fetchrow($result))
0816              {
0817                  $hold_ary[$row['group_id']][$row['forum_id']][$row['auth_option']] = $row['auth_setting'];
0818              }
0819              $db->sql_freeresult($result);
0820          }
0821   
0822          return $hold_ary;
0823      }
0824   
0825      /**
0826      * Get raw acl data based on user for caching user_permissions
0827      * This function returns the same data as acl_raw_data(), but without the user id as the first key within the array.
0828      */
0829      function acl_raw_data_single_user($user_id)
0830      {
0831          global $db, $cache;
0832   
0833          // Check if the role-cache is there
0834          if (($role_cache = $cache->get('_role_cache')) === false)
0835          {
0836              $role_cache = array();
0837   
0838              // We pre-fetch roles
0839              $sql = 'SELECT *
0840                  FROM ' . ACL_ROLES_DATA_TABLE . '
0841                  ORDER BY role_id ASC';
0842              $result = $db->sql_query($sql);
0843   
0844              while ($row = $db->sql_fetchrow($result))
0845              {
0846                  $role_cache[$row['role_id']][$row['auth_option_id']] = (int) $row['auth_setting'];
0847              }
0848              $db->sql_freeresult($result);
0849   
0850              foreach ($role_cache as $role_id => $role_options)
0851              {
0852                  $role_cache[$role_id] = serialize($role_options);
0853              }
0854   
0855              $cache->put('_role_cache', $role_cache);
0856          }
0857   
0858          $hold_ary = array();
0859   
0860          // Grab user-specific permission settings
0861          $sql = 'SELECT forum_id, auth_option_id, auth_role_id, auth_setting
0862              FROM ' . ACL_USERS_TABLE . '
0863              WHERE user_id = ' . $user_id;
0864          $result = $db->sql_query($sql);
0865   
0866          while ($row = $db->sql_fetchrow($result))
0867          {
0868              // If a role is assigned, assign all options included within this role. Else, only set this one option.
0869              if ($row['auth_role_id'])
0870              {
0871                  $hold_ary[$row['forum_id']] = (empty($hold_ary[$row['forum_id']])) ? unserialize($role_cache[$row['auth_role_id']]) : $hold_ary[$row['forum_id']] + unserialize($role_cache[$row['auth_role_id']]);
0872              }
0873              else
0874              {
0875                  $hold_ary[$row['forum_id']][$row['auth_option_id']] = $row['auth_setting'];
0876              }
0877          }
0878          $db->sql_freeresult($result);
0879   
0880          // Now grab group-specific permission settings
0881          $sql = 'SELECT a.forum_id, a.auth_option_id, a.auth_role_id, a.auth_setting
0882              FROM ' . ACL_GROUPS_TABLE . ' a, ' . USER_GROUP_TABLE . ' ug, ' . GROUPS_TABLE . ' g
0883              WHERE a.group_id = ug.group_id
0884                  AND g.group_id = ug.group_id
0885                  AND ug.user_pending = 0
0886                  AND NOT (ug.group_leader = 1 AND g.group_skip_auth = 1)
0887                  AND ug.user_id = ' . $user_id;
0888          $result = $db->sql_query($sql);
0889   
0890          while ($row = $db->sql_fetchrow($result))
0891          {
0892              if (!$row['auth_role_id'])
0893              {
0894                  $this->_set_group_hold_ary($hold_ary[$row['forum_id']], $row['auth_option_id'], $row['auth_setting']);
0895              }
0896              else if (!empty($role_cache[$row['auth_role_id']]))
0897              {
0898                  foreach (unserialize($role_cache[$row['auth_role_id']]) as $option_id => $setting)
0899                  {
0900                      $this->_set_group_hold_ary($hold_ary[$row['forum_id']], $option_id, $setting);
0901                  }
0902              }
0903          }
0904          $db->sql_freeresult($result);
0905   
0906          return $hold_ary;
0907      }
0908   
0909      /**
0910      * Private function snippet for setting a specific piece of the hold_ary
0911      */
0912      function _set_group_hold_ary(&$hold_ary, $option_id, $setting)
0913      {
0914          if (!isset($hold_ary[$option_id]) || (isset($hold_ary[$option_id]) && $hold_ary[$option_id] != ACL_NEVER))
0915          {
0916              $hold_ary[$option_id] = $setting;
0917   
0918              // If we detect ACL_NEVER, we will unset the flag option (within building the bitstring it is correctly set again)
0919              if ($setting == ACL_NEVER)
0920              {
0921                  $flag = substr($this->acl_options['option'][$option_id], 0, strpos($this->acl_options['option'][$option_id], '_') + 1);
0922                  $flag = (int) $this->acl_options['id'][$flag];
0923   
0924                  if (isset($hold_ary[$flag]) && $hold_ary[$flag] == ACL_YES)
0925                  {
0926                      unset($hold_ary[$flag]);
0927   
0928  /*                    This is uncommented, because i suspect this being slightly wrong due to mixed permission classes being possible
0929                      if (in_array(ACL_YES, $hold_ary))
0930                      {
0931                          $hold_ary[$flag] = ACL_YES;
0932                      }*/
0933                  }
0934              }
0935          }
0936      }
0937   
0938      /**
0939      * Authentication plug-ins is largely down to Sergey Kanareykin, our thanks to him.
0940      */
0941      function login($username, $password, $autologin = false, $viewonline = 1, $admin = 0)
0942      {
0943          global $db, $user, $phpbb_root_path, $phpEx, $phpbb_container;
0944          global $phpbb_dispatcher;
0945   
0946          /* @var $provider_collection \phpbb\auth\provider_collection */
0947          $provider_collection = $phpbb_container->get('auth.provider_collection');
0948   
0949          $provider = $provider_collection->get_provider();
0950          if ($provider)
0951          {
0952              $login = $provider->login($username, $password);
0953   
0954              // If the auth module wants us to create an empty profile do so and then treat the status as LOGIN_SUCCESS
0955              if ($login['status'] == LOGIN_SUCCESS_CREATE_PROFILE)
0956              {
0957                  // we are going to use the user_add function so include functions_user.php if it wasn't defined yet
0958                  if (!function_exists('user_add'))
0959                  {
0960                      include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
0961                  }
0962   
0963                  user_add($login['user_row'], (isset($login['cp_data'])) ? $login['cp_data'] : false);
0964   
0965                  $sql = 'SELECT user_id, username, user_password, user_passchg, user_email, user_type
0966                      FROM ' . USERS_TABLE . "
0967                      WHERE username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'";
0968                  $result = $db->sql_query($sql);
0969                  $row = $db->sql_fetchrow($result);
0970                  $db->sql_freeresult($result);
0971   
0972                  if (!$row)
0973                  {
0974                      return array(
0975                          'status'        => LOGIN_ERROR_EXTERNAL_AUTH,
0976                          'error_msg'        => 'AUTH_NO_PROFILE_CREATED',
0977                          'user_row'        => array('user_id' => ANONYMOUS),
0978                      );
0979                  }
0980   
0981                  $login = array(
0982                      'status'    => LOGIN_SUCCESS,
0983                      'error_msg'    => false,
0984                      'user_row'    => $row,
0985                  );
0986              }
0987   
0988              // If the auth provider wants us to link an empty account do so and redirect
0989              if ($login['status'] == LOGIN_SUCCESS_LINK_PROFILE)
0990              {
0991                  // If this status exists a fourth field is in the $login array called 'redirect_data'
0992                  // This data is passed along as GET data to the next page allow the account to be linked
0993   
0994                  $params = array('mode' => 'login_link');
0995                  $url = append_sid($phpbb_root_path . 'ucp.' . $phpEx, array_merge($params, $login['redirect_data']));
0996   
0997                  redirect($url);
0998              }
0999   
1000              /**
1001               * Event is triggered after checking for valid username and password, and before the actual session creation.
1002               *
1003               * @event core.auth_login_session_create_before
1004               * @var    array    login                Variable containing login array
1005               * @var    bool    admin                Boolean variable whether user is logging into the ACP
1006               * @var    string    username            Username of user to log in
1007               * @var    bool    autologin            Boolean variable signaling whether login is triggered via auto login
1008               * @since 3.1.7-RC1
1009               */
1010              $vars = array(
1011                  'login',
1012                  'admin',
1013                  'username',
1014                  'autologin',
1015              );
1016              extract($phpbb_dispatcher->trigger_event('core.auth_login_session_create_before', compact($vars)));
1017   
1018              // If login succeeded, we will log the user in... else we pass the login array through...
1019              if ($login['status'] == LOGIN_SUCCESS)
1020              {
1021                  $old_session_id = $user->session_id;
1022   
1023                  if ($admin)
1024                  {
1025                      global $SID, $_SID;
1026   
1027                      $cookie_expire = time() - 31536000;
1028                      $user->set_cookie('u', '', $cookie_expire);
1029                      $user->set_cookie('sid', '', $cookie_expire);
1030                      unset($cookie_expire);
1031   
1032                      $SID = '?sid=';
1033                      $user->session_id = $_SID = '';
1034                  }
1035   
1036                  $result = $user->session_create($login['user_row']['user_id'], $admin, $autologin, $viewonline);
1037   
1038                  // Successful session creation
1039                  if ($result === true)
1040                  {
1041                      // If admin re-authentication we remove the old session entry because a new one has been created...
1042                      if ($admin)
1043                      {
1044                          // the login array is used because the user ids do not differ for re-authentication
1045                          $sql = 'DELETE FROM ' . SESSIONS_TABLE . "
1046                              WHERE session_id = '" . $db->sql_escape($old_session_id) . "'
1047                              AND session_user_id = {$login['user_row']['user_id']}";
1048                          $db->sql_query($sql);
1049                      }
1050   
1051                      return array(
1052                          'status'        => LOGIN_SUCCESS,
1053                          'error_msg'        => false,
1054                          'user_row'        => $login['user_row'],
1055                      );
1056                  }
1057   
1058                  return array(
1059                      'status'        => LOGIN_BREAK,
1060                      'error_msg'        => $result,
1061                      'user_row'        => $login['user_row'],
1062                  );
1063              }
1064   
1065              return $login;
1066          }
1067   
1068          trigger_error('Authentication method not found', E_USER_ERROR);
1069      }
1070   
1071      /**
1072      * Fill auth_option statement for later querying based on the supplied options
1073      */
1074      function build_auth_option_statement($key, $auth_options, &$sql_opts)
1075      {
1076          global $db;
1077   
1078          if (!is_array($auth_options))
1079          {
1080              if (strpos($auth_options, '%') !== false)
1081              {
1082                  $sql_opts = "AND $key " . $db->sql_like_expression(str_replace('%', $db->get_any_char(), $auth_options));
1083              }
1084              else
1085              {
1086                  $sql_opts = "AND $key = '" . $db->sql_escape($auth_options) . "'";
1087              }
1088          }
1089          else
1090          {
1091              $is_like_expression = false;
1092   
1093              foreach ($auth_options as $option)
1094              {
1095                  if (strpos($option, '%') !== false)
1096                  {
1097                      $is_like_expression = true;
1098                  }
1099              }
1100   
1101              if (!$is_like_expression)
1102              {
1103                  $sql_opts = 'AND ' . $db->sql_in_set($key, $auth_options);
1104              }
1105              else
1106              {
1107                  $sql = array();
1108   
1109                  foreach ($auth_options as $option)
1110                  {
1111                      if (strpos($option, '%') !== false)
1112                      {
1113                          $sql[] = $key . ' ' . $db->sql_like_expression(str_replace('%', $db->get_any_char(), $option));
1114                      }
1115                      else
1116                      {
1117                          $sql[] = $key . " = '" . $db->sql_escape($option) . "'";
1118                      }
1119                  }
1120   
1121                  $sql_opts = 'AND (' . implode(' OR ', $sql) . ')';
1122              }
1123          }
1124      }
1125  }
1126