Obtain an exclusive lock before writing to the database

This prevents race conditions caused by multiple instances of TinyIB
accessing the database simultaneously.

Resolves #251.
This commit is contained in:
Trevor Slocum 2022-04-08 14:55:02 -07:00
parent 93c91aec20
commit 57b50658a2
3 changed files with 22 additions and 0 deletions

View File

@ -257,6 +257,8 @@ if (!$loggedin) {
$redirect = true;
// Check if the request is to make a post
if (!isset($_GET['delete']) && !isset($_GET['manage']) && (isset($_POST['name']) || isset($_POST['email']) || isset($_POST['subject']) || isset($_POST['message']) || isset($_POST['file']) || isset($_POST['embed']) || isset($_POST['password']))) {
$lock = lockDatabase();
if (TINYIB_DBMIGRATE) {
fancyDie(__('Posting is currently disabled.<br>Please try again in a few moments.'));
}
@ -600,6 +602,8 @@ if (!isset($_GET['delete']) && !isset($_GET['manage']) && (isset($_POST['name'])
die();
// Check if the request is to report a post
} elseif (isset($_GET['report']) && !isset($_GET['manage'])) {
$lock = lockDatabase();
if (!TINYIB_REPORT) {
fancyDie(__('Reporting is disabled.'));
}
@ -681,6 +685,8 @@ EOF;
fancyDie(__('Post reported.'), $go_back);
// Check if the request is to delete a post and/or its associated image
} elseif (isset($_GET['delete']) && !isset($_GET['manage'])) {
$lock = lockDatabase();
if (!isset($_POST['delete'])) {
fancyDie(__('Tick the box next to a post and click "Delete" to delete it.'));
}
@ -721,6 +727,8 @@ EOF;
$redirect = false;
// Check if the request is to access the management area
} elseif (isset($_GET['manage'])) {
$lock = lockDatabase();
$text = '';
$onload = '';
$navbar = '&nbsp;';

View File

@ -6,6 +6,7 @@ if (!defined('TINYIB_BOARD')) {
define('TINYIB_NEWTHREAD', '0');
define('TINYIB_INDEXPAGE', false);
define('TINYIB_RESPAGE', true);
define('TINYIB_LOCKFILE', 'tinyib.lock');
define('TINYIB_WORDBREAK_IDENTIFIER', '@!@TINYIB_WORDBREAK@!@');
// Account roles

View File

@ -11,6 +11,19 @@ if (!function_exists('array_column')) {
}
}
// lockDatabase obtains an exclusive lock to prevent race conditions when
// accessing the database.
function lockDatabase() {
if (TINYIB_LOCKFILE == '') {
return true;
}
$fp = fopen(TINYIB_LOCKFILE, 'c+');
if (!flock($fp, LOCK_EX)) {
fancyDie('Failed to lock control file.');
}
return $fp;
}
function hashData($data, $force = false) {
global $bcrypt_salt;
if (substr($data, 0, 4) == '$2y$' && !$force) {