I noticed on my system that every time an invited user registered via their invitation, the buddylistinvite module was automatically making them a buddy, not of the user who actually invited them, but instead a buddy of user ID #12. While I'm new to both Drupal and PHP, after investigating the code, I believe that there are two code defects that affect not only buddylists, but potentially role escalation as well.
The buddylistinvite module implements hook_invite of the invite module, and keys off of the escalate case, which has been invoked by the invite module's helper function _invite_role_escalate(). I believe that there is a defect in the first line of _invite_role_escalate():
function _invite_role_escalate($invitee) {
$inviter_uid = db_result(db_query("SELECT uid FROM {invite} WHERE mid = %d", $user->uid));
The invite database table creates an association between an inviter (the uid field) and the invitee (the mid field), and thus the first line is supposed to be retrieving the user ID of the inviter of the invitee. However, instead of directly using the invitee's user ID, it instead utilizes the global variable $user, but never declared the variable as global. My impression is that this code would never be invoked unless the global variable $user is actually the invitee, but without the global variable declaration the $inviter_uid is for some reason always being set to 12 on my system. However, instead of declaring $user global, I believe that the line should be directly using $invitee instead:
function _invite_role_escalate($invitee) {
$inviter_uid = db_result(db_query("SELECT uid FROM {invite} WHERE mid = %d", $invitee->uid));
Unfortunately, with this change alone, the invitee is always made a buddy of the anonymous user instead of the actual inviter. The invite table does not know the user ID of the invitee until the invitee registers, so the mid field is initially set to zero (ie, the anonymous user). At the time _invite_role_escalate() is being currently invoked, the mid field has not been updated yet. The update occurs in helper function _invite_set_timestamp(), which is being called by invite module's implementation of hook user:
function invite_user($op, &$edit, &$user, $category = NULL) {
switch ($op) {
case 'insert':
$result = db_query("SELECT * FROM {invite} WHERE reg_code = '%s'", $edit['invite_code']);
if ($registration = db_fetch_object($result)) {
$targetrole = variable_get('invite_target_role', '2');
_invite_role_escalate($user);
/*
** if they sign up as a different email to the one sent to them, they do
** not get "joined" properly in the invitee's invite screen.
** this bit fixes that
*/
$userRegMail = $_POST[edit][mail];
_invite_set_timestamp($userRegMail, $user->uid, $edit['invite_code']);
_invite_unblock($user->uid);
} else {
watchdog('invite', 'User '.$user->name.' registration code failed', $link = NULL);
}
break;
}
}
Note, however, that _invite_role_escalate() is being called before the call to _invite_set_timestamp(). Moving the _invite_role_escalate() call after the _invite_set_timestamp() call appears to solve the problem:
if ($registration = db_fetch_object($result)) {
$targetrole = variable_get('invite_target_role', '2');
/*
** if they sign up as a different email to the one sent to them, they do
** not get "joined" properly in the invitee's invite screen.
** this bit fixes that
*/
$userRegMail = $_POST[edit][mail];
_invite_set_timestamp($userRegMail, $user->uid, $edit['invite_code']);
_invite_role_escalate($user);
_invite_unblock($user->uid);
} else {
I have tested the above changes on my system and it resolved the buddylist issue I was noticing. While I also believe that there were probably also issues with role escalation in general that resulted from these defects, I am less clear on that point. Furthermore, as a Drupal and PHP noobie, I may have broken something else with these changes, but I don't currently believe that is the case.
G^2
Comments
Comment #1
Nick Wilson commentedHi, thanks for the detailed report. If you can submit a patch agaisnt the currnet STABLE version i'll be very happy to implement it.
thanks
Comment #2
sja1 commentedI submitted a patch yesterday which fixes this problem, though in a different way. Instead of moving the location of the call, I added $reg_code as a parameter to avoid selecting on mid altogether, and select the invitee userid based on the reg_code which is unique.
The name of the issue containing the patch is "Two important bugs preventing code from working properly".
As suggested by the title, the patch also fixes a second bug in which a db_query was using %d to pass in a value for $reg_code, when it needs to use '%s'.
To provide some insight into why you were having user 12 selected everytime, this was happening because in your invite table, user 12 is the first row in the table that has mid = 0 (i.e. the first row relating to an as yet unaccepted invitation). On my system, every new user was created as buddy to user 1, because user one had submitted the earliest invite that was still unanswered.
Comment #3
Nick Wilson commentedok so lets close this one and deal with the other, thanks