includes/sessions.php
changeset 304 e2cb5f1432c8
parent 271 f088805540ae
parent 292 b3cfaf0a505c
child 313 854eecfada20
equal deleted inserted replaced
280:dc08c70ca550 304:e2cb5f1432c8
   148   /**
   148   /**
   149    * Regex that defines a valid username, minus the ^ and $, these are added later
   149    * Regex that defines a valid username, minus the ^ and $, these are added later
   150    * @var string
   150    * @var string
   151    */
   151    */
   152    
   152    
   153   //var $valid_username = '([A-Za-z0-9 \!\@\(\)-]+)';
       
   154   var $valid_username = '([^<>&\?\'"%\n\r\t\a\/]+)';
   153   var $valid_username = '([^<>&\?\'"%\n\r\t\a\/]+)';
   155    
   154    
   156   /**
   155   /**
   157    * What we're allowed to do as far as permissions go. This changes based on the value of the "auth" URI param.
   156    * What we're allowed to do as far as permissions go. This changes based on the value of the "auth" URI param.
   158    * @var string
   157    * @var string
   259    
   258    
   260   function __construct()
   259   function __construct()
   261   {
   260   {
   262     global $db, $session, $paths, $template, $plugins; // Common objects
   261     global $db, $session, $paths, $template, $plugins; // Common objects
   263     
   262     
   264     if ( defined('IN_ENANO_INSTALL') )
   263     if ( defined('IN_ENANO_INSTALL') && !defined('IN_ENANO_UPGRADE') )
   265     {
   264     {
   266       @include(ENANO_ROOT.'/config.new.php');
   265       @include(ENANO_ROOT.'/config.new.php');
   267     }
   266     }
   268     else
   267     else
   269     {
   268     {
   280     {
   279     {
   281       if(is_writable(ENANO_ROOT.'/config.php'))
   280       if(is_writable(ENANO_ROOT.'/config.php'))
   282       {
   281       {
   283         // Generate and stash a private key
   282         // Generate and stash a private key
   284         // This should only happen during an automated silent gradual migration to the new encryption platform.
   283         // This should only happen during an automated silent gradual migration to the new encryption platform.
   285         $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
   284         $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
   286         $this->private_key = $aes->gen_readymade_key();
   285         $this->private_key = $aes->gen_readymade_key();
   287         
   286         
   288         $config = file_get_contents(ENANO_ROOT.'/config.php');
   287         $config = file_get_contents(ENANO_ROOT.'/config.php');
   289         if(!$config)
   288         if(!$config)
   290         {
   289         {
   509             $super = $this->compat_validate_session($key);
   508             $super = $this->compat_validate_session($key);
   510           }
   509           }
   511           else
   510           else
   512           {
   511           {
   513             $key = strrev($_REQUEST['auth']);
   512             $key = strrev($_REQUEST['auth']);
   514             $super = $this->validate_session($key);
   513             if ( !empty($key) && ( strlen($key) / 2 ) % 4 == 0 )
       
   514             {
       
   515               $super = $this->validate_session($key);
       
   516             }
   515           }
   517           }
   516           if(is_array($super))
   518           if(is_array($super))
   517           {
   519           {
   518             $this->auth_level = intval($super['auth_level']);
   520             $this->auth_level = intval($super['auth_level']);
   519             $this->sid_super = $_REQUEST['auth'];
   521             $this->sid_super = $_REQUEST['auth'];
   527       $this->register_guest_session();
   529       $this->register_guest_session();
   528     }
   530     }
   529     if(!$this->compat)
   531     if(!$this->compat)
   530     {
   532     {
   531       // init groups
   533       // init groups
   532       $q = $this->sql('SELECT g.group_name,g.group_id,m.is_mod FROM '.table_prefix.'groups AS g
   534       $q = $this->sql('SELECT g.group_name,g.group_id,m.is_mod FROM '.table_prefix.'groups AS g' . "\n"
   533           LEFT JOIN '.table_prefix.'group_members AS m
   535         . '  LEFT JOIN '.table_prefix.'group_members AS m' . "\n"
   534             ON g.group_id=m.group_id
   536         . '    ON g.group_id=m.group_id' . "\n"
   535           WHERE ( m.user_id='.$this->user_id.' 
   537         . '  WHERE ( m.user_id='.$this->user_id.'' . "\n" 
   536             OR g.group_name=\'Everyone\')
   538         . '    OR g.group_name=\'Everyone\')' . "\n"
   537             ' . ( enano_version() == '1.0RC1' ? '' : 'AND ( m.pending != 1 OR m.pending IS NULL )' ) . '
   539         . '    ' . ( enano_version() == '1.0RC1' ? '' : 'AND ( m.pending != 1 OR m.pending IS NULL )' ) . '' . "\n"
   538           ORDER BY group_id ASC;'); // Make sure "Everyone" comes first so the permissions can be overridden
   540         . '  ORDER BY group_id ASC;'); // Make sure "Everyone" comes first so the permissions can be overridden
   539       if($row = $db->fetchrow())
   541       if($row = $db->fetchrow())
   540       {
   542       {
   541         do {
   543         do {
   542           $this->groups[$row['group_id']] = $row['group_name'];
   544           $this->groups[$row['group_id']] = $row['group_name'];
   543           $this->group_mod[$row['group_id']] = ( intval($row['is_mod']) == 1 );
   545           $this->group_mod[$row['group_id']] = ( intval($row['is_mod']) == 1 );
   616         $db->free_result();
   618         $db->free_result();
   617       }
   619       }
   618     }
   620     }
   619     
   621     
   620     // Instanciate the Rijndael encryption object
   622     // Instanciate the Rijndael encryption object
   621     $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
   623     $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
   622     
   624     
   623     // Fetch our decryption key
   625     // Fetch our decryption key
   624     
   626     
   625     $aes_key = $this->fetch_public_key($aes_key_id);
   627     $aes_key = $this->fetch_public_key($aes_key_id);
   626     if(!$aes_key)
   628     if ( !$aes_key )
       
   629     {
       
   630       // It could be that our key cache is full. If it seems larger than 65KB, clear it
       
   631       if ( strlen(getConfig('login_key_cache')) > 65000 )
       
   632       {
       
   633         setConfig('login_key_cache', '');
       
   634         return array(
       
   635           'success' => false,
       
   636           'error' => 'key_not_found_cleared',
       
   637           );
       
   638       }
   627       return array(
   639       return array(
   628         'success' => false,
   640         'success' => false,
   629         'error' => 'key_not_found'
   641         'error' => 'key_not_found'
   630         );
   642         );
       
   643     }
   631     
   644     
   632     // Convert the key to a binary string
   645     // Convert the key to a binary string
   633     $bin_key = hexdecode($aes_key);
   646     $bin_key = hexdecode($aes_key);
   634     
   647     
   635     if(strlen($bin_key) != AES_BITS / 8)
   648     if(strlen($bin_key) != AES_BITS / 8)
   860         $db->free_result();
   873         $db->free_result();
   861       }
   874       }
   862     }
   875     }
   863     
   876     
   864     // Instanciate the Rijndael encryption object
   877     // Instanciate the Rijndael encryption object
   865     $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
   878     $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
   866     
   879     
   867     // Initialize our success switch
   880     // Initialize our success switch
   868     $success = false;
   881     $success = false;
   869     
   882     
   870     // Retrieve the real password from the database
   883     // Retrieve the real password from the database
  1057     
  1070     
  1058     // Unencrypted session key
  1071     // Unencrypted session key
  1059     $session_key = "u=$username;p=$passha1;s=$salt";
  1072     $session_key = "u=$username;p=$passha1;s=$salt";
  1060     
  1073     
  1061     // Encrypt the key
  1074     // Encrypt the key
  1062     $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
  1075     $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
  1063     $session_key = $aes->encrypt($session_key, $this->private_key, ENC_HEX);
  1076     $session_key = $aes->encrypt($session_key, $this->private_key, ENC_HEX);
  1064     
  1077     
  1065     // If we're registering an elevated-privilege key, it needs to be on GET
  1078     // If we're registering an elevated-privilege key, it needs to be on GET
  1066     if($level > USER_LEVEL_MEMBER)
  1079     if($level > USER_LEVEL_MEMBER)
  1067     {
  1080     {
  1170     $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE, true);
  1183     $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE, true);
  1171     $decrypted_key = $aes->decrypt($key, $this->private_key, ENC_HEX);
  1184     $decrypted_key = $aes->decrypt($key, $this->private_key, ENC_HEX);
  1172     
  1185     
  1173     if ( !$decrypted_key )
  1186     if ( !$decrypted_key )
  1174     {
  1187     {
  1175       die_semicritical('AES encryption error', '<p>Something went wrong during the AES decryption process.</p><pre>'.print_r($decrypted_key, true).'</pre>');
  1188       // die_semicritical('AES encryption error', '<p>Something went wrong during the AES decryption process.</p><pre>'.print_r($decrypted_key, true).'</pre>');
       
  1189       return false;
  1176     }
  1190     }
  1177     
  1191     
  1178     $n = preg_match('/^u='.$this->valid_username.';p=([A-Fa-f0-9]+?);s=([A-Fa-f0-9]+?)$/', $decrypted_key, $keydata);
  1192     $n = preg_match('/^u='.$this->valid_username.';p=([A-Fa-f0-9]+?);s=([A-Fa-f0-9]+?)$/', $decrypted_key, $keydata);
  1179     if($n < 1)
  1193     if($n < 1)
  1180     {
  1194     {
  1181       // echo '(debug) $session->validate_session: Key does not match regex<br />Decrypted key: '.$decrypted_key;
  1195       // echo '(debug) $session->validate_session: Key does not match regex<br />Decrypted key: '.$decrypted_key;
  1182       return false;
  1196       return false;
  1183     }
  1197     }
  1184     $keyhash = md5($key);
  1198     $keyhash = md5($key);
  1185     $salt = $db->escape($keydata[3]);
  1199     $salt = $db->escape($keydata[3]);
  1186     $query = $db->sql_query('SELECT u.user_id AS uid,u.username,u.password,u.email,u.real_name,u.user_level,u.theme,u.style,u.signature,u.reg_time,u.account_active,u.activation_key,k.source_ip,k.time,k.auth_level,COUNT(p.message_id) AS num_pms,u.user_lang,x.* FROM '.table_prefix.'session_keys AS k
  1200     // using a normal call to $db->sql_query to avoid failing on errors here
  1187                                LEFT JOIN '.table_prefix.'users AS u
  1201     $query = $db->sql_query('SELECT u.user_id AS uid,u.username,u.password,u.email,u.real_name,u.user_level,u.theme,u.style,u.signature,' . "\n"
  1188                                  ON ( u.user_id=k.user_id )
  1202                              . '    u.reg_time,u.account_active,u.activation_key,k.source_ip,k.time,k.auth_level,COUNT(p.message_id) AS num_pms,' . "\n"
  1189                                LEFT JOIN '.table_prefix.'users_extra AS x
  1203                              . '    x.* FROM '.table_prefix.'session_keys AS k' . "\n"
  1190                                  ON ( u.user_id=x.user_id OR x.user_id IS NULL )
  1204                              . '  LEFT JOIN '.table_prefix.'users AS u' . "\n"
  1191                                LEFT JOIN '.table_prefix.'privmsgs AS p
  1205                              . '    ON ( u.user_id=k.user_id )' . "\n"
  1192                                  ON ( p.message_to=u.username AND p.message_read=0 )
  1206                              . '  LEFT JOIN '.table_prefix.'users_extra AS x' . "\n"
  1193                                WHERE k.session_key=\''.$keyhash.'\'
  1207                              . '    ON ( u.user_id=x.user_id OR x.user_id IS NULL )' . "\n"
  1194                                  AND k.salt=\''.$salt.'\'
  1208                              . '  LEFT JOIN '.table_prefix.'privmsgs AS p' . "\n"
  1195                                GROUP BY u.user_id;');
  1209                              . '    ON ( p.message_to=u.username AND p.message_read=0 )' . "\n"
       
  1210                              . '  WHERE k.session_key=\''.$keyhash.'\'' . "\n"
       
  1211                              . '    AND k.salt=\''.$salt.'\'' . "\n"
       
  1212                              . '  GROUP BY u.user_id;');
  1196     if ( !$query )
  1213     if ( !$query )
  1197     {
  1214     {
  1198       $query = $this->sql('SELECT u.user_id AS uid,u.username,u.password,u.email,u.real_name,u.user_level,u.theme,u.style,u.signature,u.reg_time,u.account_active,u.activation_key,k.source_ip,k.time,k.auth_level,COUNT(p.message_id) AS num_pms FROM '.table_prefix.'session_keys AS k
  1215       $query = $this->sql('SELECT u.user_id AS uid,u.username,u.password,u.email,u.real_name,u.user_level,u.theme,u.style,u.signature,u.reg_time,u.account_active,u.activation_key,k.source_ip,k.time,k.auth_level,COUNT(p.message_id) AS num_pms FROM '.table_prefix.'session_keys AS k
  1199                              LEFT JOIN '.table_prefix.'users AS u
  1216                              LEFT JOIN '.table_prefix.'users AS u
  1200                                ON ( u.user_id=k.user_id )
  1217                                ON ( u.user_id=k.user_id )
  1335     global $db, $session, $paths, $template, $plugins; // Common objects
  1352     global $db, $session, $paths, $template, $plugins; // Common objects
  1336     $ou = $this->username;
  1353     $ou = $this->username;
  1337     $oid = $this->user_id;
  1354     $oid = $this->user_id;
  1338     if($level > USER_LEVEL_CHPREF)
  1355     if($level > USER_LEVEL_CHPREF)
  1339     {
  1356     {
  1340       $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
  1357       $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
  1341       if(!$this->user_logged_in || $this->auth_level < USER_LEVEL_MOD)
  1358       if(!$this->user_logged_in || $this->auth_level < USER_LEVEL_MOD)
  1342       {
  1359       {
  1343         return 'success';
  1360         return 'success';
  1344       }
  1361       }
  1345       // Destroy elevated privileges
  1362       // Destroy elevated privileges
  1414    * @return string Hex-encoded AES key
  1431    * @return string Hex-encoded AES key
  1415    */
  1432    */
  1416    
  1433    
  1417   function rijndael_genkey()
  1434   function rijndael_genkey()
  1418   {
  1435   {
  1419     $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
  1436     $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
  1420     $key = $aes->gen_readymade_key();
  1437     $key = $aes->gen_readymade_key();
  1421     $keys = getConfig('login_key_cache');
  1438     $keys = getConfig('login_key_cache');
  1422     if(is_string($keys))
  1439     if(is_string($keys))
  1423       $keys .= $key;
  1440       $keys .= $key;
  1424     else
  1441     else
  1432    * @return string
  1449    * @return string
  1433    */
  1450    */
  1434    
  1451    
  1435   function dss_rand()
  1452   function dss_rand()
  1436   {
  1453   {
  1437     $aes = new AESCrypt();
  1454     $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
  1438     $random = $aes->randkey(128);
  1455     $random = $aes->randkey(128);
  1439     unset($aes);
  1456     unset($aes);
  1440     return md5(microtime() . $random);
  1457     return md5(microtime() . $random);
  1441   }
  1458   }
  1442   
  1459   
  1549    
  1566    
  1550   function check_banlist()
  1567   function check_banlist()
  1551   {
  1568   {
  1552     global $db, $session, $paths, $template, $plugins; // Common objects
  1569     global $db, $session, $paths, $template, $plugins; // Common objects
  1553     $col_reason = ( $this->compat ) ? '"No reason entered (session manager is in compatibility mode)" AS reason' : 'reason';
  1570     $col_reason = ( $this->compat ) ? '"No reason entered (session manager is in compatibility mode)" AS reason' : 'reason';
  1554     $is_banned = false;
  1571     $banned = false;
  1555     if ( $this->user_logged_in )
  1572     if ( $this->user_logged_in )
  1556     {
  1573     {
  1557       // check by IP, email, and username
  1574       // check by IP, email, and username
  1558       $sql = "SELECT $col_reason, ban_value, ban_type, is_regex FROM " . table_prefix . "banlist WHERE \n"
  1575       $sql = "SELECT $col_reason, ban_value, ban_type, is_regex FROM " . table_prefix . "banlist WHERE \n"
  1559             . "    ( ban_type = " . BAN_IP    . " AND is_regex = 0 ) OR \n"
  1576             . "    ( ban_type = " . BAN_IP    . " AND is_regex = 0 ) OR \n"
  1644   function create_user($username, $password, $email, $real_name = '', $coppa = false)
  1661   function create_user($username, $password, $email, $real_name = '', $coppa = false)
  1645   {
  1662   {
  1646     global $db, $session, $paths, $template, $plugins; // Common objects
  1663     global $db, $session, $paths, $template, $plugins; // Common objects
  1647     
  1664     
  1648     // Initialize AES
  1665     // Initialize AES
  1649     $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
  1666     $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
  1650     
  1667     
  1651     if(!preg_match('#^'.$this->valid_username.'$#', $username)) return 'The username you chose contains invalid characters.';
  1668     if(!preg_match('#^'.$this->valid_username.'$#', $username)) return 'The username you chose contains invalid characters.';
  1652     $username = str_replace('_', ' ', $username);
  1669     $username = str_replace('_', ' ', $username);
  1653     $user_orig = $username;
  1670     $user_orig = $username;
  1654     $username = $this->prepare_text($username);
  1671     $username = $this->prepare_text($username);
  2000    * @return bool
  2017    * @return bool
  2001    */
  2018    */
  2002    
  2019    
  2003   function register_temp_password($user_id, $password)
  2020   function register_temp_password($user_id, $password)
  2004   {
  2021   {
  2005     $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
  2022     $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
  2006     $temp_pass = $aes->encrypt($password, $this->private_key, ENC_HEX);
  2023     $temp_pass = $aes->encrypt($password, $this->private_key, ENC_HEX);
  2007     $this->sql('UPDATE '.table_prefix.'users SET temp_password=\'' . $temp_pass . '\',temp_password_time='.time().' WHERE user_id='.intval($user_id).';');
  2024     $this->sql('UPDATE '.table_prefix.'users SET temp_password=\'' . $temp_pass . '\',temp_password_time='.time().' WHERE user_id='.intval($user_id).';');
  2008   }
  2025   }
  2009   
  2026   
  2010   /**
  2027   /**
  2111     
  2128     
  2112     // Scan the user ID for problems
  2129     // Scan the user ID for problems
  2113     if(intval($user_id) < 1) $errors[] = 'SQL injection attempt';
  2130     if(intval($user_id) < 1) $errors[] = 'SQL injection attempt';
  2114     
  2131     
  2115     // Instanciate the AES encryption class
  2132     // Instanciate the AES encryption class
  2116     $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
  2133     $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
  2117     
  2134     
  2118     // If all of our input vars are false, then we've effectively done our job so get out of here
  2135     // If all of our input vars are false, then we've effectively done our job so get out of here
  2119     if($username === false && $password === false && $email === false && $realname === false && $signature === false && $user_level === false)
  2136     if($username === false && $password === false && $email === false && $realname === false && $signature === false && $user_level === false)
  2120     {
  2137     {
  2121    // echo 'debug: $session->update_user(): success (no changes requested)';
  2138    // echo 'debug: $session->update_user(): success (no changes requested)';
  2405     // Initialize the permissions list with some defaults
  2422     // Initialize the permissions list with some defaults
  2406     $this->perms = $this->acl_types;
  2423     $this->perms = $this->acl_types;
  2407     $this->acl_defaults_used = $this->perms;
  2424     $this->acl_defaults_used = $this->perms;
  2408     
  2425     
  2409     // Fetch sitewide defaults from the permissions table
  2426     // Fetch sitewide defaults from the permissions table
  2410     $bs = 'SELECT rules FROM '.table_prefix.'acl WHERE page_id IS NULL AND namespace IS NULL AND ( ';
  2427     $bs = 'SELECT rules, target_type, target_id FROM '.table_prefix.'acl' . "\n"
       
  2428              . '  WHERE page_id IS NULL AND namespace IS NULL AND' . "\n"
       
  2429              . '  ( ';
  2411     
  2430     
  2412     $q = Array();
  2431     $q = Array();
  2413     $q[] = '( target_type='.ACL_TYPE_USER.' AND target_id='.$this->user_id.' )';
  2432     $q[] = '( target_type='.ACL_TYPE_USER.' AND target_id='.$this->user_id.' )';
  2414     if(count($this->groups) > 0)
  2433     if(count($this->groups) > 0)
  2415     {
  2434     {
  2416       foreach($this->groups as $g_id => $g_name)
  2435       foreach($this->groups as $g_id => $g_name)
  2417       {
  2436       {
  2418         $q[] = '( target_type='.ACL_TYPE_GROUP.' AND target_id='.intval($g_id).' )';
  2437         $q[] = '( target_type='.ACL_TYPE_GROUP.' AND target_id='.intval($g_id).' )';
  2419       }
  2438       }
  2420     }
  2439     }
  2421     $bs .= implode(' OR ', $q) . ' ) ORDER BY target_type ASC, target_id ASC;';
  2440     $bs .= implode(" OR \n    ", $q) . " ) \n  ORDER BY target_type ASC, target_id ASC;";
  2422     $q = $this->sql($bs);
  2441     $q = $this->sql($bs);
  2423     if ( $row = $db->fetchrow() )
  2442     if ( $row = $db->fetchrow() )
  2424     {
  2443     {
  2425       do {
  2444       do {
  2426         $rules = $this->string_to_perm($row['rules']);
  2445         $rules = $this->string_to_perm($row['rules']);
  2460         $q[] = '( target_type='.ACL_TYPE_GROUP.' AND target_id='.intval($g_id).' )';
  2479         $q[] = '( target_type='.ACL_TYPE_GROUP.' AND target_id='.intval($g_id).' )';
  2461       }
  2480       }
  2462     }
  2481     }
  2463     // The reason we're using an ORDER BY statement here is because ACL_TYPE_GROUP is less than ACL_TYPE_USER, causing the user's individual
  2482     // The reason we're using an ORDER BY statement here is because ACL_TYPE_GROUP is less than ACL_TYPE_USER, causing the user's individual
  2464     // permissions to override group permissions.
  2483     // permissions to override group permissions.
  2465     $bs .= implode(' OR ', $q) . ' ) AND (' . $pg_info . ' ( page_id=\''.$db->escape($paths->cpage['urlname_nons']).'\' AND namespace=\''.$db->escape($paths->namespace).'\' ) )     
  2484     $bs .= implode(" OR\n    ", $q) . " )\n  AND (" . $pg_info . ' ( page_id=\''.$db->escape($paths->cpage['urlname_nons']).'\' AND namespace=\''.$db->escape($paths->namespace).'\' ) )     
  2466       ORDER BY target_type ASC, page_id ASC, namespace ASC;';
  2485       ORDER BY target_type ASC, page_id ASC, namespace ASC;';
  2467     $q = $this->sql($bs);
  2486     $q = $this->sql($bs);
  2468     if ( $row = $db->fetchrow() )
  2487     if ( $row = $db->fetchrow() )
  2469     {
  2488     {
  2470       do {
  2489       do {
  2902     {
  2921     {
  2903       $pg_info .= ' ( page_id=\'' . $g_id . '\' AND namespace=\'__PageGroup\' ) OR';
  2922       $pg_info .= ' ( page_id=\'' . $g_id . '\' AND namespace=\'__PageGroup\' ) OR';
  2904     }
  2923     }
  2905     
  2924     
  2906     // Build a query to grab ACL info
  2925     // Build a query to grab ACL info
  2907     $bs = 'SELECT rules FROM '.table_prefix.'acl WHERE ( ';
  2926     $bs = 'SELECT rules FROM '.table_prefix.'acl WHERE ' . "\n"
       
  2927           . '  ( ';
  2908     $q = Array();
  2928     $q = Array();
  2909     $q[] = '( target_type='.ACL_TYPE_USER.' AND target_id='.$session->user_id.' )';
  2929     $q[] = '( target_type='.ACL_TYPE_USER.' AND target_id='.$session->user_id.' )';
  2910     if(count($session->groups) > 0)
  2930     if(count($session->groups) > 0)
  2911     {
  2931     {
  2912       foreach($session->groups as $g_id => $g_name)
  2932       foreach($session->groups as $g_id => $g_name)
  2914         $q[] = '( target_type='.ACL_TYPE_GROUP.' AND target_id='.intval($g_id).' )';
  2934         $q[] = '( target_type='.ACL_TYPE_GROUP.' AND target_id='.intval($g_id).' )';
  2915       }
  2935       }
  2916     }
  2936     }
  2917     // The reason we're using an ORDER BY statement here is because ACL_TYPE_GROUP is less than ACL_TYPE_USER, causing the user's individual
  2937     // The reason we're using an ORDER BY statement here is because ACL_TYPE_GROUP is less than ACL_TYPE_USER, causing the user's individual
  2918     // permissions to override group permissions.
  2938     // permissions to override group permissions.
  2919     $bs .= implode(' OR ', $q) . ' ) AND (' . $pg_info . ' page_id=\''.$db->escape($page_id).'\' AND namespace=\''.$db->escape($namespace).'\' )     
  2939     $bs .= implode(" OR\n    ", $q) . ' ) AND (' . $pg_info . ' page_id=\''.$db->escape($page_id).'\' AND namespace=\''.$db->escape($namespace).'\' )     
  2920       ORDER BY target_type ASC, page_id ASC, namespace ASC;';
  2940       ORDER BY target_type ASC, page_id ASC, namespace ASC;';
  2921     $q = $session->sql($bs);
  2941     $q = $session->sql($bs);
  2922     if ( $row = $db->fetchrow() )
  2942     if ( $row = $db->fetchrow() )
  2923     {
  2943     {
  2924       do {
  2944       do {