-
-
Save rmbolger/bc24d4fb3e0a729c322a56f0ec621eb8 to your computer and use it in GitHub Desktop.
function Get-UidFromSid | |
{ | |
[CmdletBinding()] | |
param( | |
[Parameter(Mandatory=$true,Position=0,ValueFromPipeline,ValueFromPipelineByPropertyName)] | |
[System.Security.Principal.SecurityIdentifier]$sid | |
) | |
Process { | |
# convert sid to byte array | |
$sidBytes = New-Object byte[] $sid.BinaryLength | |
$sid.GetBinaryForm($sidBytes, 0) | |
Write-Verbose ("SID bytes: $([System.BitConverter]::ToString($sidBytes))") | |
# copy the sections we need | |
$ridDomainBytes = New-Object byte[] 8 | |
[System.Array]::Copy($sidBytes, 16, $ridDomainBytes, 0, 4) | |
$ridUserBytes = New-Object byte[] 8 | |
[System.Array]::Copy($sidBytes, 24, $ridUserBytes, 0, 4) | |
Write-Verbose ("Domain portion: $([System.BitConverter]::ToString($ridDomainBytes))") | |
Write-Verbose ("User portion: $([System.BitConverter]::ToString($ridUserBytes))") | |
# fix endian'ness if necessary | |
if (![System.BitConverter]::IsLittleEndian) | |
{ | |
[System.Array]::Reverse($ridDomainBytes) | |
[System.Array]::Reverse($ridUserBytes) | |
} | |
# convert the byte arrays to longs | |
$ridDomain = [System.BitConverter]::ToInt64($ridDomainBytes, 0); | |
$ridUser = [System.BitConverter]::ToInt64($ridUserBytes, 0); | |
Write-Verbose "Domain(Int64) = $ridDomain, User(Int64) = $ridUser" | |
# Now we're going to use the first 9 bits of the domain rid followed by the | |
# first 22 bits of the user rid to make a single 31 bit integer (32-bit signed) | |
# that will be the new unique UID value for this SID | |
$ridDomain = ($ridDomain -band 0x1ff) -shl 22 | |
$ridUser = $ridUser -band 0x3fffff | |
Write-Verbose "Domain(Int64) = $ridDomain, User(Int64) = $ridUser" | |
return ($ridDomain + $ridUser) | |
} | |
<# | |
.SYNOPSIS | |
Calculate the UID value for a Windows SID. | |
.DESCRIPTION | |
This function duplicates Centrify's algorithm for generating unique UID | |
values for Active Directory users and groups. The original algorithm was | |
provided by Centrify and ported to PowerShell by Ryan Bolger. | |
.PARAMETER sid | |
The SecurityIdentifier (SID) object to calculate against. | |
.OUTPUTS | |
System.Int32 value of the resulting UID. | |
.EXAMPLE | |
Get-UidFromSid ([System.Security.Principal.SecurityIdentifier]'S-1-5-21-3040497277-3966670145-4188292625-1137') | |
Calculate a UID from a fictional SID. | |
.EXAMPLE | |
Get-ADUser myuser | Get-UidFromSid | |
Calculate a UID from an existing Active Directory user via pipeline input. | |
#> | |
} |
// using System; | |
// using System.Security.Principal; | |
public static long GetUidFromSid(SecurityIdentifier sid) | |
{ | |
//convert to byte array | |
byte[] sidBytes = new byte[sid.BinaryLength]; | |
sid.GetBinaryForm(sidBytes, 0); | |
// copy the sections we need | |
byte[] ridDomainBytes = new byte[8]; | |
Array.Copy(sidBytes, 16, ridDomainBytes, 0, 4); | |
byte[] ridUserBytes = new byte[8]; | |
Array.Copy(sidBytes, 24, ridUserBytes, 0, 4); | |
// fix endian'ness if necessary | |
if (!BitConverter.IsLittleEndian) | |
{ | |
Array.Reverse(ridDomainBytes); | |
Array.Reverse(ridUserBytes); | |
} | |
// convert the byte arrays to longs | |
long ridDomain = BitConverter.ToInt64(ridDomainBytes, 0); | |
long ridUser = BitConverter.ToInt64(ridUserBytes, 0); | |
// Now we're going to use the first 9 bits of the domain rid followed by the | |
// first 22 bits of the user rid to make a single 31 bit integer (32-bit signed) | |
// that will be the new unique UID value for this SID | |
ridDomain = (ridDomain & 0x1ff) << 22; | |
ridUser = ridUser & 0x3fffff; | |
return (ridDomain + ridUser); | |
} |
from __future__ import print_function | |
import sys | |
# This script is designed to accept a SID in SDDL format from stdin and output | |
# a UID value that can be used in the uidNumber or gidNumber attribute on an | |
# Active Directory domain object. The algorithm was originally provided by | |
# Centrify and has been ported to Python by Ryan Bolger. | |
# The code was originally written for Python 2.6.6 on RHEL 6 and has also been | |
# tested with Python 2.7.6 on Windows. | |
# All verbose output should be written to stderr and the only output in stdout | |
# should be the UID/GID value. | |
# Usage examples: | |
# | |
# echo S-1-5-21-3040497277-3966670145-4188292625-1137 | python SIDtoUID.py | |
# adquery user da06076 --sid | python SIDtoUID.py | |
# | |
# The SID in the example above should convert to UID 1346372721 | |
def SIDtoUID(strSid): | |
# An Active Directory SID in SDDL form for non-built-in users/groups should | |
# always be in the following format: | |
# S-1-5-21-XXXXXXXXXX-XXXXXXXXXXX-XXXXXXXXXX-YYYY | |
# The X's are three 32-bit integers that comprise the 96-bit randomly | |
# generated domain identifier | |
# The Y's are a single 32-bit integer that is the object's relative ID in | |
# the domain (RID) | |
# For the purpose of this algorithm, we only care about the second section of | |
# the domain identifier and the user/group RID. So instead of fully parsing | |
# the complete SDDL into its binary form, we're going to take a short cut and | |
# just grab those chunks with only some basic sanity checking. | |
# make sure the beginning looks right | |
if not strSid.startswith('S-1-5-21-'): | |
print("ERROR: SID string was invalid.", file=sys.stderr) | |
exit(1) | |
# make sure we have the right number of elements | |
elements = strSid.upper().split("-") | |
if len(elements) != 8: | |
print("ERROR: Not enough sub-authority elements found.", file=sys.stderr) | |
exit(1) | |
# grab the elements we care about | |
ridDomain = int(elements[5]) | |
ridUser = int(elements[7]) | |
# Now we're going to use the first 9 bits of the domain rid followed by the | |
# first 22 bits of the user rid to make a single 31 bit integer (32-bit signed) | |
# that will be the new unique UID value for this SID | |
ridDomain = (ridDomain & 0x1ff) << 22 | |
ridUser = ridUser & 0x3fffff | |
uid = ridDomain + ridUser | |
return uid | |
for line in sys.stdin: | |
print(SIDtoUID(line)) | |
#!/usr/bin/env bash | |
# This script is designed to accept a SID in SDDL format from stdin and output | |
# a UID value that can be used in the uidNumber or gidNumber attribute on an | |
# Active Directory domain object. The algorithm was originally provided by | |
# Centrify and has been ported to Bash by Ryan Bolger. | |
# All verbose output should be written to stderr and the only output in stdout | |
# should be the UID/GID value. | |
# Usage examples: | |
# | |
# echo S-1-5-21-3040497277-3966670145-4188292625-1137 | ./SIDtoUID.sh | |
# adquery user da06076 --sid | ./SIDtoUID.sh | |
# | |
# The SID in the example above should convert to UID 1346372721 | |
set -o nounset -o pipefail | |
#set -x | |
SIDtoUID() | |
{ | |
# make sure the beginning looks right | |
if [[ $1 != S-1-5-21-* ]]; then | |
>&2 echo "ERROR: SID string was invalid." | |
exit 1 | |
fi | |
# make sure we have the right number of elements | |
IFS='-' read -ra elements <<< "$1" | |
if [[ ${#elements[@]} != 8 ]]; then | |
>&2 echo "ERROR: Not enough sub-authority elements found." | |
exit 1 | |
fi | |
# grab the elements we care about | |
ridDomain=${elements[5]} | |
ridUser=${elements[7]} | |
# Now we're going to use the first 9 bits of the domain rid followed by the | |
# first 22 bits of the user rid to make a single 31 bit integer (32-bit signed) | |
# that will be the new unique UID value for this SID | |
let "ridDomain = ($ridDomain & 0x1ff) << 22" | |
let "ridUser = ($ridUser & 0x3fffff)" | |
let "uid = $ridDomain + $ridUser" | |
echo $uid | |
} | |
# grab SIDs from file in first argument or stdin | |
while read sid; do | |
SIDtoUID $sid | |
done < "${1:-/dev/stdin}" |
I saw that you updated the gist, thank you very much @rmbolger! May I suggest to edit your answer at https://serverfault.com/a/748395/120699 to add a link to this gist (so that others can learn from it)?
Done
Is there known way in Python or bash for converting a SID to a UID like in SSSD ? The provided code is not consistent with SSSD. For example:
SIDtoUID.sh returns 210303094 for S-1-5-21-527237240-706699826-725345543-587894 and SSSD returns 589787894.
I'm not super familiar with SSSD, but I would think it is either using a different algorithm to generate the UI or it's not generating anything and simply returning the value that was already set in AD for that user.
@rmbolger since the same function can also be used to generate GIDs I modified your code a little bit
function Get-UniqueIDFromSid
{
[CmdletBinding()]
param(
[Parameter(Mandatory=$true,Position=0,ValueFromPipeline,ValueFromPipelineByPropertyName)]
[System.Security.Principal.SecurityIdentifier]$sid
)
Process {
# convert sid to byte array
$sidBytes = New-Object byte[] $sid.BinaryLength
$sid.GetBinaryForm($sidBytes, 0)
Write-Verbose ("SID bytes: $([System.BitConverter]::ToString($sidBytes))")
# copy the sections we need
$ridDomainBytes = New-Object byte[] 8
[System.Array]::Copy($sidBytes, 16, $ridDomainBytes, 0, 4)
$ridUserOrGroupBytes = New-Object byte[] 8
[System.Array]::Copy($sidBytes, 24, $ridUserOrGroupBytes, 0, 4)
Write-Verbose ("Domain portion: $([System.BitConverter]::ToString($ridDomainBytes))")
Write-Verbose ("User/Group portion: $([System.BitConverter]::ToString($ridUserOrGroupBytes))")
# fix endian'ness if necessary
if (![System.BitConverter]::IsLittleEndian)
{
[System.Array]::Reverse($ridDomainBytes)
[System.Array]::Reverse($ridUserOrGroupBytes)
}
# convert the byte arrays to longs
$ridDomain = [System.BitConverter]::ToInt64($ridDomainBytes, 0);
$ridUserOrGroup = [System.BitConverter]::ToInt64($ridUserOrGroupBytes, 0);
Write-Verbose "Domain(Int64) = $ridDomain, User/Group(Int64) = $ridUserOrGroup"
# Now we're going to use the first 9 bits of the domain rid followed by the
# first 22 bits of the user/group rid to make a single 31 bit integer (32-bit signed)
# that will be the new unique UID/GID value for this SID
$ridDomain = ($ridDomain -band 0x1ff) -shl 22
$ridUserOrGroup = $ridUserOrGroup -band 0x3fffff
Write-Verbose "Domain(Int64) = $ridDomain, User/Group(Int64) = $ridUserOrGroup"
return ($ridDomain + $ridUserOrGroup)
}
<#
.SYNOPSIS
Calculate the UID/GID value for a Windows SID.
.DESCRIPTION
This function duplicates Centrify's algorithm for generating unique UID/GID
values for Active Directory users and groups. The original algorithm was
provided by Centrify and ported to PowerShell by Ryan Bolger.
.PARAMETER sid
The SecurityIdentifier (SID) object to calculate against.
.OUTPUTS
System.Int32 value of the resulting UID/GID.
.EXAMPLE
Get-UniqueIDFromSid ([System.Security.Principal.SecurityIdentifier]'S-1-5-21-3040497277-3966670145-4188292625-1137')
Calculate a UID/GID from a fictional SID.
.EXAMPLE
Get-ADUser myuser | Get-UniqueIDFromSid
Calculate a UID from an existing Active Directory user via pipeline input.
.EXAMPLE
Get-ADGroup mygroup | Get-UniqueIDFromSid
Calculate a GID from an existing Active Directory group via pipeline input.
#>
}
Had to go searching for the old code, but happy to oblige.