includes/sessions.php
changeset 1079 fcc42560afe6
parent 1071 f374801eb775
child 1081 745200a9cc2a
equal deleted inserted replaced
1078:67a4c839c7e1 1079:fcc42560afe6
   170    */
   170    */
   171   
   171   
   172   var $csrf_token = false;
   172   var $csrf_token = false;
   173   
   173   
   174   /**
   174   /**
       
   175    * Password change disabled, for auth plugins
       
   176    * @var bool
       
   177    */
       
   178   
       
   179   var $password_change_disabled = false;
       
   180   
       
   181   /**
       
   182    * Password change page URL + title, for auth plugins
       
   183    * @var array
       
   184    */
       
   185   
       
   186   var $password_change_dest = array('url' => '', 'title' => '');
       
   187   
       
   188   /**
   175    * Switch to track if we're started or not.
   189    * Switch to track if we're started or not.
   176    * @access private
   190    * @access private
   177    * @var bool
   191    * @var bool
   178    */
   192    */
   179    
   193    
   921     {
   935     {
   922       $session_key = $this->pk_encrypt("u=$username;p=" . sha1($password_hmac) . ";s=$salt");
   936       $session_key = $this->pk_encrypt("u=$username;p=" . sha1($password_hmac) . ";s=$salt");
   923     }
   937     }
   924     else
   938     else
   925     {
   939     {
   926       $session_key = hmac_sha1($password_hmac, $salt);
   940       $key_pieces = array($password_hmac);
       
   941       $sk_mode = 'generate';
       
   942       $code = $plugins->setHook('session_key_calc');
       
   943       foreach ( $code as $cmd )
       
   944       {
       
   945         eval($cmd);
       
   946       }
       
   947       $key_pieces = implode("\xFF", $key_pieces);
       
   948       
       
   949       $session_key = hmac_sha1($key_pieces, $salt);
   927     }
   950     }
   928     
   951     
   929     // Minimum level
   952     // Minimum level
   930     $level = max(array($level, USER_LEVEL_MEMBER));
   953     $level = max(array($level, USER_LEVEL_MEMBER));
   931     
   954     
  1244     }
  1267     }
  1245     
  1268     
  1246     // $loose_call is turned on only from validate_aes_session
  1269     // $loose_call is turned on only from validate_aes_session
  1247     if ( !$loose_call )
  1270     if ( !$loose_call )
  1248     {
  1271     {
  1249       $correct_key = hexdecode(hmac_sha1($row['password'], $row['salt']));
  1272       $key_pieces = array($row['password']);
       
  1273       $user_id =& $row['uid'];
       
  1274       $sk_mode = 'validate';
       
  1275       $code = $plugins->setHook('session_key_calc');
       
  1276       foreach ( $code as $cmd )
       
  1277       {
       
  1278         eval($cmd);
       
  1279       }
       
  1280       $key_pieces = implode("\xFF", $key_pieces);
       
  1281       $correct_key = hexdecode(hmac_sha1($key_pieces, $row['salt']));
  1250       $user_key = hexdecode($key);
  1282       $user_key = hexdecode($key);
  1251       if ( $correct_key !== $user_key || !is_string($user_key) )
  1283       if ( $correct_key !== $user_key || !is_string($user_key) )
  1252       {
  1284       {
  1253         return false;
  1285         return false;
  1254       }
  1286       }
  1528     }
  1560     }
  1529     return $url;
  1561     return $url;
  1530   }
  1562   }
  1531   
  1563   
  1532   /**
  1564   /**
  1533    * Grabs the user's password MD5
  1565    * Prevent the user from changing their password. Authentication plugins may call this to enforce single sign-on.
  1534    * @return string, or bool false if access denied
  1566    * @param string URL to page where the user may change their password
       
  1567    * @param string Title of the page where the user may change their password
       
  1568    * @return null
       
  1569    */
       
  1570   
       
  1571   function disable_password_change($change_url = false, $change_title = false)
       
  1572   {
       
  1573     if ( $this->password_change_disabled )
       
  1574     {
       
  1575       // don't allow calling twice. if we have two plugins doing this, somebody is bad at configuring websites.
       
  1576       return false;
       
  1577     }
       
  1578     
       
  1579     if ( is_string($change_url) && is_string($change_title) )
       
  1580     {
       
  1581       $this->password_change_dest = array(
       
  1582           'url' => $change_url,
       
  1583           'title' => $change_title
       
  1584         );
       
  1585     }
       
  1586     else
       
  1587     {
       
  1588       $this->password_change_dest = array(
       
  1589           'url' => false,
       
  1590           'title' => false
       
  1591         );
       
  1592     }
       
  1593     
       
  1594     $this->password_change_disabled = true;
       
  1595   }
       
  1596   
       
  1597   /**
       
  1598    * Grabs the user's password MD5 - NOW DEPRECATED AND DISABLED.
       
  1599    * @return bool false
  1535    */
  1600    */
  1536    
  1601    
  1537   function grab_password_hash()
  1602   function grab_password_hash()
  1538   {
  1603   {
  1539     return false;
  1604     return false;
  2259     return 'Linux rocks!';
  2324     return 'Linux rocks!';
  2260     
  2325     
  2261   }
  2326   }
  2262   
  2327   
  2263   /**
  2328   /**
  2264    * Updates a user's information in the database. Note that any of the values except $user_id can be false if you want to preserve the old values.
  2329    * Change a user's e-mail address.
  2265    * Not localized because this really isn't used a whole lot anymore.
       
  2266    * @param int $user_id The user ID of the user to update - this cannot be changed
  2330    * @param int $user_id The user ID of the user to update - this cannot be changed
  2267    * @param string $username The new username
       
  2268    * @param string $old_pass The current password - only required if sessionManager::$user_level < USER_LEVEL_ADMIN. This should usually be an UNENCRYPTED string. This can also be an array - if it is, key 0 is treated as data AES-encrypted with key 1
       
  2269    * @param string $password The new password
       
  2270    * @param string $email The new e-mail address
  2331    * @param string $email The new e-mail address
  2271    * @param string $realname The new real name
       
  2272    * @param string $signature The updated forum/comment signature
       
  2273    * @param int $user_level The updated user level
       
  2274    * @return string 'success' if successful, or array of error strings on failure
  2332    * @return string 'success' if successful, or array of error strings on failure
  2275    */
  2333    */
  2276    
  2334    
  2277   function update_user($user_id, $username = false, $old_pass = false, $password = false, $email = false, $realname = false, $signature = false, $user_level = false)
  2335   function change_email($user_id, $email)
  2278   {
  2336   {
  2279     global $db, $session, $paths, $template, $plugins; // Common objects
  2337     global $db, $session, $paths, $template, $plugins; // Common objects
  2280     
  2338     
  2281     // Create some arrays
  2339     // Create some arrays
  2282     
  2340     
  2283     $errors = Array(); // Used to hold error strings
  2341     $errors = array(); // Used to hold error strings
  2284     $strs = Array();   // Sub-query statements
       
  2285     
  2342     
  2286     // Scan the user ID for problems
  2343     // Scan the user ID for problems
  2287     if(intval($user_id) < 1) $errors[] = 'SQL injection attempt';
  2344     if ( intval($user_id) < 1 )
  2288     
  2345       $errors[] = 'SQL injection attempt';
  2289     // Instanciate the AES encryption class
  2346     
  2290     $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
  2347     $user_id = intval($user_id);
  2291     
  2348     
  2292     // If all of our input vars are false, then we've effectively done our job so get out of here
  2349     // Verify e-mail address
  2293     if($username === false && $password === false && $email === false && $realname === false && $signature === false && $user_level === false)
  2350     if ( !check_email_address($email) )
  2294     {
  2351       $errors[] = 'user_err_email_not_valid';
  2295    // echo 'debug: $session->update_user(): success (no changes requested)';
  2352     
  2296       return 'success';
  2353     if ( count($errors) > 0 )
  2297     }
  2354       return $errors;
  2298     
  2355     
  2299     // Initialize our authentication check
  2356     // Make query
  2300     $authed = false;
  2357     $email = $db->escape($email);
  2301     
  2358     $q = $db->sql_query('UPDATE ' . table_prefix . "users SET email = '$email' WHERE user_id = $user_id;");
  2302     // Verify the inputted password
       
  2303     if(is_string($old_pass))
       
  2304     {
       
  2305       $q = $this->sql('SELECT password FROM '.table_prefix.'users WHERE user_id='.$user_id.';');
       
  2306       if($db->numrows() < 1)
       
  2307       {
       
  2308         $errors[] = 'The password data could not be selected for verification.';
       
  2309       }
       
  2310       else
       
  2311       {
       
  2312         $row = $db->fetchrow();
       
  2313         $real = $aes->decrypt($row['password'], $this->private_key, ENC_HEX);
       
  2314         if($real == $old_pass)
       
  2315           $authed = true;
       
  2316       }
       
  2317     }
       
  2318     
       
  2319     elseif(is_array($old_pass))
       
  2320     {
       
  2321       $old_pass = $aes->decrypt($old_pass[0], $old_pass[1]);
       
  2322       $q = $this->sql('SELECT password FROM '.table_prefix.'users WHERE user_id='.$user_id.';');
       
  2323       if($db->numrows() < 1)
       
  2324       {
       
  2325         $errors[] = 'The password data could not be selected for verification.';
       
  2326       }
       
  2327       else
       
  2328       {
       
  2329         $row = $db->fetchrow();
       
  2330         $real = $aes->decrypt($row['password'], $this->private_key, ENC_HEX);
       
  2331         if($real == $old_pass)
       
  2332           $authed = true;
       
  2333       }
       
  2334     }
       
  2335     
       
  2336     // Initialize our query
       
  2337     $q = 'UPDATE '.table_prefix.'users SET ';
       
  2338     
       
  2339     if($this->auth_level >= USER_LEVEL_ADMIN || $authed) // Need the current password in order to update the e-mail address, change the username, or reset the password
       
  2340     {
       
  2341       // Username
       
  2342       if(is_string($username))
       
  2343       {
       
  2344         // Check the username for problems
       
  2345         if(!preg_match('#^'.$this->valid_username.'$#', $username))
       
  2346           $errors[] = 'The username you entered contains invalid characters.';
       
  2347         $strs[] = 'username=\''.$db->escape($username).'\'';
       
  2348       }
       
  2349       // Password
       
  2350       if(is_string($password) && strlen($password) >= 6)
       
  2351       {
       
  2352         // Password needs to be encrypted before being stashed
       
  2353         $encpass = $aes->encrypt($password, $this->private_key, ENC_HEX);
       
  2354         if(!$encpass)
       
  2355           $errors[] = 'The password could not be encrypted due to an internal error.';
       
  2356         $strs[] = 'password=\''.$encpass.'\'';
       
  2357       }
       
  2358       // E-mail addy
       
  2359       if(is_string($email))
       
  2360       {
       
  2361         if(!check_email_address($email))
       
  2362           $errors[] = 'The e-mail address you entered is invalid.';
       
  2363         $strs[] = 'email=\''.$db->escape($email).'\'';
       
  2364       }
       
  2365     }
       
  2366     // Real name
       
  2367     if(is_string($realname))
       
  2368     {
       
  2369       $strs[] = 'real_name=\''.$db->escape($realname).'\'';
       
  2370     }
       
  2371     // Forum/comment signature
       
  2372     if(is_string($signature))
       
  2373     {
       
  2374       $strs[] = 'signature=\''.$db->escape($signature).'\'';
       
  2375     }
       
  2376     // User level
       
  2377     if(is_int($user_level))
       
  2378     {
       
  2379       $strs[] = 'user_level='.$user_level;
       
  2380     }
       
  2381     
       
  2382     // Add our generated query to the query string
       
  2383     $q .= implode(',', $strs);
       
  2384     
       
  2385     // One last error check
       
  2386     if(sizeof($strs) < 1) $errors[] = 'An internal error occured building the SQL query, this is a bug';
       
  2387     if(sizeof($errors) > 0) return $errors;
       
  2388     
       
  2389     // Free our temp arrays
       
  2390     unset($strs, $errors);
       
  2391     
       
  2392     // Finalize the query and run it
       
  2393     $q .= ' WHERE user_id='.$user_id.';';
       
  2394     $this->sql($q);
       
  2395     
  2359     
  2396     // We also need to trigger re-activation.
  2360     // We also need to trigger re-activation.
  2397     if ( is_string($email) )
  2361     switch(getConfig('account_activation', 'none'))
  2398     {
  2362     {
  2399       switch(getConfig('account_activation'))
  2363       case 'user':
  2400       {
  2364       case 'admin':
  2401         case 'user':
  2365         
  2402         case 'admin':
  2366         // Note: even with admin activation, activation e-mails are sent when an e-mail is changed.
  2403           
  2367         
  2404           if ( $session->user_level >= USER_LEVEL_MOD && getConfig('account_activation') == 'admin' )
  2368         if ( $session->user_level >= USER_LEVEL_MOD && getConfig('account_activation') == 'admin' )
  2405             // Don't require re-activation by admins for admins
  2369           // Trust admins and moderators
  2406             break;
  2370           break;
  2407           
  2371         
  2408           // retrieve username
  2372         // retrieve username
  2409           if ( !$username )
  2373         if ( !$username )
       
  2374         {
       
  2375           $q = $this->sql('SELECT username FROM ' . table_prefix . "users WHERE user_id = $user_id;");
       
  2376           if($db->numrows() < 1)
  2410           {
  2377           {
  2411             $q = $this->sql('SELECT username FROM '.table_prefix.'users WHERE user_id='.$user_id.';');
  2378             $errors[] = 'The username could not be selected.';
  2412             if($db->numrows() < 1)
       
  2413             {
       
  2414               $errors[] = 'The username could not be selected.';
       
  2415             }
       
  2416             else
       
  2417             {
       
  2418               $row = $db->fetchrow();
       
  2419               $username = $row['username'];
       
  2420             }
       
  2421           }
  2379           }
  2422           if ( !$username )
  2380           else
  2423             return $errors;
       
  2424           
       
  2425           // Generate a totally random activation key
       
  2426           $actkey = sha1 ( microtime() . mt_rand() );
       
  2427           $a = $this->send_activation_mail($username, $actkey);
       
  2428           if(!$a)
       
  2429           {
  2381           {
  2430             $this->admin_activation_request($username);
  2382             $row = $db->fetchrow();
       
  2383             $username = $row['username'];
  2431           }
  2384           }
  2432           // Deactivate the account until e-mail is confirmed
  2385         }
  2433           $q = $db->sql_query('UPDATE '.table_prefix.'users SET account_active=0,activation_key=\'' . $actkey . '\' WHERE user_id=' . $user_id . ';');
  2386         if ( !$username )
  2434           break;
  2387           return $errors;
  2435       }
  2388         
       
  2389         // Generate an activation key
       
  2390         $actkey = sha1 ( microtime() . mt_rand() );
       
  2391         $a = $this->send_activation_mail($username, $actkey);
       
  2392         if(!$a)
       
  2393         {
       
  2394           $this->admin_activation_request($username);
       
  2395         }
       
  2396         // Deactivate the account until e-mail is confirmed
       
  2397         $q = $db->sql_query('UPDATE ' . table_prefix . "users SET account_active = 0, activation_key = '$actkey' WHERE user_id = $user_id;");
       
  2398         break;
  2436     }
  2399     }
  2437     
  2400     
  2438     // Yay! We're done
  2401     // Yay! We're done
  2439     return 'success';
  2402     return 'success';
  2440   }
  2403   }