diff --git a/apps/user_ldap/lib/access.php b/apps/user_ldap/lib/access.php index 44162e32d4..12c6f8118d 100644 --- a/apps/user_ldap/lib/access.php +++ b/apps/user_ldap/lib/access.php @@ -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)); } /** diff --git a/apps/user_ldap/tests/access.php b/apps/user_ldap/tests/access.php index f436784675..8ff3980080 100644 --- a/apps/user_ldap/tests/access.php +++ b/apps/user_ldap/tests/access.php @@ -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); diff --git a/apps/user_ldap/tests/data/sid.dat b/apps/user_ldap/tests/data/sid.dat deleted file mode 100644 index 3d500c6a87..0000000000 Binary files a/apps/user_ldap/tests/data/sid.dat and /dev/null differ