From d1410b46a9822aefc6547db95add1c1f7fa1f617 Mon Sep 17 00:00:00 2001 From: Andreas Fischer Date: Fri, 19 Sep 2014 00:01:57 +0200 Subject: [PATCH] user_ldap: Reimplement convertSID2Str() without BCMath dependency. Also explicitly format sub-id integers as unsigned, which is required for 32-bit systems. --- apps/user_ldap/lib/access.php | 48 +++++++++++++---------- apps/user_ldap/tests/access.php | 63 ++++++++++++++---------------- apps/user_ldap/tests/data/sid.dat | Bin 24 -> 0 bytes 3 files changed, 57 insertions(+), 54 deletions(-) delete mode 100644 apps/user_ldap/tests/data/sid.dat diff --git a/apps/user_ldap/lib/access.php b/apps/user_ldap/lib/access.php index 159b0d7300..8db0a9cfae 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 3d500c6a872f3c8904df6fe85af623dbce42b0b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24 bcmZQ%VE_SEQ6RCb@hP8gPLB2|Bi48TCDsJ$