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