Also explicitly format sub-id integers as unsigned, which is required for 32-bit systems.tags/v8.0.0alpha1
@@ -1316,32 +1316,38 @@ class Access extends LDAPUtility implements user\IUserTools { | |||
* converts a binary SID into a string representation | |||
* @param string $sid | |||
* @return string | |||
* @link http://blogs.freebsdish.org/tmclaugh/2010/07/21/finding-a-users-primary-group-in-ad/#comment-2855 | |||
*/ | |||
public function convertSID2Str($sid) { | |||
try { | |||
if(!function_exists('bcadd')) { | |||
\OCP\Util::writeLog('user_ldap', | |||
'You need to install bcmath module for PHP to have support ' . | |||
'for AD primary groups', \OCP\Util::WARN); | |||
throw new \Exception('missing bcmath module'); | |||
} | |||
$srl = ord($sid[0]); | |||
$numberSubID = ord($sid[1]); | |||
$x = substr($sid, 2, 6); | |||
$h = unpack('N', "\x0\x0" . substr($x,0,2)); | |||
$l = unpack('N', substr($x,2,6)); | |||
$iav = bcadd(bcmul($h[1], bcpow(2,32)), $l[1]); | |||
$subIDs = array(); | |||
for ($i=0; $i<$numberSubID; $i++) { | |||
$subID = unpack('V', substr($sid, 8+4*$i, 4)); | |||
$subIDs[] = $subID[1]; | |||
} | |||
} catch (\Exception $e) { | |||
// The format of a SID binary string is as follows: | |||
// 1 byte for the revision level | |||
// 1 byte for the number n of variable sub-ids | |||
// 6 bytes for identifier authority value | |||
// n*4 bytes for n sub-ids | |||
// | |||
// Example: 010400000000000515000000a681e50e4d6c6c2bca32055f | |||
// Legend: RRNNAAAAAAAAAAAA11111111222222223333333344444444 | |||
$revision = ord($sid[0]); | |||
$numberSubID = ord($sid[1]); | |||
$subIdStart = 8; // 1 + 1 + 6 | |||
$subIdLength = 4; | |||
if (strlen($sid) !== $subIdStart + $subIdLength * $numberSubID) { | |||
// Incorrect number of bytes present. | |||
return ''; | |||
} | |||
return sprintf('S-%d-%d-%s', $srl, $iav, implode('-', $subIDs)); | |||
// 6 bytes = 48 bits can be represented using floats without loss of | |||
// precision (see https://gist.github.com/bantu/886ac680b0aef5812f71) | |||
$iav = number_format(hexdec(bin2hex(substr($sid, 2, 6))), 0, '', ''); | |||
$subIDs = array(); | |||
for ($i = 0; $i < $numberSubID; $i++) { | |||
$subID = unpack('V', substr($sid, $subIdStart + $subIdLength * $i, $subIdLength)); | |||
$subIDs[] = sprintf('%u', $subID[1]); | |||
} | |||
// Result for example above: S-1-5-21-249921958-728525901-1594176202 | |||
return sprintf('S-%d-%s-%s', $revision, $iav, implode('-', $subIDs)); | |||
} | |||
/** |
@@ -78,55 +78,52 @@ class Test_Access extends \PHPUnit_Framework_TestCase { | |||
$this->assertTrue($expected === $access->escapeFilterPart($input)); | |||
} | |||
public function testConvertSID2StrSuccess() { | |||
/** @dataProvider convertSID2StrSuccessData */ | |||
public function testConvertSID2StrSuccess(array $sidArray, $sidExpected) { | |||
list($lw, $con, $um) = $this->getConnecterAndLdapMock(); | |||
$access = new Access($con, $lw, $um); | |||
if(!function_exists('\bcadd')) { | |||
$this->markTestSkipped('bcmath not available'); | |||
} | |||
$sidBinary = file_get_contents(__DIR__ . '/data/sid.dat'); | |||
$sidExpected = 'S-1-5-21-249921958-728525901-1594176202'; | |||
$sidBinary = implode('', $sidArray); | |||
$this->assertSame($sidExpected, $access->convertSID2Str($sidBinary)); | |||
} | |||
public function convertSID2StrSuccessData() { | |||
return array( | |||
array( | |||
array( | |||
"\x01", | |||
"\x04", | |||
"\x00\x00\x00\x00\x00\x05", | |||
"\x15\x00\x00\x00", | |||
"\xa6\x81\xe5\x0e", | |||
"\x4d\x6c\x6c\x2b", | |||
"\xca\x32\x05\x5f", | |||
), | |||
'S-1-5-21-249921958-728525901-1594176202', | |||
), | |||
array( | |||
array( | |||
"\x01", | |||
"\x02", | |||
"\xFF\xFF\xFF\xFF\xFF\xFF", | |||
"\xFF\xFF\xFF\xFF", | |||
"\xFF\xFF\xFF\xFF", | |||
), | |||
'S-1-281474976710655-4294967295-4294967295', | |||
), | |||
); | |||
} | |||
public function testConvertSID2StrInputError() { | |||
list($lw, $con, $um) = $this->getConnecterAndLdapMock(); | |||
$access = new Access($con, $lw, $um); | |||
if(!function_exists('\bcadd')) { | |||
$this->markTestSkipped('bcmath not available'); | |||
} | |||
$sidIllegal = 'foobar'; | |||
$sidExpected = ''; | |||
$this->assertSame($sidExpected, $access->convertSID2Str($sidIllegal)); | |||
} | |||
public function testConvertSID2StrNoBCMath() { | |||
if(function_exists('\bcadd')) { | |||
$removed = false; | |||
if(function_exists('runkit_function_remove')) { | |||
$removed = !runkit_function_remove('\bcadd'); | |||
} | |||
if(!$removed) { | |||
$this->markTestSkipped('bcadd could not be removed for ' . | |||
'testing without bcmath'); | |||
} | |||
} | |||
list($lw, $con, $um) = $this->getConnecterAndLdapMock(); | |||
$access = new Access($con, $lw, $um); | |||
$sidBinary = file_get_contents(__DIR__ . '/data/sid.dat'); | |||
$sidExpected = ''; | |||
$this->assertSame($sidExpected, $access->convertSID2Str($sidBinary)); | |||
} | |||
public function testGetDomainDNFromDNSuccess() { | |||
list($lw, $con, $um) = $this->getConnecterAndLdapMock(); | |||
$access = new Access($con, $lw, $um); |