// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using dnlib.DotNet.MD;
using dnlib.DotNet.Pdb;
namespace dnlib.DotNet {
///
/// A high-level representation of a row in the DeclSecurity table
///
[DebuggerDisplay("{Action} Count={SecurityAttributes.Count}")]
public abstract class DeclSecurity : IHasCustomAttribute, IHasCustomDebugInformation {
///
/// The row id in its table
///
protected uint rid;
///
public MDToken MDToken => new MDToken(Table.DeclSecurity, rid);
///
public uint Rid {
get => rid;
set => rid = value;
}
///
public int HasCustomAttributeTag => 8;
///
/// From column DeclSecurity.Action
///
public SecurityAction Action {
get => action;
set => action = value;
}
///
protected SecurityAction action;
///
/// From column DeclSecurity.PermissionSet
///
public IList SecurityAttributes {
get {
if (securityAttributes is null)
InitializeSecurityAttributes();
return securityAttributes;
}
}
///
protected IList securityAttributes;
/// Initializes
protected virtual void InitializeSecurityAttributes() =>
Interlocked.CompareExchange(ref securityAttributes, new List(), null);
///
/// Gets all custom attributes
///
public CustomAttributeCollection CustomAttributes {
get {
if (customAttributes is null)
InitializeCustomAttributes();
return customAttributes;
}
}
///
protected CustomAttributeCollection customAttributes;
/// Initializes
protected virtual void InitializeCustomAttributes() =>
Interlocked.CompareExchange(ref customAttributes, new CustomAttributeCollection(), null);
///
public bool HasCustomAttributes => CustomAttributes.Count > 0;
///
public int HasCustomDebugInformationTag => 8;
///
public bool HasCustomDebugInfos => CustomDebugInfos.Count > 0;
///
/// Gets all custom debug infos
///
public IList CustomDebugInfos {
get {
if (customDebugInfos is null)
InitializeCustomDebugInfos();
return customDebugInfos;
}
}
///
protected IList customDebugInfos;
/// Initializes
protected virtual void InitializeCustomDebugInfos() =>
Interlocked.CompareExchange(ref customDebugInfos, new List(), null);
///
/// true if is not empty
///
public bool HasSecurityAttributes => SecurityAttributes.Count > 0;
///
/// Gets the blob data or null if there's none
///
/// Blob data or null
public abstract byte[] GetBlob();
///
/// Returns the .NET Framework 1.x XML string or null if it's not a .NET Framework 1.x format
///
///
public string GetNet1xXmlString() => GetNet1xXmlStringInternal(SecurityAttributes);
internal static string GetNet1xXmlStringInternal(IList secAttrs) {
if (secAttrs is null || secAttrs.Count != 1)
return null;
var sa = secAttrs[0];
if (sa is null || sa.TypeFullName != "System.Security.Permissions.PermissionSetAttribute")
return null;
if (sa.NamedArguments.Count != 1)
return null;
var na = sa.NamedArguments[0];
if (na is null || !na.IsProperty || na.Name != "XML")
return null;
if (na.ArgumentType.GetElementType() != ElementType.String)
return null;
var arg = na.Argument;
if (arg.Type.GetElementType() != ElementType.String)
return null;
var utf8 = arg.Value as UTF8String;
if (utf8 is not null)
return utf8;
if (arg.Value is string s)
return s;
return null;
}
}
///
/// A DeclSecurity row created by the user and not present in the original .NET file
///
public class DeclSecurityUser : DeclSecurity {
///
/// Default constructor
///
public DeclSecurityUser() {
}
///
/// Constructor
///
/// The security action
/// The security attributes (now owned by this)
public DeclSecurityUser(SecurityAction action, IList securityAttrs) {
this.action = action;
securityAttributes = securityAttrs;
}
///
public override byte[] GetBlob() => null;
}
///
/// Created from a row in the DeclSecurity table
///
sealed class DeclSecurityMD : DeclSecurity, IMDTokenProviderMD {
/// The module where this instance is located
readonly ModuleDefMD readerModule;
readonly uint origRid;
readonly uint permissionSet;
///
public uint OrigRid => origRid;
///
protected override void InitializeSecurityAttributes() {
var gpContext = new GenericParamContext();
var tmp = DeclSecurityReader.Read(readerModule, permissionSet, gpContext);
Interlocked.CompareExchange(ref securityAttributes, tmp, null);
}
///
protected override void InitializeCustomAttributes() {
var list = readerModule.Metadata.GetCustomAttributeRidList(Table.DeclSecurity, origRid);
var tmp = new CustomAttributeCollection(list.Count, list, (list2, index) => readerModule.ReadCustomAttribute(list[index]));
Interlocked.CompareExchange(ref customAttributes, tmp, null);
}
///
protected override void InitializeCustomDebugInfos() {
var list = new List();
var gpContext = new GenericParamContext();
readerModule.InitializeCustomDebugInfos(new MDToken(MDToken.Table, origRid), gpContext, list);
Interlocked.CompareExchange(ref customDebugInfos, list, null);
}
///
/// Constructor
///
/// The module which contains this DeclSecurity row
/// Row ID
/// If is null
/// If is invalid
public DeclSecurityMD(ModuleDefMD readerModule, uint rid) {
#if DEBUG
if (readerModule is null)
throw new ArgumentNullException("readerModule");
if (readerModule.TablesStream.DeclSecurityTable.IsInvalidRID(rid))
throw new BadImageFormatException($"DeclSecurity rid {rid} does not exist");
#endif
origRid = rid;
this.rid = rid;
this.readerModule = readerModule;
bool b = readerModule.TablesStream.TryReadDeclSecurityRow(origRid, out var row);
Debug.Assert(b);
permissionSet = row.PermissionSet;
action = (SecurityAction)row.Action;
}
///
public override byte[] GetBlob() => readerModule.BlobStream.Read(permissionSet);
}
}