summaryrefslogtreecommitdiff
path: root/LedgerSMB/Session/DB.pm
blob: c38d1de19872aa348994d6856c09b7fdfc54c373 (plain)
  1. #=====================================================================
  2. # LedgerSMB
  3. # Small Medium Business Accounting software
  4. # http://www.ledgersmb.org/
  5. #
  6. #
  7. # Copyright (C) 2006
  8. # This work contains copyrighted information from a number of sources all used
  9. # with permission. It is released under the GNU General Public License
  10. # Version 2 or, at your option, any later version. See COPYRIGHT file for
  11. # details.
  12. #
  13. #
  14. #======================================================================
  15. #
  16. # This file has undergone whitespace cleanup.
  17. #
  18. #======================================================================
  19. # This package contains session related functions:
  20. #
  21. # check - checks validity of session based on the user's cookie and login
  22. #
  23. # create - creates a new session, writes cookie upon success
  24. #
  25. # destroy - destroys session
  26. #
  27. # password_check - compares the password with the stored cryted password
  28. # (ver. < 1.2) and the md5 one (ver. >= 1.2)
  29. #====================================================================
  30. package Session;
  31. sub session_check {
  32. my ($cookie, $form) = @_;
  33. my ($sessionid, $token) = split /:/, $cookie;
  34. # use the central database handle
  35. my $dbh = ${LedgerSMB::Sysconfig::GLOBALDBH};
  36. my $checkQuery = $dbh->prepare("SELECT sl_login FROM session WHERE session_id = ? AND token = ? AND last_used > now() - ?::interval");
  37. my $updateAge = $dbh->prepare("UPDATE session SET last_used = now() WHERE session_id = ?;");
  38. #must be an integer
  39. $sessionid =~ s/[^0-9]//g;
  40. $sessionid = int $sessionid;
  41. #must be 32 chars long and contain hex chars
  42. $token =~ s/[^0-9a-f]//g;
  43. $token = substr($token, 0, 32);
  44. if (!$myconfig{timeout}){
  45. $timeout = "1 day";
  46. } else {
  47. $timeout = "$myconfig{timeout} seconds";
  48. }
  49. $checkQuery->execute($sessionid, $token, $timeout)
  50. || $form->dberror(__FILE__.':'.__LINE__.': Looking for session: ');
  51. my $sessionValid = $checkQuery->rows;
  52. if($sessionValid){
  53. #user has a valid session cookie, now check the user
  54. my ($sessionLogin) = $checkQuery->fetchrow_array;
  55. my $login = $form->{login};
  56. $login =~ s/[^a-zA-Z0-9@.-]//g;
  57. if($sessionLogin eq $login){
  58. $updateAge->execute($sessionid) || $form->dberror(__FILE__.':'.__LINE__.': Updating session age: ');
  59. return 1;
  60. } else {
  61. #something's wrong, they have the cookie, but wrong user. Hijack attempt?
  62. #delete the cookie in the browser
  63. print qq|Set-Cookie: LedgerSMB=; path=/;\n|;
  64. return 0;
  65. }
  66. } else {
  67. #cookie is not valid
  68. #delete the cookie in the browser
  69. print qq|Set-Cookie: LedgerSMB=; path=/;\n|;
  70. print qq|Set-Cookie: DiedHere=true; path=/;\n|;
  71. return 0;
  72. }
  73. }
  74. sub session_create {
  75. my ($form) = @_;
  76. # use the central database handle
  77. my $dbh = ${LedgerSMB::Sysconfig::GLOBALDBH};
  78. # TODO Change this to use %myconfig
  79. my $deleteExisting = $dbh->prepare("DELETE FROM session WHERE sl_login = ? AND age(last_used) > ?::interval");
  80. my $seedRandom = $dbh->prepare("SELECT setseed(?);");
  81. my $fetchSequence = $dbh->prepare("SELECT nextval('session_session_id_seq'), md5(random());");
  82. my $createNew = $dbh->prepare("INSERT INTO session (session_id, sl_login, token) VALUES(?, ?, ?);");
  83. # this is assuming that $form->{login} is safe, which might be a bad assumption
  84. # so, I'm going to remove some chars, which might make previously valid logins invalid
  85. my $login = $form->{login};
  86. $login =~ s/[^a-zA-Z0-9@.-]//g;
  87. #delete any existing stale sessions with this login if they exist
  88. if (!$myconfig{timeout}){
  89. $myconfig{timeout} = 86400;
  90. }
  91. $deleteExisting->execute($login, "$myconfig{timeout} seconds") || $form->dberror(__FILE__.':'.__LINE__.': Delete from session: ');
  92. #doing the random stuff in the db so that LedgerSMB won't
  93. #require a good random generator - maybe this should be reviewed, pgsql's isn't great either
  94. $fetchSequence->execute() || $form->dberror(__FILE__.':'.__LINE__.': Fetch sequence id: ');
  95. my ($newSessionID, $newToken) = $fetchSequence->fetchrow_array;
  96. #create a new session
  97. $createNew->execute($newSessionID, $login, $newToken) || $form->dberror(__FILE__.':'.__LINE__.': Create new session: ');
  98. #reseed the random number generator
  99. my $randomSeed = 1.0 * ('0.'. (time() ^ ($$ + ($$ <<15))));
  100. $seedRandom->execute($randomSeed)|| $form->dberror(__FILE__.':'.__LINE__.': Reseed random generator: ');
  101. $newCookieValue = $newSessionID . ':' . $newToken;
  102. #now set the cookie in the browser
  103. #TODO set domain from ENV, also set path to install path
  104. print qq|Set-Cookie: LedgerSMB=$newCookieValue; path=/;\n|;
  105. $form->{LedgerSMB} = $newCookieValue;
  106. }
  107. sub session_destroy {
  108. my ($form) = @_;
  109. my $login = $form->{login};
  110. $login =~ s/[^a-zA-Z0-9@.-]//g;
  111. # use the central database handle
  112. my $dbh = ${LedgerSMB::Sysconfig::GLOBALDBH};
  113. my $deleteExisting = $dbh->prepare("DELETE FROM session WHERE sl_login = ?;");
  114. $deleteExisting->execute($login) || $form->dberror(__FILE__.':'.__LINE__.': Delete from session: ');
  115. #delete the cookie in the browser
  116. print qq|Set-Cookie: LedgerSMB=; path=/;\n|;
  117. }
  118. sub password_check {
  119. use Digest::MD5;
  120. my ($form, $username, $password) = @_;
  121. # use the central database handle
  122. my $dbh = ${LedgerSMB::Sysconfig::GLOBALDBH};
  123. my $fetchPassword = $dbh->prepare("SELECT uc.password, uc.crypted_password
  124. FROM users as u, users_conf as uc
  125. WHERE u.username = ?
  126. AND u.id = uc.id;");
  127. $fetchPassword->execute($username) || $form->dberror(__FILE__.':'.__LINE__.': Fetching password : ');
  128. my ($md5Password, $cryptPassword) = $fetchPassword->fetchrow_array;
  129. if ($cryptPassword){
  130. #First time login from old system, check crypted password
  131. if ((crypt $password, substr($username, 0, 2)) eq $cryptPassword) {
  132. #password was good, convert to md5 password and null crypted
  133. my $updatePassword = $dbh->prepare("UPDATE users_conf
  134. SET password = md5(?),
  135. crypted_password = null
  136. FROM users
  137. WHERE users_conf.id = users.id
  138. AND users.username = ?;");
  139. $updatePassword->execute($password, $username) || $form->dberror(__FILE__.':'.__LINE__.': Converting password : ');
  140. return 1;
  141. } else {
  142. return 0; #password failed
  143. }
  144. }elsif ($md5Password){
  145. if ($md5Password ne (Digest::MD5::md5_hex $password) ) {
  146. return 0;
  147. }
  148. else{
  149. return 1;
  150. }
  151. } else {
  152. #both the md5Password and cryptPasswords were blank
  153. return 0;
  154. }
  155. }
  156. 1;