Reputation: 1278
I want to retrieve base64 encoded objectSid from an LDAP query to an Active Directory database and convert them to the standard SID representation. Can you please give me a Python snippet that does that?
Upvotes: 7
Views: 7442
Reputation: 8027
If you're using Linux and have Samba installed:
from samba.dcerpc import security
from samba.ndr import ndr_unpack
def convert(binary_sid):
return str(ndr_unpack(security.dom_sid, binary_sid))
Where binary_sid
is the binary representation of the sid.
Upvotes: 3
Reputation: 5949
use or see implementation in ldap3
ldap-doc
source
ldap3.protocol.formatters.formatters.format_sid
Upvotes: 8
Reputation: 615
A SID in format S-1-5-21-2562418665-3218585558-1813906818-1576
has the following hex raw format: 010500000000000515000000e967bb98d6b7d7bf82051e6c28060000
and can be break down as follows:
S
: it means simply this is an objectSid01
: (1) is the revision ans is always 1 as far as I know05
: count of sub authorities or you can simply say dash count minus two000000000005
: (5) big endian15000000
: (21) small endiane967bb98
: (2562418665) small endiand6b7d7bf
: (3218585558) small endian82051e6c
: (1813906818) small endian28060000
: (1576) small endianSmall endian should be read in reverse order. That is how the binary data is represented, where is the least significant byte is stored first. Accordingly Big endian is the order where the most significant byte is stored first. Here is a good article explaining the byte order.
This is a brief introduction about the structure of the objecSid, and this is a nice blog post.
According to these information let's try to read a SID, which is returned as a binary from the LDAP query. The binascii
library can be used for Python 2 as well as for Python 3:
from binascii import b2a_hex
def sid_to_str(sid):
try:
# Python 3
if str is not bytes:
# revision
revision = int(sid[0])
# count of sub authorities
sub_authorities = int(sid[1])
# big endian
identifier_authority = int.from_bytes(sid[2:8], byteorder='big')
# If true then it is represented in hex
if identifier_authority >= 2 ** 32:
identifier_authority = hex(identifier_authority)
# loop over the count of small endians
sub_authority = '-' + '-'.join([str(int.from_bytes(sid[8 + (i * 4): 12 + (i * 4)], byteorder='little')) for i in range(sub_authorities)])
# Python 2
else:
revision = int(b2a_hex(sid[0]))
sub_authorities = int(b2a_hex(sid[1]))
identifier_authority = int(b2a_hex(sid[2:8]), 16)
if identifier_authority >= 2 ** 32:
identifier_authority = hex(identifier_authority)
sub_authority = '-' + '-'.join([str(int(b2a_hex(sid[11 + (i * 4): 7 + (i * 4): -1]), 16)) for i in range(sub_authorities)])
objectSid = 'S-' + str(revision) + '-' + str(identifier_authority) + sub_authority
return objectSid
except Exception:
pass
return sid
sid = b'\x01\x05\x00\x00\x00\x00\x00\x05\x15\x00\x00\x00\xe9\x67\xbb\x98\xd6\xb7\xd7\xbf\x82\x05\x1e\x6c\x28\x06\x00\x00'
print(sid_to_str(sid)) # S-1-5-21-2562418665-3218585558-1813906818-1576
Upvotes: 5
Reputation: 3411
This is @Giovanni Mascellani answer, adapted for Python 3.x:
import struct
def convert(binary):
version = struct.unpack('B', binary[0:1])[0]
# I do not know how to treat version != 1 (it does not exist yet)
assert version == 1, version
length = struct.unpack('B', binary[1:2])[0]
authority = struct.unpack(b'>Q', b'\x00\x00' + binary[2:8])[0]
string = 'S-%d-%d' % (version, authority)
binary = binary[8:]
assert len(binary) == 4 * length
for i in range(length):
value = struct.unpack('<L', binary[4*i:4*(i+1)])[0]
string += '-%d' % value
return string
Upvotes: 9
Reputation: 1278
This should do the trick:
import struct
def convert(binary):
version = struct.unpack('B', binary[0])[0]
# I do not know how to treat version != 1 (it does not exist yet)
assert version == 1, version
length = struct.unpack('B', binary[1])[0]
authority = struct.unpack('>Q', '\x00\x00' + binary[2:8])[0]
string = 'S-%d-%d' % (version, authority)
binary = binary[8:]
assert len(binary) == 4 * length
for i in xrange(length):
value = struct.unpack('<L', binary[4*i:4*(i+1)])[0]
string += '-%d' % value
return string
References: http://blogs.msdn.com/b/oldnewthing/archive/2004/03/15/89753.aspx and http://codeimpossible.com/2008/04/07/Converting-a-Security-Identifier-from-binary-to-string/.
Upvotes: 12