]> source.dussan.org Git - nextcloud-server.git/commitdiff
user_ldap: Reimplement convertSID2Str() without BCMath dependency.
authorAndreas Fischer <bantu@owncloud.com>
Thu, 18 Sep 2014 22:01:57 +0000 (00:01 +0200)
committerMorris Jobke <hey@morrisjobke.de>
Wed, 12 Nov 2014 18:47:44 +0000 (19:47 +0100)
Also explicitly format sub-id integers as unsigned, which is required for
32-bit systems.

apps/user_ldap/lib/access.php
apps/user_ldap/tests/access.php
apps/user_ldap/tests/data/sid.dat [deleted file]

index a2ca16dcda337e05a1b7647c3e9d59424eee4917..d89029abf1795bcfc1d777a831952212dca06304 100644 (file)
@@ -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));
        }
 
        /**
index f436784675dcff53bb71cc23f1366efdea327590..8ff39800808171978f950f93dd6398c82c930310 100644 (file)
@@ -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 (file)
index 3d500c6..0000000
Binary files a/apps/user_ldap/tests/data/sid.dat and /dev/null differ