{"id":865,"date":"2012-02-28T13:24:56","date_gmt":"2012-02-28T12:24:56","guid":{"rendered":"http:\/\/web03.partners.extranet.chrisse.com\/?p=865"},"modified":"2012-02-28T13:24:56","modified_gmt":"2012-02-28T12:24:56","slug":"how-the-active-directory-data-store-really-works-inside-ntds-dit-code-1-3","status":"publish","type":"post","link":"https:\/\/blog.chrisse.se\/?p=865","title":{"rendered":"How the Active Directory &#8211; Data Store Really Works (Inside NTDS.dit) &#8211; Code [1-3]"},"content":{"rendered":"<p>So what is the &#8220;Code [1-3]&#8221; all about and where is Part 4 of the series that you might expect?<br \/>\nBefore I go ahead with Part 4 I thought it would be a good idea to sum up Part 1 to Part 3 with code (So that you know how we figured out all this stuff while we was coding on ESEDump) \u2013 Note: This most may be targeted for the developer audience more than the general Active Directory administrator.<\/p>\n<p><strong>Disclaimer: <\/strong><em>The code samples provided here is code snippets that doesn&#8217;t represent any code actual code from the DSA and or any other Microsoft products and technologies, nor those they represent the complete source of ESEDump<br \/>\n<\/em><\/p>\n<p><strong><br \/>\nESEHelper \u2013 A managed ESE wrapper around the ESE APIs<br \/>\n<\/strong><\/p>\n<p>We decided that we wanted to work with ESE in C# (and when we first started this project EseManaged from codeplex wasn&#8217;t around) and even if we could have used it later on \u2013 I guess we wanted full control and decided to stick with our own wrapper. So when you see references to &#8220;EseHelper&#8221; in the code snippets below \u2013 you know it&#8217;s just a wrapper around: <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/gg269259(v=exchg.10).aspx\" target=\"_blank\">Extensible Storage Engine Native APIs<\/a> \u2013 there is no secrets around this <span style=\"font-family: Wingdings;\">J<\/span><\/p>\n<p><strong>JET_RETRIVECOLUMN structure custom methods<br \/>\n<\/strong><\/p>\n<p>We extended the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/gg269334(v=exchg.10).aspx\">JET_RETRIVECOLUMN<\/a> structure with some additional methods to retrieve data.<\/p>\n<p style=\"margin-left: 72pt;\"><span style=\"font-family: Franklin Gothic Demi; font-size: 10pt;\">Table\u00a00: JET_RETRIVECOLUMN structure<br \/>\n<\/span><\/p>\n<div style=\"margin-left: 77pt;\">\n<table style=\"border-collapse: collapse;\" border=\"0\">\n<colgroup>\n<col style=\"width: 886px;\" \/><\/colgroup>\n<tbody valign=\"top\">\n<tr style=\"background: #d9d9d9;\">\n<td style=\"padding-left: 7px; padding-right: 7px; border-top: solid gray 1.5pt; border-left: solid gray 1.5pt; border-bottom: solid gray 0.5pt; border-right: solid gray 1.5pt;\" valign=\"middle\">\n<p style=\"text-align: center;\"><span style=\"font-family: Franklin Gothic Demi Cond; font-size: 9pt;\">Code Snippet<\/span><\/p>\n<\/td>\n<\/tr>\n<tr style=\"height: 23px;\">\n<td style=\"padding-left: 7px; padding-right: 7px; border-top: none; border-left: solid gray 1.5pt; border-bottom: solid gray 1.5pt; border-right: solid gray 1.5pt;\"><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ The custom methods in JET_RETRIEVECOLUMN allow us to quickly<\/span><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ interpret each column&#8217;s data depending on its data type (string, integer, etc.)<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">internal<\/span><br \/>\n<span style=\"color: blue;\">struct<\/span><br \/>\n<span style=\"color: #2b91af;\">JET_RETRIEVECOLUMN<\/span><\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">{<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">public<\/span><br \/>\n<span style=\"color: blue;\">int<\/span> columnid;<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">public<\/span> IntPtr pvData; <span style=\"color: green;\">\/\/ Pointer to the data block in memory<\/span><\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">public<\/span><br \/>\n<span style=\"color: blue;\">int<\/span> cbData; <span style=\"color: green;\">\/\/ Size of the allocated data block<\/span><\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">public<\/span><br \/>\n<span style=\"color: blue;\">int<\/span> cbActual; <span style=\"color: green;\">\/\/ Size of the actual\/used data<\/span><\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">public<\/span><br \/>\n<span style=\"color: blue;\">int<\/span> grbit;<\/span><\/p>\n<p><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Offset to the first byte to be retrieved from a column of type<\/span><\/p>\n<p><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ JET_coltypLongBinary or JET_coltypLongText<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">public<\/span><br \/>\n<span style=\"color: blue;\">int<\/span> ibLongValue;<\/span><\/p>\n<p><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Number of values in a multi-valued column<\/span><\/p>\n<p><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Can be used to retrive a specific value<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">public<\/span><br \/>\n<span style=\"color: blue;\">int<\/span> itagSequence;<\/span><\/p>\n<p><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ The columnid of the tagged, multi-valued, or sparse column<\/span><\/p>\n<p><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ when all tagged columns are retrieved by passing 0<\/span><\/p>\n<p><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ as the columnid to JetRetrieveColumn.&#8221;<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">public<\/span><br \/>\n<span style=\"color: blue;\">int<\/span> columnidNextTagged;<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">public<\/span><br \/>\n<span style=\"color: blue;\">int<\/span> err;<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">public<\/span><br \/>\n<span style=\"color: blue;\">void<\/span> Initialize(ColumnInfo att)<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">{<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">this<\/span>.Initialize(att.ID, 0);<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">}<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">public<\/span><br \/>\n<span style=\"color: blue;\">void<\/span> Initialize(ColumnInfo att, <span style=\"color: blue;\">int<\/span> cbData)<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">{<\/span><\/p>\n<p><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Initialize with a data block of cbData size<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">this<\/span>.Initialize(att.ID, cbData);<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">}<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">public<\/span><br \/>\n<span style=\"color: blue;\">void<\/span> Initialize(<span style=\"color: blue;\">int<\/span> columnid)<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">{<\/span><\/p>\n<p><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Initialize with an empty data block<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">this<\/span>.Initialize(columnid, 0);<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">}<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">public<\/span><br \/>\n<span style=\"color: blue;\">void<\/span> Initialize(<span style=\"color: blue;\">int<\/span> columnid, <span style=\"color: blue;\">int<\/span> cbData)<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">{<\/span><\/p>\n<p><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Reset the fields<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">this<\/span>.cbActual = 0;<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">this<\/span>.cbData = 0;<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">this<\/span>.err = 0;<\/span><\/p>\n<p><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Make sure to free any previously used memory in this instance<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">if<\/span> (<span style=\"color: blue;\">this<\/span>.pvData != IntPtr.Zero)<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">{<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">Marshal.FreeHGlobal(<span style=\"color: blue;\">this<\/span>.pvData);<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">this<\/span>.pvData = IntPtr.Zero;<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">}<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">this<\/span>.columnid = columnid;<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">this<\/span>.itagSequence = 1;<\/span><\/p>\n<p><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Allocate a new memory block if necessary (if &gt; 0 bytes requested)<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">this<\/span>.cbData = cbData;<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">if<\/span> (<span style=\"color: blue;\">this<\/span>.cbData &gt; 0)<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">this<\/span>.pvData = Marshal.AllocHGlobal(<span style=\"color: blue;\">this<\/span>.cbData);<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">}<\/span><\/p>\n<p><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Copies the current memory block into a byte array<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">public<\/span><br \/>\n<span style=\"color: blue;\">byte<\/span>[] GetData()<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">{<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">byte<\/span>[] output = <span style=\"color: blue;\">new<\/span><br \/>\n<span style=\"color: blue;\">byte<\/span>[<span style=\"color: blue;\">this<\/span>.cbActual];<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">Marshal.Copy(<span style=\"color: blue;\">this<\/span>.pvData, output, 0, output.Length);<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">return<\/span> output;<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">}<\/span><\/p>\n<p><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Interpret the inner data as a GUID<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">public<\/span> Guid GetGuid()<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">{<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">IntPtr pGuid = <span style=\"color: blue;\">this<\/span>.pvData;<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">byte<\/span>[] bGuid = <span style=\"color: blue;\">new<\/span><br \/>\n<span style=\"color: blue;\">byte<\/span>[16];<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">Marshal.Copy(pGuid, bGuid, 0, bGuid.Length);<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">return<\/span><br \/>\n<span style=\"color: blue;\">new<\/span> Guid(bGuid);<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">}<\/span><\/p>\n<p><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Interpret the inner data as a string (automatically checks ASCII or Unicode encoding)<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">public<\/span><br \/>\n<span style=\"color: blue;\">string<\/span> GetString()<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">{<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">byte<\/span>[] data = <span style=\"color: blue;\">this<\/span>.GetData();<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">if<\/span> (IsUnicode(data))<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">return<\/span> Encoding.Unicode.GetString(data, 0, data.Length);<\/span><\/p>\n<p><span style=\"color: blue; font-family: Consolas; font-size: 9pt;\">else<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">return<\/span> Encoding.ASCII.GetString(data, 0, data.Length);<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">}<\/span><\/p>\n<p><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Interpret the inner data as a 32-bit integer<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">public<\/span><br \/>\n<span style=\"color: blue;\">int<\/span> GetInteger()<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">{<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">return<\/span> BitConverter.ToInt32(<span style=\"color: blue;\">this<\/span>.GetData(), 0);<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">}<\/span><\/p>\n<p><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Interpret the inner data as a 64-bit integer<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">public<\/span><br \/>\n<span style=\"color: blue;\">long<\/span> GetLong()<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">{<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">return<\/span> BitConverter.ToInt64(<span style=\"color: blue;\">this<\/span>.GetData(), 0);<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">}<\/span><\/p>\n<p><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Interpret the inner data as a boolean (true\/false)<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">public<\/span><br \/>\n<span style=\"color: blue;\">bool<\/span> GetBool()<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">{<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">return<\/span> Marshal.ReadByte(<span style=\"color: blue;\">this<\/span>.pvData) == 1 ? <span style=\"color: blue;\">true<\/span> : <span style=\"color: blue;\">false<\/span>;<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">}<\/span><\/p>\n<p><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Determines if a string in a data block is of Unicode or ASCII encoding<\/span><\/p>\n<p><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ TODO: International 2-byte characters unsupported?<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">private<\/span><br \/>\n<span style=\"color: blue;\">bool<\/span> IsUnicode(<span style=\"color: blue;\">byte<\/span>[] data)<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">{<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">bool<\/span> isUnicode = <span style=\"color: blue;\">false<\/span>;<\/span><\/p>\n<p><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Unicode strings&#8217; data always have an even number of bytes<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">if<\/span> (data.Length % 2 == 0)<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">for<\/span> (<span style=\"color: blue;\">int<\/span> i = 0; i &lt; data.Length; i += 2)<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">if<\/span> (data[i + 1] == <span style=\"color: #a31515;\">&#8216;\\0&#8217;<\/span>)<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">isUnicode |= <span style=\"color: blue;\">true<\/span>;<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">return<\/span> isUnicode;<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">}<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">}<\/span><\/p>\n<p><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ ColumnInfo stores column metadata (ID, type, table owner)<\/span><\/p>\n<p><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Used when retrieving JET columns<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">internal<\/span><br \/>\n<span style=\"color: blue;\">struct<\/span><br \/>\n<span style=\"color: #2b91af;\">ColumnInfo<\/span><\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">{<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">public<\/span><br \/>\n<span style=\"color: blue;\">int<\/span> ID;<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">public<\/span><br \/>\n<span style=\"color: blue;\">string<\/span> Name;<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">public<\/span><br \/>\n<span style=\"color: blue;\">int<\/span> DataType;<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">public<\/span><br \/>\n<span style=\"color: blue;\">string<\/span> AltName; <span style=\"color: green;\">\/\/added for attribute name<\/span><\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">public<\/span><br \/>\n<span style=\"color: blue;\">int<\/span> AltId; <span style=\"color: green;\">\/\/ added for attribute id<\/span><\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">public<\/span> IntPtr TableId; <span style=\"color: green;\">\/\/ added for table support in caching<\/span><\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">public<\/span> ColumnInfo(<span style=\"color: blue;\">int<\/span> id, <span style=\"color: blue;\">string<\/span> name, <span style=\"color: blue;\">int<\/span> type, <span style=\"color: blue;\">string<\/span> altname, <span style=\"color: blue;\">int<\/span> altid, IntPtr tableid)<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">{<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">this<\/span>.ID = id;<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">this<\/span>.Name = name;<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">this<\/span>.DataType = type;<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">this<\/span>.AltName = altname; <span style=\"color: green;\">\/\/added for attribute name<\/span><\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">this<\/span>.AltId = altid;<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">this<\/span>.TableId = tableid; <span style=\"color: green;\">\/\/added for table support in caching<\/span><\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">}<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">}<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>&nbsp;<\/p>\n<p><strong>Perform Initialization and Attach to NTDS.dit<br \/>\n<\/strong><\/p>\n<p>First thing we had to figure out was how we attached to the database (NTDS.dit) using <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/gg294068(v=exchg.10).aspx\">JetInit<\/a>, <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/gg294131(v=exchg.10).aspx\">JetBeginSession<\/a>, <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/gg294074(v=exchg.10).aspx\">JetAttachDatabase<\/a> and finally calling <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/gg269299(v=exchg.10).aspx\">JetOpenDatabase<\/a> in addition to those callas we had to set several parameters with <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/gg294044(v=exchg.10).aspx\">JetSetSystemParameter<\/a> for our usage, e.g there is things that need to be turned off as we attach\/open the DB as read-only due to the nature of our application.<\/p>\n<p style=\"margin-left: 72pt;\"><span style=\"font-family: Franklin Gothic Demi; font-size: 10pt;\">Table\u00a01: ESE Initialization<br \/>\n<\/span><\/p>\n<div style=\"margin-left: 77pt;\">\n<table style=\"border-collapse: collapse;\" border=\"0\">\n<colgroup>\n<col style=\"width: 886px;\" \/><\/colgroup>\n<tbody valign=\"top\">\n<tr style=\"background: #d9d9d9;\">\n<td style=\"padding-left: 7px; padding-right: 7px; border-top: solid gray 1.5pt; border-left: solid gray 1.5pt; border-bottom: solid gray 0.5pt; border-right: solid gray 1.5pt;\" valign=\"middle\">\n<p style=\"text-align: center;\"><span style=\"font-family: Franklin Gothic Demi Cond; font-size: 9pt;\">Code Snippet<\/span><\/p>\n<\/td>\n<\/tr>\n<tr style=\"height: 23px;\">\n<td style=\"padding-left: 7px; padding-right: 7px; border-top: none; border-left: solid gray 1.5pt; border-bottom: solid gray 1.5pt; border-right: solid gray 1.5pt;\"><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ E.Check makes sure a JET API call is successful, i.e. JET_errSuccess (0)<\/span><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ If the call fails, we throw an exception\/write to the Console<\/span><\/p>\n<p><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Initialize ESENT. Setting JetInit will inspect the logfiles to see if the last<\/span><\/p>\n<p><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ shutdown was clean. If it wasn&#8217;t (e.g. the application crashed) recovery will be<\/span><\/p>\n<p><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ run automatically bringing the database to a consistent state.<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">err = E.Check(EseHelper.JetSetSystemParameter(<span style=\"color: blue;\">ref<\/span> instance, EseHelper.JET_sesidNil, <span style=\"color: blue;\">new<\/span><br \/>\n<span style=\"color: #2b91af;\">IntPtr<\/span>(EseHelper.JET_paramDatabasePageSize), <span style=\"color: blue;\">new<\/span><br \/>\n<span style=\"color: #2b91af;\">IntPtr<\/span>(0x2000), <span style=\"color: blue;\">null<\/span>));<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">err = E.Check(EseHelper.JetCreateInstance(<span style=\"color: blue;\">out<\/span> instance, <span style=\"color: #a31515;\">&#8220;instance&#8221;<\/span>));<\/span><\/p>\n<p><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Set up the recovery option (off), the maximum number temporary tables (7) and temporary path<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">err = E.Check(EseHelper.JetSetSystemParameter(<span style=\"color: blue;\">ref<\/span> instance, EseHelper.JET_sesidNil, <span style=\"color: blue;\">new<\/span><br \/>\n<span style=\"color: #2b91af;\">IntPtr<\/span>(EseHelper.JET_paramRecovery), <span style=\"color: #2b91af;\">IntPtr<\/span>.Zero, <span style=\"color: #a31515;\">&#8220;off&#8221;<\/span>));<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">err = E.Check(EseHelper.JetSetSystemParameter(<span style=\"color: blue;\">ref<\/span> instance, EseHelper.JET_sesidNil, <span style=\"color: blue;\">new<\/span><br \/>\n<span style=\"color: #2b91af;\">IntPtr<\/span>(EseHelper.JET_paramEnableOnlineDefrag), <span style=\"color: #2b91af;\">IntPtr<\/span>.Zero, <span style=\"color: blue;\">null<\/span>));<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">err = E.Check(EseHelper.JetSetSystemParameter(<span style=\"color: blue;\">ref<\/span> instance, EseHelper.JET_sesidNil, <span style=\"color: blue;\">new<\/span><br \/>\n<span style=\"color: #2b91af;\">IntPtr<\/span>(0xa), <span style=\"color: #2b91af;\">IntPtr<\/span>.Zero, <span style=\"color: blue;\">null<\/span>));<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">err = E.Check(EseHelper.JetSetSystemParameter(<span style=\"color: blue;\">ref<\/span> instance, EseHelper.JET_sesidNil, <span style=\"color: blue;\">new<\/span><br \/>\n<span style=\"color: #2b91af;\">IntPtr<\/span>(EseHelper.JET_paramMaxTemporaryTables), <span style=\"color: blue;\">new<\/span><br \/>\n<span style=\"color: #2b91af;\">IntPtr<\/span>(7), <span style=\"color: blue;\">null<\/span>));<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">err = E.Check(EseHelper.JetSetSystemParameter(<span style=\"color: blue;\">ref<\/span> instance, EseHelper.JET_sesidNil, <span style=\"color: blue;\">new<\/span><br \/>\n<span style=\"color: #2b91af;\">IntPtr<\/span>(EseHelper.JET_paramTempPath), <span style=\"color: #2b91af;\">IntPtr<\/span>.Zero, System.IO.<span style=\"color: #2b91af;\">Path<\/span>.GetTempPath()));<\/span><\/p>\n<p><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Initialize ESE and begin a session<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">err = E.Check(EseHelper.JetInit(<span style=\"color: blue;\">ref<\/span> instance));<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">err = E.Check(EseHelper.JetBeginSession(instance, <span style=\"color: blue;\">out<\/span> sesid, <span style=\"color: blue;\">null<\/span>, <span style=\"color: blue;\">null<\/span>));<\/span><\/p>\n<p><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Attach a database<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">err = E.Check(EseHelper.JetAttachDatabase(sesid, <span style=\"color: #a31515;\">&#8220;NTDS.dit&#8221;<\/span>, 1));<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">err = E.Check(EseHelper.JetOpenDatabase(sesid, <span style=\"color: #a31515;\">&#8220;NTDS.dit&#8221;<\/span>, <span style=\"color: blue;\">null<\/span>, <span style=\"color: blue;\">out<\/span> dbid, 1));<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>&nbsp;<\/p>\n<p><strong>List the tables inside NTDS.dit<br \/>\n<\/strong><\/p>\n<p>We figured out that by statically opening the &#8220;MSysObjects&#8221; and positioning over the &#8220;RootObjects&#8221; index we could enumerate the tables inside the database using the following code snippet.<\/p>\n<p style=\"margin-left: 72pt;\"><span style=\"font-family: Franklin Gothic Demi; font-size: 10pt;\">Table\u00a02: ESE Enumerate tables inside the database<br \/>\n<\/span><\/p>\n<div style=\"margin-left: 77pt;\">\n<table style=\"border-collapse: collapse;\" border=\"0\">\n<colgroup>\n<col style=\"width: 886px;\" \/><\/colgroup>\n<tbody valign=\"top\">\n<tr style=\"background: #d9d9d9;\">\n<td style=\"padding-left: 7px; padding-right: 7px; border-top: solid gray 1.5pt; border-left: solid gray 1.5pt; border-bottom: solid gray 0.5pt; border-right: solid gray 1.5pt;\" valign=\"middle\">\n<p style=\"text-align: center;\"><span style=\"font-family: Franklin Gothic Demi Cond; font-size: 9pt;\">Code Snippet<\/span><\/p>\n<\/td>\n<\/tr>\n<tr style=\"height: 23px;\">\n<td style=\"padding-left: 7px; padding-right: 7px; border-top: none; border-left: solid gray 1.5pt; border-bottom: solid gray 1.5pt; border-right: solid gray 1.5pt;\"><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Simplified:<\/span><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Method to obtain a list of tables for a given JET database<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">private<\/span><br \/>\n<span style=\"color: blue;\">static<\/span><br \/>\n<span style=\"color: blue;\">void<\/span> GetTableNames(IntPtr instance, IntPtr sesid, IntPtr dbid, <span style=\"color: blue;\">ref<\/span> EseErrors err)<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">{<\/span><\/p>\n<p style=\"margin-left: 36pt;\"><span style=\"font-family: Consolas; font-size: 9pt;\">IntPtr tableid = IntPtr.Zero;<\/span><\/p>\n<p style=\"margin-left: 36pt;\"><span style=\"font-family: Consolas; font-size: 9pt;\">List&lt;<span style=\"color: blue;\">string<\/span>&gt; tables = <span style=\"color: blue;\">new<\/span> List&lt;<span style=\"color: blue;\">string<\/span>&gt;();<\/span><\/p>\n<p style=\"margin-left: 36pt;\"><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ E.Check makes sure a JET API call is successful, i.e. JET_errSuccess (0)<\/span><\/p>\n<p style=\"margin-left: 36pt;\"><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ If the call fails, we throw an exception\/write to the Console<\/span><\/p>\n<p style=\"margin-left: 36pt;\"><span style=\"font-family: Consolas; font-size: 9pt;\">err = E.Check(EseHelper.JetOpenTable(sesid, dbid, <span style=\"color: #a31515;\">&#8220;MSysObjects&#8221;<\/span>, IntPtr.Zero, 0, 0, <span style=\"color: blue;\">out<\/span> tableid));<\/span><\/p>\n<p style=\"margin-left: 36pt;\"><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Select the first row in the RootObjects record set<\/span><\/p>\n<p style=\"margin-left: 36pt;\"><span style=\"font-family: Consolas; font-size: 9pt;\">err = E.Check(EseHelper.JetSetCurrentIndex(sesid, tableid, <span style=\"color: #a31515;\">&#8220;RootObjects&#8221;<\/span>));<\/span><\/p>\n<p style=\"margin-left: 36pt;\"><span style=\"font-family: Consolas; font-size: 9pt;\">err = E.Check(EseHelper.JetMove(sesid, tableid, EseHelper.JET_MoveFirst, 0));<\/span><\/p>\n<p style=\"margin-left: 36pt;\"><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Allocate a column array of one element &#8212; we only need the name column<\/span><\/p>\n<p style=\"margin-left: 36pt;\"><span style=\"font-family: Consolas; font-size: 9pt;\">EseHelper.JET_RETRIEVECOLUMN[] array = <span style=\"color: blue;\">new<\/span> EseHelper.JET_RETRIEVECOLUMN[1];<\/span><\/p>\n<p style=\"margin-left: 36pt;\"><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Loop until we reach the end of the record set or an error occurs<\/span><\/p>\n<p style=\"margin-left: 36pt;\"><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">while<\/span> (err == 0)<\/span><\/p>\n<p style=\"margin-left: 36pt;\"><span style=\"font-family: Consolas; font-size: 9pt;\">{<\/span><\/p>\n<p style=\"margin-left: 36pt;\"><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Allocate 0x41 bytes for this column&#8217;s value<\/span><\/p>\n<p style=\"margin-left: 36pt;\"><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ 0x80 is the column ID (table name)<\/span><\/p>\n<p style=\"margin-left: 36pt;\"><span style=\"font-family: Consolas; font-size: 9pt;\">array[0].Initialize(0x80, 0x41);<\/span><\/p>\n<p style=\"margin-left: 36pt;\"><span style=\"font-family: Consolas; font-size: 9pt;\">err = E.Check(EseHelper.JetRetrieveColumns(sesid, tableid, Marshal.UnsafeAddrOfPinnedArrayElement(array, 0), array.Length));<\/span><\/p>\n<p style=\"margin-left: 36pt;\"><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">foreach<\/span> (EseHelper.JET_RETRIEVECOLUMN column <span style=\"color: blue;\">in<\/span> array)<\/span><\/p>\n<p style=\"margin-left: 36pt;\"><span style=\"font-family: Consolas; font-size: 9pt;\">{<\/span><\/p>\n<p style=\"margin-left: 72pt;\"><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">if<\/span> (column.cbData != 0x04)<\/span><\/p>\n<p style=\"margin-left: 72pt;\"><span style=\"font-family: Consolas; font-size: 9pt;\">{<\/span><\/p>\n<p style=\"margin-left: 72pt;\"><span style=\"font-family: Consolas; font-size: 9pt;\"><span style=\"color: blue;\">string<\/span> table = column.GetString();<\/span><\/p>\n<p style=\"margin-left: 72pt;\"><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Print out the table<\/span><\/p>\n<p style=\"margin-left: 72pt;\"><span style=\"font-family: Consolas; font-size: 9pt;\">Console.WriteLine(table);<\/span><\/p>\n<p style=\"margin-left: 72pt;\"><span style=\"font-family: Consolas; font-size: 9pt;\">}<\/span><\/p>\n<p style=\"margin-left: 36pt;\"><span style=\"font-family: Consolas; font-size: 9pt;\">}<\/span><\/p>\n<p style=\"margin-left: 36pt;\"><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Select the next record (table info row)<\/span><\/p>\n<p style=\"margin-left: 36pt;\"><span style=\"font-family: Consolas; font-size: 9pt;\">err = E.Check(EseHelper.JetMove(sesid, tableid, EseHelper.JET_MoveNext, 0));<\/span><\/p>\n<p style=\"margin-left: 36pt;\"><span style=\"font-family: Consolas; font-size: 9pt;\">}<\/span><\/p>\n<p style=\"margin-left: 36pt;\"><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Clean up<\/span><\/p>\n<p style=\"margin-left: 36pt;\"><span style=\"font-family: Consolas; font-size: 9pt;\">err = E.Check(EseHelper.JetCloseTable(sesid, tableid));<\/span><\/p>\n<p style=\"margin-left: 36pt;\"><span style=\"font-family: Consolas; font-size: 9pt;\">Console.WriteLine();<\/span><\/p>\n<p><span style=\"font-family: Consolas; font-size: 9pt;\">}<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>&nbsp;<\/p>\n<p><strong>Retrieving the Ancestors_col<br \/>\n<\/strong><\/p>\n<p>In <a href=\"http:\/\/blogs.chrisse.se\/blogs\/chrisse\/archive\/2012\/02\/20\/how-the-active-directory-data-store-really-works-inside-ntds-dit-part-3.aspx\">Part 3<\/a>, we&#8217;re discussing the usage of the &#8220;Ancestors_col&#8221; column and how it&#8217;s used to walk subtrees in the database, the DNTs are stored as bytes within the &#8220;Acenstors_col&#8221; and are read as in the code snippet below.<\/p>\n<p style=\"margin-left: 72pt;\"><span style=\"font-family: Franklin Gothic Demi; font-size: 10pt;\">Table\u00a03: Ancestors_col<br \/>\n<\/span><\/p>\n<div style=\"margin-left: 77pt;\">\n<table style=\"border-collapse: collapse;\" border=\"0\">\n<colgroup>\n<col style=\"width: 886px;\" \/><\/colgroup>\n<tbody valign=\"top\">\n<tr style=\"background: #d9d9d9;\">\n<td style=\"padding-left: 7px; padding-right: 7px; border-top: solid gray 1.5pt; border-left: solid gray 1.5pt; border-bottom: solid gray 0.5pt; border-right: solid gray 1.5pt;\" valign=\"middle\">\n<p style=\"text-align: center;\"><span style=\"font-family: Franklin Gothic Demi Cond; font-size: 9pt;\">Code Snippet<\/span><\/p>\n<\/td>\n<\/tr>\n<tr style=\"height: 23px;\">\n<td style=\"padding-left: 7px; padding-right: 7px; border-top: none; border-left: solid gray 1.5pt; border-bottom: solid gray 1.5pt; border-right: solid gray 1.5pt;\"><span style=\"font-family: Courier New; font-size: 10pt;\"><span style=\"color: blue;\">if<\/span> (column.err != <span style=\"color: #2b91af;\">EseErrors<\/span>.ColumnNull)<br \/>\n<\/span><span style=\"font-family: Courier New; font-size: 10pt;\">{<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"><br \/>\n<span style=\"color: blue;\">string<\/span> ancestory = <span style=\"color: blue;\">null<\/span>;<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"><br \/>\n<span style=\"color: blue;\">char<\/span>[] ancestor_separator = { <span style=\"color: #a31515;\">&#8216;,&#8217;<\/span> };<br \/>\n<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"><br \/>\n<\/span><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Walk through every ancestry record in the returned column data<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"><br \/>\n<\/span><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Construct the ancestry string with the returned DNTs<\/span><span style=\"font-family: Courier New; font-size: 10pt;\"><br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"><br \/>\n<span style=\"color: blue;\">for<\/span> (<span style=\"color: blue;\">int<\/span> i = 0; i &lt; column.GetData().Length; i += <span style=\"color: blue;\">sizeof<\/span>(<span style=\"color: blue;\">int<\/span>))<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"> {<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"><br \/>\n<span style=\"color: blue;\">int<\/span> dnt = <span style=\"color: #2b91af;\">BitConverter<\/span>.ToInt32(column.GetData(), i);<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"> ancestory = ancestory + dnt + <span style=\"color: #a31515;\">&#8220;,&#8221;<\/span>;<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"> }<br \/>\n<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"><br \/>\n<\/span><span style=\"color: green; font-family: Consolas; font-size: 9pt;\">\/\/ Remove any trailing &#8220;,&#8221; characters<\/span><span style=\"font-family: Courier New; font-size: 10pt;\"><br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"> ancestory = ancestory.TrimEnd(ancestor_separator);<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"> output = ancestory;<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\">}<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>&nbsp;<\/p>\n<p><strong>Reading an object&#8217;s full distinguished name<br \/>\n<\/strong><\/p>\n<p><strong>Note:<\/strong> This is our way to read an objects full distinguished name, given an object&#8217;s DNT (Distinguished Name Tag) \u2013 But this is not considered safe by the DSA as mentioned in <a href=\"http:\/\/blogs.chrisse.se\/blogs\/chrisse\/archive\/2012\/02\/20\/how-the-active-directory-data-store-really-works-inside-ntds-dit-part-3.aspx\">Part 3<\/a> as the &#8220;Ancestors_col&#8221; is being processed by a background task and might not be in-sync all the times. (Safer would be to walk the tree up \u2013 by each PDNT until PDNT == 2)<\/p>\n<p style=\"margin-left: 72pt;\"><span style=\"font-family: Franklin Gothic Demi; font-size: 10pt;\">Table\u00a04: Get an objects distinguished name by its DNT<br \/>\n<\/span><\/p>\n<div style=\"margin-left: 77pt;\">\n<table style=\"border-collapse: collapse;\" border=\"0\">\n<colgroup>\n<col style=\"width: 886px;\" \/><\/colgroup>\n<tbody valign=\"top\">\n<tr style=\"height: 21px; background: #d9d9d9;\">\n<td style=\"padding-left: 7px; padding-right: 7px; border-top: solid gray 1.5pt; border-left: solid gray 1.5pt; border-bottom: solid gray 0.5pt; border-right: solid gray 1.5pt;\" valign=\"middle\">\n<p style=\"text-align: center;\"><span style=\"font-family: Franklin Gothic Demi Cond; font-size: 9pt;\">Code Snippet<\/span><\/p>\n<\/td>\n<\/tr>\n<tr style=\"height: 23px;\">\n<td style=\"padding-left: 7px; padding-right: 7px; border-top: none; border-left: solid gray 1.5pt; border-bottom: solid gray 1.5pt; border-right: solid gray 1.5pt;\"><span style=\"font-family: Courier New; font-size: 10pt;\"><span style=\"color: blue;\">internal<\/span><br \/>\n<span style=\"color: blue;\">static<\/span><br \/>\n<span style=\"color: blue;\">string<\/span> DBGetDN(<span style=\"color: #2b91af;\">IntPtr<\/span> sesid, <span style=\"color: #2b91af;\">IntPtr<\/span> tableid, <span style=\"color: blue;\">int<\/span> tag, <span style=\"color: blue;\">ref<\/span><br \/>\n<span style=\"color: #2b91af;\">EseErrors<\/span> err)<br \/>\n<\/span><span style=\"font-family: Courier New; font-size: 10pt;\">{<br \/>\n<\/span><\/p>\n<p><span style=\"color: green; font-family: Courier New; font-size: 10pt;\">\/\/ 0 (zero) means where already positioned at the obejct.<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"><span style=\"color: blue;\">if<\/span> (tag != 0)<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"> DBFindDNT(sesid, tableid, tag, <span style=\"color: blue;\">ref<\/span> err);<br \/>\n<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"><span style=\"color: #2b91af;\">List<\/span>&lt;<span style=\"color: blue;\">string<\/span>&gt; DN = <span style=\"color: blue;\">new<\/span><br \/>\n<span style=\"color: #2b91af;\">List<\/span>&lt;<span style=\"color: blue;\">string<\/span>&gt;();<br \/>\n<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"><span style=\"color: #2b91af;\">EseHelper<\/span>.<span style=\"color: #2b91af;\">JET_RETRIEVECOLUMN<\/span>[] Ancestors = <span style=\"color: blue;\">new<\/span><br \/>\n<span style=\"color: #2b91af;\">EseHelper<\/span>.<span style=\"color: #2b91af;\">JET_RETRIEVECOLUMN<\/span>[1];<br \/>\n<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\">Ancestors[0].Initialize(<span style=\"color: #2b91af;\">attid<\/span>.GetByDisplayName(<span style=\"color: #a31515;\">&#8220;Ancestors_col&#8221;<\/span>, tableid), 256 * 6);<br \/>\n<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\">err = <span style=\"color: #2b91af;\">E<\/span>.Check(<span style=\"color: #2b91af;\">EseHelper<\/span>.JetRetrieveColumns(sesid, tableid, <span style=\"color: #2b91af;\">Marshal<\/span>.UnsafeAddrOfPinnedArrayElement(Ancestors, 0), Ancestors.Length));<br \/>\n<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: green; font-family: Courier New; font-size: 10pt;\">\/\/ Ensure the &#8220;Ancestors_col&#8221; exist and contains data.<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"><span style=\"color: blue;\">if<\/span> (Ancestors[0].err != <span style=\"color: #2b91af;\">EseErrors<\/span>.ColumnNull)<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\">{<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"><br \/>\n<span style=\"color: green;\">\/\/ Loop thru all ancestors.<br \/>\n<\/span><\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"><br \/>\n<span style=\"color: blue;\">for<\/span> (<span style=\"color: blue;\">int<\/span> i = 0; i &lt; Ancestors[0].GetData().Length; i += <span style=\"color: blue;\">sizeof<\/span>(<span style=\"color: blue;\">int<\/span>))<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"> {<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"><br \/>\n<span style=\"color: blue;\">int<\/span> dnt = <span style=\"color: #2b91af;\">BitConverter<\/span>.ToInt32(Ancestors[0].GetData(), i);<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"><br \/>\n<span style=\"color: blue;\">if<\/span> (dnt != 2) <span style=\"color: green;\">\/\/ &#8220;2&#8221; == $ROOT_OBJECT$ == We hit the top most DN Component.<br \/>\n<\/span><\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"> {<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"><br \/>\n<span style=\"color: green;\">\/\/ Move the cursor over the ancestor<br \/>\n<\/span><\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"> DBFindDNT(sesid, tableid, dnt, <span style=\"color: blue;\">ref<\/span> err);<br \/>\n<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"><br \/>\n<span style=\"color: green;\">\/\/ Define a list of attributes we want to read off each ancestor (object)<br \/>\n<\/span><\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"><br \/>\n<span style=\"color: #2b91af;\">EseHelper<\/span>.<span style=\"color: #2b91af;\">JET_RETRIEVECOLUMN<\/span>[] attrList = <span style=\"color: blue;\">new<\/span><br \/>\n<span style=\"color: #2b91af;\">EseHelper<\/span>.<span style=\"color: #2b91af;\">JET_RETRIEVECOLUMN<\/span>[2];<br \/>\n<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"> attrList[0].Initialize(<span style=\"color: #2b91af;\">attid<\/span>.GetByDisplayName(<span style=\"color: #a31515;\">&#8220;RDNtyp_col&#8221;<\/span>, tableid), 256 * 24);<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"> attrList[1].Initialize(<span style=\"color: #2b91af;\">attid<\/span>.GetByDisplayName(<span style=\"color: #a31515;\">&#8220;name&#8221;<\/span>, tableid), 256 * 24);<br \/>\n<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"> err = <span style=\"color: #2b91af;\">E<\/span>.Check(<span style=\"color: #2b91af;\">EseHelper<\/span>.JetRetrieveColumns(sesid, tableid, <span style=\"color: #2b91af;\">Marshal<\/span>.UnsafeAddrOfPinnedArrayElement(attrList, 0), attrList.Length));<br \/>\n<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"><br \/>\n<span style=\"color: green;\">\/\/ Make sure the object has both a RDNType and a Name<br \/>\n<\/span><\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"><br \/>\n<span style=\"color: blue;\">if<\/span> (attrList[0].err != <span style=\"color: #2b91af;\">EseErrors<\/span>.ColumnNull &amp;&amp; attrList[1].err != <span style=\"color: #2b91af;\">EseErrors<\/span>.ColumnNull)<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"> {<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"><br \/>\n<span style=\"color: blue;\">string<\/span> RDNType = DBGetRDNType(tableid, attrList[0].GetInteger());<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"><br \/>\n<span style=\"color: blue;\">string<\/span> Name = attrList[1].GetString();<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"><br \/>\n<span style=\"color: green;\">\/\/ Construct this ancestors RDN.<br \/>\n<\/span><\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"> DN.Add(RDNType + <span style=\"color: #a31515;\">&#8220;=&#8221;<\/span> + Name);<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"> }<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"> }<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"> }<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"> DN.Reverse();<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"><br \/>\n<span style=\"color: blue;\">return<\/span><br \/>\n<span style=\"color: blue;\">string<\/span>.Join(<span style=\"color: #a31515;\">&#8220;,&#8221;<\/span>, DN.ToArray());<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\">}<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\"><span style=\"color: blue;\">return<\/span><br \/>\n<span style=\"color: blue;\">null<\/span>;<br \/>\n<\/span><\/p>\n<p><span style=\"font-family: Courier New; font-size: 10pt;\">}<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>&nbsp;<\/p>\n<p style=\"margin-left: 72pt;\"><span style=\"font-family: Franklin Gothic Demi; font-size: 10pt;\">Table\u00a05: Get an objects distinguished name (object is referenced by sAMAccountName: ADCH)<br \/>\n<\/span><\/p>\n<div style=\"margin-left: 77pt;\">\n<table style=\"border-collapse: collapse;\" border=\"0\">\n<colgroup>\n<col style=\"width: 886px;\" \/><\/colgroup>\n<tbody valign=\"top\">\n<tr style=\"height: 9px; background: #d9d9d9;\">\n<td style=\"padding-left: 7px; padding-right: 7px; border-top: solid gray 1.5pt; border-left: solid gray 1.5pt; border-bottom: solid gray 0.5pt; border-right: solid gray 1.5pt;\" valign=\"middle\">\n<p style=\"text-align: center;\"><span style=\"font-family: Franklin Gothic Demi Cond; font-size: 9pt;\">ESEDump<\/span><\/p>\n<\/td>\n<\/tr>\n<tr style=\"height: 23px;\">\n<td style=\"padding-left: 7px; padding-right: 7px; border-top: none; border-left: solid gray 1.5pt; border-bottom: solid gray 1.5pt; border-right: solid gray 1.5pt;\"><img decoding=\"async\" src=\"http:\/\/blogs.chrisse.se\/wordpress\/wp-content\/uploads\/2012\/03\/022812_1224_HowtheActiv12.png\" alt=\"\" \/><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>So what is the &#8220;Code [1-3]&#8221; all about and where is Part 4 of the series that you might expect? Before I go ahead with Part 4 I thought it would be a good idea to sum up Part 1 to Part 3 with code (So that you know how we figured out all this &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/blog.chrisse.se\/?p=865\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;How the Active Directory &#8211; Data Store Really Works (Inside NTDS.dit) &#8211; Code [1-3]&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_exactmetrics_skip_tracking":false,"_exactmetrics_sitenote_active":false,"_exactmetrics_sitenote_note":"","_exactmetrics_sitenote_category":0,"footnotes":""},"categories":[1],"tags":[6,14,16],"class_list":["post-865","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-active-directory","tag-extensible-storage-engine-ese","tag-ntds-dit"],"_links":{"self":[{"href":"https:\/\/blog.chrisse.se\/index.php?rest_route=\/wp\/v2\/posts\/865","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.chrisse.se\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.chrisse.se\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.chrisse.se\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.chrisse.se\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=865"}],"version-history":[{"count":0,"href":"https:\/\/blog.chrisse.se\/index.php?rest_route=\/wp\/v2\/posts\/865\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.chrisse.se\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=865"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.chrisse.se\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=865"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.chrisse.se\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=865"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}