mirror of
https://github.com/renbaoshuo/S2OJ.git
synced 2024-11-23 11:58:41 +00:00
96d4a3ecf7
Due to historical reasons, the code is in subfolder "1". With SVN removal, we place the code back and remove the annoying "1" folder.
185 lines
5.1 KiB
PHP
185 lines
5.1 KiB
PHP
<?php
|
|
/*
|
|
* ntlm_sasl_client.php
|
|
*
|
|
* @(#) $Id: ntlm_sasl_client.php,v 1.3 2004/11/17 08:00:37 mlemos Exp $
|
|
*
|
|
**
|
|
** Source: http://www.phpclasses.org/browse/file/7495.html
|
|
** License: BSD (http://www.phpclasses.org/package/1888-PHP-Single-API-for-standard-authentication-mechanisms.html)
|
|
** Bundled with Permission
|
|
**
|
|
*/
|
|
|
|
define("SASL_NTLM_STATE_START", 0);
|
|
define("SASL_NTLM_STATE_IDENTIFY_DOMAIN", 1);
|
|
define("SASL_NTLM_STATE_RESPOND_CHALLENGE", 2);
|
|
define("SASL_NTLM_STATE_DONE", 3);
|
|
|
|
class ntlm_sasl_client_class
|
|
{
|
|
var $credentials=array();
|
|
var $state=SASL_NTLM_STATE_START;
|
|
|
|
Function Initialize(&$client)
|
|
{
|
|
if(!function_exists($function="mcrypt_encrypt")
|
|
|| !function_exists($function="mhash"))
|
|
{
|
|
$extensions=array(
|
|
"mcrypt_encrypt"=>"mcrypt",
|
|
"mhash"=>"mhash"
|
|
);
|
|
$client->error="the extension ".$extensions[$function]." required by the NTLM SASL client class is not available in this PHP configuration";
|
|
return(0);
|
|
}
|
|
return(1);
|
|
}
|
|
|
|
Function ASCIIToUnicode($ascii)
|
|
{
|
|
for($unicode="",$a=0;$a<strlen($ascii);$a++)
|
|
$unicode.=substr($ascii,$a,1).chr(0);
|
|
return($unicode);
|
|
}
|
|
|
|
Function TypeMsg1($domain,$workstation)
|
|
{
|
|
$domain_length=strlen($domain);
|
|
$workstation_length=strlen($workstation);
|
|
$workstation_offset=32;
|
|
$domain_offset=$workstation_offset+$workstation_length;
|
|
return(
|
|
"NTLMSSP\0".
|
|
"\x01\x00\x00\x00".
|
|
"\x07\x32\x00\x00".
|
|
pack("v",$domain_length).
|
|
pack("v",$domain_length).
|
|
pack("V",$domain_offset).
|
|
pack("v",$workstation_length).
|
|
pack("v",$workstation_length).
|
|
pack("V",$workstation_offset).
|
|
$workstation.
|
|
$domain
|
|
);
|
|
}
|
|
|
|
Function NTLMResponse($challenge,$password)
|
|
{
|
|
$unicode=$this->ASCIIToUnicode($password);
|
|
$md4=mhash(MHASH_MD4,$unicode);
|
|
$padded=$md4.str_repeat(chr(0),21-strlen($md4));
|
|
$iv_size=mcrypt_get_iv_size(MCRYPT_DES,MCRYPT_MODE_ECB);
|
|
$iv=mcrypt_create_iv($iv_size,MCRYPT_RAND);
|
|
for($response="",$third=0;$third<21;$third+=7)
|
|
{
|
|
for($packed="",$p=$third;$p<$third+7;$p++)
|
|
$packed.=str_pad(decbin(ord(substr($padded,$p,1))),8,"0",STR_PAD_LEFT);
|
|
for($key="",$p=0;$p<strlen($packed);$p+=7)
|
|
{
|
|
$s=substr($packed,$p,7);
|
|
$b=$s.((substr_count($s,"1") % 2) ? "0" : "1");
|
|
$key.=chr(bindec($b));
|
|
}
|
|
$ciphertext=mcrypt_encrypt(MCRYPT_DES,$key,$challenge,MCRYPT_MODE_ECB,$iv);
|
|
$response.=$ciphertext;
|
|
}
|
|
return $response;
|
|
}
|
|
|
|
Function TypeMsg3($ntlm_response,$user,$domain,$workstation)
|
|
{
|
|
$domain_unicode=$this->ASCIIToUnicode($domain);
|
|
$domain_length=strlen($domain_unicode);
|
|
$domain_offset=64;
|
|
$user_unicode=$this->ASCIIToUnicode($user);
|
|
$user_length=strlen($user_unicode);
|
|
$user_offset=$domain_offset+$domain_length;
|
|
$workstation_unicode=$this->ASCIIToUnicode($workstation);
|
|
$workstation_length=strlen($workstation_unicode);
|
|
$workstation_offset=$user_offset+$user_length;
|
|
$lm="";
|
|
$lm_length=strlen($lm);
|
|
$lm_offset=$workstation_offset+$workstation_length;
|
|
$ntlm=$ntlm_response;
|
|
$ntlm_length=strlen($ntlm);
|
|
$ntlm_offset=$lm_offset+$lm_length;
|
|
$session="";
|
|
$session_length=strlen($session);
|
|
$session_offset=$ntlm_offset+$ntlm_length;
|
|
return(
|
|
"NTLMSSP\0".
|
|
"\x03\x00\x00\x00".
|
|
pack("v",$lm_length).
|
|
pack("v",$lm_length).
|
|
pack("V",$lm_offset).
|
|
pack("v",$ntlm_length).
|
|
pack("v",$ntlm_length).
|
|
pack("V",$ntlm_offset).
|
|
pack("v",$domain_length).
|
|
pack("v",$domain_length).
|
|
pack("V",$domain_offset).
|
|
pack("v",$user_length).
|
|
pack("v",$user_length).
|
|
pack("V",$user_offset).
|
|
pack("v",$workstation_length).
|
|
pack("v",$workstation_length).
|
|
pack("V",$workstation_offset).
|
|
pack("v",$session_length).
|
|
pack("v",$session_length).
|
|
pack("V",$session_offset).
|
|
"\x01\x02\x00\x00".
|
|
$domain_unicode.
|
|
$user_unicode.
|
|
$workstation_unicode.
|
|
$lm.
|
|
$ntlm
|
|
);
|
|
}
|
|
|
|
Function Start(&$client, &$message, &$interactions)
|
|
{
|
|
if($this->state!=SASL_NTLM_STATE_START)
|
|
{
|
|
$client->error="NTLM authentication state is not at the start";
|
|
return(SASL_FAIL);
|
|
}
|
|
$this->credentials=array(
|
|
"user"=>"",
|
|
"password"=>"",
|
|
"realm"=>"",
|
|
"workstation"=>""
|
|
);
|
|
$defaults=array();
|
|
$status=$client->GetCredentials($this->credentials,$defaults,$interactions);
|
|
if($status==SASL_CONTINUE)
|
|
$this->state=SASL_NTLM_STATE_IDENTIFY_DOMAIN;
|
|
Unset($message);
|
|
return($status);
|
|
}
|
|
|
|
Function Step(&$client, $response, &$message, &$interactions)
|
|
{
|
|
switch($this->state)
|
|
{
|
|
case SASL_NTLM_STATE_IDENTIFY_DOMAIN:
|
|
$message=$this->TypeMsg1($this->credentials["realm"],$this->credentials["workstation"]);
|
|
$this->state=SASL_NTLM_STATE_RESPOND_CHALLENGE;
|
|
break;
|
|
case SASL_NTLM_STATE_RESPOND_CHALLENGE:
|
|
$ntlm_response=$this->NTLMResponse(substr($response,24,8),$this->credentials["password"]);
|
|
$message=$this->TypeMsg3($ntlm_response,$this->credentials["user"],$this->credentials["realm"],$this->credentials["workstation"]);
|
|
$this->state=SASL_NTLM_STATE_DONE;
|
|
break;
|
|
case SASL_NTLM_STATE_DONE:
|
|
$client->error="NTLM authentication was finished without success";
|
|
return(SASL_FAIL);
|
|
default:
|
|
$client->error="invalid NTLM authentication step state";
|
|
return(SASL_FAIL);
|
|
}
|
|
return(SASL_CONTINUE);
|
|
}
|
|
};
|
|
|
|
?>
|