plugins/SpecialUserFuncs.php
changeset 507 586fd7d3202d
parent 504 bc8e0e9ee01d
child 517 c6118b9e13bd
equal deleted inserted replaced
506:da0f2a76add5 507:586fd7d3202d
   167       }
   167       }
   168       unset($x, $y);
   168       unset($x, $y);
   169     }
   169     }
   170     
   170     
   171     // 1.1.3: generate diffie hellman key
   171     // 1.1.3: generate diffie hellman key
       
   172     require_once( ENANO_ROOT . '/includes/diffiehellman.php' );
   172     global $dh_supported, $_math;
   173     global $dh_supported, $_math;
   173     
   174     
   174     $response['dh_supported'] = $dh_supported;
   175     $response['dh_supported'] = $dh_supported;
   175     if ( $dh_supported )
   176     if ( $dh_supported )
   176     {
   177     {
   204     $level = USER_LEVEL_MEMBER;
   205     $level = USER_LEVEL_MEMBER;
   205   }
   206   }
   206   if ( $level <= USER_LEVEL_MEMBER && $session->user_logged_in )
   207   if ( $level <= USER_LEVEL_MEMBER && $session->user_logged_in )
   207     $paths->main_page();
   208     $paths->main_page();
   208   $template->header();
   209   $template->header();
   209   echo '<form action="'.makeUrl($paths->nslist['Special'].'Login').'" method="post" name="loginform" onsubmit="runEncryption();">';
   210   echo '<form action="'.makeUrl($paths->nslist['Special'].'Login').'" method="post" name="loginform" onsubmit="try{runEncryption();}catch(e){};">';
   210   $header = ( $level > USER_LEVEL_MEMBER ) ? $lang->get('user_login_message_short_elev') : $lang->get('user_login_message_short');
   211   $header = ( $level > USER_LEVEL_MEMBER ) ? $lang->get('user_login_message_short_elev') : $lang->get('user_login_message_short');
   211   if ( isset($_POST['login']) )
   212   if ( isset($_POST['login']) )
   212   {
   213   {
   213     $errstring = $__login_status['error'];
   214     $errstring = $__login_status['error'];
   214     switch($__login_status['error'])
   215     switch($__login_status['error'])
   224         break;
   225         break;
   225       case 'invalid_credentials':
   226       case 'invalid_credentials':
   226         $errstring = $lang->get('user_err_invalid_credentials');
   227         $errstring = $lang->get('user_err_invalid_credentials');
   227         if ( $__login_status['lockout_policy'] == 'lockout' )
   228         if ( $__login_status['lockout_policy'] == 'lockout' )
   228         {
   229         {
   229           $errstring .= $lang->get('err_invalid_credentials_lockout', array('lockout_fails' => $__login_status['lockout_fails']));
   230           $errstring .= $lang->get('err_invalid_credentials_lockout', array('fails' => $__login_status['lockout_fails']));
   230         }
   231         }
   231         else if ( $__login_status['lockout_policy'] == 'captcha' )
   232         else if ( $__login_status['lockout_policy'] == 'captcha' )
   232         {
   233         {
   233           $errstring .= $lang->get('user_err_invalid_credentials_lockout_captcha', array('lockout_fails' => $__login_status['lockout_fails']));
   234           $errstring .= $lang->get('user_err_invalid_credentials_lockout_captcha', array('fails' => $__login_status['lockout_fails']));
   234         }
   235         }
   235         break;
   236         break;
   236       case 'backend_fail':
   237       case 'backend_fail':
   237         $errstring = $lang->get('user_err_backend_fail');
   238         $errstring = $lang->get('user_err_backend_fail');
   238         break;
   239         break;
   246         if ( $time_rem < 1 )
   247         if ( $time_rem < 1 )
   247           $time_rem = $__login_status['lockout_duration'];
   248           $time_rem = $__login_status['lockout_duration'];
   248         
   249         
   249         $s = ( $time_rem == 1 ) ? '' : $lang->get('meta_plural');
   250         $s = ( $time_rem == 1 ) ? '' : $lang->get('meta_plural');
   250         
   251         
   251         $captcha_string = ( $__login_status['lockout_policy'] == 'captcha' ) ? $lang->get('err_locked_out_captcha_blurb') : '';
   252         $captcha_string = ( $__login_status['lockout_policy'] == 'captcha' ) ? $lang->get('user_err_locked_out_captcha_blurb') : '';
   252         $errstring = $lang->get('user_err_locked_out', array('plural' => $s, 'captcha_blurb' => $captcha_string, 'time_rem' => $time_rem));
   253         $errstring = $lang->get('user_err_locked_out', array('plural' => $s, 'captcha_blurb' => $captcha_string, 'time_rem' => $time_rem));
   253         
   254         
   254         break;
   255         break;
   255     }
   256     }
   256     echo '<div class="error-box-mini">'.$errstring.'</div>';
   257     echo '<div class="error-box-mini">'.$errstring.'</div>';
   328              </td>
   329              </td>
   329            </tr>
   330            </tr>
   330            <?php
   331            <?php
   331          }
   332          }
   332          ?>
   333          ?>
   333          <tr>
   334          <?php
   334            <td class="row3" colspan="3">
   335          if ( $level <= USER_LEVEL_MEMBER && ( !isset($_GET['use_crypt']) || ( isset($_GET['use_crypt']) && $_GET['use_crypt']!='0' ) ) )
   335              <?php
   336          {
   336              if ( $level <= USER_LEVEL_MEMBER && ( !isset($_GET['use_crypt']) || ( isset($_GET['use_crypt']) && $_GET['use_crypt']!='0' ) ) )
   337            echo '<tr>
   337              {
   338              <td class="row3" colspan="3">';
   338                $returnpage_link = ( $return = $paths->getAllParams() ) ? '/' . $return : '';
   339              
   339                $nocrypt_link = makeUrlNS('Special', "Login$returnpage_link", "level=$level&use_crypt=0", true);
   340            $returnpage_link = ( $return = $paths->getAllParams() ) ? '/' . $return : '';
   340                echo '<p><b>' . $lang->get('user_login_nocrypt_title') . '</b> ' . $lang->get('user_login_nocrypt_body', array('nocrypt_link' => $nocrypt_link)) . '</p>';
   341            $nocrypt_link = makeUrlNS('Special', "Login$returnpage_link", "level=$level&use_crypt=0", true);
   341                echo '<p>' . $lang->get('user_login_nocrypt_countrylist') . '</p>';
   342            echo '<p><b>' . $lang->get('user_login_nocrypt_title') . '</b> ' . $lang->get('user_login_nocrypt_body', array('nocrypt_link' => $nocrypt_link)) . '</p>';
   342              }
   343            echo '<p>' . $lang->get('user_login_nocrypt_countrylist') . '</p>';
   343              else if ( $level <= USER_LEVEL_MEMBER && ( isset($_GET['use_crypt']) && $_GET['use_crypt']=='0' ) )
   344            
   344              {
   345            echo '  </td>
   345                $returnpage_link = ( $return = $paths->getAllParams() ) ? '/' . $return : '';
   346            </tr>';
   346                $usecrypt_link = makeUrlNS('Special', "Login$returnpage_link", "level=$level&use_crypt=1", true);
   347          }
   347                echo '<p><b>' . $lang->get('user_login_usecrypt_title') . '</b> ' . $lang->get('user_login_usecrypt_body', array('usecrypt_link' => $usecrypt_link)) . '</p>';
   348          else if ( $level <= USER_LEVEL_MEMBER && ( isset($_GET['use_crypt']) && $_GET['use_crypt']=='0' ) )
   348                echo '<p>' . $lang->get('user_login_usecrypt_countrylist') . '</p>';
   349          {
   349              }
   350            echo '<tr>
   350              ?>
   351              <td class="row3" colspan="3">';
   351            </td>
   352              
   352          </tr>
   353            $returnpage_link = ( $return = $paths->getAllParams() ) ? '/' . $return : '';
       
   354            $usecrypt_link = makeUrlNS('Special', "Login$returnpage_link", "level=$level&use_crypt=1", true);
       
   355            echo '<p><b>' . $lang->get('user_login_usecrypt_title') . '</b> ' . $lang->get('user_login_usecrypt_body', array('usecrypt_link' => $usecrypt_link)) . '</p>';
       
   356            echo '<p>' . $lang->get('user_login_usecrypt_countrylist') . '</p>';
       
   357            
       
   358            echo '  </td>
       
   359            </tr>';
       
   360          }
       
   361          ?>
       
   362          
   353          <tr>
   363          <tr>
   354            <th colspan="3" style="text-align: center" class="subhead"><input type="submit" name="login" value="Log in" tabindex="<?php echo ( $level <= USER_LEVEL_MEMBER ) ? '3' : '2'; ?>" /></th>
   364            <th colspan="3" style="text-align: center" class="subhead"><input type="submit" name="login" value="Log in" tabindex="<?php echo ( $level <= USER_LEVEL_MEMBER ) ? '3' : '2'; ?>" /></th>
   355          </tr>
   365          </tr>
   356       </table>
   366       </table>
   357     </div>
   367     </div>
   367       <?php else: ?>
   377       <?php else: ?>
   368       <script type="text/javascript">
   378       <script type="text/javascript">
   369         document.forms.loginform.pass.focus();
   379         document.forms.loginform.pass.focus();
   370       </script>
   380       </script>
   371       <?php endif; ?>
   381       <?php endif; ?>
       
   382       <?php
       
   383       // 1.1.4
       
   384       
       
   385       require_once( ENANO_ROOT . '/includes/diffiehellman.php' );
       
   386       
       
   387       global $dh_supported, $_math;
       
   388       if ( $dh_supported )
       
   389       {
       
   390         $dh_key_priv = dh_gen_private();
       
   391         $dh_key_pub = dh_gen_public($dh_key_priv);
       
   392         $dh_key_priv = $_math->str($dh_key_priv);
       
   393         $dh_key_pub = $_math->str($dh_key_pub);
       
   394         // store the keys in the DB
       
   395         $q = $db->sql_query('INSERT INTO ' . table_prefix . "diffiehellman( public_key, private_key ) VALUES ( '$dh_key_pub', '$dh_key_priv' );");
       
   396         if ( !$q )
       
   397           $db->_die();
       
   398         
       
   399         echo "<input type=\"hidden\" name=\"dh_supported\" value=\"true\" />
       
   400               <input type=\"hidden\" name=\"dh_public_key\" value=\"$dh_key_pub\" />
       
   401               <input type=\"hidden\" name=\"dh_client_public_key\" value=\"\" />";
       
   402       }
       
   403       else
       
   404       {
       
   405         echo "<input type=\"hidden\" name=\"dh_supported\" value=\"false\" />";
       
   406       }
       
   407       ?>
   372     </form>
   408     </form>
   373     <?php
   409     <?php
   374       echo $session->aes_javascript('loginform', 'pass', 'use_crypt', 'crypt_key', 'crypt_data', 'challenge_data');
   410       echo $session->aes_javascript('loginform', 'pass', 'use_crypt', 'crypt_key', 'crypt_data', 'challenge_data', 'dh_supported', 'dh_public_key', 'dh_client_public_key');
   375     ?>
   411     ?>
   376   <?php
   412   <?php
   377   $template->footer();
   413   $template->footer();
   378 }
   414 }
   379 
   415 
   405     $db->close();
   441     $db->close();
   406     exit;
   442     exit;
   407   }
   443   }
   408   if ( isset($_GET['act']) && $_GET['act'] == 'ajaxlogin' )
   444   if ( isset($_GET['act']) && $_GET['act'] == 'ajaxlogin' )
   409   {
   445   {
   410     $plugins->attachHook('login_password_reset', 'SpecialLogin_SendResponse_PasswordReset($row[\'user_id\'], $row[\'temp_password\']);');
   446     die('This version of the Enano LoginAPI is deprecated. Please use the action.json method instead.');
   411     $data = enano_json_decode($_POST['params']);
   447     $db->close();
   412     $captcha_hash = ( isset($data['captcha_hash']) ) ? $data['captcha_hash'] : false;
   448     exit;
   413     $captcha_code = ( isset($data['captcha_code']) ) ? $data['captcha_code'] : false;
   449   }
   414     $level = ( isset($data['level']) ) ? intval($data['level']) : USER_LEVEL_MEMBER;
   450   if(isset($_POST['login']))
   415     
   451   {
   416     // 1.1.3: Diffie Hellman
   452     $captcha_hash = ( isset($_POST['captcha_hash']) ) ? $_POST['captcha_hash'] : false;
   417     global $dh_supported;
   453     $captcha_code = ( isset($_POST['captcha_code']) ) ? $_POST['captcha_code'] : false;
   418     global $_math;
   454     if ( $_POST['use_crypt'] == 'yes' )
   419     if ( $data['diffiehellman'] && isset($data['publickey_client']) && isset($data['publickey_server']) && isset($data['crypt_key_check']) )
   455     {
   420     {
   456       $result = $session->login_with_crypto($_POST['username'], $_POST['crypt_data'], $_POST['crypt_key'], $_POST['challenge_data'], intval($_POST['auth_level']), $captcha_hash, $captcha_code);
       
   457     }
       
   458     else if ( $_POST['use_crypt'] == 'yes_dh' )
       
   459     {
       
   460       // retrieve and decrypt the password using DiffieHellman
       
   461       
       
   462       require_once( ENANO_ROOT . '/includes/diffiehellman.php' );
       
   463       global $dh_supported, $_math;
       
   464       
   421       if ( !$dh_supported )
   465       if ( !$dh_supported )
   422       {
   466       {
   423         die('Special:Login: Illegal request for Diffie Hellman exchange');
   467         die_semicritical('DiffieHellman error', 'Server does not support DiffieHellman, denying logon request');
   424       }
   468       }
   425       // retrieve our public key
       
   426       if ( !preg_match('/^[0-9]+$/', $data['publickey_server']) )
       
   427       {
       
   428         die('Special:Login: Illegal request for Diffie Hellman exchange');
       
   429       }
       
   430       $pubkey_server =& $data['publickey_server'];
       
   431       
   469       
   432       // retrieve our private key
   470       // Fetch private key
   433       $q = $db->sql_query('SELECT private_key, key_id FROM ' . table_prefix . "diffiehellman WHERE public_key = '$pubkey_server';");
   471       $dh_public = $_POST['dh_public_key'];
       
   472       if ( !preg_match('/^[0-9]+$/', $dh_public) )
       
   473       {
       
   474         die_semicritical('DiffieHellman error', 'Public key not integer: ' . $dh_public);
       
   475       }
       
   476       $q = $db->sql_query('SELECT private_key, key_id FROM ' . table_prefix . "diffiehellman WHERE public_key = '$dh_public';");
   434       if ( !$q )
   477       if ( !$q )
   435         $db->die_json();
   478         $db->die_json();
   436       
   479       
   437       if ( $db->numrows() < 1 )
   480       if ( $db->numrows() < 1 )
   438       {
   481       {
   439         die('Special:Login: Couldn\'t lookup Diffie Hellman key: ' . $pubkey_server);
   482         die_semicritical('DiffieHellman error', 'ERR_DH_KEY_NOT_FOUND');
   440       }
   483       }
   441       list($privkey_server, $key_id) = $db->fetchrow_num();
   484       
       
   485       list($dh_private, $dh_key_id) = $db->fetchrow_num();
   442       $db->free_result();
   486       $db->free_result();
   443       
   487       
   444       // get shared secret
   488       // We have the private key, now delete the key pair, we no longer need it
   445       $dh_secret = dh_gen_shared_secret($privkey_server, $data['publickey_client']);
   489       $q = $db->sql_query('DELETE FROM ' . table_prefix . "diffiehellman WHERE key_id = $dh_key_id;");
       
   490       if ( !$q )
       
   491         $db->die_json();
       
   492       
       
   493       // Generate the shared secret
       
   494       $dh_secret = dh_gen_shared_secret($dh_private, $_POST['dh_client_public_key']);
   446       $dh_secret = $_math->str($dh_secret);
   495       $dh_secret = $_math->str($dh_secret);
   447       $secret_check = sha1($dh_secret);
   496       
   448       if ( $secret_check !== $data['crypt_key_check'] )
   497       // Did we get all our math right?
   449       {
   498       $dh_secret_check = sha1($dh_secret);
   450         die(enano_json_encode(array(
   499       $dh_hash = $_POST['crypt_key'];
   451             'mode' => 'error',
   500       if ( $dh_secret_check !== $dh_hash )
   452             'error' => 'Diffie Hellman redundancy check failed, couldn\'t rebuild the AES key.',
   501       {
   453             'debug' => array(
   502         die_semicritical('DiffieHellman error', 'ERR_DH_HASH_NO_MATCH');
   454               'server private key' => $privkey_server,
   503       }
   455               'client public key' => $data['publickey_client'],
   504       
   456               'expected sha1' => $data['crypt_key_check'],
   505       // All good! Generate the AES key
   457               'actual sha1' => $secret_check
   506       $aes_key = substr(sha256($dh_secret), 0, ( AES_BITS / 4 ));
   458               )
   507       
   459           )));
   508       // decrypt user info
   460       }
   509       $aes_key = hexdecode($aes_key);
   461       // we have the secret, now get the sha256 hash
   510       $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
   462       $crypt_key = substr(sha256($dh_secret), 0, ( AES_BITS / 4 ));
   511       $password = $aes->decrypt($_POST['crypt_data'], $aes_key, ENC_HEX);
   463     }
   512       
   464     else if ( !$data['diffiehellman'] && isset($data['crypt_key']) && isset($data['crypt_data']) )
   513       $result = $session->login_without_crypto($_POST['username'], $password, false, intval($_POST['auth_level']), $captcha_hash, $captcha_code);
   465     {
       
   466       $crypt_key = $data['crypt_key'];
       
   467     }
       
   468     else
       
   469     {
       
   470       die('Special:Login: Illegal request');
       
   471     }
       
   472     
       
   473     $result = $session->login_with_crypto($data['username'], $data['crypt_data'], $crypt_key, $data['challenge'], $level, $captcha_hash, $captcha_code, !$dh_supported);
       
   474     
       
   475     if ( $result['success'] )
       
   476     {
       
   477       $response = Array(
       
   478           'result' => 'success',
       
   479           'key' => $session->sid_super // ( ( $session->sid_super ) ? $session->sid_super : $session->sid )
       
   480         );
       
   481     }
       
   482     else
       
   483     {
       
   484       $captcha = '';
       
   485       if ( $result['error'] == 'locked_out' && $result['lockout_policy'] == 'captcha' )
       
   486       {
       
   487         $session->kill_captcha();
       
   488         $captcha = $session->make_captcha();
       
   489       }
       
   490       $response = Array(
       
   491           'result' => 'error',
       
   492           'data' => $result,
       
   493           'captcha' => $captcha
       
   494         );
       
   495     }
       
   496     $response = enano_json_encode($response);
       
   497     echo $response;
       
   498     $db->close();
       
   499     exit;
       
   500   }
       
   501   if(isset($_POST['login'])) {
       
   502     $captcha_hash = ( isset($_POST['captcha_hash']) ) ? $_POST['captcha_hash'] : false;
       
   503     $captcha_code = ( isset($_POST['captcha_code']) ) ? $_POST['captcha_code'] : false;
       
   504     if($_POST['use_crypt'] == 'yes')
       
   505     {
       
   506       $result = $session->login_with_crypto($_POST['username'], $_POST['crypt_data'], $_POST['crypt_key'], $_POST['challenge_data'], intval($_POST['auth_level']), $captcha_hash, $captcha_code);
       
   507     }
   514     }
   508     else
   515     else
   509     {
   516     {
   510       $result = $session->login_without_crypto($_POST['username'], $_POST['pass'], false, intval($_POST['auth_level']), $captcha_hash, $captcha_code);
   517       $result = $session->login_without_crypto($_POST['username'], $_POST['pass'], false, intval($_POST['auth_level']), $captcha_hash, $captcha_code);
   511     }
   518     }