From 535505c9acd0dda9cf664c38f5f8cb8dd61dc0cd Mon Sep 17 00:00:00 2001
From: Florian Schlichting <fsfs@debian.org>
Date: Sat, 4 Apr 2020 17:33:10 +0200
Subject: [PATCH 1/2] Drop LSIDLogin function (fix: #18, CVE-2020-11729)

it's current implementation is insecure, particularly when used with an
LDAP backend, and given that users only ever need to log in to create
new collections, simply deleting it altogether doesn't hurt that much
---
 inc/Session.php | 111 ------------------------------------------------
 1 file changed, 111 deletions(-)

--- a/inc/Session.php
+++ b/inc/Session.php
@@ -369,12 +369,6 @@
             // Recognise that we have started a session now too...
             $this->Session($sid);
             dbg_error_log( "Login", " Login: New session $session_id started for $username ($user_no)" );
-            if ( isset($_POST['remember']) && intval($_POST['remember']) > 0 ) {
-              $cookie = md5( $user_no ) . ";";
-              $cookie .= session_salted_md5($user_no . $usr->username . $usr->password);
-              $GLOBALS['lsid'] = $cookie;
-              setcookie( "lsid", $cookie, time() + (86400 * 3600), "/" );   // will expire in ten or so years
-            }
             $this->just_logged_in = true;
 
             // Unset all of the submitted values, so we don't accidentally submit an unexpected form.
@@ -432,100 +426,6 @@
 
 
 /**
-* Attempts to logs in using a long-term session ID
-*
-* This is all horribly insecure, but its hard not to be.
-*
-* @param string $lsid The user's value of the lsid cookie.
-* @return boolean Whether or not the user's lsid cookie got them in the door.
-*/
-  function LSIDLogin( $lsid ) {
-    global $c;
-    dbg_error_log( "Login", " LSIDLogin: Attempting login for $lsid" );
-
-    list($md5_user_no,$validation_string) = explode( ';', $lsid );
-    $qry = new AwlQuery( "SELECT * FROM usr WHERE md5(user_no::text)=? AND active", $md5_user_no );
-    if ( $qry->Exec('Login') && $qry->rows() == 1 ) {
-      $usr = $qry->Fetch();
-      list( $x, $salt, $y) = explode('*', $validation_string);
-      $my_validation = session_salted_md5($usr->user_no . $usr->username . $usr->password, $salt);
-      if ( $validation_string == $my_validation ) {
-        // Now get the next session ID to create one from...
-        $qry = new AwlQuery( "SELECT nextval('session_session_id_seq')" );
-        if ( $qry->Exec('Login') && $qry->rows() == 1 ) {
-          $seq = $qry->Fetch();
-          $session_id = $seq->nextval;
-          $session_key = md5( rand(1010101,1999999999) . microtime() );  // just some random shite
-          dbg_error_log( "Login", " LSIDLogin: Valid username/password for $username ($usr->user_no)" );
-
-          // And create a session
-          $sql = "INSERT INTO session (session_id, user_no, session_key) VALUES( ?, ?, ? )";
-          $qry = new AwlQuery( $sql, $session_id, $usr->user_no, $session_key );
-          if ( $qry->Exec('Login') ) {
-            // Assign our session ID variable
-            $sid = "$session_id;$session_key";
-
-            //  Create a cookie for the sesssion
-            setcookie('sid',$sid, 0,'/');
-            // Recognise that we have started a session now too...
-            $this->Session($sid);
-            dbg_error_log( "Login", " LSIDLogin: New session $session_id started for $this->username ($usr->user_no)" );
-
-            $this->just_logged_in = true;
-
-            // Unset all of the submitted values, so we don't accidentally submit an unexpected form.
-            unset($_POST['username']);
-            unset($_POST['password']);
-            unset($_POST['submit']);
-            unset($_GET['submit']);
-            unset($GLOBALS['submit']);
-
-            if ( function_exists('local_session_sql') ) {
-              $sql = local_session_sql();
-            }
-            else {
-              $sql = "SELECT session.*, usr.* FROM session JOIN usr USING ( user_no )";
-            }
-            $sql .= " WHERE session.session_id = ? AND (md5(session.session_start::text) = ? OR session.session_key = ?) ORDER BY session.session_start DESC LIMIT 2";
-
-            $qry = new AwlQuery($sql, $session_id, $session_key, $session_key);
-            if ( $qry->Exec('Session') && 1 == $qry->rows() ) {
-              $this->AssignSessionDetails( $qry->Fetch() );
-            }
-
-            $rc = true;
-            return $rc;
-          }
-   // else ...
-          $this->cause = 'ERR: Could not create new session.';
-        }
-        else {
-          $this->cause = 'ERR: Could not increment session sequence.';
-        }
-      }
-      else {
-        dbg_error_log( "Login", " LSIDLogin: $validation_string != $my_validation ($salt - $usr->user_no, $usr->username, $usr->password)");
-        $client_messages[] = i18n('Invalid username or password.');
-        if ( isset($c->dbg['Login']) || isset($c->dbg['ALL']) )
-          $this->cause = 'WARN: Invalid password.';
-        else
-          $this->cause = 'WARN: Invalid username or password.';
-      }
-    }
-    else {
-    $client_messages[] = i18n('Invalid username or password.');
-    if ( isset($c->dbg['Login']) || isset($c->dbg['ALL']) )
-      $this->cause = 'WARN: Invalid username.';
-    else
-      $this->cause = 'WARN: Invalid username or password.';
-    }
-
-    dbg_error_log( "Login", " LSIDLogin: $this->cause" );
-    return false;
-  }
-
-
-/**
 * Renders some HTML for a basic login panel
 *
 * @return string The HTML to display a login panel.
@@ -535,7 +435,6 @@
     dbg_error_log( "Login", " RenderLoginPanel: action_target='%s'", $action_target );
     $userprompt = translate("User Name");
     $pwprompt = translate("Password");
-    $rememberprompt = str_replace( ' ', '&nbsp;', translate("forget me not"));
     $gobutton = htmlspecialchars(translate("GO!"));
     $gotitle = htmlspecialchars(translate("Enter your username and password then click here to log in."));
     $temppwprompt = translate("If you have forgotten your password then");
@@ -554,7 +453,6 @@
 <th class="prompt">$pwprompt:</th>
 <td class="entry">
 <input class="password" type="password" name="password" size="12" />
- &nbsp;<label>$rememberprompt: <input class="checkbox" type="checkbox" name="remember" value="1" /></label>
 </td>
 </tr>
 <tr>
@@ -813,10 +711,6 @@
       setcookie( 'sid', '', 0,'/');
       unset($_COOKIE['sid']);
       unset($GLOBALS['sid']);
-      unset($_COOKIE['lsid']); // Allow a cookied person to be un-logged-in for one page view.
-      unset($GLOBALS['lsid']);
-
-      if ( isset($_GET['forget']) ) setcookie( 'lsid', '', 0,'/');
     }
   }
 
@@ -831,11 +725,6 @@
       $this->Login( $_POST['username'], $_POST['password'] );
       @dbg_error_log( "Login", ":_CheckLogin: User %s(%s) - %s (%d) login status is %d", $_POST['username'], $this->fullname, $this->user_no, $this->logged_in );
     }
-    else if ( !isset($_COOKIE['sid']) && isset($_COOKIE['lsid']) && $_COOKIE['lsid'] != "" ) {
-      // Validate long-term session details
-      $this->LSIDLogin( $_COOKIE['lsid'] );
-      dbg_error_log( "Login", ":_CheckLogin: User $this->username - $this->fullname ($this->user_no) login status is $this->logged_in" );
-    }
     else if ( !isset($_COOKIE['sid']) && isset($c->authenticate_hook['server_auth_type']) ) {
       /**
       * The authentication has happened in the server, and we should accept it if so.
