Investigating why Subaccount mod is logging me out.

Started by zushiba, March 20, 2023, 11:09:52 PM

Previous topic - Next topic

zushiba

Hi all, I updated the old Subaccount mod to work with 2.1.3 for my wife. She's tried every other forum software but keeps wanting to come back to SMF.

I've got the mod 90% functional, except for account switching. Upon attempting to switch from one account to another I'm being logged out.

The mod doesn't allow for one to log in to subaccounts, it's supposed to transition you between the main account and a linked subaccount seamlessly. I have to imagine that somewhere along the last ~7 years since the mod has been updated the login process has been modified in various ways that are now incompatible with the actual switching routine.

It's been a loooong time since I've kept up with SMF development so I'm sort of lost and looking to see if anyone has any clues.

So the form to switch accounts passes the other account ID, the session name/value.

Example
<form action="https://oursite.org/smf/index.php?action=switchsubaccount" method="post" name="subaccount_drop" id="subaccount_drop" enctype="multipart/form-data">
<select name="subaccount" size="1" onchange="document.subaccount_drop.submit()">
<option selected="selected">Switch Account</option>
<option value="3">Blutto</option>
</select>
<input type="hidden" name="ff6e1d7c1db5" value="43971d2304cb8b9c53a6af1f0edd9938">
</form>

And here is the code that's actually executed when attempting to switch.

function SwitchSubAccount($location = '')
{
global $smcFunc, $user_info, $sourcedir, $modSettings, $cookiename;

// This attempts to set a new cookie with the subaccount id and the password.
// Perhaps incorporating password checking would be good in this... future feature?
// For now we'll rely on current logged in info and a valid session...
checkSession('request');

// Clean the variable, just in case...
$_REQUEST['subaccount'] = !empty($_REQUEST['subaccount']) ? (int) $_REQUEST['subaccount'] : -1;

// If the subaccount doesn't exist in the current users subaccount list, leave, NOW!
if (!array_key_exists($_REQUEST['subaccount'], $user_info['subaccounts']))
redirectexit(empty($location) ? (!empty($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : $_SESSION['old_url']) : $location);

// Get the information for this subaccount
$request = $smcFunc['db_query']('', '
SELECT id_member, passwd, password_salt, is_shareable
FROM {db_prefix}members
WHERE id_member = {int:to_switch}
LIMIT 1',
array(
'to_switch' => $_REQUEST['subaccount'],
)
);
$new_user = $smcFunc['db_fetch_assoc']($request);
$smcFunc['db_free_result']($request);

// Let's setup a new cookie then redirect to wherever we came from
if (isset($_COOKIE[$cookiename]) && preg_match('~^a:[34]:\{i:0;i:\d{1,7};i:1;s:(0|128):"([a-fA-F0-9]{128})?";i:2;[id]:\d{1,14};(i:3;i:\d;)?\}$~', $_COOKIE[$cookiename]) === 1)
list (, , $timeout) = @unserialize($_COOKIE[$cookiename]);
elseif (isset($_SESSION['login_' . $cookiename]))
list (, , $timeout) = @unserialize($_SESSION['login_' . $cookiename]);
else
trigger_error('SwitchSubAccount(): Cannot change subaccount without a session or cookie', E_USER_ERROR);

// Store the timeout, so the same one is used for possibly too cookies
$timeout -= time();

require_once($sourcedir . '/Subs-Auth.php');
setLoginCookie($timeout, $new_user['id_member'], hash_salt($new_user['passwd'], $new_user['password_salt']));

// Create a new cookie so we know where we came from if we are switching to a shareable account
if (!empty($new_user['is_shareable']))
{
// Since this probably won't be happening a lot, a small extra bit of overhead isn't going to kill us here
$id_parent = !empty($user_info['id_parent']) ? $user_info['id_parent'] : $user_info['id'];

$request = $smcFunc['db_query']('', '
SELECT passwd, password_salt
FROM {db_prefix}members
WHERE id_member = {int:id_parent}',
array(
'id_parent' => $id_parent,
)
);
$old_user = $smcFunc['db_fetch_assoc']($request);

setParentCookie($timeout, $id_parent, sha1($old_user['passwd'] . $old_user['password_salt']));
}
// otherwise kill the parent cookie, don't really need it
else
setParentCookie(-3600, 0);

// Update log_online
$smcFunc['db_query']('', '
UPDATE {db_prefix}log_online
SET id_member = {int:new_user}
WHERE id_member = {int:user}',
array(
'new_user' => $new_user['id_member'],
'user' => $user_info['id'],
)
);

// You've logged in, haven't you?
updateMemberData($new_user['id_member'], array('last_login' => time(), 'member_ip' => $user_info['ip'], 'member_ip2' => $_SERVER['BAN_CHECK_IP']));

redirectexit(empty($location) ? (!empty($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : $_SESSION['old_url']) : $location);
}

Arantor

The cookie format is now completely different in 2.1, not to mention the password hashing system is different.

Check the core code for $_COOKIE[$cookiename] and you should find not only the traces of the above but what's been added to it.
Holder of controversial views, all of which my own.


zushiba

Thanks Arantor!, That was the issue. I tracked down the new login method in LogInOut.php and replaced the dated logic in the Sub Account mod and that did the trick :)

All that's left is to fix the subaccounts listing on the memberlist and it'll be pretty much 99.999% operational.

Advertisement: