3c1f479b9d
Former-commit-id: 806294f5ded97629b74c85c09952f2a74fe182d9
545 lines
16 KiB
C#
545 lines
16 KiB
C#
//
|
|
// System.Security.Permissions.FileIOPermission.cs
|
|
//
|
|
// Authors:
|
|
// Nick Drochak, ndrochak@gol.com
|
|
// Sebastien Pouliot <sebastien@ximian.com>
|
|
//
|
|
// Copyright (C) 2001 Nick Drochak, All Rights Reserved
|
|
// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
|
|
using System.Collections;
|
|
using System.IO;
|
|
using System.Text;
|
|
|
|
using System.Runtime.InteropServices;
|
|
using System.Security.AccessControl;
|
|
|
|
namespace System.Security.Permissions {
|
|
|
|
[ComVisible (true)]
|
|
[Serializable]
|
|
public sealed class FileIOPermission
|
|
: CodeAccessPermission, IBuiltInPermission, IUnrestrictedPermission {
|
|
|
|
private const int version = 1;
|
|
|
|
private static char[] BadPathNameCharacters;
|
|
private static char[] BadFileNameCharacters;
|
|
|
|
static FileIOPermission ()
|
|
{
|
|
// we keep a local (static) copies to avoid calls/allocations
|
|
BadPathNameCharacters = Path.GetInvalidPathChars ();
|
|
BadFileNameCharacters = Path.GetInvalidFileNameChars ();
|
|
}
|
|
|
|
private bool m_Unrestricted = false;
|
|
private FileIOPermissionAccess m_AllFilesAccess = FileIOPermissionAccess.NoAccess;
|
|
private FileIOPermissionAccess m_AllLocalFilesAccess = FileIOPermissionAccess.NoAccess;
|
|
private ArrayList readList;
|
|
private ArrayList writeList;
|
|
private ArrayList appendList;
|
|
private ArrayList pathList;
|
|
|
|
public FileIOPermission (PermissionState state)
|
|
{
|
|
if (CheckPermissionState (state, true) == PermissionState.Unrestricted) {
|
|
m_Unrestricted = true;
|
|
m_AllFilesAccess = FileIOPermissionAccess.AllAccess;
|
|
m_AllLocalFilesAccess = FileIOPermissionAccess.AllAccess;
|
|
}
|
|
CreateLists ();
|
|
}
|
|
|
|
public FileIOPermission (FileIOPermissionAccess access, string path)
|
|
{
|
|
if (path == null)
|
|
throw new ArgumentNullException ("path");
|
|
|
|
CreateLists ();
|
|
// access and path will be validated in AddPathList
|
|
AddPathList (access, path);
|
|
}
|
|
|
|
public FileIOPermission (FileIOPermissionAccess access, string[] pathList)
|
|
{
|
|
if (pathList == null)
|
|
throw new ArgumentNullException ("pathList");
|
|
|
|
CreateLists ();
|
|
// access and path will be validated in AddPathList
|
|
AddPathList (access, pathList);
|
|
}
|
|
|
|
internal void CreateLists ()
|
|
{
|
|
readList = new ArrayList ();
|
|
writeList = new ArrayList ();
|
|
appendList = new ArrayList ();
|
|
pathList = new ArrayList ();
|
|
}
|
|
|
|
[MonoTODO ("(2.0) Access Control isn't implemented")]
|
|
public FileIOPermission (FileIOPermissionAccess access, AccessControlActions control, string path)
|
|
{
|
|
throw new NotImplementedException ();
|
|
}
|
|
|
|
[MonoTODO ("(2.0) Access Control isn't implemented")]
|
|
public FileIOPermission (FileIOPermissionAccess access, AccessControlActions control, string[] pathList)
|
|
{
|
|
throw new NotImplementedException ();
|
|
}
|
|
|
|
internal FileIOPermission (FileIOPermissionAccess access, string[] pathList, bool checkForDuplicates, bool needFullPath)
|
|
{
|
|
}
|
|
|
|
public FileIOPermissionAccess AllFiles {
|
|
get { return m_AllFilesAccess; }
|
|
set {
|
|
// if we are already set to unrestricted, don't change this property
|
|
if (!m_Unrestricted){
|
|
m_AllFilesAccess = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
public FileIOPermissionAccess AllLocalFiles {
|
|
get { return m_AllLocalFilesAccess; }
|
|
set {
|
|
// if we are already set to unrestricted, don't change this property
|
|
if (!m_Unrestricted){
|
|
m_AllLocalFilesAccess = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void AddPathList (FileIOPermissionAccess access, string path)
|
|
{
|
|
if ((FileIOPermissionAccess.AllAccess & access) != access)
|
|
ThrowInvalidFlag (access, true);
|
|
ThrowIfInvalidPath (path);
|
|
AddPathInternal (access, path);
|
|
}
|
|
|
|
public void AddPathList (FileIOPermissionAccess access, string[] pathList)
|
|
{
|
|
if ((FileIOPermissionAccess.AllAccess & access) != access)
|
|
ThrowInvalidFlag (access, true);
|
|
ThrowIfInvalidPath (pathList);
|
|
foreach (string path in pathList) {
|
|
AddPathInternal (access, path);
|
|
}
|
|
}
|
|
|
|
// internal to avoid duplicate checks
|
|
internal void AddPathInternal (FileIOPermissionAccess access, string path)
|
|
{
|
|
// call InsecureGetFullPath (and not GetFullPath) to avoid recursion
|
|
path = Path.InsecureGetFullPath (path);
|
|
|
|
if ((access & FileIOPermissionAccess.Read) == FileIOPermissionAccess.Read)
|
|
readList.Add (path);
|
|
if ((access & FileIOPermissionAccess.Write) == FileIOPermissionAccess.Write)
|
|
writeList.Add (path);
|
|
if ((access & FileIOPermissionAccess.Append) == FileIOPermissionAccess.Append)
|
|
appendList.Add (path);
|
|
if ((access & FileIOPermissionAccess.PathDiscovery) == FileIOPermissionAccess.PathDiscovery)
|
|
pathList.Add (path);
|
|
}
|
|
|
|
public override IPermission Copy ()
|
|
{
|
|
if (m_Unrestricted)
|
|
return new FileIOPermission (PermissionState.Unrestricted);
|
|
|
|
FileIOPermission copy = new FileIOPermission (PermissionState.None);
|
|
copy.readList = (ArrayList) readList.Clone ();
|
|
copy.writeList = (ArrayList) writeList.Clone ();
|
|
copy.appendList = (ArrayList) appendList.Clone ();
|
|
copy.pathList = (ArrayList) pathList.Clone ();
|
|
copy.m_AllFilesAccess = m_AllFilesAccess;
|
|
copy.m_AllLocalFilesAccess = m_AllLocalFilesAccess;
|
|
return copy;
|
|
}
|
|
|
|
public override void FromXml (SecurityElement esd)
|
|
{
|
|
// General validation in CodeAccessPermission
|
|
CheckSecurityElement (esd, "esd", version, version);
|
|
// Note: we do not (yet) care about the return value
|
|
// as we only accept version 1 (min/max values)
|
|
|
|
if (IsUnrestricted (esd)) {
|
|
m_Unrestricted = true;
|
|
}
|
|
else{
|
|
m_Unrestricted = false;
|
|
string fileList = esd.Attribute ("Read");
|
|
string[] files;
|
|
if (fileList != null){
|
|
files = fileList.Split (';');
|
|
AddPathList (FileIOPermissionAccess.Read, files);
|
|
}
|
|
fileList = esd.Attribute ("Write");
|
|
if (fileList != null){
|
|
files = fileList.Split (';');
|
|
AddPathList (FileIOPermissionAccess.Write, files);
|
|
}
|
|
fileList = esd.Attribute ("Append");
|
|
if (fileList != null){
|
|
files = fileList.Split (';');
|
|
AddPathList (FileIOPermissionAccess.Append, files);
|
|
}
|
|
fileList = esd.Attribute ("PathDiscovery");
|
|
if (fileList != null){
|
|
files = fileList.Split (';');
|
|
AddPathList (FileIOPermissionAccess.PathDiscovery, files);
|
|
}
|
|
}
|
|
}
|
|
|
|
public string[] GetPathList (FileIOPermissionAccess access)
|
|
{
|
|
if ((FileIOPermissionAccess.AllAccess & access) != access)
|
|
ThrowInvalidFlag (access, true);
|
|
|
|
ArrayList result = new ArrayList ();
|
|
switch (access) {
|
|
case FileIOPermissionAccess.NoAccess:
|
|
break;
|
|
case FileIOPermissionAccess.Read:
|
|
result.AddRange (readList);
|
|
break;
|
|
case FileIOPermissionAccess.Write:
|
|
result.AddRange (writeList);
|
|
break;
|
|
case FileIOPermissionAccess.Append:
|
|
result.AddRange (appendList);
|
|
break;
|
|
case FileIOPermissionAccess.PathDiscovery:
|
|
result.AddRange (pathList);
|
|
break;
|
|
default:
|
|
ThrowInvalidFlag (access, false);
|
|
break;
|
|
}
|
|
return (result.Count > 0) ? (string[]) result.ToArray (typeof (string)) : null;
|
|
}
|
|
|
|
public override IPermission Intersect (IPermission target)
|
|
{
|
|
FileIOPermission fiop = Cast (target);
|
|
if (fiop == null)
|
|
return null;
|
|
|
|
if (IsUnrestricted ())
|
|
return fiop.Copy ();
|
|
if (fiop.IsUnrestricted ())
|
|
return Copy ();
|
|
|
|
FileIOPermission result = new FileIOPermission (PermissionState.None);
|
|
result.AllFiles = m_AllFilesAccess & fiop.AllFiles;
|
|
result.AllLocalFiles = m_AllLocalFilesAccess & fiop.AllLocalFiles;
|
|
|
|
IntersectKeys (readList, fiop.readList, result.readList);
|
|
IntersectKeys (writeList, fiop.writeList, result.writeList);
|
|
IntersectKeys (appendList, fiop.appendList, result.appendList);
|
|
IntersectKeys (pathList, fiop.pathList, result.pathList);
|
|
|
|
return (result.IsEmpty () ? null : result);
|
|
}
|
|
|
|
public override bool IsSubsetOf (IPermission target)
|
|
{
|
|
FileIOPermission fiop = Cast (target);
|
|
if (fiop == null)
|
|
return false;
|
|
if (fiop.IsEmpty ())
|
|
return IsEmpty ();
|
|
|
|
if (IsUnrestricted ())
|
|
return fiop.IsUnrestricted ();
|
|
else if (fiop.IsUnrestricted ())
|
|
return true;
|
|
|
|
if ((m_AllFilesAccess & fiop.AllFiles) != m_AllFilesAccess)
|
|
return false;
|
|
if ((m_AllLocalFilesAccess & fiop.AllLocalFiles) != m_AllLocalFilesAccess)
|
|
return false;
|
|
|
|
if (!KeyIsSubsetOf (appendList, fiop.appendList))
|
|
return false;
|
|
if (!KeyIsSubsetOf (readList, fiop.readList))
|
|
return false;
|
|
if (!KeyIsSubsetOf (writeList, fiop.writeList))
|
|
return false;
|
|
if (!KeyIsSubsetOf (pathList, fiop.pathList))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
public bool IsUnrestricted ()
|
|
{
|
|
return m_Unrestricted;
|
|
}
|
|
|
|
public void SetPathList (FileIOPermissionAccess access, string path)
|
|
{
|
|
if ((FileIOPermissionAccess.AllAccess & access) != access)
|
|
ThrowInvalidFlag (access, true);
|
|
ThrowIfInvalidPath (path);
|
|
// note: throw before clearing the actual list
|
|
Clear (access);
|
|
AddPathInternal (access, path);
|
|
}
|
|
|
|
public void SetPathList (FileIOPermissionAccess access, string[] pathList)
|
|
{
|
|
if ((FileIOPermissionAccess.AllAccess & access) != access)
|
|
ThrowInvalidFlag (access, true);
|
|
ThrowIfInvalidPath (pathList);
|
|
// note: throw before clearing the actual list
|
|
Clear (access);
|
|
foreach (string path in pathList)
|
|
AddPathInternal (access, path);
|
|
}
|
|
|
|
public override SecurityElement ToXml ()
|
|
{
|
|
SecurityElement se = Element (1);
|
|
if (m_Unrestricted) {
|
|
se.AddAttribute ("Unrestricted", "true");
|
|
}
|
|
else {
|
|
string[] paths = GetPathList (FileIOPermissionAccess.Append);
|
|
if (null != paths && paths.Length > 0) {
|
|
se.AddAttribute ("Append", String.Join (";", paths));
|
|
}
|
|
paths = GetPathList (FileIOPermissionAccess.Read);
|
|
if (null != paths && paths.Length > 0) {
|
|
se.AddAttribute ("Read", String.Join (";", paths));
|
|
}
|
|
paths = GetPathList (FileIOPermissionAccess.Write);
|
|
if (null != paths && paths.Length > 0) {
|
|
se.AddAttribute ("Write", String.Join (";", paths));
|
|
}
|
|
paths = GetPathList (FileIOPermissionAccess.PathDiscovery);
|
|
if (null != paths && paths.Length > 0) {
|
|
se.AddAttribute ("PathDiscovery", String.Join (";", paths));
|
|
}
|
|
}
|
|
return se;
|
|
}
|
|
|
|
public override IPermission Union (IPermission other)
|
|
{
|
|
FileIOPermission fiop = Cast (other);
|
|
if (fiop == null)
|
|
return Copy ();
|
|
|
|
if (IsUnrestricted () || fiop.IsUnrestricted ())
|
|
return new FileIOPermission (PermissionState.Unrestricted);
|
|
|
|
if (IsEmpty () && fiop.IsEmpty ())
|
|
return null;
|
|
|
|
FileIOPermission result = (FileIOPermission) Copy ();
|
|
result.AllFiles |= fiop.AllFiles;
|
|
result.AllLocalFiles |= fiop.AllLocalFiles;
|
|
|
|
string[] paths = fiop.GetPathList (FileIOPermissionAccess.Read);
|
|
if (paths != null)
|
|
UnionKeys (result.readList, paths);
|
|
|
|
paths = fiop.GetPathList (FileIOPermissionAccess.Write);
|
|
if (paths != null)
|
|
UnionKeys (result.writeList, paths);
|
|
|
|
paths = fiop.GetPathList (FileIOPermissionAccess.Append);
|
|
if (paths != null)
|
|
UnionKeys (result.appendList, paths);
|
|
|
|
paths = fiop.GetPathList (FileIOPermissionAccess.PathDiscovery);
|
|
if (paths != null)
|
|
UnionKeys (result.pathList, paths);
|
|
|
|
return result;
|
|
}
|
|
|
|
[MonoTODO ("(2.0)")]
|
|
[ComVisible (false)]
|
|
public override bool Equals (object obj)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
[MonoTODO ("(2.0)")]
|
|
[ComVisible (false)]
|
|
public override int GetHashCode ()
|
|
{
|
|
return base.GetHashCode ();
|
|
}
|
|
|
|
// IBuiltInPermission
|
|
int IBuiltInPermission.GetTokenIndex ()
|
|
{
|
|
return (int) BuiltInToken.FileIO;
|
|
}
|
|
|
|
// helpers
|
|
|
|
private bool IsEmpty ()
|
|
{
|
|
return ((!m_Unrestricted) && (appendList.Count == 0) && (readList.Count == 0)
|
|
&& (writeList.Count == 0) && (pathList.Count == 0));
|
|
}
|
|
|
|
private static FileIOPermission Cast (IPermission target)
|
|
{
|
|
if (target == null)
|
|
return null;
|
|
|
|
FileIOPermission fiop = (target as FileIOPermission);
|
|
if (fiop == null) {
|
|
ThrowInvalidPermission (target, typeof (FileIOPermission));
|
|
}
|
|
|
|
return fiop;
|
|
}
|
|
|
|
internal static void ThrowInvalidFlag (FileIOPermissionAccess access, bool context)
|
|
{
|
|
string msg = null;
|
|
if (context)
|
|
msg = Locale.GetText ("Unknown flag '{0}'.");
|
|
else
|
|
msg = Locale.GetText ("Invalid flag '{0}' in this context.");
|
|
throw new ArgumentException (String.Format (msg, access), "access");
|
|
}
|
|
|
|
internal static void ThrowIfInvalidPath (string path)
|
|
{
|
|
string dir = Path.GetDirectoryName (path);
|
|
if ((dir != null) && (dir.LastIndexOfAny (BadPathNameCharacters) >= 0)) {
|
|
string msg = String.Format (Locale.GetText ("Invalid path characters in path: '{0}'"), path);
|
|
throw new ArgumentException (msg, "path");
|
|
}
|
|
|
|
string fname = Path.GetFileName (path);
|
|
if ((fname != null) && (fname.LastIndexOfAny (BadFileNameCharacters) >= 0)) {
|
|
string msg = String.Format (Locale.GetText ("Invalid filename characters in path: '{0}'"), path);
|
|
throw new ArgumentException (msg, "path");
|
|
}
|
|
// LAMESPEC: docs don't say it must be a rooted path, but the MS implementation enforces it, so we will too.
|
|
if (!Path.IsPathRooted (path)) {
|
|
string msg = Locale.GetText ("Absolute path information is required.");
|
|
throw new ArgumentException (msg, "path");
|
|
}
|
|
}
|
|
|
|
internal static void ThrowIfInvalidPath (string[] paths)
|
|
{
|
|
foreach (string path in paths)
|
|
ThrowIfInvalidPath (path);
|
|
}
|
|
|
|
// we known that access is valid at this point
|
|
internal void Clear (FileIOPermissionAccess access)
|
|
{
|
|
if ((access & FileIOPermissionAccess.Read) == FileIOPermissionAccess.Read)
|
|
readList.Clear ();
|
|
if ((access & FileIOPermissionAccess.Write) == FileIOPermissionAccess.Write)
|
|
writeList.Clear ();
|
|
if ((access & FileIOPermissionAccess.Append) == FileIOPermissionAccess.Append)
|
|
appendList.Clear ();
|
|
if ((access & FileIOPermissionAccess.PathDiscovery) == FileIOPermissionAccess.PathDiscovery)
|
|
pathList.Clear ();
|
|
}
|
|
|
|
// note: all path in IList are already "full paths"
|
|
internal static bool KeyIsSubsetOf (IList local, IList target)
|
|
{
|
|
bool result = false;
|
|
foreach (string l in local) {
|
|
foreach (string t in target) {
|
|
if (Path.IsPathSubsetOf (t, l)) {
|
|
result = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!result)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
internal static void UnionKeys (IList list, string[] paths)
|
|
{
|
|
foreach (string path in paths) {
|
|
int len = list.Count;
|
|
if (len == 0) {
|
|
list.Add (path);
|
|
}
|
|
else {
|
|
int i;
|
|
for (i=0; i < len; i++) {
|
|
string s = (string) list [i];
|
|
if (Path.IsPathSubsetOf (path, s)) {
|
|
// replace (with reduced version)
|
|
list [i] = path;
|
|
break;
|
|
}
|
|
else if (Path.IsPathSubsetOf (s, path)) {
|
|
// no need to add
|
|
break;
|
|
}
|
|
}
|
|
if (i == len) {
|
|
list.Add (path);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
internal static void IntersectKeys (IList local, IList target, IList result)
|
|
{
|
|
foreach (string l in local) {
|
|
foreach (string t in target) {
|
|
if (t.Length > l.Length) {
|
|
if (Path.IsPathSubsetOf (l ,t))
|
|
result.Add (t);
|
|
}
|
|
else {
|
|
if (Path.IsPathSubsetOf (t, l))
|
|
result.Add (l);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|