plugins/yubikey/auth.php
author Dan
Mon, 09 Nov 2009 09:21:05 -0500
changeset 33 1303cf9c594c
parent 32 b00055a88867
child 34 6e947fa21237
permissions -rw-r--r--
Removed lockout check, as it is now done in the login preprocess layer.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
0
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
     1
<?php
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
     2
3
d0fe7acaf0e8 Maybe we could actually make yubikey_enable in config not ignored!
Dan
parents: 2
diff changeset
     3
if ( getConfig('yubikey_enable', '1') != '1' )
d0fe7acaf0e8 Maybe we could actually make yubikey_enable in config not ignored!
Dan
parents: 2
diff changeset
     4
    return true;
d0fe7acaf0e8 Maybe we could actually make yubikey_enable in config not ignored!
Dan
parents: 2
diff changeset
     5
0
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
     6
// hook into auth
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
     7
$plugins->attachHook('login_process_userdata_json', 'return yubikey_auth_hook_json($userinfo, $req["level"], @$req["remember"]);');
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
     8
// hook into special page init
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
     9
$plugins->attachHook('session_started', 'yubikey_add_special_pages();');
32
b00055a88867 Added session key salt support
Dan
parents: 25
diff changeset
    10
// session key security
b00055a88867 Added session key salt support
Dan
parents: 25
diff changeset
    11
$plugins->attachHook('session_key_calc', 'yubikey_sk_calc($user_id, $key_pieces, $sk_mode);');
0
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    12
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    13
function yubikey_auth_hook_json(&$userdata, $level, $remember)
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    14
{
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    15
  global $db, $session, $paths, $template, $plugins; // Common objects
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    16
  global $lang;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    17
  
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    18
  $do_validate_otp = false;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    19
  $do_validate_user = false;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    20
  $do_validate_pass = false;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    21
  
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    22
  $user_flag = ( $level >= USER_LEVEL_CHPREF ) ? YK_SEC_ELEV_USERNAME : YK_SEC_NORMAL_USERNAME;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    23
  $pass_flag = ( $level >= USER_LEVEL_CHPREF ) ? YK_SEC_ELEV_PASSWORD : YK_SEC_NORMAL_PASSWORD;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    24
  
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    25
  $auth_log_prefix = ( $level >= USER_LEVEL_CHPREF ) ? 'admin_' : '';
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    26
  
2
6edc6ebb3b39 Minor: if input OTP is empty and password looks like OTP, now copies password to OTP in memory and treats password field as OTP. Will require patch in Enano trunk to work for html login.
Dan
parents: 0
diff changeset
    27
  // Sort of a hack: if the password looks like an OTP and the OTP field is empty, use the password as the OTP
6edc6ebb3b39 Minor: if input OTP is empty and password looks like OTP, now copies password to OTP in memory and treats password field as OTP. Will require patch in Enano trunk to work for html login.
Dan
parents: 0
diff changeset
    28
  if ( empty($userdata['yubikey_otp']) && preg_match('/^[cbdefghijklnrtuv]{44}$/', $userdata['password'] ) )
6edc6ebb3b39 Minor: if input OTP is empty and password looks like OTP, now copies password to OTP in memory and treats password field as OTP. Will require patch in Enano trunk to work for html login.
Dan
parents: 0
diff changeset
    29
  {
6edc6ebb3b39 Minor: if input OTP is empty and password looks like OTP, now copies password to OTP in memory and treats password field as OTP. Will require patch in Enano trunk to work for html login.
Dan
parents: 0
diff changeset
    30
    $userdata['yubikey_otp'] = $userdata['password'];
6edc6ebb3b39 Minor: if input OTP is empty and password looks like OTP, now copies password to OTP in memory and treats password field as OTP. Will require patch in Enano trunk to work for html login.
Dan
parents: 0
diff changeset
    31
  }
6edc6ebb3b39 Minor: if input OTP is empty and password looks like OTP, now copies password to OTP in memory and treats password field as OTP. Will require patch in Enano trunk to work for html login.
Dan
parents: 0
diff changeset
    32
  
33
1303cf9c594c Removed lockout check, as it is now done in the login preprocess layer.
Dan
parents: 32
diff changeset
    33
  // Lockouts removed from here - they're done during preprocessing now.
25
2e7ccbdfdc0a SECURITY: Added recognition for lockouts
Dan
parents: 17
diff changeset
    34
  
0
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    35
  if ( !empty($userdata['username']) )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    36
  {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    37
    // get flags
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    38
    $q = $db->sql_query('SELECT user_id, user_yubikey_flags FROM ' . table_prefix . "users WHERE " . ENANO_SQLFUNC_LOWERCASE . "(username) = '" . $db->escape(strtolower($userdata['username'])) . "';");
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    39
    if ( !$q )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    40
      $db->die_json();
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    41
    
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    42
    if ( $db->numrows() < 1 )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    43
    {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    44
      // Username not found - let the main login function handle it
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    45
      $db->free_result();
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    46
      return null;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    47
    }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    48
    list($user_id, $flags) = $db->fetchrow_num();
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    49
    $flags = intval($flags);
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    50
    // At the point the username is validated.
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    51
    $do_validate_user = false;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    52
    $do_validate_pass = $flags & $pass_flag;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    53
    if ( empty($userdata['yubikey_otp']) )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    54
    {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    55
      // no OTP was provided
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    56
      // make sure the user has allowed logging in with no OTP
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    57
      if ( !($flags & YK_SEC_ALLOW_NO_OTP) )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    58
      {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    59
        // We also might have no Yubikeys enrolled.
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    60
        $q = $db->sql_query('SELECT 1 FROM ' . table_prefix . "yubikey WHERE user_id = $user_id;");
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    61
        if ( !$q )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    62
          $db->die_json();
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    63
        
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    64
        if ( $db->numrows() > 0 )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    65
        {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    66
          // Yep at least one key is enrolled.
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    67
          // I don't think these should be logged because they'll usually just be innocent mistakes.
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    68
          $db->free_result();
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    69
          return array(
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    70
              'mode' => 'error',
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    71
              'error' => 'yubiauth_err_must_have_otp'
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    72
            );
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    73
        }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    74
        // Nope, no keys enrolled, user hasn't enabled Yubikey support
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    75
        $db->free_result();
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    76
      }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    77
      // we're ok, use normal password auth
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    78
      return null;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    79
    }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    80
    else
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    81
    {
17
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
    82
      // user did enter an OTP; make sure it's associated with the username
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
    83
      $yubi_uid = $db->escape(substr($userdata['yubikey_otp'], 0, 12));
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
    84
      $q = $db->sql_query('SELECT 1 FROM ' . table_prefix . 'yubikey WHERE yubi_uid = \'' . $yubi_uid . '\';');
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
    85
      if ( !$q )
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
    86
        $db->die_json();
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
    87
      if ( $db->numrows() < 1 )
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
    88
      {
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
    89
        $db->free_result();
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
    90
        return array(
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
    91
            'mode' => 'error',
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
    92
            'error' => 'yubiauth_err_key_not_authorized'
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
    93
          );
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
    94
      }
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
    95
      $db->free_result();
0
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    96
      $do_validate_otp = true;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    97
    }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    98
  }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    99
  else if ( !empty($userdata['yubikey_otp']) )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   100
  {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   101
    // we have an OTP, but no username to work with
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   102
    $yubi_uid = substr($userdata['yubikey_otp'], 0, 12);
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   103
    if ( !preg_match('/^[cbdefghijklnrtuv]{12}$/', $yubi_uid ) )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   104
    {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   105
      return array(
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   106
          'mode' => 'error',
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   107
          'error' => 'yubiauth_err_invalid_otp'
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   108
        );
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   109
    }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   110
    $q = $db->sql_query('SELECT u.user_id, u.username, u.user_yubikey_flags FROM ' . table_prefix . "users AS u\n"
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   111
                      . "  LEFT JOIN " . table_prefix . "yubikey AS y\n"
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   112
                      . "    ON ( y.user_id = u.user_id )\n"
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   113
                      . "  WHERE y.yubi_uid = '$yubi_uid'\n"
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   114
                      . "  GROUP BY u.user_yubikey_flags;");
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   115
    if ( !$q )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   116
      $db->_die();
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   117
    
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   118
    if ( $db->numrows() < 1 )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   119
    {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   120
      if ( !$do_validate_pass )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   121
        $session->sql('INSERT INTO ' . table_prefix . "logs(log_type,action,time_id,date_string,author,edit_summary,page_text) VALUES\n"
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   122
                   . '  (\'security\', \'' . $auth_log_prefix . 'auth_bad\', '.time().', \''.enano_date('d M Y h:i a').'\', \'(Yubikey)\', '
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   123
                      . '\''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   124
      
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   125
      return array(
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   126
          'mode' => 'error',
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   127
          'error' => 'yubiauth_err_key_not_authorized'
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   128
        );
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   129
    }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   130
    
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   131
    list($user_id, $username, $flags) = $db->fetchrow_num();
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   132
    $do_validate_otp = true;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   133
    $do_validate_user = $flags & $user_flag;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   134
    $do_validate_pass = $flags & $pass_flag;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   135
  }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   136
  else
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   137
  {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   138
    // Nothing - no username or OTP. This request can't be used; throw it out.
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   139
    return array(
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   140
        'mode' => 'error',
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   141
        'error' => 'yubiauth_err_nothing_provided'
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   142
      );
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   143
  }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   144
  if ( $do_validate_otp )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   145
  {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   146
    // We need to validate the OTP.
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   147
    $otp_check = yubikey_validate_otp($userdata['yubikey_otp']);
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   148
    if ( !$otp_check['success'] )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   149
    {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   150
      if ( !$do_validate_pass )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   151
        $session->sql('INSERT INTO ' . table_prefix . "logs(log_type,action,time_id,date_string,author,edit_summary,page_text) VALUES\n"
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   152
                   . '  (\'security\', \'' . $auth_log_prefix . 'auth_bad\', '.time().', \''.enano_date('d M Y h:i a').'\', \'(Yubikey)\', '
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   153
                      . '\''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
17
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
   154
      
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
   155
      if ( $otp_check['error'] === 'http_failed' )
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
   156
      {
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
   157
        return array(
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
   158
            'mode' => 'error',
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
   159
            'error' => 'yubiauth_err_' . $otp_check['error'],
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
   160
            'http_error' => $otp_check['http_error']
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
   161
          );
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
   162
      }
0
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   163
      return array(
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   164
          'mode' => 'error',
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   165
          'error' => 'yubiauth_err_' . $otp_check['error']
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   166
        );
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   167
    }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   168
  }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   169
  if ( $do_validate_user )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   170
  {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   171
    if ( empty($username) )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   172
    {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   173
      return array(
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   174
          'mode' => 'error',
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   175
          'error' => 'yubiauth_err_must_have_username'
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   176
        );
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   177
    }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   178
    if ( strtolower($username) !== strtolower($userdata['username']) )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   179
    {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   180
      // Username incorrect
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   181
      if ( !$do_validate_pass )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   182
        $session->sql('INSERT INTO ' . table_prefix . "logs(log_type,action,time_id,date_string,author,edit_summary,page_text) VALUES\n"
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   183
                   . '  (\'security\', \'' . $auth_log_prefix . 'auth_bad\', '.time().', \''.enano_date('d M Y h:i a').'\', \'(Yubikey)\', '
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   184
                      . '\''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   185
      return array(
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   186
          'mode' => 'error',
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   187
          'error' => 'invalid_credentials'
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   188
        );
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   189
    }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   190
  }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   191
  // Do we need to have the password validated?
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   192
  if ( $do_validate_pass )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   193
  {
5
2114640729a5 Auth: added string for pass required
Dan
parents: 3
diff changeset
   194
    if ( empty($userdata['password']) )
2114640729a5 Auth: added string for pass required
Dan
parents: 3
diff changeset
   195
    {
2114640729a5 Auth: added string for pass required
Dan
parents: 3
diff changeset
   196
      return array(
2114640729a5 Auth: added string for pass required
Dan
parents: 3
diff changeset
   197
          'mode' => 'error',
2114640729a5 Auth: added string for pass required
Dan
parents: 3
diff changeset
   198
          'error' => 'yubiauth_err_must_have_password'
2114640729a5 Auth: added string for pass required
Dan
parents: 3
diff changeset
   199
        );
2114640729a5 Auth: added string for pass required
Dan
parents: 3
diff changeset
   200
    }
0
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   201
    // Yes; return and let the login API continue
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   202
    return null;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   203
  }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   204
  else
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   205
  {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   206
    // No password required; validated, issue session key
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   207
    $session->sql('INSERT INTO ' . table_prefix . "logs(log_type,action,time_id,date_string,author,edit_summary,page_text) VALUES\n"
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   208
                   . '  (\'security\', \'' . $auth_log_prefix . 'auth_good\', '.time().', \''.enano_date('d M Y h:i a').'\', \'' . $db->escape($userdata['username']) . '\', '
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   209
                      . '\''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   210
        
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   211
    $q = $db->sql_query('SELECT password FROM ' . table_prefix . "users WHERE user_id = $user_id;");
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   212
    if ( !$q )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   213
      $db->_die();
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   214
    
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   215
    list($password) = $db->fetchrow_num();
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   216
    $db->free_result();
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   217
    
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   218
    $session->register_session($user_id, $userdata['username'], $password, $level, $remember);
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   219
    return true;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   220
  }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   221
}
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   222
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   223
function yubikey_add_special_pages()
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   224
{
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   225
  global $db, $session, $paths, $template, $plugins; // Common objects
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   226
  global $lang;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   227
  
3
d0fe7acaf0e8 Maybe we could actually make yubikey_enable in config not ignored!
Dan
parents: 2
diff changeset
   228
  if ( getConfig('yubikey_enable', '1') != '1' )
d0fe7acaf0e8 Maybe we could actually make yubikey_enable in config not ignored!
Dan
parents: 2
diff changeset
   229
    return true;
d0fe7acaf0e8 Maybe we could actually make yubikey_enable in config not ignored!
Dan
parents: 2
diff changeset
   230
  
0
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   231
  $paths->add_page(array(
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   232
      'name' => $lang->get('yubiauth_specialpage_yubikey'),
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   233
      'urlname' => 'Yubikey',
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   234
      'namespace' => 'Special',
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   235
      'visible' => 0, 'protected' => 0, 'comments_on' => 0, 'special' => 0
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   236
    ));
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   237
}
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   238
32
b00055a88867 Added session key salt support
Dan
parents: 25
diff changeset
   239
function yubikey_sk_calc($user_id, &$key_pieces, &$sk_mode)
b00055a88867 Added session key salt support
Dan
parents: 25
diff changeset
   240
{
b00055a88867 Added session key salt support
Dan
parents: 25
diff changeset
   241
  global $db, $session, $paths, $template, $plugins; // Common objects
b00055a88867 Added session key salt support
Dan
parents: 25
diff changeset
   242
  // hash the user's yubikeys
b00055a88867 Added session key salt support
Dan
parents: 25
diff changeset
   243
  $q = $db->sql_query('SELECT yubi_uid FROM ' . table_prefix . "yubikey WHERE user_id = $user_id;");
b00055a88867 Added session key salt support
Dan
parents: 25
diff changeset
   244
  if ( !$q )
b00055a88867 Added session key salt support
Dan
parents: 25
diff changeset
   245
    $db->_die();
b00055a88867 Added session key salt support
Dan
parents: 25
diff changeset
   246
  
b00055a88867 Added session key salt support
Dan
parents: 25
diff changeset
   247
  while ( $row = $db->fetchrow() )
b00055a88867 Added session key salt support
Dan
parents: 25
diff changeset
   248
  {
b00055a88867 Added session key salt support
Dan
parents: 25
diff changeset
   249
    $key_pieces[] = $row['yubi_uid'];
b00055a88867 Added session key salt support
Dan
parents: 25
diff changeset
   250
  }
b00055a88867 Added session key salt support
Dan
parents: 25
diff changeset
   251
}
b00055a88867 Added session key salt support
Dan
parents: 25
diff changeset
   252
0
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   253
function page_Special_Yubikey()
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   254
{
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   255
  global $db, $session, $paths, $template, $plugins; // Common objects
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   256
  
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   257
  header('Content-type: text/javascript');
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   258
  /*
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   259
  if ( isset($_GET['validate_otp']) )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   260
  {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   261
    echo enano_json_encode(yubikey_validate_otp($_GET['validate_otp']));
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   262
    return true;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   263
  }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   264
  */
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   265
  if ( isset($_GET['get_flags']) || isset($_POST['get_flags']) )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   266
  {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   267
    $yubi_uid = substr($_REQUEST['get_flags'], 0, 12);
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   268
    if ( !preg_match('/^[cbdefghijklnrtuv]{12}$/', $yubi_uid) )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   269
    {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   270
      return print enano_json_encode(array(
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   271
          'mode' => 'error',
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   272
          'error' => 'invalid_otp'
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   273
        ));
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   274
    }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   275
    $q = $db->sql_query('SELECT u.user_yubikey_flags FROM ' . table_prefix . "users AS u\n"
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   276
                      . "  LEFT JOIN " . table_prefix . "yubikey AS y\n"
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   277
                      . "    ON ( y.user_id = u.user_id )\n"
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   278
                      . "  WHERE y.yubi_uid = '$yubi_uid'\n"
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   279
                      . "  GROUP BY u.user_yubikey_flags;");
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   280
    if ( !$q )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   281
      $db->_die();
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   282
    
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   283
    if ( $db->numrows() < 1 )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   284
    {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   285
      return print enano_json_encode(array(
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   286
          'mode' => 'error',
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   287
          'error' => 'key_not_authorized'
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   288
        ));
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   289
    }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   290
    
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   291
    list($flags) = $db->fetchrow_num();
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   292
    
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   293
    echo enano_json_encode(array(
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   294
        // We strip YK_SEC_ALLOW_NO_OTP here for security reasons.
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   295
        'flags' => intval($flags & ~YK_SEC_ALLOW_NO_OTP)
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   296
      ));
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   297
    
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   298
    return true;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   299
  }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   300
}
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   301