Yes, it looks very close to a drop-in replacement to the one I found. I don't even have to change the build process again. The file names match. Wish I would have seen that sooner!
>> I have added three defines in qmailadmin.h, that should actually be >> set by ./configure options: >> > > I think we should also add a probability how often the garbage collector > is executed and deletes the expired session files. Executing it every > time QmailAdmin is executed is IMO to much and slows it only down.
I already garbage collect only after a successful login, so it doesn't run with every hit, but probability testing won't be hard to add. I should also make it so the page paints before the garbage collection starts so it doesn't slow the user.
> You could read from /dev/random or /dev/urandom, if present. There's > a patch pending for vpopmail that uses that device for random data.
I guess if vpopmail uses it it should be safe for QmailAdmin. I know that should work on my Linux boxes... How do you tell if it is present? ./configure? What happens if it is not there? I suspect the whole block of code and configure.in(?) can be stolen from vpopmail.
> Random numbers are more or less always generated out of the current > time, but I think we perhaps could generate the SESSION_SECRET string > randomly, too. Or repeat the hashing a random time (1-10 for example).
If you always have a good random generator avialble that is much better than a preset secret. I don't know enough about c portability to decide. One thing I've heard is that /dev/?random can sometimes block if there isn't enough enthropy available. That could be bad on a lightly loaded machine.
I don't need to retain the random input values for anything, I am just trying to make it very hard to predict SessionID values.
> Why get the things messed up? I would do a logout like > 1) Delete the cookie/no more sids in the urls > 2) Delete the session file on the server > > On a relogin you create everything new as it would be the first login.
What it does now...
in get_session_id() The first time you hit QmailAdmin the program checks for a cookie. There is none, so it sets SessionFromCookie = 0. Then it checks for SessionID in Request.(Get/Put) Again there is none so it generates a new SessionID.
in paint_headers() Since SessionFromCookie is 0 (false) and SessionID is set a Set-cookie header for SessionID will be sent.
Since there is no session file associated with the new SessionID and the [Login] button was not clicked, you are only allowed to login. show_login() calls send_template() and paints the login page, then the progran is done. Since SessionFromCookie is 0 a hidden field is included in the page containing SessionID.
-- the user enters user/domain/password then clicks [login] --
This time through...
in get_session_id() SessionID is found in Cookie, so SessionFromCookie = 1, and SessionID is set.
in paint_headers SessionFromCookie is 1, so do not send a SetCookie header.
Still no session file matching your SessionID, but this time [Login] was clicked so verify the login. If the login is good create the session file then call show_menu -- else call show_login, with the fields still filled in the way the user left them. (I hate having to re-enter everything even more than I hate being dropped into an error page that tells me to hit [Back] and try again.)
As long as a cookie is found, the SessionID will not be appended to link URLS, and the hidden field may not be added to forms. Right now it is always added, and that does not hurt anything. Mere mortals will never see it. A ##t? could be used to hide the hidden SessionID field. On the other hand it might be nice to be able to view the SessionID with View Source if you have a problem. I don't have to decide yet...
-- the user does whatever, then clicks the exit link --
in get_session_id() SessionID is found in Cookie, so SessionFromCookie = 1, and SessionID is set.
in main() Since exit was selected, delete the session file, set SessionFromCookie to 0, and set SessionID = "".
in paint_headers() Since SessionFromCookie is 0 and SessionID is blank, send a Set-cookie header with an old Expires value. The browser will delete the cookie.
Then we need to paint something to the browser... But what?
Things I have considered...
o Delay setting the cookie until there is a valid login. I very much like setting the SessionID cookie the first time I paint the show_login.html template. This way I know that the next operation will be a form entry. If I wait until I have a valid login the next operation will be a menu, and every link will have to have the SessionID appended in case cookies are off. That looks uggly...
o Don't worry about leaving the cookie in the browser. Things worked well right up to the time I decided it wasn't cool to do a logout without cleaning up the cookie. That is tacky...
o Have an exit page that tells you that you have been logged out. More work... To do this cleanly I will have to modify ##x in the template processor. I will want both the returntext/returnhttp link, and a logout link. With cookies enabled you will be able to follow the return* link, and come back to your QmailAdmin session -- already in progress.
I'm leaning towards the exit page.
One other thing I an looking at...
If you enter a user name and a password, but leave the domain name blank, check the system passwords. (via PAM?) If the username/password match then check to see if the user is a member of the vchkpw group. If so then present them with a list of all domains. Allow them to edit, add and delete domains. Selecting a domain from the list will take you to the main menu for that domain. A link will be provided to go back to the domain list. A single login can manage all domains.
It may be better to have our own password file for SYSTEM_ADMINS. Either way the program already sets AdminType = SYSTEM_ADMIN if you login as rwidmer, with domain blank and anything in password. All my rights checking is done with < or > and the most important checks have been moved into command.c. I just have to figure out how to authenticate the login.
NO_ADMIN 0 USER_ADMIN 1 DOMAIN_ADMIN 2 SYSTEM_ADMIN 3
Rick