[Web] add verify selected tfa
This commit is contained in:
		@@ -830,11 +830,15 @@ function check_login($user, $pass, $app_passwd_data = false) {
 | 
			
		||||
  $stmt->execute(array(':user' => $user));
 | 
			
		||||
  $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
 | 
			
		||||
  foreach ($rows as $row) {
 | 
			
		||||
    // verify password
 | 
			
		||||
    if (verify_hash($row['password'], $pass)) {
 | 
			
		||||
      if (get_tfa($user)['name'] != "none") {
 | 
			
		||||
      // check for tfa authenticators
 | 
			
		||||
      $authenticators = get_tfa($user);
 | 
			
		||||
      if (isset($authenticators['additional']) && is_array($authenticators['additional']) && count($authenticators['additional']) > 0) {
 | 
			
		||||
        // active tfa authenticators found, set pending user login
 | 
			
		||||
        $_SESSION['pending_mailcow_cc_username'] = $user;
 | 
			
		||||
        $_SESSION['pending_mailcow_cc_role'] = "admin";
 | 
			
		||||
        $_SESSION['pending_tfa_method'] = get_tfa($user)['name'];
 | 
			
		||||
        $_SESSION['pending_tfa_methods'] = $authenticators['additional'];
 | 
			
		||||
        unset($_SESSION['ldelay']);
 | 
			
		||||
        $_SESSION['return'][] =  array(
 | 
			
		||||
          'type' => 'info',
 | 
			
		||||
@@ -842,8 +846,7 @@ function check_login($user, $pass, $app_passwd_data = false) {
 | 
			
		||||
          'msg' => 'awaiting_tfa_confirmation'
 | 
			
		||||
        );
 | 
			
		||||
        return "pending";
 | 
			
		||||
      }
 | 
			
		||||
      else {
 | 
			
		||||
      } else {
 | 
			
		||||
        unset($_SESSION['ldelay']);
 | 
			
		||||
        // Reactivate TFA if it was set to "deactivate TFA for next login"
 | 
			
		||||
        $stmt = $pdo->prepare("UPDATE `tfa` SET `active`='1' WHERE `username` = :user");
 | 
			
		||||
@@ -866,11 +869,14 @@ function check_login($user, $pass, $app_passwd_data = false) {
 | 
			
		||||
  $stmt->execute(array(':user' => $user));
 | 
			
		||||
  $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
 | 
			
		||||
  foreach ($rows as $row) {
 | 
			
		||||
    // verify password
 | 
			
		||||
    if (verify_hash($row['password'], $pass) !== false) {
 | 
			
		||||
      if (get_tfa($user)['name'] != "none") {
 | 
			
		||||
      // check for tfa authenticators
 | 
			
		||||
      $authenticators = get_tfa($user);
 | 
			
		||||
      if (isset($authenticators['additional']) && is_array($authenticators['additional']) && count($authenticators['additional']) > 0) {
 | 
			
		||||
        $_SESSION['pending_mailcow_cc_username'] = $user;
 | 
			
		||||
        $_SESSION['pending_mailcow_cc_role'] = "domainadmin";
 | 
			
		||||
        $_SESSION['pending_tfa_method'] = get_tfa($user)['name'];
 | 
			
		||||
        $_SESSION['pending_tfa_method'] = $authenticators['additional'];
 | 
			
		||||
        unset($_SESSION['ldelay']);
 | 
			
		||||
        $_SESSION['return'][] =  array(
 | 
			
		||||
          'type' => 'info',
 | 
			
		||||
@@ -1142,47 +1148,46 @@ function set_tfa($_data) {
 | 
			
		||||
  global $yubi;
 | 
			
		||||
  global $tfa;
 | 
			
		||||
  $_data_log = $_data;
 | 
			
		||||
  $access_denied = null;
 | 
			
		||||
  !isset($_data_log['confirm_password']) ?: $_data_log['confirm_password'] = '*';
 | 
			
		||||
  $username = $_SESSION['mailcow_cc_username'];
 | 
			
		||||
  if (!isset($_SESSION['mailcow_cc_role']) || empty($username)) {
 | 
			
		||||
      $_SESSION['return'][] =  array(
 | 
			
		||||
        'type' => 'danger',
 | 
			
		||||
        'log' => array(__FUNCTION__, $_data_log),
 | 
			
		||||
        'msg' => 'access_denied'
 | 
			
		||||
      );
 | 
			
		||||
      return false;
 | 
			
		||||
  }
 | 
			
		||||
  $stmt = $pdo->prepare("SELECT `password` FROM `admin`
 | 
			
		||||
      WHERE `username` = :username");
 | 
			
		||||
  $stmt->execute(array(':username' => $username));
 | 
			
		||||
  $row = $stmt->fetch(PDO::FETCH_ASSOC);
 | 
			
		||||
  $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
 | 
			
		||||
  if (!empty($num_results)) {
 | 
			
		||||
    if (!verify_hash($row['password'], $_data["confirm_password"])) {
 | 
			
		||||
      $_SESSION['return'][] =  array(
 | 
			
		||||
        'type' => 'danger',
 | 
			
		||||
        'log' => array(__FUNCTION__, $_data_log),
 | 
			
		||||
        'msg' => 'access_denied'
 | 
			
		||||
      );
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  $stmt = $pdo->prepare("SELECT `password` FROM `mailbox`
 | 
			
		||||
      WHERE `username` = :username");
 | 
			
		||||
  $stmt->execute(array(':username' => $username));
 | 
			
		||||
  $row = $stmt->fetch(PDO::FETCH_ASSOC);
 | 
			
		||||
  $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
 | 
			
		||||
  if (!empty($num_results)) {
 | 
			
		||||
    if (!verify_hash($row['password'], $_data["confirm_password"])) {
 | 
			
		||||
      $_SESSION['return'][] =  array(
 | 
			
		||||
        'type' => 'danger',
 | 
			
		||||
        'log' => array(__FUNCTION__, $_data_log),
 | 
			
		||||
        'msg' => 'access_denied'
 | 
			
		||||
      );
 | 
			
		||||
      return false;
 | 
			
		||||
 | 
			
		||||
  // check for empty user and role
 | 
			
		||||
  if (!isset($_SESSION['mailcow_cc_role']) || empty($username)) $access_denied = true;
 | 
			
		||||
 | 
			
		||||
  // check admin confirm password
 | 
			
		||||
  if ($access_denied === null) {
 | 
			
		||||
    $stmt = $pdo->prepare("SELECT `password` FROM `admin`
 | 
			
		||||
        WHERE `username` = :username");
 | 
			
		||||
    $stmt->execute(array(':username' => $username));
 | 
			
		||||
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
 | 
			
		||||
    if ($row) {
 | 
			
		||||
      if (!verify_hash($row['password'], $_data["confirm_password"])) $access_denied = true;
 | 
			
		||||
      else $access_denied = false;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // check mailbox confirm password
 | 
			
		||||
  if ($access_denied === null) {
 | 
			
		||||
    $stmt = $pdo->prepare("SELECT `password` FROM `mailbox`
 | 
			
		||||
        WHERE `username` = :username");
 | 
			
		||||
    $stmt->execute(array(':username' => $username));
 | 
			
		||||
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
 | 
			
		||||
    if ($row) {
 | 
			
		||||
      if (!verify_hash($row['password'], $_data["confirm_password"])) $access_denied = true;
 | 
			
		||||
      else $access_denied = false;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // set access_denied error
 | 
			
		||||
  if ($access_denied){
 | 
			
		||||
    $_SESSION['return'][] =  array(
 | 
			
		||||
      'type' => 'danger',
 | 
			
		||||
      'log' => array(__FUNCTION__, $_data_log),
 | 
			
		||||
      'msg' => 'access_denied'
 | 
			
		||||
    );
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  switch ($_data["tfa_method"]) {
 | 
			
		||||
    case "yubi_otp":
 | 
			
		||||
@@ -1265,9 +1270,6 @@ function set_tfa($_data) {
 | 
			
		||||
    case "webauthn":
 | 
			
		||||
        $key_id = (!isset($_data["key_id"])) ? 'unidentified' : $_data["key_id"];
 | 
			
		||||
 | 
			
		||||
        $stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username AND `authmech` != 'webauthn'");
 | 
			
		||||
        $stmt->execute(array(':username' => $username));
 | 
			
		||||
 | 
			
		||||
        $stmt = $pdo->prepare("INSERT INTO `tfa` (`username`, `key_id`, `authmech`, `keyHandle`, `publicKey`, `certificate`, `counter`, `active`)
 | 
			
		||||
        VALUES (?, ?, 'webauthn', ?, ?, ?, ?, '1')");
 | 
			
		||||
        $stmt->execute(array(
 | 
			
		||||
@@ -1439,25 +1441,27 @@ function unset_tfa_key($_data) {
 | 
			
		||||
  global $pdo;
 | 
			
		||||
  global $lang;
 | 
			
		||||
  $_data_log = $_data;
 | 
			
		||||
  $access_denied = null;
 | 
			
		||||
  $id = intval($_data['unset_tfa_key']);
 | 
			
		||||
  $username = $_SESSION['mailcow_cc_username'];
 | 
			
		||||
  if (!isset($_SESSION['mailcow_cc_role']) || empty($username)) {
 | 
			
		||||
    $_SESSION['return'][] =  array(
 | 
			
		||||
      'type' => 'danger',
 | 
			
		||||
      'log' => array(__FUNCTION__, $_data_log),
 | 
			
		||||
      'msg' => 'access_denied'
 | 
			
		||||
    );
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // check for empty user and role
 | 
			
		||||
  if (!isset($_SESSION['mailcow_cc_role']) || empty($username)) $access_denied = true;
 | 
			
		||||
 | 
			
		||||
  try {
 | 
			
		||||
    if (!is_numeric($id)) {
 | 
			
		||||
      $_SESSION['return'][] =  array(
 | 
			
		||||
    if (!is_numeric($id)) $access_denied = true;
 | 
			
		||||
    
 | 
			
		||||
    // set access_denied error
 | 
			
		||||
    if ($access_denied){
 | 
			
		||||
      $_SESSION['return'][] = array(
 | 
			
		||||
        'type' => 'danger',
 | 
			
		||||
        'log' => array(__FUNCTION__, $_data_log),
 | 
			
		||||
        'msg' => 'access_denied'
 | 
			
		||||
      );
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    } 
 | 
			
		||||
 | 
			
		||||
    // check if it's last key
 | 
			
		||||
    $stmt = $pdo->prepare("SELECT COUNT(*) AS `keys` FROM `tfa`
 | 
			
		||||
      WHERE `username` = :username AND `active` = '1'");
 | 
			
		||||
    $stmt->execute(array(':username' => $username));
 | 
			
		||||
@@ -1470,6 +1474,8 @@ function unset_tfa_key($_data) {
 | 
			
		||||
      );
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // delete key
 | 
			
		||||
    $stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username AND `id` = :id");
 | 
			
		||||
    $stmt->execute(array(':username' => $username, ':id' => $id));
 | 
			
		||||
    $_SESSION['return'][] =  array(
 | 
			
		||||
@@ -1487,7 +1493,7 @@ function unset_tfa_key($_data) {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
function get_tfa($username = null) {
 | 
			
		||||
function get_tfa($username = null, $key_id = null) {
 | 
			
		||||
  global $pdo;
 | 
			
		||||
  if (isset($_SESSION['mailcow_cc_username'])) {
 | 
			
		||||
    $username = $_SESSION['mailcow_cc_username'];
 | 
			
		||||
@@ -1495,92 +1501,116 @@ function get_tfa($username = null) {
 | 
			
		||||
  elseif (empty($username)) {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  $stmt = $pdo->prepare("SELECT * FROM `tfa`
 | 
			
		||||
      WHERE `username` = :username AND `active` = '1'");
 | 
			
		||||
  $stmt->execute(array(':username' => $username));
 | 
			
		||||
  $row = $stmt->fetch(PDO::FETCH_ASSOC);
 | 
			
		||||
 | 
			
		||||
  if (isset($row["authmech"])) {
 | 
			
		||||
    switch ($row["authmech"]) {
 | 
			
		||||
      case "yubi_otp":
 | 
			
		||||
        $data['name'] = "yubi_otp";
 | 
			
		||||
        $data['pretty'] = "Yubico OTP";
 | 
			
		||||
        $stmt = $pdo->prepare("SELECT `id`, `key_id`, RIGHT(`secret`, 12) AS 'modhex' FROM `tfa` WHERE `authmech` = 'yubi_otp' AND `username` = :username");
 | 
			
		||||
        $stmt->execute(array(
 | 
			
		||||
          ':username' => $username,
 | 
			
		||||
        ));
 | 
			
		||||
        $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
 | 
			
		||||
        while($row = array_shift($rows)) {
 | 
			
		||||
          $data['additional'][] = $row;
 | 
			
		||||
  if (!isset($key_id)){
 | 
			
		||||
    // fetch all tfa methods - just get information about possible authenticators
 | 
			
		||||
    $stmt = $pdo->prepare("SELECT `id`, `key_id`, `authmech` FROM `tfa`
 | 
			
		||||
        WHERE `username` = :username AND `active` = '1'");
 | 
			
		||||
    $stmt->execute(array(':username' => $username));
 | 
			
		||||
    $results = $stmt->fetchAll(PDO::FETCH_ASSOC);
 | 
			
		||||
 
 | 
			
		||||
    // no tfa methods found
 | 
			
		||||
    if (count($results) == 0) {
 | 
			
		||||
        $data['name'] = 'none';
 | 
			
		||||
        $data['pretty'] = "-";
 | 
			
		||||
        $data['additional'] = array();
 | 
			
		||||
        return $data;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $data['additional'] = $results;
 | 
			
		||||
    return $data;
 | 
			
		||||
  } else {
 | 
			
		||||
    // fetch specific authenticator details by key_id
 | 
			
		||||
    $stmt = $pdo->prepare("SELECT * FROM `tfa`
 | 
			
		||||
    WHERE `username` = :username AND `active` = '1'");
 | 
			
		||||
    $stmt->execute(array(':username' => $username));
 | 
			
		||||
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
 | 
			
		||||
 | 
			
		||||
    if (isset($row["authmech"])) {
 | 
			
		||||
        switch ($row["authmech"]) {
 | 
			
		||||
          case "yubi_otp":
 | 
			
		||||
            $data['name'] = "yubi_otp";
 | 
			
		||||
            $data['pretty'] = "Yubico OTP";
 | 
			
		||||
            $stmt = $pdo->prepare("SELECT `id`, `key_id`, RIGHT(`secret`, 12) AS 'modhex' FROM `tfa` WHERE `authmech` = 'yubi_otp' AND `username` = :username");
 | 
			
		||||
            $stmt->execute(array(
 | 
			
		||||
              ':username' => $username,
 | 
			
		||||
            ));
 | 
			
		||||
            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
 | 
			
		||||
            while($row = array_shift($rows)) {
 | 
			
		||||
              $data['additional'][] = $row;
 | 
			
		||||
            }
 | 
			
		||||
            return $data;
 | 
			
		||||
          break;
 | 
			
		||||
          // u2f - deprecated, should be removed
 | 
			
		||||
          case "u2f":
 | 
			
		||||
            $data['name'] = "u2f";
 | 
			
		||||
            $data['pretty'] = "Fido U2F";
 | 
			
		||||
            $stmt = $pdo->prepare("SELECT `id`, `key_id` FROM `tfa` WHERE `authmech` = 'u2f' AND `username` = :username");
 | 
			
		||||
            $stmt->execute(array(
 | 
			
		||||
              ':username' => $username,
 | 
			
		||||
            ));
 | 
			
		||||
            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
 | 
			
		||||
            while($row = array_shift($rows)) {
 | 
			
		||||
              $data['additional'][] = $row;
 | 
			
		||||
            }
 | 
			
		||||
            return $data;
 | 
			
		||||
          break;
 | 
			
		||||
          case "hotp":
 | 
			
		||||
            $data['name'] = "hotp";
 | 
			
		||||
            $data['pretty'] = "HMAC-based OTP";
 | 
			
		||||
            return $data;
 | 
			
		||||
          break;
 | 
			
		||||
          case "totp":
 | 
			
		||||
            $data['name'] = "totp";
 | 
			
		||||
            $data['pretty'] = "Time-based OTP";
 | 
			
		||||
            $stmt = $pdo->prepare("SELECT `id`, `key_id`, `secret` FROM `tfa` WHERE `authmech` = 'totp' AND `username` = :username");
 | 
			
		||||
            $stmt->execute(array(
 | 
			
		||||
              ':username' => $username,
 | 
			
		||||
            ));
 | 
			
		||||
            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
 | 
			
		||||
            while($row = array_shift($rows)) {
 | 
			
		||||
              $data['additional'][] = $row;
 | 
			
		||||
            }
 | 
			
		||||
            return $data;
 | 
			
		||||
          break;
 | 
			
		||||
          case "webauthn":
 | 
			
		||||
            $data['name'] = "webauthn";
 | 
			
		||||
            $data['pretty'] = "WebAuthn";
 | 
			
		||||
            $stmt = $pdo->prepare("SELECT `id`, `key_id` FROM `tfa` WHERE `authmech` = 'webauthn' AND `username` = :username");
 | 
			
		||||
            $stmt->execute(array(
 | 
			
		||||
              ':username' => $username,
 | 
			
		||||
            ));
 | 
			
		||||
            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
 | 
			
		||||
            while($row = array_shift($rows)) {
 | 
			
		||||
              $data['additional'][] = $row;
 | 
			
		||||
            }
 | 
			
		||||
            return $data;
 | 
			
		||||
          break;
 | 
			
		||||
          default:
 | 
			
		||||
            $data['name'] = 'none';
 | 
			
		||||
            $data['pretty'] = "-";
 | 
			
		||||
            return $data;
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
        return $data;
 | 
			
		||||
      break;
 | 
			
		||||
      // u2f - deprecated, should be removed
 | 
			
		||||
      case "u2f":
 | 
			
		||||
        $data['name'] = "u2f";
 | 
			
		||||
        $data['pretty'] = "Fido U2F";
 | 
			
		||||
        $stmt = $pdo->prepare("SELECT `id`, `key_id` FROM `tfa` WHERE `authmech` = 'u2f' AND `username` = :username");
 | 
			
		||||
        $stmt->execute(array(
 | 
			
		||||
          ':username' => $username,
 | 
			
		||||
        ));
 | 
			
		||||
        $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
 | 
			
		||||
        while($row = array_shift($rows)) {
 | 
			
		||||
          $data['additional'][] = $row;
 | 
			
		||||
        }
 | 
			
		||||
        return $data;
 | 
			
		||||
      break;
 | 
			
		||||
      case "hotp":
 | 
			
		||||
        $data['name'] = "hotp";
 | 
			
		||||
        $data['pretty'] = "HMAC-based OTP";
 | 
			
		||||
        return $data;
 | 
			
		||||
      break;
 | 
			
		||||
      case "totp":
 | 
			
		||||
        $data['name'] = "totp";
 | 
			
		||||
        $data['pretty'] = "Time-based OTP";
 | 
			
		||||
        $stmt = $pdo->prepare("SELECT `id`, `key_id`, `secret` FROM `tfa` WHERE `authmech` = 'totp' AND `username` = :username");
 | 
			
		||||
        $stmt->execute(array(
 | 
			
		||||
          ':username' => $username,
 | 
			
		||||
        ));
 | 
			
		||||
        $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
 | 
			
		||||
        while($row = array_shift($rows)) {
 | 
			
		||||
          $data['additional'][] = $row;
 | 
			
		||||
        }
 | 
			
		||||
        return $data;
 | 
			
		||||
      break;
 | 
			
		||||
      case "webauthn":
 | 
			
		||||
        $data['name'] = "webauthn";
 | 
			
		||||
        $data['pretty'] = "WebAuthn";
 | 
			
		||||
        $stmt = $pdo->prepare("SELECT `id`, `key_id` FROM `tfa` WHERE `authmech` = 'webauthn' AND `username` = :username");
 | 
			
		||||
        $stmt->execute(array(
 | 
			
		||||
          ':username' => $username,
 | 
			
		||||
        ));
 | 
			
		||||
        $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
 | 
			
		||||
        while($row = array_shift($rows)) {
 | 
			
		||||
          $data['additional'][] = $row;
 | 
			
		||||
        }
 | 
			
		||||
        return $data;
 | 
			
		||||
      break;
 | 
			
		||||
      default:
 | 
			
		||||
      }
 | 
			
		||||
      else {
 | 
			
		||||
        $data['name'] = 'none';
 | 
			
		||||
        $data['pretty'] = "-";
 | 
			
		||||
        return $data;
 | 
			
		||||
      break;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  else {
 | 
			
		||||
    $data['name'] = 'none';
 | 
			
		||||
    $data['pretty'] = "-";
 | 
			
		||||
    return $data;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
function verify_tfa_login($username, $_data, $WebAuthn) {
 | 
			
		||||
    global $pdo;
 | 
			
		||||
    global $yubi;
 | 
			
		||||
    global $u2f;
 | 
			
		||||
    global $tfa;
 | 
			
		||||
function verify_tfa_login($username, $_data) {
 | 
			
		||||
  global $pdo;
 | 
			
		||||
  global $yubi;
 | 
			
		||||
  global $u2f;
 | 
			
		||||
  global $tfa;
 | 
			
		||||
  global $WebAuthn;
 | 
			
		||||
 | 
			
		||||
  if ($_data['tfa_method'] != 'u2f'){
 | 
			
		||||
    $stmt = $pdo->prepare("SELECT `authmech` FROM `tfa`
 | 
			
		||||
        WHERE `username` = :username AND `active` = '1'");
 | 
			
		||||
    $stmt->execute(array(':username' => $username));
 | 
			
		||||
        WHERE `username` = :username AND `key_id` = :key_id AND `active` = '1'");
 | 
			
		||||
    $stmt->execute(array(':username' => $username, ':key_id' => $_data['key_id']));
 | 
			
		||||
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
 | 
			
		||||
 | 
			
		||||
    switch ($row["authmech"]) {
 | 
			
		||||
@@ -1597,9 +1627,10 @@ function verify_tfa_login($username, $_data, $WebAuthn) {
 | 
			
		||||
            $stmt = $pdo->prepare("SELECT `id`, `secret` FROM `tfa`
 | 
			
		||||
                WHERE `username` = :username
 | 
			
		||||
                AND `authmech` = 'yubi_otp'
 | 
			
		||||
                AND `key_id` = ':key_id'
 | 
			
		||||
                AND `active`='1'
 | 
			
		||||
                AND `secret` LIKE :modhex");
 | 
			
		||||
            $stmt->execute(array(':username' => $username, ':modhex' => '%' . $yubico_modhex_id));
 | 
			
		||||
            $stmt->execute(array(':username' => $username, ':modhex' => '%' . $yubico_modhex_id, ':key_id' => $_data['key_id']));
 | 
			
		||||
            $row = $stmt->fetch(PDO::FETCH_ASSOC);
 | 
			
		||||
            $yubico_auth = explode(':', $row['secret']);
 | 
			
		||||
            $yubi = new Auth_Yubico($yubico_auth[0], $yubico_auth[1]);
 | 
			
		||||
@@ -1636,8 +1667,9 @@ function verify_tfa_login($username, $_data, $WebAuthn) {
 | 
			
		||||
            $stmt = $pdo->prepare("SELECT `id`, `secret` FROM `tfa`
 | 
			
		||||
                WHERE `username` = :username
 | 
			
		||||
                AND `authmech` = 'totp'
 | 
			
		||||
                AND `key_id` = :key_id
 | 
			
		||||
                AND `active`='1'");
 | 
			
		||||
            $stmt->execute(array(':username' => $username));
 | 
			
		||||
            $stmt->execute(array(':username' => $username, ':key_id' => $_data['key_id']));
 | 
			
		||||
            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
 | 
			
		||||
            foreach ($rows as $row) {
 | 
			
		||||
                if ($tfa->verifyCode($row['secret'], $_data['token']) === true) {
 | 
			
		||||
@@ -1666,13 +1698,6 @@ function verify_tfa_login($username, $_data, $WebAuthn) {
 | 
			
		||||
            return false;
 | 
			
		||||
            }
 | 
			
		||||
        break;
 | 
			
		||||
        // u2f - deprecated, should be removed
 | 
			
		||||
        case "u2f":
 | 
			
		||||
            // delete old keys that used u2f
 | 
			
		||||
            $stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `authmech` = :authmech AND `username` = :username");
 | 
			
		||||
            $stmt->execute(array(':authmech' => 'u2f', ':username' => $username));
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        case "webauthn":
 | 
			
		||||
            $tokenData = json_decode($_data['token']);
 | 
			
		||||
            $clientDataJSON = base64_decode($tokenData->clientDataJSON);
 | 
			
		||||
@@ -1681,7 +1706,7 @@ function verify_tfa_login($username, $_data, $WebAuthn) {
 | 
			
		||||
            $id = base64_decode($tokenData->id);
 | 
			
		||||
            $challenge = $_SESSION['challenge'];
 | 
			
		||||
 | 
			
		||||
            $stmt = $pdo->prepare("SELECT `key_id`, `keyHandle`, `username`, `publicKey` FROM `tfa` WHERE `keyHandle` = :tokenId");
 | 
			
		||||
            $stmt = $pdo->prepare("SELECT `id`, `key_id`, `keyHandle`, `username`, `publicKey` FROM `tfa` WHERE `keyHandle` = :tokenId");
 | 
			
		||||
            $stmt->execute(array(':tokenId' => $tokenData->id));
 | 
			
		||||
            $process_webauthn = $stmt->fetch(PDO::FETCH_ASSOC);
 | 
			
		||||
 | 
			
		||||
@@ -1738,7 +1763,7 @@ function verify_tfa_login($username, $_data, $WebAuthn) {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            $_SESSION["mailcow_cc_username"] = $process_webauthn['username'];
 | 
			
		||||
            $_SESSION['tfa_id'] = $process_webauthn['key_id'];
 | 
			
		||||
            $_SESSION['tfa_id'] = $process_webauthn['id'];
 | 
			
		||||
            $_SESSION['authReq'] = null;
 | 
			
		||||
            unset($_SESSION["challenge"]);
 | 
			
		||||
            $_SESSION['return'][] =  array(
 | 
			
		||||
@@ -1759,6 +1784,17 @@ function verify_tfa_login($username, $_data, $WebAuthn) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
  } else {
 | 
			
		||||
    // delete old keys that used u2f
 | 
			
		||||
    $stmt = $pdo->prepare("SELECT * FROM `tfa` WHERE `authmech` = 'u2f' AND `username` = :username");
 | 
			
		||||
    $stmt->execute(array(':username' => $username));
 | 
			
		||||
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
 | 
			
		||||
    if (count($rows) == 0) return false;
 | 
			
		||||
 | 
			
		||||
    $stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `authmech` = 'u2f' AND `username` = :username");
 | 
			
		||||
    $stmt->execute(array(':username' => $username));
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
function admin_api($access, $action, $data = null) {
 | 
			
		||||
  global $pdo;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user