plugins/yubikey/auth.php
author Dan
Wed, 19 Aug 2009 01:30:04 -0400
changeset 32 b00055a88867
parent 25 2e7ccbdfdc0a
child 33 1303cf9c594c
permissions -rw-r--r--
Added session key salt support
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
  
25
2e7ccbdfdc0a SECURITY: Added recognition for lockouts
Dan
parents: 17
diff changeset
    33
  // Look for a lockout
2e7ccbdfdc0a SECURITY: Added recognition for lockouts
Dan
parents: 17
diff changeset
    34
  $lockout_info = $session->get_lockout_info($lockdata);
2e7ccbdfdc0a SECURITY: Added recognition for lockouts
Dan
parents: 17
diff changeset
    35
  if ( $lockout_info['locked_out'] )
2e7ccbdfdc0a SECURITY: Added recognition for lockouts
Dan
parents: 17
diff changeset
    36
  {
2e7ccbdfdc0a SECURITY: Added recognition for lockouts
Dan
parents: 17
diff changeset
    37
    // pass on to normal auth so the lockout can be sent back properly
2e7ccbdfdc0a SECURITY: Added recognition for lockouts
Dan
parents: 17
diff changeset
    38
    return null;
2e7ccbdfdc0a SECURITY: Added recognition for lockouts
Dan
parents: 17
diff changeset
    39
  }
2e7ccbdfdc0a SECURITY: Added recognition for lockouts
Dan
parents: 17
diff changeset
    40
  
0
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    41
  if ( !empty($userdata['username']) )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    42
  {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    43
    // get flags
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    44
    $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
    45
    if ( !$q )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    46
      $db->die_json();
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    47
    
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    48
    if ( $db->numrows() < 1 )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    49
    {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    50
      // Username not found - let the main login function handle it
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    51
      $db->free_result();
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    52
      return null;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    53
    }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    54
    list($user_id, $flags) = $db->fetchrow_num();
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    55
    $flags = intval($flags);
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    56
    // At the point the username is validated.
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    57
    $do_validate_user = false;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    58
    $do_validate_pass = $flags & $pass_flag;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    59
    if ( empty($userdata['yubikey_otp']) )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    60
    {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    61
      // no OTP was provided
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    62
      // make sure the user has allowed logging in with no OTP
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    63
      if ( !($flags & YK_SEC_ALLOW_NO_OTP) )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    64
      {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    65
        // We also might have no Yubikeys enrolled.
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    66
        $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
    67
        if ( !$q )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    68
          $db->die_json();
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    69
        
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    70
        if ( $db->numrows() > 0 )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    71
        {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    72
          // Yep at least one key is enrolled.
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    73
          // 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
    74
          $db->free_result();
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    75
          return array(
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    76
              'mode' => 'error',
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    77
              'error' => 'yubiauth_err_must_have_otp'
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    78
            );
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    79
        }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    80
        // Nope, no keys enrolled, user hasn't enabled Yubikey support
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    81
        $db->free_result();
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    82
      }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    83
      // we're ok, use normal password auth
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    84
      return null;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    85
    }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    86
    else
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
    87
    {
17
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
    88
      // 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
    89
      $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
    90
      $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
    91
      if ( !$q )
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
    92
        $db->die_json();
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
    93
      if ( $db->numrows() < 1 )
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();
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
    96
        return array(
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
    97
            'mode' => 'error',
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
    98
            '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
    99
          );
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
   100
      }
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
   101
      $db->free_result();
0
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   102
      $do_validate_otp = true;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   103
    }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   104
  }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   105
  else if ( !empty($userdata['yubikey_otp']) )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   106
  {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   107
    // we have an OTP, but no username to work with
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   108
    $yubi_uid = substr($userdata['yubikey_otp'], 0, 12);
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   109
    if ( !preg_match('/^[cbdefghijklnrtuv]{12}$/', $yubi_uid ) )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   110
    {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   111
      return array(
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   112
          'mode' => 'error',
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   113
          'error' => 'yubiauth_err_invalid_otp'
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   114
        );
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   115
    }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   116
    $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
   117
                      . "  LEFT JOIN " . table_prefix . "yubikey AS y\n"
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   118
                      . "    ON ( y.user_id = u.user_id )\n"
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   119
                      . "  WHERE y.yubi_uid = '$yubi_uid'\n"
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   120
                      . "  GROUP BY u.user_yubikey_flags;");
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   121
    if ( !$q )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   122
      $db->_die();
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   123
    
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   124
    if ( $db->numrows() < 1 )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   125
    {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   126
      if ( !$do_validate_pass )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   127
        $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
   128
                   . '  (\'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
   129
                      . '\''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   130
      
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   131
      return array(
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   132
          'mode' => 'error',
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   133
          'error' => 'yubiauth_err_key_not_authorized'
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   134
        );
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   135
    }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   136
    
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   137
    list($user_id, $username, $flags) = $db->fetchrow_num();
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   138
    $do_validate_otp = true;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   139
    $do_validate_user = $flags & $user_flag;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   140
    $do_validate_pass = $flags & $pass_flag;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   141
  }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   142
  else
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   143
  {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   144
    // Nothing - no username or OTP. This request can't be used; throw it out.
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   145
    return array(
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   146
        'mode' => 'error',
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   147
        'error' => 'yubiauth_err_nothing_provided'
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   148
      );
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_otp )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   151
  {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   152
    // We need to validate the OTP.
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   153
    $otp_check = yubikey_validate_otp($userdata['yubikey_otp']);
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   154
    if ( !$otp_check['success'] )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   155
    {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   156
      if ( !$do_validate_pass )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   157
        $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
   158
                   . '  (\'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
   159
                      . '\''.$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
   160
      
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
   161
      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
   162
      {
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
   163
        return array(
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
   164
            'mode' => 'error',
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
   165
            '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
   166
            '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
   167
          );
e04c0f64e972 SECURITY (critical): If username provided, any Yubikey could be used to log in.
Dan
parents: 5
diff changeset
   168
      }
0
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   169
      return array(
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   170
          'mode' => 'error',
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   171
          'error' => 'yubiauth_err_' . $otp_check['error']
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   172
        );
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   173
    }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   174
  }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   175
  if ( $do_validate_user )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   176
  {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   177
    if ( empty($username) )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   178
    {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   179
      return array(
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   180
          'mode' => 'error',
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   181
          'error' => 'yubiauth_err_must_have_username'
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   182
        );
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   183
    }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   184
    if ( strtolower($username) !== strtolower($userdata['username']) )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   185
    {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   186
      // Username incorrect
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   187
      if ( !$do_validate_pass )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   188
        $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
   189
                   . '  (\'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
   190
                      . '\''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   191
      return array(
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   192
          'mode' => 'error',
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   193
          'error' => 'invalid_credentials'
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   194
        );
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   195
    }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   196
  }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   197
  // Do we need to have the password validated?
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   198
  if ( $do_validate_pass )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   199
  {
5
2114640729a5 Auth: added string for pass required
Dan
parents: 3
diff changeset
   200
    if ( empty($userdata['password']) )
2114640729a5 Auth: added string for pass required
Dan
parents: 3
diff changeset
   201
    {
2114640729a5 Auth: added string for pass required
Dan
parents: 3
diff changeset
   202
      return array(
2114640729a5 Auth: added string for pass required
Dan
parents: 3
diff changeset
   203
          'mode' => 'error',
2114640729a5 Auth: added string for pass required
Dan
parents: 3
diff changeset
   204
          'error' => 'yubiauth_err_must_have_password'
2114640729a5 Auth: added string for pass required
Dan
parents: 3
diff changeset
   205
        );
2114640729a5 Auth: added string for pass required
Dan
parents: 3
diff changeset
   206
    }
0
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   207
    // Yes; return and let the login API continue
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   208
    return null;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   209
  }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   210
  else
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   211
  {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   212
    // No password required; validated, issue session key
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   213
    $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
   214
                   . '  (\'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
   215
                      . '\''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   216
        
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   217
    $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
   218
    if ( !$q )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   219
      $db->_die();
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   220
    
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   221
    list($password) = $db->fetchrow_num();
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   222
    $db->free_result();
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   223
    
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   224
    $session->register_session($user_id, $userdata['username'], $password, $level, $remember);
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   225
    return true;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   226
  }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   227
}
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   228
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   229
function yubikey_add_special_pages()
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   230
{
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   231
  global $db, $session, $paths, $template, $plugins; // Common objects
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   232
  global $lang;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   233
  
3
d0fe7acaf0e8 Maybe we could actually make yubikey_enable in config not ignored!
Dan
parents: 2
diff changeset
   234
  if ( getConfig('yubikey_enable', '1') != '1' )
d0fe7acaf0e8 Maybe we could actually make yubikey_enable in config not ignored!
Dan
parents: 2
diff changeset
   235
    return true;
d0fe7acaf0e8 Maybe we could actually make yubikey_enable in config not ignored!
Dan
parents: 2
diff changeset
   236
  
0
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   237
  $paths->add_page(array(
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   238
      'name' => $lang->get('yubiauth_specialpage_yubikey'),
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   239
      'urlname' => 'Yubikey',
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   240
      'namespace' => 'Special',
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   241
      'visible' => 0, 'protected' => 0, 'comments_on' => 0, 'special' => 0
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   242
    ));
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   243
}
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   244
32
b00055a88867 Added session key salt support
Dan
parents: 25
diff changeset
   245
function yubikey_sk_calc($user_id, &$key_pieces, &$sk_mode)
b00055a88867 Added session key salt support
Dan
parents: 25
diff changeset
   246
{
b00055a88867 Added session key salt support
Dan
parents: 25
diff changeset
   247
  global $db, $session, $paths, $template, $plugins; // Common objects
b00055a88867 Added session key salt support
Dan
parents: 25
diff changeset
   248
  // hash the user's yubikeys
b00055a88867 Added session key salt support
Dan
parents: 25
diff changeset
   249
  $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
   250
  if ( !$q )
b00055a88867 Added session key salt support
Dan
parents: 25
diff changeset
   251
    $db->_die();
b00055a88867 Added session key salt support
Dan
parents: 25
diff changeset
   252
  
b00055a88867 Added session key salt support
Dan
parents: 25
diff changeset
   253
  while ( $row = $db->fetchrow() )
b00055a88867 Added session key salt support
Dan
parents: 25
diff changeset
   254
  {
b00055a88867 Added session key salt support
Dan
parents: 25
diff changeset
   255
    $key_pieces[] = $row['yubi_uid'];
b00055a88867 Added session key salt support
Dan
parents: 25
diff changeset
   256
  }
b00055a88867 Added session key salt support
Dan
parents: 25
diff changeset
   257
}
b00055a88867 Added session key salt support
Dan
parents: 25
diff changeset
   258
0
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   259
function page_Special_Yubikey()
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   260
{
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   261
  global $db, $session, $paths, $template, $plugins; // Common objects
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   262
  
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   263
  header('Content-type: text/javascript');
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['validate_otp']) )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   266
  {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   267
    echo enano_json_encode(yubikey_validate_otp($_GET['validate_otp']));
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   268
    return true;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   269
  }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   270
  */
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   271
  if ( isset($_GET['get_flags']) || isset($_POST['get_flags']) )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   272
  {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   273
    $yubi_uid = substr($_REQUEST['get_flags'], 0, 12);
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   274
    if ( !preg_match('/^[cbdefghijklnrtuv]{12}$/', $yubi_uid) )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   275
    {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   276
      return print enano_json_encode(array(
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   277
          'mode' => 'error',
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   278
          'error' => 'invalid_otp'
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   279
        ));
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   280
    }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   281
    $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
   282
                      . "  LEFT JOIN " . table_prefix . "yubikey AS y\n"
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   283
                      . "    ON ( y.user_id = u.user_id )\n"
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   284
                      . "  WHERE y.yubi_uid = '$yubi_uid'\n"
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   285
                      . "  GROUP BY u.user_yubikey_flags;");
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   286
    if ( !$q )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   287
      $db->_die();
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   288
    
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   289
    if ( $db->numrows() < 1 )
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   290
    {
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   291
      return print enano_json_encode(array(
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   292
          'mode' => 'error',
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   293
          'error' => 'key_not_authorized'
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   294
        ));
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   295
    }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   296
    
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   297
    list($flags) = $db->fetchrow_num();
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   298
    
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   299
    echo enano_json_encode(array(
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   300
        // We strip YK_SEC_ALLOW_NO_OTP here for security reasons.
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   301
        'flags' => intval($flags & ~YK_SEC_ALLOW_NO_OTP)
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   302
      ));
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   303
    
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   304
    return true;
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   305
  }
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   306
}
9d2c4f04a0d0 First commit! Hoping everything works.
Dan
parents:
diff changeset
   307