Eventhough you can use sess_read to read and restore a users session (e.g. you come form a client without cookies ... Flash bug .. swfupload ) but you still have the session id posted by $_POST or something (services will also do that probably).

In that case, using sess_read(SID) will load the proper $user object, with the correct $user->sid . But session_id() is not set correctly, so e.g. form token validation fails (uses session_id, not $user->id).

Patch would be

--- includes/session.inc
+++ includes/session.inc
@@ -36,7 +36,8 @@ function sess_read($key) {
   if ($user && $user->uid > 0 && $user->status == 1) {
     // This is done to unserialize the data member of $user
     $user = drupal_unpack($user);
-
+    // Set the internal PHP session_id. If thats out of sync, token validation will fail
+    session_id($user->sid);
CommentFileSizeAuthor
#10 session.inc__0.patch555 bytesdawehner
#4 session.inc_.patch368 byteseugenmayer

Comments

eugenmayer’s picture

Status: Active » Needs review
EvanDonovan’s picture

Status: Needs review » Active

"Needs review" is only for bugs with a patch needing review. Setting to active.

eugenmayer’s picture

Status: Active » Needs review

Well there is patch above? :)

eugenmayer’s picture

StatusFileSize
new368 bytes

Attched the patch as "downloadable" file. Told it gets ignore otherwise. Whatever suits you master ..

Status: Needs review » Needs work

The last submitted patch, session.inc_.patch, failed testing.

eugenmayer’s picture

Patch is against 6.x not 7.x

dawehner’s picture

Version: 6.16 » 7.x-dev
Status: Needs work » Needs review
function _drupal_session_read($sid) {
  global $user, $is_https;

  // Write and Close handlers are called after destructing objects
  // since PHP 5.0.5.
  // Thus destructors can use sessions but session handler can't use objects.
  // So we are moving session closure before destructing objects.
  drupal_register_shutdown_function('session_write_close');

  // Handle the case of first time visitors and clients that don't store
  // cookies (eg. web crawlers).
  $insecure_session_name = substr(session_name(), 1);
  if (!isset($_COOKIE[session_name()]) && !isset($_COOKIE[$insecure_session_name])) {
    $user = drupal_anonymous_user();
    return '';
  }

  // Otherwise, if the session is still active, we have a record of the
  // client's session in the database. If it's HTTPS then we are either have
  // a HTTPS session or we are about to log in so we check the sessions table
  // for an anonymous session with the non-HTTPS-only cookie.
  if ($is_https) {
    $user = db_query("SELECT u.*, s.* FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.ssid = :ssid", array(':ssid' => $sid))->fetchObject();
    if (!$user) {
      if (isset($_COOKIE[$insecure_session_name])) {
        $user = db_query("SELECT u.*, s.* FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.sid = :sid AND s.uid = 0", array(
        ':sid' => $_COOKIE[$insecure_session_name]))
        ->fetchObject();
      }
    }
  }
  else {
    $user = db_query("SELECT u.*, s.* FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.sid = :sid", array(':sid' => $sid))->fetchObject();
  }

  // We found the client's session record and they are an authenticated,
  // active user.
  if ($user && $user->uid > 0 && $user->status == 1) {
    // This is done to unserialize the data member of $user.
    $user->data = unserialize($user->data);

    // Add roles element to $user.
    $user->roles = array();
    $user->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user';
    $user->roles += db_query("SELECT r.rid, r.name FROM {role} r INNER JOIN {users_roles} ur ON ur.rid = r.rid WHERE ur.uid = :uid", array(':uid' => $user->uid))->fetchAllKeyed(0, 1);
  }
  // We didn't find the client's record (session has expired), or they are
  // blocked, or they are an anonymous user.
  else {
    $session = isset($user->session) ? $user->session : '';
    $user = drupal_anonymous_user($session);
  }

  return $user->session;
}

This bug should be first fixed in d7. Let's see first what the testbot says. I guess a simpletest could help here, too :)

dawehner’s picture

#4: session.inc_.patch queued for re-testing.

Status: Needs review » Needs work

The last submitted patch, session.inc_.patch, failed testing.

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new555 bytes

Rerole for d7

eugenmayer’s picture

Thanks daniel. So i guess the procedure will be to implement it in D7 and backport my patch back to d6, or?

dawehner’s picture

Yes, i think thats the default patch behavior.

damien tournoud’s picture

Title: Sessions are not loaded correctly ( session_id and $user->sid are out of sync) » Support external session loading
Category: bug » feature
Priority: Critical » Normal
Status: Needs review » Needs work

I fail to see where the "critical bug" is here. Someone calling a *private* core function directly is not something we want or need to support.

Also, marking as needs work, because supposing we want to do that, the code is not correct: the correct session identifier to use depends on HTTP vs HTTPS.

damien tournoud’s picture

If we want to implement that as a feature request, I suggest adding a function that simply sets $_COOKIE[session_name()] and calls drupal_session_initialize().

eugenmayer’s picture

Category: feature » bug
Status: Needs work » Needs review

Well, this method is supposed to restore the session out of the DB. And it takes one argument, the session-id. It restores the session, but it fails to check to set the session_id, so half of the system works, half not.

If we have our own session-handler, we need to take care of this, and i defently see that as a bug. As internal session id and the "oftern used" session ($user->sid) are not in sync and therefor causes confusion.

Setting back to old status - not marking critical thought - you are right that this does not affect a lot of env.

eugenmayer’s picture

Title: Support external session loading » Sessions are not loaded correctly ( session_id and $user->sid are out of sync)

Title..

damien tournoud’s picture

Title: Sessions are not loaded correctly ( session_id and $user->sid are out of sync) » Support external session loading
Category: bug » feature
Status: Needs review » Needs work

Sorry, but you are *not* supposed to call a function explicitly marked as private. _drupal_session_read()/sess_read() are supposed to be called from PHP only.

And again, you probably don't even have to, I guess that simply doing this should work:

session_id($my_externally_retrieved_id);
session_start();

Refer to the PHP documentation for proper use of the session API. Calling a private API function of Drupal doesn't qualify as "proper use".

eugenmayer’s picture

I really have no motivation argueing here. Private function yes or now. The "private" function does not what it is designed for - it is simply incomplete.

Do what you want

damien tournoud’s picture

On the contrary, _drupal_session_read()/sess_read() do exactly what they are designed for: being registered as PHP "read" session callbacks.

See http://php.net/manual/en/function.session-set-save-handler.php for the documentation and example of those callbacks. You will see that *none of them* call session_id(), that's just not what they are designed for.

Status: Needs work » Closed (outdated)

Automatically closed because Drupal 7 security and bugfix support has ended as of 5 January 2025. If the issue verifiably applies to later versions, please reopen with details and update the version.