C#使用DirectorySecurity的SetOwner设置文件夹所有者只能设为当前用户

看到有人问了这个问题,查询并实验后发现确实有这个问题,测试代码如下:

static void Main(string[] args)
{
    try
    {
        string folderPath = @"e:\testSecurity";

        Directory.CreateDirectory(folderPath);

        DirectorySecurity defaultFSec = Directory.GetAccessControl(folderPath);

        IdentityReference newUser = new NTAccount("User2");

        defaultFSec.SetOwner(newUser);

        Directory.SetAccessControl(folderPath, defaultFSec);
    }
    catch(Exception ex)
    {
        Console.WriteLine(ex);
    }
    Console.ReadLine();
}

结果是System.InvalidOperationException: The security identifier is not allowed to be the owner of this object.

2005年在Microsoft Connect上就有人提出了这个问题,微软说下个版本将会考虑添加这个功能,然而现在似乎还不行。

当然总是有什么其他办法的,既然资源管理器可以做到,那么直接调用API就是一个可行的办法。Richard Willis给出了一个实现方法,我这里把他的代码转贴一下:

sealed class UnmanagedCode
{
    [DllImport("kernel32.dll", SetLastError=true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool CloseHandle(IntPtr hObject);

    // Use this signature if you do not want the previous state
    [DllImport("advapi32.dll", SetLastError=true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool AdjustTokenPrivileges(IntPtr tokenHandle,
        [MarshalAs(UnmanagedType.Bool)]bool disableAllPrivileges,
        ref TOKEN_PRIVILEGES newState,
        UInt32 bufferLength,
        IntPtr previousState,
        IntPtr returnLength);

    [DllImport("kernel32.dll", ExactSpelling = true)]
    static extern IntPtr GetCurrentProcess();

    [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
    static extern bool OpenProcessToken
        (IntPtr processHandle, int desiredAccess, ref IntPtr phtok);

    [DllImport("advapi32.dll", SetLastError = true)]
    static extern bool LookupPrivilegeValue
            (string host, string name, ref LUID lpLuid);

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    struct TOKEN_PRIVILEGES
    {
        public UInt32 PrivilegeCount;
        public LUID Luid;
        public UInt32 Attributes;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct LUID
    {
       public uint LowPart;
       public int HighPart;
    }

    const int SE_PRIVILEGE_ENABLED = 0x00000002;
    const int TOKEN_QUERY = 0x00000008;
    const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
    //http://msdn.microsoft.com/en-us/library/bb530716(VS.85).aspx
    const string SE_RESTORE_PRIVILEGE = "SeRestorePrivilege"; 

    public static void GiveRestorePrivilege()
    {
        TOKEN_PRIVILEGES tokenPrivileges;
        tokenPrivileges.PrivilegeCount = 1;
        tokenPrivileges.Luid = new LUID();
        tokenPrivileges.Attributes = SE_PRIVILEGE_ENABLED;

        IntPtr tokenHandle = RetrieveProcessToken();

        try
        {
            bool success = LookupPrivilegeValue
                        (null, SE_RESTORE_PRIVILEGE, ref tokenPrivileges.Luid);
            if (success == false)
            {
                int lastError = Marshal.GetLastWin32Error();
                throw new Exception(
                    string.Format("Could not find privilege {0}. Error {1}",
                                        SE_RESTORE_PRIVILEGE, lastError));
            }

            success = AdjustTokenPrivileges(
                                                tokenHandle, false,
                                                ref tokenPrivileges, 0,
                                                IntPtr.Zero, IntPtr.Zero);
            if (success == false)
            {
                int lastError = Marshal.GetLastWin32Error();
                throw new Exception(
                    string.Format("Could not assign privilege {0}. Error {1}",
                                    SE_RESTORE_PRIVILEGE, lastError));
            }
        }
        finally
        {
            CloseHandle(tokenHandle);
        }

    }

    static IntPtr RetrieveProcessToken()
    {
        IntPtr processHandle = GetCurrentProcess();
        IntPtr tokenHandle = IntPtr.Zero;
        bool success = OpenProcessToken(processHandle,
                                        TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
                                        ref tokenHandle);
        if (success == false)
        {
            int lastError = Marshal.GetLastWin32Error();
            throw new Exception(
                string.Format("Could not retrieve process token. Error {0}",
                                    lastError));
        }
        return tokenHandle;
    }
}

posted on 2010-06-30 02:35  Gildor Wang  阅读(1067)  评论(0编辑  收藏  举报

导航