예제 #1
0
        /// <summary>
        /// + Open MSysObjects
        /// + Enumerate columns
        ///
        /// We're only interested in attributes for ntds.dit
        /// </summary>
        /// <returns></returns>
        private MSysObjectsRow[] EnumColumns()
        {
            // 此处用了打开表时的只读属性,读的时候应该会快一点.
            wrn = Api.JetOpenTable(sesId, dbId, MSYSOBJECTS, null, 0, OpenTableGrbit.ReadOnly | OpenTableGrbit.Sequential, out _tableid);
            if (wrn == JET_wrn.Success)
            {
                //JET_COLUMNLIST columndef;
                // 检索有关表列的信息。将列名称映射到列ID的字典
                //Api.JetGetTableColumnInfo(sesId, _tableid, null, out columndef);
                var columnDictionary = Api.GetColumnDictionary(sesId, _tableid);

                // 循环遍历表,向字典添加属性ID和列名
                Api.MoveBeforeFirst(sesId, _tableid);
                while (Api.TryMoveNext(sesId, _tableid))
                {
                    var nameColumn = new Utf8StringColumnValue {
                        Columnid = columnDictionary["Name"]
                    };

                    Api.RetrieveColumns(sesId, _tableid, nameColumn);
                    if (nameColumn.Value.StartsWith("ATT", StringComparison.Ordinal))
                    {
                        mSysObjects.Add(new MSysObjectsRow
                        {
                            AttributeId = int.Parse(Regex.Replace(nameColumn.Value, "[A-Za-z-]", string.Empty, RegexOptions.None), CultureInfo.InvariantCulture),
                            ColumnName  = nameColumn.Value
                        });
                        // AttributeId = 2128564599
                        // ColumnName = ATTf-2128564599
                    }
                }
            }
            Api.JetCloseTable(sesId, _tableid);
            return(mSysObjects.ToArray());
        }
예제 #2
0
 /// <summary>
 /// 加载 ntds.dit,并打开
 /// </summary>
 /// <param name="fname"></param>
 /// <returns></returns>
 public Boolean NTDSLoad(String dbPath)
 {
     // 应用实例对象和会话对象进行数据库的操作
     // 在打开数据库之前,得先用 JetAttachDatabase 将备用数据库附加到当前会话,不然会引发 No such database 异常.
     wrn = Api.JetAttachDatabase(sesId, dbPath, AttachDatabaseGrbit.ReadOnly);
     if (wrn == JET_wrn.Success)
     {
         // 打开数据库
         wrn = Api.JetOpenDatabase(sesId, dbPath, null, out dbId, OpenDatabaseGrbit.ReadOnly);
         if (wrn == JET_wrn.Success)
         {
             // 针对数据库的一系列操作
             _mSysObjects = EnumColumns();
             _ldapDisplayNameToDatatableColumnNameDictionary = EnumerateDatatableTableLdapDisplayNames(_mSysObjects);
             _datatable = EnumerateDatatableTable(_ldapDisplayNameToDatatableColumnNameDictionary);
         }
         else
         {
             Console.WriteLine("[!] error at JetOpenDatabase()");
         }
     }
     else
     {
         Console.WriteLine("[!] error at JetAttachDatabase()");
     }
     return(wrn == JET_wrn.Success);
 }
예제 #3
0
 /// <summary>
 /// Update the output members of the class from a NATIVE_RETRIEVECOLUMN
 /// structure. This should be done after the columns are retrieved.
 /// </summary>
 /// <param name="native">
 /// The structure containing the updated output fields.
 /// </param>
 internal void UpdateFromNativeRetrievecolumn(NATIVE_RETRIEVECOLUMN native)
 {
     this.cbActual           = checked ((int)native.cbActual);
     this.columnidNextTagged = new JET_COLUMNID {
         Value = native.columnidNextTagged
     };
     this.err = (JET_wrn)native.err;
 }
예제 #4
0
 internal static void Check(JET_wrn wrn, String message)
 {
     if (wrn == JET_wrn.Success)
     {
         return;
     }
     throw new ApplicationException(message + " " + wrn);
 }
        /// <summary>
        /// Create the nullable return value.
        /// </summary>
        /// <typeparam name="T">The (struct) type to return.</typeparam>
        /// <param name="data">The data retrieved from the column.</param>
        /// <param name="dataSize">The size of the data.</param>
        /// <param name="wrn">The warning code from esent.</param>
        /// <param name="actualDataSize">The actual size of the data retireved fomr esent.</param>
        /// <returns>A nullable struct of type T.</returns>
        private static T?CreateReturnValue <T>(T data, int dataSize, JET_wrn wrn, int actualDataSize) where T : struct
        {
            if (JET_wrn.ColumnNull == wrn)
            {
                return(new T?());
            }

            CheckDataSize(dataSize, actualDataSize);
            return(data);
        }
        /// <summary>
        /// Retrieves a string column value from the current record. The record is that
        /// record associated with the index entry at the current position of the cursor.
        /// </summary>
        /// <param name="sesid">The session to use.</param>
        /// <param name="tableid">The cursor to retrieve the column from.</param>
        /// <param name="columnid">The columnid to retrieve.</param>
        /// <param name="encoding">The string encoding to use when converting data.</param>
        /// <param name="grbit">Retrieval options.</param>
        /// <returns>The data retrieved from the column as a string. Null if the column is null.</returns>
        public static string RetrieveColumnAsString(
            JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, Encoding encoding, RetrieveColumnGrbit grbit)
        {
            // This is an optimization for retrieving Unicode strings
            if (Encoding.Unicode == encoding)
            {
                return(RetrieveUnicodeString(sesid, tableid, columnid, grbit));
            }

            // Retrieving a string happens in two stages: first the data is retrieved into a data
            // buffer and then the buffer is converted to a string. The buffer isn't needed for
            // very long so we try to use a cached buffer.
            byte[] cachedBuffer = Caches.ColumnCache.Allocate();
            byte[] data         = cachedBuffer;

            int     dataSize;
            JET_wrn wrn = JetRetrieveColumn(sesid, tableid, columnid, data, data.Length, out dataSize, grbit, null);

            if (JET_wrn.ColumnNull == wrn)
            {
                return(null);
            }

            if (JET_wrn.BufferTruncated == wrn)
            {
                Debug.Assert(dataSize > data.Length, "Expected column to be bigger than buffer");
                data = new byte[dataSize];
                wrn  = JetRetrieveColumn(sesid, tableid, columnid, data, data.Length, out dataSize, grbit, null);
                if (JET_wrn.BufferTruncated == wrn)
                {
                    string error = String.Format(
                        CultureInfo.CurrentCulture,
                        "Column size changed from {0} to {1}. The record was probably updated by another thread.",
                        data.Length,
                        dataSize);
                    Trace.TraceError(error);
                    throw new InvalidOperationException(error);
                }
            }

            // If we are about to decode ASCII data then use the UTF8 decoder instead. This
            // is done because the UTF8 decoder is faster and will produce the same results
            // on ASCII data. Different results will be produced on invalid data, but that
            // behaviour can be considered undefined.
            Encoding decoder = (encoding is ASCIIEncoding) ? asciiDecoder : encoding;
            string   s       = decoder.GetString(data, 0, dataSize);

            // Now we have extracted the string from the buffer we can free (cache) the buffer.
            Caches.ColumnCache.Free(ref cachedBuffer);

            return(s);
        }
 public static ulong?RetrieveColumnAsUInt64(
     JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, RetrieveColumnGrbit grbit)
 {
     unsafe
     {
         const int DataSize = sizeof(ulong);
         ulong     data;
         var       pointer = new IntPtr(&data);
         int       actualDataSize;
         JET_wrn   wrn = JetRetrieveColumn(
             sesid, tableid, columnid, pointer, DataSize, out actualDataSize, grbit, null);
         return(CreateReturnValue(data, DataSize, wrn, actualDataSize));
     }
 }
        /// <summary>
        /// Retrieves the size of a single column value from the current record.
        /// The record is that record associated with the index entry at the
        /// current position of the cursor. Alternatively, this function can
        /// retrieve a column from a record being created in the cursor copy
        /// buffer. This function can also retrieve column data from an index
        /// entry that references the current record.
        /// </summary>
        /// <param name="sesid">The session to use.</param>
        /// <param name="tableid">The cursor to retrieve the column from.</param>
        /// <param name="columnid">The columnid to retrieve.</param>
        /// <param name="itagSequence">
        /// The sequence number of value in a multi-valued column.
        /// The array of values is one-based. The first value is
        /// sequence 1, not 0. If the record column has only one value then
        /// 1 should be passed as the itagSequence.
        /// </param>
        /// <param name="grbit">Retrieve column options.</param>
        /// <returns>The size of the column. 0 if the column is null.</returns>
        public static int?RetrieveColumnSize(
            JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, int itagSequence, RetrieveColumnGrbit grbit)
        {
            var retinfo = new JET_RETINFO {
                itagSequence = itagSequence
            };
            int     dataSize;
            JET_wrn wrn = JetRetrieveColumn(
                sesid, tableid, columnid, null, 0, out dataSize, grbit, retinfo);

            if (JET_wrn.ColumnNull == wrn)
            {
                return(null);
            }

            return(dataSize);
        }
        /// <summary>
        /// Retrieve a Unicode (UTF16) string. This is optimized to take advantage of the fact
        /// that no conversion is needed.
        /// </summary>
        /// <param name="sesid">The session to use.</param>
        /// <param name="tableid">The table to retrieve from.</param>
        /// <param name="columnid">The column to retrieve.</param>
        /// <param name="grbit">Retrieve options.</param>
        /// <returns>The string retrieved from the column.</returns>
        private static unsafe string RetrieveUnicodeString(JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, RetrieveColumnGrbit grbit)
        {
            // 512 Unicode characters (1kb on stack)
            const int BufferSize = 512;
            char *    buffer     = stackalloc char[BufferSize];
            int       actualDataSize;
            JET_wrn   wrn = JetRetrieveColumn(sesid, tableid, columnid, new IntPtr(buffer), BufferSize * sizeof(char), out actualDataSize, grbit, null);

            if (JET_wrn.ColumnNull == wrn)
            {
                return(null);
            }

            if (JET_wrn.Success == wrn)
            {
                ////return StringCache.GetString(buffer, 0, actualDataSize);
                return(new string(buffer, 0, actualDataSize / sizeof(char)));
            }

            Debug.Assert(JET_wrn.BufferTruncated == wrn, "Unexpected warning code");

            // Create a fake string of the appropriate size and then fill it in.
            var s = new string('\0', actualDataSize / sizeof(char));

            fixed(char *p = s)
            {
                int newDataSize;

                wrn = JetRetrieveColumn(sesid, tableid, columnid, new IntPtr(p), actualDataSize, out newDataSize, grbit, null);
                if (JET_wrn.BufferTruncated == wrn)
                {
                    string error = String.Format(
                        CultureInfo.CurrentCulture,
                        "Column size changed from {0} to {1}. The record was probably updated by another thread.",
                        actualDataSize,
                        newDataSize);
                    Trace.TraceError(error);
                    throw new InvalidOperationException(error);
                }
            }

            return(s);
        }
예제 #10
0
 /// <summary>
 /// 对 EseNt 数据库的一些初始化操作
 /// </summary>
 public NTDS()
 {
     // set the page size for NTDS.dit(该函数用于设置数据库引擎的许多配置设置。)
     wrn = Api.JetSetSystemParameter(JET_INSTANCE.Nil, JET_SESID.Nil, JET_param.DatabasePageSize, (IntPtr)8192, null);
     if (wrn == JET_wrn.Success)
     {
         // 创建一个实例对象 - JetCreateInstance
         instance = new Instance("SharpNTDSDumpEx_0_1");
         instance.Parameters.Recovery = false;
         // 对当前实例初始化
         instance.Init();
         // 开始一个会话对象
         sesId = new Session(instance);
     }
     else
     {
         Console.WriteLine("[!] error at JetSetSystemParameter()");
     }
 }
예제 #11
0
        /// <summary>
        /// Retrieves a single column value from the current record. The record is that
        /// record associated with the index entry at the current position of the cursor.
        /// Alternatively, this function can retrieve a column from a record being created
        /// in the cursor copy buffer. This function can also retrieve column data from an
        /// index entry that references the current record. In addition to retrieving the
        /// actual column value, JetRetrieveColumn can also be used to retrieve the size
        /// of a column, before retrieving the column data itself so that application
        /// buffers can be sized appropriately.
        /// </summary>
        /// <param name="sesid">The session to use.</param>
        /// <param name="tableid">The cursor to retrieve the column from.</param>
        /// <param name="columnid">The columnid to retrieve.</param>
        /// <param name="grbit">Retrieve column options.</param>
        /// <param name="retinfo">
        /// If pretinfo is give as NULL then the function behaves as though an itagSequence
        /// of 1 and an ibLongValue of 0 (zero) were given. This causes column retrieval to
        /// retrieve the first value of a multi-valued column, and to retrieve long data at
        /// offset 0 (zero).
        /// </param>
        /// <returns>The data retrieved from the column. Null if the column is null.</returns>
        public static byte[] RetrieveColumn(
            JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, RetrieveColumnGrbit grbit, JET_RETINFO retinfo)
        {
            // We expect most column values retrieved this way to be small (retrieving a 1GB LV as one
            // chunk is a bit extreme!). Allocate a cached buffer and use that, allocating a larger one
            // if needed.
            byte[]  cache = Caches.ColumnCache.Allocate();
            byte[]  data  = cache;
            int     dataSize;
            JET_wrn wrn = JetRetrieveColumn(
                sesid, tableid, columnid, data, data.Length, out dataSize, grbit, retinfo);

            if (JET_wrn.ColumnNull == wrn)
            {
                // null column
                data = null;
            }
            else if (JET_wrn.Success == wrn)
            {
                data = MemoryCache.Duplicate(data, dataSize);
            }
            else
            {
                // there is more data to retrieve
                Debug.Assert(JET_wrn.BufferTruncated == wrn, "Unexpected warning", wrn.ToString());
                data = new byte[dataSize];
                wrn  = JetRetrieveColumn(
                    sesid, tableid, columnid, data, data.Length, out dataSize, grbit, retinfo);
                if (JET_wrn.Success != wrn)
                {
                    string error = String.Format(
                        CultureInfo.CurrentCulture,
                        "Column size changed from {0} to {1}. The record was probably updated by another thread.",
                        data.Length,
                        dataSize);
                    Trace.TraceError(error);
                    throw new InvalidOperationException(error);
                }
            }

            Caches.ColumnCache.Free(ref cache);
            return(data);
        }
예제 #12
0
        /// <summary>
        /// Initializes a new instance of the Database class.
        /// </summary>
        /// <param name="instance">An initialized instance to be used with Database. The instance should have a database attached and ready to use.</param>
        /// <param name="ownsInstance">True if the instance handle passed into the constructur should be owned by the Database.</param>
        /// <param name="customConfig">A custom config set to use with the engine. The config set should atleast contain the attached database filename.</param>
        /// <remarks>Database will only manage the handle lifetime if ownsInstance is set to true. If its set to false, the caller is responsible for managing the teardown of the instance.</remarks>
        public Database(JET_INSTANCE instance, bool ownsInstance, IConfigSet customConfig)
        {
            this.config = new DatabaseConfig();
            this.config.Merge(customConfig);
            this.instance     = instance;
            this.ownsInstance = ownsInstance;

            // Ensure that there is an attached database at a path specified by the config set
            using (var session = new Session(this.instance))
            {
                JET_DBID dbid;
                JET_wrn  wrn = Api.JetOpenDatabase(session, this.config.DatabaseFilename, null, out dbid, OpenDatabaseGrbit.ReadOnly);
                Contract.Ensures(wrn == JET_wrn.Success);
                Api.JetCloseDatabase(session, dbid, CloseDatabaseGrbit.None);
            }

            // The config set is live now
            this.config.GetParamDelegate = this.TryGetParam;
            this.config.SetParamDelegate = this.SetParam;
        }
예제 #13
0
        /// <summary>
        /// 获取列对应 LdapDisplayName
        /// </summary>
        /// <param name="mSysObjects"></param>
        /// <returns></returns>
        private Dictionary <string, string> EnumerateDatatableTableLdapDisplayNames(MSysObjectsRow[] mSysObjects)
        {
            var ldapDisplayNameToColumnNameDictionary = new Dictionary <string, string>();
            var unmatchedCount = 0;

            wrn = Api.JetOpenTable(sesId, dbId, DATATABLE, null, 0, OpenTableGrbit.ReadOnly | OpenTableGrbit.Sequential, out _tableid);
            if (wrn == JET_wrn.Success)
            {
                // 获取将列名称映射到列ID的字典
                var columnDictionary = Api.GetColumnDictionary(sesId, _tableid);
                // 遍历所有表
                Api.MoveBeforeFirst(sesId, _tableid);
                while (Api.TryMoveNext(sesId, _tableid))
                {
                    var ldapDisplayNameColumn = new StringColumnValue {
                        Columnid = columnDictionary["ATTm131532"]
                    };
                    var attributeIdColumn = new Int32ColumnValue {
                        Columnid = columnDictionary["ATTc131102"]
                    };
                    Api.RetrieveColumns(sesId, _tableid, attributeIdColumn, ldapDisplayNameColumn);
                    if (attributeIdColumn.Value != null)
                    {
                        if (Array.Find(mSysObjects, x => x.AttributeId == attributeIdColumn.Value) == null)
                        {
                            unmatchedCount++;
                        }
                        else
                        {
                            //Console.WriteLine(mSysObjects.First(x => x.AttributeId == attributeIdColumn.Value).ColumnName + ldapDisplayNameColumn.Value);
                            ldapDisplayNameToColumnNameDictionary.Add(ldapDisplayNameColumn.Value, mSysObjects.First(x => x.AttributeId == attributeIdColumn.Value).ColumnName);
                        }
                    }
                }
                //var pekListColumn = new BytesColumnValue { Columnid = columnDictionary[ldapDisplayNameToColumnNameDictionary["pekList"]] };
                //Console.WriteLine(pekListColumn);
            }

            return(ldapDisplayNameToColumnNameDictionary);
        }
예제 #14
0
        /// <summary>
        /// Retrieves a single column value from the current record. The record is that
        /// record associated with the index entry at the current position of the cursor.
        /// Alternatively, this function can retrieve a column from a record being created
        /// in the cursor copy buffer. This function can also retrieve column data from an
        /// index entry that references the current record. In addition to retrieving the
        /// actual column value, JetRetrieveColumn can also be used to retrieve the size
        /// of a column, before retrieving the column data itself so that application
        /// buffers can be sized appropriately.
        /// </summary>
        /// <param name="sesid">The session to use.</param>
        /// <param name="tableid">The cursor to retrieve the column from.</param>
        /// <param name="columnid">The columnid to retrieve.</param>
        /// <param name="grbit">Retrieve column options.</param>
        /// <param name="retinfo">
        /// If pretinfo is give as NULL then the function behaves as though an itagSequence
        /// of 1 and an ibLongValue of 0 (zero) were given. This causes column retrieval to
        /// retrieve the first value of a multi-valued column, and to retrieve long data at
        /// offset 0 (zero).
        /// </param>
        /// <returns>The data retrieved from the column. Null if the column is null.</returns>
        public static byte[] RetrieveColumn(
            JET_SESID sesid, JET_TABLEID tableid, JET_COLUMNID columnid, RetrieveColumnGrbit grbit, JET_RETINFO retinfo)
        {
            // We expect most column values retrieved this way to be small (retrieving a 1GB LV as one
            // chunk is a bit extreme!). Allocate a small buffer and use that, allocating a larger one
            // if needed.
            var     data = new byte[256];
            int     dataSize;
            JET_wrn wrn = JetRetrieveColumn(
                sesid, tableid, columnid, data, data.Length, out dataSize, grbit, retinfo);

            if (JET_wrn.ColumnNull == wrn)
            {
                // null column
                data = null;
            }
            else
            {
                Array.Resize(ref data, dataSize);
                if (JET_wrn.BufferTruncated == wrn)
                {
                    // there is more data to retrieve
                    wrn = JetRetrieveColumn(
                        sesid, tableid, columnid, data, data.Length, out dataSize, grbit, retinfo);
                    if (JET_wrn.Success != wrn)
                    {
                        string error = String.Format(
                            CultureInfo.CurrentCulture,
                            "Column size changed from {0} to {1}. The record was probably updated by another thread.",
                            data.Length,
                            dataSize);
                        Trace.TraceError(error);
                        throw new InvalidOperationException(error);
                    }
                }
            }

            return(data);
        }
예제 #15
0
        private DatatableRow[] EnumerateDatatableTable(Dictionary <string, string> ldapDisplayNameToDatatableColumnNameDictionary)
        {
            var datatable    = new List <DatatableRow>();
            var deletedCount = 0;

            wrn = Api.JetOpenTable(sesId, dbId, DATATABLE, null, 0, OpenTableGrbit.ReadOnly | OpenTableGrbit.Sequential, out _tableid);
            if (wrn == JET_wrn.Success)
            {
                // 获取将列名称映射到列ID的字典
                var columnDictionary = Api.GetColumnDictionary(sesId, _tableid);
                // 遍历所有表
                Api.MoveBeforeFirst(sesId, _tableid);
                while (Api.TryMoveNext(sesId, _tableid))
                {
                    var accountExpiresColumn = new BytesColumnValue {
                        Columnid = columnDictionary[ldapDisplayNameToDatatableColumnNameDictionary["accountExpires"]]
                    };
                    var displayNameColumn = new StringColumnValue {
                        Columnid = columnDictionary[ldapDisplayNameToDatatableColumnNameDictionary["displayName"]]
                    };
                    var distinguishedNameTagColumn = new Int32ColumnValue {
                        Columnid = columnDictionary["DNT_col"]
                    };
                    var groupTypeColumn = new Int32ColumnValue {
                        Columnid = columnDictionary[ldapDisplayNameToDatatableColumnNameDictionary["groupType"]]
                    };
                    var isDeletedColumn = new Int32ColumnValue {
                        Columnid = columnDictionary[ldapDisplayNameToDatatableColumnNameDictionary["isDeleted"]]
                    };
                    var lastLogonColumn = new LdapDateTimeColumnValue {
                        Columnid = columnDictionary[ldapDisplayNameToDatatableColumnNameDictionary["lastLogonTimestamp"]]
                    };
                    var lmColumn = new BytesColumnValue {
                        Columnid = columnDictionary[ldapDisplayNameToDatatableColumnNameDictionary["dBCSPwd"]]
                    };
                    var lmHistoryColumn = new BytesColumnValue {
                        Columnid = columnDictionary[ldapDisplayNameToDatatableColumnNameDictionary["lmPwdHistory"]]
                    };
                    var nameColumn = new StringColumnValue {
                        Columnid = columnDictionary[ldapDisplayNameToDatatableColumnNameDictionary["name"]]
                    };
                    var ntColumn = new BytesColumnValue {
                        Columnid = columnDictionary[ldapDisplayNameToDatatableColumnNameDictionary["unicodePwd"]]
                    };
                    var ntHistoryColumn = new BytesColumnValue {
                        Columnid = columnDictionary[ldapDisplayNameToDatatableColumnNameDictionary["ntPwdHistory"]]
                    };
                    var objColumn = new BoolColumnValue {
                        Columnid = columnDictionary["OBJ_col"]
                    };
                    var objectCategoryColumn = new Int32ColumnValue {
                        Columnid = columnDictionary[ldapDisplayNameToDatatableColumnNameDictionary["objectCategory"]]
                    };
                    var objectSidColumn = new BytesColumnValue {
                        Columnid = columnDictionary[ldapDisplayNameToDatatableColumnNameDictionary["objectSid"]]
                    };
                    var parentDistinguishedNameTagColumn = new Int32ColumnValue {
                        Columnid = columnDictionary["PDNT_col"]
                    };
                    var passwordLastSetColumn = new LdapDateTimeColumnValue {
                        Columnid = columnDictionary[ldapDisplayNameToDatatableColumnNameDictionary["pwdLastSet"]]
                    };
                    var pekListColumn = new BytesColumnValue {
                        Columnid = columnDictionary[ldapDisplayNameToDatatableColumnNameDictionary["pekList"]]
                    };
                    var primaryGroupIdColumn = new Int32ColumnValue {
                        Columnid = columnDictionary[ldapDisplayNameToDatatableColumnNameDictionary["primaryGroupID"]]
                    };
                    var rdnTypeColumn = new Int32ColumnValue {
                        Columnid = columnDictionary["RDNtyp_col"]
                    };                                                                                      // The RDNTyp_col holds the Attribute-ID for the attribute being used as the RDN, such as CN, OU, DC
                    var samAccountNameColumn = new StringColumnValue {
                        Columnid = columnDictionary[ldapDisplayNameToDatatableColumnNameDictionary["sAMAccountName"]]
                    };
                    var timeColumn = new LdapDateTimeColumnValue {
                        Columnid = columnDictionary["time_col"]
                    };
                    var userAccountControlColumn = new Int32ColumnValue {
                        Columnid = columnDictionary[ldapDisplayNameToDatatableColumnNameDictionary["userAccountControl"]]
                    };
                    var supplementalCredentialsColumn = new BytesColumnValue {
                        Columnid = columnDictionary[ldapDisplayNameToDatatableColumnNameDictionary["supplementalCredentials"]]
                    };

                    var columns = new List <ColumnValue>
                    {
                        accountExpiresColumn,
                        displayNameColumn,
                        distinguishedNameTagColumn,
                        groupTypeColumn,
                        isDeletedColumn,
                        lastLogonColumn,
                        nameColumn,
                        objColumn,
                        objectCategoryColumn,
                        objectSidColumn,
                        parentDistinguishedNameTagColumn,
                        passwordLastSetColumn,
                        primaryGroupIdColumn,
                        rdnTypeColumn,
                        samAccountNameColumn,
                        timeColumn,
                        userAccountControlColumn,
                        // dumpHashes
                        pekListColumn,
                        lmColumn,
                        ntColumn,
                        supplementalCredentialsColumn,
                        // includeHistoryHashes
                        lmHistoryColumn,
                        ntHistoryColumn,
                    };
                    Api.RetrieveColumns(sesId, _tableid, columns.ToArray());

                    // 跳过删除的对象
                    if (isDeletedColumn.Value.HasValue && isDeletedColumn.Value != 0)
                    {
                        deletedCount++;
                        continue;
                    }

                    // 一些已删除的对象没有isDeleted标志,但确实在DN后面附加了一个字符串 (https://support.microsoft.com/en-us/help/248047/phantoms--tombstones-and-the-infrastructure-master)
                    if (nameColumn.Value?.Contains("\nDEL:") ?? false)
                    {
                        deletedCount++;
                        continue;
                    }

                    SecurityIdentifier sid = null;
                    uint rid = 0;
                    if (objectSidColumn.Error == JET_wrn.Success)
                    {
                        var sidBytes = objectSidColumn.Value;
                        var ridBytes = sidBytes.Skip(sidBytes.Length - sizeof(int)).Take(sizeof(int)).Reverse().ToArray();
                        sidBytes = sidBytes.Take(sidBytes.Length - sizeof(int)).Concat(ridBytes).ToArray();
                        rid      = BitConverter.ToUInt32(ridBytes, 0);
                        sid      = new SecurityIdentifier(sidBytes, 0);
                    }
                    var row = new DatatableRow
                    {
                        AccountExpires          = accountExpiresColumn.Value,
                        DisplayName             = displayNameColumn.Value,
                        Dnt                     = distinguishedNameTagColumn.Value,
                        GroupType               = groupTypeColumn.Value,
                        LastLogon               = lastLogonColumn.Value,
                        Name                    = nameColumn.Value,
                        ObjectCategoryDnt       = objectCategoryColumn.Value,
                        Rid                     = rid,
                        Sid                     = sid,
                        ParentDnt               = parentDistinguishedNameTagColumn.Value,
                        Phantom                 = objColumn.Value == false,
                        LastPasswordChange      = passwordLastSetColumn.Value,
                        PrimaryGroupDnt         = primaryGroupIdColumn.Value,
                        RdnType                 = rdnTypeColumn.Value,
                        SamAccountName          = samAccountNameColumn.Value,
                        UserAccountControlValue = userAccountControlColumn.Value,
                    };

                    if (pekListColumn.Value != null)
                    {
                        row.PekList = pekListColumn.Value;
                    }

                    if (lmColumn.Value != null)
                    {
                        row.EncryptedLmHash = lmColumn.Value;
                    }

                    if (ntColumn.Value != null)
                    {
                        row.EncryptedNtHash = ntColumn.Value;
                    }

                    if (lmHistoryColumn.Value != null)
                    {
                        row.EncryptedLmHistory = lmHistoryColumn.Value;
                    }

                    if (ntHistoryColumn.Value != null)
                    {
                        row.EncryptedNtHistory = ntHistoryColumn.Value;
                    }

                    if (supplementalCredentialsColumn.Value != null)
                    {
                        row.SupplementalCredentialsBlob = supplementalCredentialsColumn.Value;
                    }

                    datatable.Add(row);
                }
            }
            return(datatable.ToArray());
        }
        public void ULongLongSortOrder()
        {
            // Create table with ULongLong column and index over ULongLong column.
            if (EsentVersion.SupportsWindows10Features)
            {
                this.CreatePopulateAndTestTable();
            }
            else
            {
                try
                {
                    this.CreatePopulateAndTestTable();
                }
                catch (EsentInvalidColumnTypeException)
                {
                    return;
                }
            }

            Api.JetCloseDatabase(this.sesId, this.databaseId, CloseDatabaseGrbit.None);
            Api.JetDetachDatabase(this.sesId, this.database);

#if !MANAGEDESENT_ON_WSA // Not exposed in MSDK
            EseInteropTestHelper.ConsoleWriteLine("Compact database.");
            Api.JetAttachDatabase(this.sesId, this.database, Windows8Grbits.PurgeCacheOnAttach);
            Api.JetCompact(this.sesId, this.database, Path.Combine(this.directory, "defragged.edb"), null, null, CompactGrbit.None);
            Api.JetDetachDatabase(this.sesId, this.database);

            this.database = Path.Combine(this.directory, "defragged.edb");
            Assert.IsTrue(EseInteropTestHelper.FileExists(this.database));
#endif // !MANAGEDESENT_ON_WSA
            Api.JetAttachDatabase(this.sesId, this.database, Windows8Grbits.PurgeCacheOnAttach);

            Api.JetOpenDatabase(this.sesId, this.database, null, out this.databaseId, OpenDatabaseGrbit.None);
            Api.JetOpenTable(this.sesId, this.databaseId, this.tableName, null, 0, OpenTableGrbit.None, out this.tableId);

            // validate order after having closed the database and restarted
            ulong ulongPrev;
            ulong ulongCur;
            Api.JetMove(this.sesId, this.tableId, JET_Move.First, MoveGrbit.None);
            int    bytesRead;
            byte[] data = new byte[8];
            Api.JetRetrieveColumn(this.sesId, this.tableId, this.columnIdKey1, data, data.Length, out bytesRead, 0, null);
            ulongPrev = BitConverter.ToUInt64(data, 0);
            for (int i = 1; i < 3; i++)
            {
                Api.JetMove(this.sesId, this.tableId, JET_Move.Next, MoveGrbit.None);
                Api.JetRetrieveColumn(this.sesId, this.tableId, this.columnIdKey1, data, data.Length, out bytesRead, 0, null);
                ulongCur = BitConverter.ToUInt64(data, 0);
                Assert.IsTrue(ulongCur.CompareTo(ulongPrev) > 0);
                ulongPrev = ulongCur;
            }

            EseInteropTestHelper.ConsoleWriteLine("Validated order.");

            // retrieve newly inserted ULongLong from index and compare values
            // to test denormalization logic
            ulong  ulongT   = 0;
            byte[] keyArray = BitConverter.GetBytes(ulongT);
            Api.JetSetCurrentIndex(this.sesId, this.tableId, this.secIndexName);
            Api.JetMakeKey(this.sesId, this.tableId, keyArray, keyArray.Length, MakeKeyGrbit.NewKey);
            Api.JetSeek(this.sesId, this.tableId, SeekGrbit.SeekEQ);
            JET_wrn err = Api.JetRetrieveColumn(this.sesId, this.tableId, this.columnIdKey1, data, data.Length, out bytesRead, RetrieveColumnGrbit.RetrieveFromIndex, null);
            Assert.AreEqual(data.Length, bytesRead);
            ulongCur = BitConverter.ToUInt64(data, 0);
            Assert.IsTrue(ulongCur.CompareTo(ulongT) == 0);

            EseInteropTestHelper.ConsoleWriteLine("Retrieved ulong is:");
            EseInteropTestHelper.ConsoleWriteLine(ulongCur.ToString());
            Assert.IsTrue(ulongCur.CompareTo(ulongT) == 0);
            EseInteropTestHelper.ConsoleWriteLine("Retrieve from index matches inserted ULongLong");

            Api.JetCloseTable(this.sesId, this.tableId);
        }
예제 #17
0
        /// <summary>
        /// Verifies the current record.
        /// </summary>
        /// <param name="tableId">The table id.</param>
        /// <param name="keyExpected">The key expected.</param>
        /// <param name="data1Expected">The data1 expected.</param>
        /// <param name="data2Expected">The data2 expected.</param>
        /// <param name="exTypeExpected">The ex type expected.</param>
        private void VerifyCurrentRecord(JET_TABLEID tableId, int keyExpected, int data1Expected, int data2Expected, Type exTypeExpected)
        {
            byte[] keyArray   = new byte[sizeof(int)];
            byte[] data1Array = new byte[sizeof(int)];
            byte[] data2Array = new byte[sizeof(int)];

            JET_RETRIEVECOLUMN[] retrieveColumns = new[]
            {
                new JET_RETRIEVECOLUMN
                {
                    columnid     = this.columnIdKey,
                    pvData       = keyArray,
                    cbData       = keyArray.Length,
                    itagSequence = 1
                },

                new JET_RETRIEVECOLUMN
                {
                    columnid     = this.columnIdData1,
                    pvData       = data1Array,
                    cbData       = data1Array.Length,
                    itagSequence = 1
                },

                new JET_RETRIEVECOLUMN
                {
                    columnid     = this.columnIdData2,
                    pvData       = data2Array,
                    cbData       = data2Array.Length,
                    itagSequence = 1
                }
            };

            try
            {
                JET_wrn err = Api.JetRetrieveColumns(this.sesId, tableId, retrieveColumns, retrieveColumns.Length);

                if (exTypeExpected != null)
                {
                    Assert.Fail("Should have thrown {0}", exTypeExpected);
                }

                Assert.AreEqual <JET_wrn>(JET_wrn.Success, err);
                Assert.AreEqual <int>(keyArray.Length, retrieveColumns[0].cbActual);
                Assert.AreEqual <int>(data1Array.Length, retrieveColumns[1].cbActual);
                Assert.AreEqual <int>(data1Array.Length, retrieveColumns[2].cbActual);

                int keyActual   = BitConverter.ToInt32(keyArray, 0);
                int data1Actual = BitConverter.ToInt32(data1Array, 0);
                int data2Actual = BitConverter.ToInt32(data2Array, 0);

                Assert.AreEqual <int>(keyExpected, keyActual);
                Assert.AreEqual <int>(data1Expected, data1Actual);
                Assert.AreEqual <int>(data2Expected, data2Actual);
            }
            catch (EsentException ex)
            {
                if (exTypeExpected != null)
                {
                    Assert.AreEqual <Type>(exTypeExpected, ex.GetType());
                }
                else
                {
                    throw;
                }
            }
        }
        public void TestDotNetGuidSortOrder()
        {
            if (!EsentVersion.SupportsWindows8Features)
            {
                return;
            }

            // Create table with GUID column and index over GUID column.
            this.CreatePopulateAndTestTable();

            Api.JetCloseDatabase(this.sesId, this.databaseId, CloseDatabaseGrbit.None);
            Api.JetDetachDatabase(this.sesId, this.database);

#if !MANAGEDESENT_ON_WSA // Not exposed in MSDK
            EseInteropTestHelper.ConsoleWriteLine("Compact database.");
            Api.JetAttachDatabase(this.sesId, this.database, Windows8Grbits.PurgeCacheOnAttach);
            Api.JetCompact(this.sesId, this.database, Path.Combine(this.directory, "defragged.edb"), null, null, CompactGrbit.None);
            Api.JetDetachDatabase(this.sesId, this.database);

            this.database = Path.Combine(this.directory, "defragged.edb");
            Assert.IsTrue(EseInteropTestHelper.FileExists(this.database));
#endif // !MANAGEDESENT_ON_WSA
            Api.JetAttachDatabase(this.sesId, this.database, Windows8Grbits.PurgeCacheOnAttach);

            Api.JetOpenDatabase(this.sesId, this.database, null, out this.databaseId, OpenDatabaseGrbit.None);
            Api.JetOpenTable(this.sesId, this.databaseId, this.tableName, null, 0, OpenTableGrbit.None, out this.tableId);

            Api.JetBeginTransaction(this.sesId);
            EseInteropTestHelper.ConsoleWriteLine("Insert more values in index.");
            for (int i = 0; i < 10000; i++)
            {
                if ((i % 2000) == 0)
                {
                    EseInteropTestHelper.ConsoleWriteLine("Added another 2000 Guids.");
                }

                Api.JetCommitTransaction(this.sesId, CommitTransactionGrbit.None);
                Api.JetBeginTransaction(this.sesId);
                this.InsertRecord(this.tableId, System.Guid.NewGuid());
            }

            Api.JetCommitTransaction(this.sesId, CommitTransactionGrbit.None);
            EseInteropTestHelper.ConsoleWriteLine("Finished inserting more values in index.");

            // validate order after having closed the database and restarted
            Guid guidPrev;
            Guid guidCur;
            Api.JetMove(this.sesId, this.tableId, JET_Move.First, MoveGrbit.None);
            int    bytesRead;
            byte[] data = new byte[16];
            Api.JetRetrieveColumn(this.sesId, this.tableId, this.columnIdKey1, data, data.Length, out bytesRead, 0, null);
            guidPrev = new System.Guid(data);
            for (int i = 1; i < 10000; i++)
            {
                Api.JetMove(this.sesId, this.tableId, JET_Move.Next, MoveGrbit.None);
                Api.JetRetrieveColumn(this.sesId, this.tableId, this.columnIdKey1, data, data.Length, out bytesRead, 0, null);
                guidCur = new System.Guid(data);
                Assert.IsTrue(guidCur.CompareTo(guidPrev) > 0);
                guidPrev = guidCur;
            }

            EseInteropTestHelper.ConsoleWriteLine("Validated order.");

            // retrieve newly inserted GUID from index and compare values
            // to test denormalization logic
            Guid guidT = System.Guid.NewGuid();
            EseInteropTestHelper.ConsoleWriteLine("Allocate random GUID...");
            EseInteropTestHelper.ConsoleWriteLine(guidT.ToString());
            this.InsertRecord(this.tableId, guidT);
            Api.JetSetCurrentIndex(this.sesId, this.tableId, this.secIndexName);
            EseInteropTestHelper.ConsoleWriteLine("Guid inserted is....");
            EseInteropTestHelper.ConsoleWriteLine("{0}", guidT);
            byte[] keyArray = guidT.ToByteArray();
            Api.JetMakeKey(this.sesId, this.tableId, keyArray, keyArray.Length, MakeKeyGrbit.NewKey);
            Api.JetSeek(this.sesId, this.tableId, SeekGrbit.SeekEQ);

            Api.JetSetCurrentIndex(this.sesId, this.tableId, this.secIndexName);
            keyArray = guidT.ToByteArray();
            Api.JetMakeKey(this.sesId, this.tableId, keyArray, keyArray.Length, MakeKeyGrbit.NewKey);
            Api.JetSeek(this.sesId, this.tableId, SeekGrbit.SeekEQ);
            JET_wrn err = Api.JetRetrieveColumn(this.sesId, this.tableId, this.columnIdKey1, data, data.Length, out bytesRead, RetrieveColumnGrbit.RetrieveFromIndex, null);
            Assert.AreEqual(data.Length, bytesRead);
            EseInteropTestHelper.ConsoleWriteLine("Found random GUID in index...");
            Guid guidTT = new System.Guid(data);
            Assert.AreEqual(guidT, guidTT);
            EseInteropTestHelper.ConsoleWriteLine("Found specific GUID in index");

            // check retrieve from index for denormalization
            // by comparing guid inserted.  They should match.
            Api.JetRetrieveColumn(this.sesId, this.tableId, this.columnIdKey1, data, data.Length, out bytesRead, RetrieveColumnGrbit.RetrieveFromIndex, null);
            guidCur = new System.Guid(data);
            EseInteropTestHelper.ConsoleWriteLine("Retrieved Guid is:");
            EseInteropTestHelper.ConsoleWriteLine(guidCur.ToString());
            Assert.IsTrue(guidCur.CompareTo(guidT) == 0);
            EseInteropTestHelper.ConsoleWriteLine("Retrieve from index matches inserted GUID");

            Api.JetCloseTable(this.sesId, this.tableId);

            this.TestTempTableWithGuidDotNetSortOrder();
        }
예제 #19
0
 /// <summary>
 /// Update the output members of the class from a NATIVE_RETRIEVECOLUMN
 /// structure. This should be done after the columns are retrieved.
 /// </summary>
 /// <param name="native">
 /// The structure containing the updated output fields.
 /// </param>
 /// <remarks>
 /// This takes a reference because a NATIVE_RETRIEVECOLUMN is quite large (40 bytes)
 /// so copying it around can be expensive.
 /// </remarks>
 internal void UpdateFromNativeRetrievecolumn(ref NATIVE_RETRIEVECOLUMN native)
 {
     this.cbActual = checked((int)native.cbActual);
     this.columnidNextTagged = new JET_COLUMNID { Value = native.columnidNextTagged };
     this.itagSequence = checked((int)native.itagSequence);
     this.err = (JET_wrn)native.err;
 }