singrdk/base/Kernel/Singularity.Security/Service/PrincipalImpl.sg

335 lines
12 KiB
Plaintext

///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
namespace Microsoft.Singularity.Security
{
using System;
using System.Threading;
using System.Collections;
using System.Text;
using Microsoft.Singularity.Loader;
using Microsoft.Singularity.Xml;
using Microsoft.Singularity.Io;
public class PrincipalImpl
{
private const string KernelName = "kernel.localhost";
private const string UnknownName = "unknown";
private const string UnknownPublisher = "unknown";
private const string DefaultNameContext = "localhost";
private const string TruncateHistoryPrivilege = "$truncate-history-privilege.localhost";
// security tags in config XML
const string AuthPolicyXmlTag = "authpolicy";
const string SubexprXmlTag = "subexpr";
const string SubexprNameXmlAttribute = "name";
const string SubexprExpansionXmlAttribute = "expansion";
const string AuthorityXmlTag = "authority";
const string AuthorityNameXmlAttribute = "name";
const string AuthorityAclXmlAttribute = "acl";
private static Hashtable! principalHT; // map from principal Val (ulong) to PrincipalT
private static Hashtable! exprHT; // map from subexpr name to description (both strings)
private static Hashtable! privHT; // map from privilege name to ArrayList of PrincipalT
private static Hashtable! authorityHT; // map from authority name to acl expansion (both strings)
private static Hashtable! publisherHT; // map from publisher name to PrincipalT
private const char CharInvocation = '+';
private const char CharRole = '@';
private const string NullName = "";
private const ulong KernelIdNum = 1;
private static ulong nextIdVal = KernelIdNum + (ulong)1;
private static SecurityDiagnostics! secDiag;
private static AclCore! aclCore;
internal class PrincipalT {
internal string! name;
internal string manifestName;
internal string[] privs;
internal ulong val;
internal PrincipalT publisherT;
internal ArrayList principalHashes;
internal PrincipalT(string! _name, string _maniName, string[] _privs, PrincipalT _publisherT)
{
name = _name;
manifestName = _maniName;
privs = _privs;
val = 0L;
publisherT = _publisherT;
principalHashes = null;
}
internal PrincipalT(string! _name, string _maniName, string[] _privs, PrincipalT _publisherT, ArrayList _principalHashes)
{
name = _name;
manifestName = _maniName;
privs = _privs;
val = 0L;
publisherT = _publisherT;
principalHashes = _principalHashes;
}
}
public static void Initialize(XmlNode! config)
{
// kernel publisher T is currently "unknown". fix this (maybe)
// one way to fix it is to have kernel manifest here, but that
// isn't currently possible.
principalHT = new Hashtable();
exprHT = new Hashtable();
privHT = new Hashtable();
authorityHT = new Hashtable();
publisherHT = new Hashtable();
secDiag = new SecurityDiagnostics();
aclCore = new AclCore("PrincipalImpl", null);
InstallPolicy(config);
principalHT.Add(KernelIdNum,
new PrincipalT(KernelName, null, null, GetPublisherT(UnknownPublisher)));
}
public static Principal Self()
{
return new Principal(KernelIdNum);
}
public static Principal MakePrincipal(ulong id)
{
return new Principal(id);
}
public static string! GetPrincipalName(Principal pr)
{
PrincipalT pT = (PrincipalT) principalHT[pr.Val];
if (pT == null)
return NullName;
return pT.name;
}
public static ArrayList GetPrincipalHashes(Principal pr)
{
PrincipalT pT = (PrincipalT) principalHT[pr.Val];
if (pT == null)
return new ArrayList();
return pT.principalHashes;
}
public static Principal NewInvocation(Principal parent, Manifest! manifest, string role, IoMemory rawImage)
{
string manifestName = manifest.Name;
string publisher = manifest.Publisher;
string name, newname;
bool eraseHistory = false;
string[] appPrivs = manifest.Privileges;
ArrayList arrarr = null;
byte[] imageHash = null;
ArrayList newprincipalHashes = null;
if (manifestName == null)
manifestName = UnknownName;
if (publisher == null)
publisher = UnknownPublisher;
PrincipalT publisherT = GetPublisherT(publisher);
manifestName = String.Format("{0}.{1}", manifestName, publisher);
name = manifestName;
// Here we look for authority to grant privilege to the new app
// Currently, we don't revisit this decision, although in future we might
if (appPrivs != null) {
for (int i=0; i< appPrivs.Length; i++) {
string s = (!)appPrivs[i];
string acl = (string) authorityHT[s];
// Would call the normal CheckAccess entry point here, but it can't equate
// the Principal type in this context, and that in the library. Grumble!
if (acl != null && aclCore.CheckAccess(acl, null,
publisherT.val, publisherT.name)) {
ArrayList arr = (ArrayList) privHT[s];
if (arr == null) {
lock (privHT) {
arr = new ArrayList();
privHT[s] = arr;
}
}
// make an array of ArrayLists which we'll add a principal handle to below
if (arrarr == null)
arrarr = new ArrayList();
arrarr.Add(arr);
if (s == TruncateHistoryPrivilege) {
eraseHistory = true;
}
}
}
}
if (eraseHistory || (parent.Val == KernelIdNum)) {
// ignore role if eraseHistory or kernel parent
newname = name;
if (imageHash != null) {
newprincipalHashes = new ArrayList();
newprincipalHashes.Add(imageHash);
}
} else {
string parentName = parent.GetName();
if (parentName == NullName)
throw new Exception("NewInvocation with null parent");
int newlength = parentName.Length + name.Length + 2;
if (role != null)
newlength += (role.Length + 1);
StringBuilder sb = new StringBuilder(parentName, newlength);
if (role != null) {
sb.Append(CharRole);
sb.Append(role);
}
sb.Append(CharInvocation);
sb.Append(name);
newname = sb.ToString();
if (imageHash != null) {
ArrayList parentHashes = parent.GetHashes();
newprincipalHashes = new ArrayList(parentHashes);
newprincipalHashes.Add(imageHash);
}
}
PrincipalT pT = new PrincipalT(newname, manifestName, appPrivs, publisherT, newprincipalHashes);
if (arrarr != null) {
foreach (Object! obj in arrarr) {
ArrayList arr = (ArrayList) obj;
lock (arr) {
arr.Add(pT);
}
}
}
lock (principalHT)
{
pT.val = nextIdVal++;
principalHT.Add(pT.val, pT);
}
return new Principal(pT.val);
}
public static void Dispose(Principal pr)
{
PrincipalT pT = null;
lock (principalHT)
{
pT = (PrincipalT) principalHT[pr.Val];
if (pT == null)
return;
principalHT.Remove(pr.Val);
}
if (pT.privs != null) {
for (int i=0; i<pT.privs.Length; i++) {
ArrayList arr = (ArrayList) privHT[(!)pT.privs[i]];
if (arr != null) {
lock (arr) {
arr.Remove(pT);
}
}
}
}
}
public static string ExpandAclIndirection(string! name)
{
if (name.Length == 0)
return null;
if (name.IndexOf('.') == -1)
name = String.Format("{0}.{1}", name, DefaultNameContext);
string res = (string) exprHT[name];
if (res != null)
return res;
ArrayList arr = (ArrayList) privHT[name];
if (arr == null)
return null;
StringBuilder sb = new StringBuilder();
lock (arr) {
sb.Append("(");
for (int i=0; i<arr.Count; i++) {
PrincipalT pT = (PrincipalT!) arr[i];
if (pT == null || pT.manifestName == null)
continue;
if (i != 0)
sb.Append('|');
sb.Append(pT.manifestName);
}
sb.Append(")");
}
return sb.ToString();
}
public static void RegisterAclCore(Object core)
{
secDiag.RegisterAclCore((AclCore!)core);
}
public static void Export()
{
secDiag.Start();
}
private static void InstallPolicy(XmlNode! config)
{
// get all group definitions to register from the xml
XmlNode policyConfig = config.GetChild(AuthPolicyXmlTag);
if (policyConfig == null) {
return;
}
bool isAuthority = false;
foreach (XmlNode! elem in policyConfig.Children) {
string name;
string target;
if (elem.Name == AuthorityXmlTag) {
name = (!)elem.GetAttribute(AuthorityNameXmlAttribute, "");
target = (!)elem.GetAttribute(AuthorityAclXmlAttribute, "");
isAuthority = true;
} else if (elem.Name == SubexprXmlTag) {
name = (!)elem.GetAttribute(SubexprNameXmlAttribute, "");
target = (!)elem.GetAttribute(SubexprExpansionXmlAttribute, "");
} else
continue;
if (name.Length != 0 && target.Length != 0) {
if (name.IndexOf('.') == -1)
name = String.Format("{0}.{1}", name, DefaultNameContext);
if (isAuthority)
authorityHT[name] = target;
else
exprHT[name] = target;
}
}
}
private static PrincipalT! GetPublisherT(string! publisher)
{
PrincipalT publisherT = (PrincipalT) publisherHT[publisher];
if (publisherT == null) {
publisherT = new PrincipalT(publisher, null, null, null);
lock (principalHT) {
publisherT.val = nextIdVal++;
principalHT.Add(publisherT.val, publisherT);
}
}
return publisherT;
}
}
}