/////////////////////////////////////////////////////////////////////////////// // // 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