Enhanced support of downlevel DB schemas
This commit is contained in:
parent
7453ac8457
commit
1e5f7eef28
|
@ -1,7 +1,6 @@
|
|||
namespace DSInternals.Common.Data
|
||||
{
|
||||
using DSInternals.Common.Cryptography;
|
||||
using DSInternals.Common.Exceptions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.AccessControl;
|
||||
|
@ -442,55 +441,49 @@
|
|||
/// </summary>
|
||||
protected void LoadRoamedCredentials(DirectoryObject dsObject)
|
||||
{
|
||||
try
|
||||
// These attributes have been added in Windows Server 2008, so they might not be present on older DCs.
|
||||
byte[] roamingTimeStamp;
|
||||
dsObject.ReadAttribute(CommonDirectoryAttributes.PKIRoamingTimeStamp, out roamingTimeStamp);
|
||||
|
||||
if (roamingTimeStamp == null)
|
||||
{
|
||||
byte[] roamingTimeStamp;
|
||||
dsObject.ReadAttribute(CommonDirectoryAttributes.PKIRoamingTimeStamp, out roamingTimeStamp);
|
||||
|
||||
if (roamingTimeStamp == null)
|
||||
{
|
||||
// This account does not have roamed credentials, so we skip their processing
|
||||
return;
|
||||
}
|
||||
|
||||
// The 16B of the value consist of two 8B actual time stamps.
|
||||
long createdTimeStamp = BitConverter.ToInt64(roamingTimeStamp, 0);
|
||||
long modifiedTimeStamp = BitConverter.ToInt64(roamingTimeStamp, sizeof(long));
|
||||
|
||||
this.RoamedCredentialsCreated = DateTime.FromFileTime(createdTimeStamp);
|
||||
this.RoamedCredentialsModified = DateTime.FromFileTime(modifiedTimeStamp);
|
||||
|
||||
byte[][] masterKeyBlobs;
|
||||
dsObject.ReadLinkedValues(CommonDirectoryAttributes.PKIDPAPIMasterKeys, out masterKeyBlobs);
|
||||
|
||||
byte[][] credentialBlobs;
|
||||
dsObject.ReadLinkedValues(CommonDirectoryAttributes.PKIAccountCredentials, out credentialBlobs);
|
||||
|
||||
// Parse the blobs and combine them into one array.
|
||||
var credentials = new List<RoamedCredential>();
|
||||
|
||||
if (masterKeyBlobs != null)
|
||||
{
|
||||
foreach (var blob in masterKeyBlobs)
|
||||
{
|
||||
credentials.Add(new RoamedCredential(blob, this.SamAccountName, this.Sid));
|
||||
}
|
||||
}
|
||||
|
||||
if(credentialBlobs != null)
|
||||
{
|
||||
foreach (var blob in credentialBlobs)
|
||||
{
|
||||
credentials.Add(new RoamedCredential(blob, this.SamAccountName, this.Sid));
|
||||
}
|
||||
}
|
||||
|
||||
this.RoamedCredentials = credentials.ToArray();
|
||||
// This account does not have roamed credentials, so we skip their processing
|
||||
return;
|
||||
}
|
||||
catch (SchemaAttributeNotFoundException)
|
||||
|
||||
// The 16B of the value consist of two 8B actual time stamps.
|
||||
long createdTimeStamp = BitConverter.ToInt64(roamingTimeStamp, 0);
|
||||
long modifiedTimeStamp = BitConverter.ToInt64(roamingTimeStamp, sizeof(long));
|
||||
|
||||
this.RoamedCredentialsCreated = DateTime.FromFileTime(createdTimeStamp);
|
||||
this.RoamedCredentialsModified = DateTime.FromFileTime(modifiedTimeStamp);
|
||||
|
||||
byte[][] masterKeyBlobs;
|
||||
dsObject.ReadLinkedValues(CommonDirectoryAttributes.PKIDPAPIMasterKeys, out masterKeyBlobs);
|
||||
|
||||
byte[][] credentialBlobs;
|
||||
dsObject.ReadLinkedValues(CommonDirectoryAttributes.PKIAccountCredentials, out credentialBlobs);
|
||||
|
||||
// Parse the blobs and combine them into one array.
|
||||
var credentials = new List<RoamedCredential>();
|
||||
|
||||
if (masterKeyBlobs != null)
|
||||
{
|
||||
// These attributes have been added in Windows Server 2008, so they might not be present on older DCs.
|
||||
foreach (var blob in masterKeyBlobs)
|
||||
{
|
||||
credentials.Add(new RoamedCredential(blob, this.SamAccountName, this.Sid));
|
||||
}
|
||||
}
|
||||
|
||||
if(credentialBlobs != null)
|
||||
{
|
||||
foreach (var blob in credentialBlobs)
|
||||
{
|
||||
credentials.Add(new RoamedCredential(blob, this.SamAccountName, this.Sid));
|
||||
}
|
||||
}
|
||||
|
||||
this.RoamedCredentials = credentials.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -498,28 +491,22 @@
|
|||
/// </summary>
|
||||
protected void LoadKeyCredentials(DirectoryObject dsObject)
|
||||
{
|
||||
try
|
||||
// This attribute has been added in Windows Server 2016, so it might not be present on older DCs.
|
||||
byte[][] keyCredentialBlobs;
|
||||
dsObject.ReadLinkedValues(CommonDirectoryAttributes.KeyCredentialLink, out keyCredentialBlobs);
|
||||
|
||||
// Parse the blobs and combine them into one array.
|
||||
var credentials = new List<KeyCredential>();
|
||||
|
||||
if (keyCredentialBlobs != null)
|
||||
{
|
||||
byte[][] keyCredentialBlobs;
|
||||
dsObject.ReadLinkedValues(CommonDirectoryAttributes.KeyCredentialLink, out keyCredentialBlobs);
|
||||
|
||||
// Parse the blobs and combine them into one array.
|
||||
var credentials = new List<KeyCredential>();
|
||||
|
||||
if (keyCredentialBlobs != null)
|
||||
foreach (var blob in keyCredentialBlobs)
|
||||
{
|
||||
foreach (var blob in keyCredentialBlobs)
|
||||
{
|
||||
credentials.Add(new KeyCredential(blob));
|
||||
}
|
||||
credentials.Add(new KeyCredential(blob));
|
||||
}
|
||||
}
|
||||
|
||||
this.KeyCredentials = credentials.ToArray();
|
||||
}
|
||||
catch (SchemaAttributeNotFoundException)
|
||||
{
|
||||
// This attribute has been added in Windows Server 2016, so it might not be present on older DCs.
|
||||
}
|
||||
this.KeyCredentials = credentials.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -69,7 +69,6 @@
|
|||
Columnid columnId = this.context.Schema.FindColumnId(CommonDirectoryAttributes.SIDHistory);
|
||||
bool hasChanged = this.cursor.AddMultiValue(columnId, valuesToAdd);
|
||||
return hasChanged;
|
||||
|
||||
}
|
||||
|
||||
public void Delete()
|
||||
|
@ -85,52 +84,110 @@
|
|||
|
||||
public override bool HasAttribute(string name)
|
||||
{
|
||||
Columnid columnId = this.context.Schema.FindColumnId(name);
|
||||
long columnSize = cursor.Record.SizeOf(columnId);
|
||||
return columnSize > 0;
|
||||
if(this.context.Schema.ContainsAttribute(name))
|
||||
{
|
||||
// Read the appropriate column and check if it has a value
|
||||
Columnid columnId = this.context.Schema.FindColumnId(name);
|
||||
long columnSize = cursor.Record.SizeOf(columnId);
|
||||
return columnSize > 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The schema does not even contain this attribute, so the object cannot have it.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override void ReadAttribute(string name, out byte[] value)
|
||||
{
|
||||
Columnid columnId = this.context.Schema.FindColumnId(name);
|
||||
value = this.cursor.RetrieveColumnAsByteArray(columnId);
|
||||
if(this.context.Schema.ContainsAttribute(name))
|
||||
{
|
||||
Columnid columnId = this.context.Schema.FindColumnId(name);
|
||||
value = this.cursor.RetrieveColumnAsByteArray(columnId);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void ReadAttribute(string name, out byte[][] value)
|
||||
{
|
||||
Columnid columnId = this.context.Schema.FindColumnId(name);
|
||||
value = this.cursor.RetrieveColumnAsMultiByteArray(columnId);
|
||||
if (this.context.Schema.ContainsAttribute(name))
|
||||
{
|
||||
Columnid columnId = this.context.Schema.FindColumnId(name);
|
||||
value = this.cursor.RetrieveColumnAsMultiByteArray(columnId);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void ReadAttribute(string name, out int? value)
|
||||
{
|
||||
Columnid columnId = this.context.Schema.FindColumnId(name);
|
||||
value = this.cursor.RetrieveColumnAsInt(columnId);
|
||||
if (this.context.Schema.ContainsAttribute(name))
|
||||
{
|
||||
Columnid columnId = this.context.Schema.FindColumnId(name);
|
||||
value = this.cursor.RetrieveColumnAsInt(columnId);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void ReadAttribute(string name, out string value)
|
||||
{
|
||||
Columnid columnId = this.context.Schema.FindColumnId(name);
|
||||
value = this.cursor.RetrieveColumnAsString(columnId);
|
||||
if (this.context.Schema.ContainsAttribute(name))
|
||||
{
|
||||
Columnid columnId = this.context.Schema.FindColumnId(name);
|
||||
value = this.cursor.RetrieveColumnAsString(columnId);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void ReadAttribute(string name, out string[] values)
|
||||
{
|
||||
Columnid columnId = this.context.Schema.FindColumnId(name);
|
||||
values = this.cursor.RetrieveColumnAsStringArray(columnId);
|
||||
if (this.context.Schema.ContainsAttribute(name))
|
||||
{
|
||||
Columnid columnId = this.context.Schema.FindColumnId(name);
|
||||
values = this.cursor.RetrieveColumnAsStringArray(columnId);
|
||||
}
|
||||
else
|
||||
{
|
||||
values = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void ReadAttribute(string name, out long? value)
|
||||
{
|
||||
Columnid columnId = this.context.Schema.FindColumnId(name);
|
||||
value = this.cursor.RetrieveColumnAsLong(columnId);
|
||||
if (this.context.Schema.ContainsAttribute(name))
|
||||
{
|
||||
Columnid columnId = this.context.Schema.FindColumnId(name);
|
||||
value = this.cursor.RetrieveColumnAsLong(columnId);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void ReadAttribute(string name, out DistinguishedName value)
|
||||
{
|
||||
Columnid columnId = this.context.Schema.FindColumnId(name);
|
||||
var dnt = this.cursor.RetrieveColumnAsDNTag(columnId);
|
||||
value = this.context.DistinguishedNameResolver.Resolve(dnt.Value);
|
||||
if (this.context.Schema.ContainsAttribute(name))
|
||||
{
|
||||
Columnid columnId = this.context.Schema.FindColumnId(name);
|
||||
var dnt = this.cursor.RetrieveColumnAsDNTag(columnId);
|
||||
value = this.context.DistinguishedNameResolver.Resolve(dnt.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void ReadAttribute(string name, out RawSecurityDescriptor value)
|
||||
|
@ -150,6 +207,7 @@
|
|||
|
||||
public void ReadAttribute(string name, out AttributeMetadataCollection value)
|
||||
{
|
||||
|
||||
byte[] binaryValue;
|
||||
this.ReadAttribute(name, out binaryValue);
|
||||
value = new AttributeMetadataCollection(binaryValue);
|
||||
|
@ -209,4 +267,4 @@
|
|||
this.SetAttribute(CommonDirectoryAttributes.PropertyMetaData, meta.ToByteArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +1,13 @@
|
|||
namespace DSInternals.DataStore
|
||||
{
|
||||
using DSInternals.Common;
|
||||
using DSInternals.Common.Data;
|
||||
using DSInternals.Common.Exceptions;
|
||||
using Microsoft.Database.Isam;
|
||||
using Microsoft.Isam.Esent.Interop;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using DSInternals.Common.Data;
|
||||
using Microsoft.Database.Isam;
|
||||
using DSInternals.Common;
|
||||
using DSInternals.Common.Exceptions;
|
||||
using Microsoft.Isam.Esent.Interop;
|
||||
|
||||
/// <summary>
|
||||
/// The ActiveDirectorySchema class represents the schema partition for a particular domain.
|
||||
|
@ -82,6 +81,12 @@
|
|||
}
|
||||
}
|
||||
|
||||
public bool ContainsAttribute(string attributeName)
|
||||
{
|
||||
Validator.AssertNotNullOrWhiteSpace(attributeName, "attributeName");
|
||||
return this.attributesByName.ContainsKey(attributeName.ToLower());
|
||||
}
|
||||
|
||||
public SchemaAttribute FindAttribute(int internalId)
|
||||
{
|
||||
SchemaAttribute attribute;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
using Microsoft.Database.Isam;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace DSInternals.DataStore
|
||||
namespace DSInternals.DataStore
|
||||
{
|
||||
using Microsoft.Database.Isam;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public class LinkResolver : IDisposable
|
||||
{
|
||||
// Column names:
|
||||
|
@ -56,6 +56,12 @@ namespace DSInternals.DataStore
|
|||
|
||||
public IEnumerable<int> GetLinkedDNTags(int dnTag, string attributeName)
|
||||
{
|
||||
if (!this.schema.ContainsAttribute(attributeName))
|
||||
{
|
||||
// If the schema does not contain this attribute at all, we pretend it to have an empty value.
|
||||
yield break;
|
||||
}
|
||||
|
||||
// TODO: Check that the attribute type is DN
|
||||
this.FindLinkedRecords(dnTag, attributeName);
|
||||
|
||||
|
@ -70,6 +76,12 @@ namespace DSInternals.DataStore
|
|||
|
||||
public IEnumerable<byte[]> GetLinkedValues(int dnTag, string attributeName)
|
||||
{
|
||||
if(!this.schema.ContainsAttribute(attributeName))
|
||||
{
|
||||
// If the schema does not contain this attribute at all, we pretend it to have an empty value.
|
||||
yield break;
|
||||
}
|
||||
|
||||
// TODO: Check that the attribute is DN-Binary.
|
||||
this.FindLinkedRecords(dnTag, attributeName);
|
||||
|
||||
|
@ -87,6 +99,7 @@ namespace DSInternals.DataStore
|
|||
this.Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && cursor != null)
|
||||
|
@ -112,4 +125,4 @@ namespace DSInternals.DataStore
|
|||
this.cursor.FindRecords(MatchCriteria.EqualTo, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue