Hi there everybody,

I post this here in the hopes of someone more knowledgeable explaining this strange occurrence to me, or that it might help someone else with a similar problem. I searched through many, many threads before posting here and found lots of similar issues, none of whose solutions worked for me. The problem is that I am getting 'Access Denied' pages from drupal after any of my users try to login.

I originally built the site on a test server where everything went fine and was able to serve the site as a demo from an IP address using both Apache and IIS 5.0 on windows XP with no problems. All users can login fine, so I know the drupal setup is ok.

I moved it onto a production server by doing a database dump and copying the drupal directory to the server. This went without any hitches and the site appears fine for anonymous users and the database cloned fine using phpmyadmin. However, now when anyone tries to login, it is as if the login does not take, and drupal returns an 'Access denied' error (not an incorrect password error) on any pages which the authorised user should be able to see. This happens for any authorised users.

Ok, so I thought, it must be something to do with the login state being carried over from the test server. So I cleared the cache and session tables. No luck there. Then I did a clean install of drupal on my production server which went fine up until the point I created the first (admin) user and tried to login at which point I had the same error.

It it clear there was some compatibility issue with the production server, but I couldn't work out what it was. It was running the same versions of Drupal, IIS, PHP and MySQL as the test server, php.ini was identical, the only change was that instead of an IP address it now had a domain name.

I am running on both servers:
- IIS 5 on Windows server 2000,
- Drupal 5.3
- php 5.2.4
- mysql 5.0.45-community-nt

Watching the session tables as I navigate the site narrows the problem. When I first hit the production site as an anonymous user I see a session created for user id 0. This session id matches the one set in the browser (firefox) cookie. So far so good. The problem comes as soon as I click the login button on the user page. What happens is that a second record is created in the sessions table with a new session id for user id 1 (the admin), but this is not updated in the browser cookies. So internally, user 1 has been logged into drupal but is given a new session which the browser cannot access. The first record remains so that the users cookie is still registered as an anonymous user. What ought to be happening is that the user id for the existing session is updated to reflect the users new status, or that the browser cookie be updated with the new session id.

I looked around the forum and found many similar issues and solutions, mostly for earlier versions of drupal which claim to have already been patched. Initially I thought it was something to do with the domain change and that the $cookie_domain value was not set correctly. After much hacking of session.inc and fiddling with the session table manually, I discovered that the cookies were being read fine. For instance, if i manually modified the user id for the session matching the cookie to '1' I could get admin access. So the system was obviously reading the value from the cookie and there seemed to be no problem with the sess_read() function.

It seems that somewhere in the sess_write() function called after the login button is pressed, the user is being assigned a new session id rather than using the existing one. After some tracing, i discovered the problem is on these lines in session.inc:

function sess_write($key, $value) {
  global $user;

 ...

  $result = db_query("SELECT sid FROM {sessions} WHERE sid = '%s'", $key);

  if (!db_num_rows($result)) {
    if ($user->uid || $value || count($_COOKIE)) {
      db_query("INSERT INTO {sessions} (sid, uid, cache, hostname, session, timestamp) VALUES ('%s', %d, %d, '%s', '%s', %d)", $key, $user->uid, isset($user->cache) ? $user->cache : '', $_SERVER["REMOTE_ADDR"], $value, time());
    }
  }
  else {
    db_query("UPDATE {sessions} SET uid = %d, cache = %d, hostname = '%s', session = '%s', timestamp = %d WHERE sid = '%s'", $user->uid, isset($user->cache) ? $user->cache : '', $_SERVER["REMOTE_ADDR"], $value, time(), $key);

   ...
  }

This query was returning zero matches, meaning that an INSERT was being done rather than the expected UPDATE. Tracing this back further, it appears the wrong value of $key is being sent to this function.

After much gnashing of teeth for the last 3 days I came up with this solution. If I manually replace $key at the top of the function with:

  $key = 'key_from_my_cookie';

or more generally:

  $key = $_COOKIE[session_name()];

The login works for each user. I tried to trace back where the sess_write() function is called from but can only find a reference to it in bootstrap.inc where it is set by the PHP session_set_save_handler() function. Unfortunately, not knowing more about drupal or the inner workings of PHP I can't trace back where the $key value comes from.

Can anyone tell me why this works, if it is a security problem and if there is a better way to solve this? I would rather not hack drupal core if i can help it :-)

Thanks for reading my (rather long - sorry) post and hope someone can help.

Comments

Kobus’s picture

Hi,

I tried implementing this. I am rather unsure where to place this proposed solution. If I put it as a line of code right after the flobal $user definition, nothing happens. If I replace the $key parameter as $key = $_COOKIE[session_name()], the site gives a blank page. There is no other place to 'replace' that in my version (Drupal 4.7.8), so this is not my solution.

I'd appreciate if someone else had another bit of info...

-- Kobus

grahamgilchrist’s picture

Hi there,
Well in my case I dropped the $key = $_COOKIE[session_name()] in straight after the 'global $user' declaration and that seems to have worked for me.

I notice you are using drupal 4.7. I recall finding a number of other solutions to 'access denied' errors for drupal 4.7 on the forums. You might have more luck looking at those since this problem is probably drupal 5.x related.

In fact, I am not even sure whether it is Drupal or PHP itself which is causing the problem. Basically the $key value which is passed to the sess_write() function is not the same as the one in the users cookie, hence it creates a new login entry in the session table rather than updating the anonymous user to a logged-in one.

sess_write() seems to only be called by the builtin PHP function session_set_save_handler(), so I have been wondering if there is a bug in PHP misreporting the session ID? Is there any reason why session_set_save_handler() should report a different session ID to the one it sets when creating the cookie? I also have two other php applications (phpbb and phpmyadmin) running on the same server which have no problem with sessions and cookies?

Why should this have worked on my test server and not on the production one? If anyone can help I am still tearing my hair out over this. I don't really want to use this hack if possible?

bu6z’s picture

Hi Graham....

We have a similar problem here. I am using this platform :
- Windows 2000 Pro
- Built-in IIS 5
- PHP 4.4.0
- MySQL 4.0.21
- Firefox 2.0.0.9
- Drupal 5.3

Before login, I found that drupal.session table contain one SID with UID=0 (Anonymous User) which is the same as specified in Firefox's cookies. After I login, drupal.session table add one more SID with UID=1 (Super User). But in Firefox, there are still contain one SID that belongs to UID=0. That's why I still see this "Access Denied" message.

I've try your suggestion to alter session.inc file by adding one line right after 'global $user' declaration. The code become like this :

function sess_read($key) {
  global $user;
  $key = $_COOKIE[session_name()];

But nothing happens. I already clear Firefox's cache and cookie. I also clean drupal.session tables after editing the code. I still found this "Access Denied" Message.
Do I miss something ?

BR//Andy

bu6z’s picture

I put it in a wrong line, sorry.

It should be like this :

function sess_write($key, $value) {
  global $user;
  $key = $_COOKIE[session_name()];

Thanks Graham.... it works for me.
Brilliant !!!

grahamgilchrist’s picture

Just an update on this issue. I still haven't sorted it and am using my (possibly unsecure?) hack.

I still think it has something to do with the cookie domain being misreported. I thought the problem could be that my live site was a subdomain of the format: www.mysite.domain.com, and that was confusing the drupal/php cookie system. So I tried running the site under a virtual directory of another I own, e.g. www.domain.com/mysite/ and everything worked fine without my hack needed, but when I tried shifting the site onto it's own server www.mysite.com the same error returned.

It has to be something to do with the domain name, but I just can't work it out. Can anyone suggest a solution?

pkiff’s picture

We had the same problem with:
Drupal 6.2 and Drupal 6.4
IIS 5
PHP 5.2.6
MySQL 5.0.45

Our Drupal domain is a subdomain in the format: mysite.domain.com.

Your solution solved our problem in both installs. Thanks a bundle!!

Not sure if this was wise, but I started a new thread that would appear if folks filtered results for 6.x and that focuses on whether your fix is secure:
http://drupal.org/node/295920

Phil.

ArchCarrier’s picture

The problem appears to be in the ?q=admin login script, because I only get the 'Access Denied' error while using the login on that page. When I try to login through ?q=user, the login does take.

Can anyone confirm this, and maybe see what's the problem on the admin page?

EDIT: This solution fixed some of the problems for me, although I still can't login through the admin link,

miller.nw’s picture

I installed Drupal 5.7 on an IIS server and was getting the same problems.
Tried the little

$key = $_COOKIE[session_name()];

trick in sesson.inc and it worked like a charm! I've been wrestling with this problem for days! I was about to jump out the window!!!

Thanks for the post!

P.S. Looks like I'm still having trouble with email.. They aren't coming through very quickly if at all. Anyone else experience this along with the problems above?

hjulien-1’s picture

Hi,
I have the same bug here... I installed Drupal on ISS and Windows XP for development and testing and everything worked great! Now I moved everything to our Windows 2000 server (using the same postgresql database) and I can't login with Drupal! I can see that the admin session is created in postgresql but I can't login... No error messages... I just stay as an anonymous user.

FYI...
Drupal 6.4 with IIS and Postgresql
Windows 2000 server
PHP 5.2.6

Weird!!!!!

BTW the fix worked for us!!!!! Thanks!!!!!
Ryk

hjulien-1’s picture

The fix worked with IE but yesterday I installed the new Google Chrome and now I can’t login anymore!!!! I have to use IE to log into my Drupal application! Back to square one!!!
Anyone else observed this problem or has a fix for it?

I've just noticed that I can't login with Firefox (FF) also!!! If I take a look at the session table, no admin or anonymous user is created with FF or Chrome!!!

Cheers
Ryk

azhan.moin’s picture

Thanks, your fix works for us too!

We moved a client site from our Debian dev box into the following environment:

IIS 5 on Windows 2000 Server, shared hosting
Drupal 5.7
PHP 4.3.8
MySQL 4.0.16-nt

cheers
Azhan
S & A Solutions

nmodi’s picture

Spent 3 days. Finally your solution to add details in session.inc worked for IIS 5. All other solutions did not work.
Issue was that
- Multi-website configuration. Base site always worked. Second website - Installation worked. After logging out, logging back never worked.
Env: Win2k IIS 5, Drupal 6.1.2, MySQL, PHP

lifepillar’s picture

…when switching to a new server is the value of the PHP setting session.cookie_secure, both in the PHP configuration file and in your own .htaccess.

For example, I happened to move a web site to a new server for which session.cookie_secure was set to 1 and, when logging in (through a non-secure connection) I got the “Access Denied” error. Changing the value of the variable to 0 solved the problem.

SheilaRuth’s picture

Even though this is an old post, it saved me! I'm in the process of moving a Drupal 5 site to a new server, and had this exact same problem. I was starting to suspect it was a problem with the session, but your fix worked for me and you saved me a lot of time, so thanks!. Once I get the site moved, I'm going to be upgrading it to 6 then 7, so I'm not too concerned about hacking the core files, since I'm going to replace them anyway. Hopefully the new version won't have this problem.