【问题标题】:C# .NET - how to determine if directory is writable, with or without UAC?C# .NET - 如何确定目录是否可写,有或没有 UAC?
【发布时间】:2011-04-15 17:20:47
【问题描述】:

我正在开发一款需要将文件复制到文件系统上给定目录的软件。它需要在支持 UAC 的操作系统(Vista、7)和 XP 上运行。为了解决写入需要 UAC 提升的目录的问题,该应用程序实际上启动了另一个进程,其中包含一个声明需要 UAC 的清单。这会生成提示,然后在用户确认时进行复制。

据我所见,一个目录可以有三种不同的逻辑权限状态——可写无 UAC 提升、可写有 UAC 提升和不可写。

我的问题是:对于给定的目录,我如何可靠地确定当前用户是否可以将文件复制(并可能覆盖)到该目录,如果可以,我如何确定是否需要 UAC 提升?

在 XP 上,这可能就像检查是否授予“允许写入”权限一样简单,但在 Vista / 7 上,有些目录未授予此权限,但使用 UAC 仍然可以执行此操作。

【问题讨论】:

    标签: c# .net permissions uac


    【解决方案1】:

    您只需尝试操作即可处理可写的无提升情况。当它失败时,您必须通过 UAC 提升来区分不可写与可写,这可能很困难。

    我认为我不希望程序为我解决这个问题(因为它们不可避免地会经常出错)。

    我认为使用这些假设来设计它是安全的:

    • 管理员有时会作为受限帐户运行他们不信任的试用软件 -> 如果您的应用要对需要 UAC 的计算机进行侵入性更改,他们想要取消而不是提升。
    • 高级管理员可以写入文件(毕竟他们是管理员)-> 不需要实际的 ACL 检查,检测受限令牌就足够了。
    • 用户可以使用其他帐户进行升级,或者可以要求同事完成 UAC 要求的操作 -> 检查受限令牌将错过这些情况。
    • 其他可恢复的事情会导致访问被拒绝,包括正在使用的文件 -> 有时正确的做法是使用相同的受限权限重试。

    总的来说,我建议尝试 AsInvoker 操作,如果访问被拒绝,会弹出一个提示,说明 Windows 拒绝了该操作,可能的原因是:文件正在使用,需要提升,需要管理员凭据,并给出用户三个按钮:

    • 取消
    • 使用当前凭据重试
    • (盾牌图标)提升权限并重试

    【讨论】:

    • 我曾考虑采用“尝试一切,看看什么有效”的方法,但想知道是否有更好的方法。以当前用户的身份尝试写入应该不会太难,如果失败则启动提升到 UAC 的过程。如果失败,请提醒无法复制。
    【解决方案2】:

    我们有一个对文件进行 WriteAccess 的方法,您可以将它用于目录(Directory.GetAccessControl 等)

        /// <summary> Checks for write access for the given file.
        /// </summary>
        /// <param name="fileName">The filename.</param>
        /// <returns>true, if write access is allowed, otherwise false</returns>
        public static bool WriteAccess(string fileName)
        {
            if ((File.GetAttributes(fileName) & FileAttributes.ReadOnly) != 0)
                return false;
    
            // Get the access rules of the specified files (user groups and user names that have access to the file)
            var rules = File.GetAccessControl(fileName).GetAccessRules(true, true, typeof(System.Security.Principal.SecurityIdentifier));
    
            // Get the identity of the current user and the groups that the user is in.
            var groups = WindowsIdentity.GetCurrent().Groups;
            string sidCurrentUser = WindowsIdentity.GetCurrent().User.Value;
    
            // Check if writing to the file is explicitly denied for this user or a group the user is in.
            if (rules.OfType<FileSystemAccessRule>().Any(r => (groups.Contains(r.IdentityReference) || r.IdentityReference.Value == sidCurrentUser) && r.AccessControlType == AccessControlType.Deny && (r.FileSystemRights & FileSystemRights.WriteData) == FileSystemRights.WriteData))
                return false;
    
            // Check if writing is allowed
            return rules.OfType<FileSystemAccessRule>().Any(r => (groups.Contains(r.IdentityReference) || r.IdentityReference.Value == sidCurrentUser) && r.AccessControlType == AccessControlType.Allow && (r.FileSystemRights & FileSystemRights.WriteData) == FileSystemRights.WriteData);
        }
    

    希望这会有所帮助。

    【讨论】:

    • 谢谢 - 我刚刚对此进行了测试,虽然这告诉我是否可以在当前身份下写入,但如果两个写入访问都被明确拒绝以及是否允许 UAC 提升,它会返回 false .我需要区分最后两种情况。不过,我会以此为起点。
    猜你喜欢
    • 2011-01-07
    • 1970-01-01
    • 1970-01-01
    • 2013-08-18
    • 2011-04-09
    • 1970-01-01
    • 2013-10-11
    • 1970-01-01
    • 2012-02-08
    相关资源
    最近更新 更多