C# .NET - 如何确定目录是否可写(带或不带 UAC)?

发布于 2024-09-24 07:44:02 字数 370 浏览 6 评论 0原文

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

据我所知,一个目录可以具有三种不同的逻辑权限状态:无需UAC提升即可写入、在UAC提升后可写入以及不可写入。

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

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

I'm working on a piece of software that needs to copy a file to a given directory on the filesystem. It needs to work on both UAC-aware OSs (Vista, 7) as well as XP. To get around the issue of writing to a directory where UAC elevation is required, the app actually kicks off another process with a manifest that states that UAC is required. This generates the prompt and then does the copy when the user confirms.

From what I can see, a directory can have three different logical permission states - writeable without UAC elevation, writeable with UAC elevation and not writeable.

My question is this: For a given directory, how do I reliably determine whether the current user can copy (and potentially overwrite) a file to that directory, and if I can, how do I determine if UAC elevation is required?

On XP, this could just be as simple as checking whether the 'Allow Write' permission is granted, but on Vista / 7, there are directories where this permission isn't granted, but this action is still possible with UAC.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

冷情妓 2024-10-01 07:44:02

我们有一个用于文件 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);
    }

希望这会有所帮助。

We have a method for WriteAccess on files, you can probably adapt it for Directories (Directory.GetAccessControl and so on)

    /// <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);
    }

Hope this helps.

别挽留 2024-10-01 07:44:02

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

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

我认为使用以下假设来设计它是安全的:

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

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

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

You handle the writable without elevation case just by trying the operation. It's when that fails, and you have to distinguish between not-writable vs writable via UAC elevation that is potentially difficult.

I don't think that I would like programs trying to figure that out for me (since they'll inevitably get it wrong quite often).

I think it's safe to design it with these assumptions:

  • Administrators sometimes run as restricted accounts to trial software they don't trust -> if your app is going to make invasive changes to the computer that require UAC they want to cancel, not elevate.
  • Elevated administrators can write the file (they are admin after all) -> no need for an actual ACL check, detecting a restricted token is enough.
  • Users may elevate using a different account, or may ask a co-worker to complete the UAC-required action -> checking for the restricted token will miss these cases.
  • Other recoverable things cause access denied, including file in use -> sometimes the right thing to do is retry using the same restricted permissions.

So altogether, I would suggest trying the operation AsInvoker, in case of access denied bring up a prompt that explains that Windows denied the operation, possible causes are: file-in-use, elevation required, administrator credentials required, and give the user three buttons:

  • Cancel
  • Retry with current credentials
  • (shield icon) Elevate permissions and retry
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文