2

I've been trying to use the Windows 10 icacls utility to do this. I did some searching here, and I found this, but it doesn't my specific question. I tried adding a comment to this question, but I don't have enough reputations.

As an administrator on my Windows 10 Professional machine, I want to prevent local users from deleting executable programs, while still providing executable access (like the Linux chmod rx command). I've set the file owner to Administrator. I've been trying to achieve this using the utility, as follows.

For the specified (non-administrator) user, the following all prevent the file being deleted, but also disable executable access

  • icacls /deny user:W
  • icacls /deny user:M
  • icacls /deny user:(D)
  • icacls /deny user:(WO)
  • icacls /deny user:F followed by /grant user:(RX)

The following allows executable access, but also allows the file to be deleted

  • icacls /deny user:(WDAC)

Is what I'm trying to do even possible? It seems that executable and write access are identical?

Paul
  • 131
  • 4

2 Answers2

2

Yes, it's possible – that's how all of the system executables are set up. You can execute notepad.exe but you cannot write to it, because you're only granted (RX) permissions to that file.

But every one of your attempts is mistaken in the assumption that /deny removes permission bits. That's not what it does – it adds an explicit denial, a concept that doesn't exist in Linux file modes. Explicit "Deny" entries within an ACL always have a higher priority than "Allow" entries, so after you have /denied F (full control) to a user, no amount of /grant will override that.

(Unix file modes and even POSIX ACLs are exclusive – either you're granted "owner" permissions or "group" permissions, but not both – so there's no difference between removing and denying a permission. However, Windows-style ACLs are additive, as in you're granted the sum of all rights granted to all SIDs that you match, so there is a need to have an "explicit deny" that overrides broader grants.)

Now in theory, /deny Foo:W would still do what you want (even if it's not the right way to do it). But due to some historical design issues, the W and M macros (each of which expands to several distinct permission bits) are not usable within 'deny' ACEs as they slightly overlap with R (in the Synchronize right, which is obscure enough that many tools won't even show it). The other post's comments have a longer explanation.

The correct way to do what you want is by removing the unwanted rights from all access entries, rather than adding denials. Unfortunately icacls lacks an option to clear or "un-grant" only specific rights from an entry, so instead you'll have to /remove the whole entries that grant excessive permissions, then re-/grant only read/execute rights to the same users or groups.

For example, if your directory has read+write rights granted to (for example) the "Users" group, you'll need to /remove Users followed by /grant Users:(OI)(CI)(RX).


Keep in mind also that renaming or deleting a file isn't necessarily a right on the file itself – it's a right on the parent directory, as you rename files by "writing" the list of files (i.e. the…directory).

So in order for your protection to be useful, it needs to be defined on the directory itself (and inherited by files) – there's no point in trying to write-restrict individual items within a directory that still allows everyone to move those items aside and replace them with new ones.

u1686_grawity
  • 426,297
  • 64
  • 894
  • 966
  • Note that an explicit allow will override an implicit deny. – Greg W Sep 02 '22 at 00:12
  • Also keep an eye on inheritance,, permissions flowing from an higher level in the structure allowing the delete. – Ace Sep 02 '22 at 05:01
  • Many thanks user1686. Indeed a nuanced way of doing things: remove all rights from owning directory, and then allow specific rights to specific files inside the directory. I tried using " icacls /remove Users" on the owning directory, but the Users rights are unchanged. The command "icacls " displays the following for Users on two separate lines: "BUILTIN\Users:(I)(RX)" and "BUILTIN\Users:(I)(OI)(CI)(IO)(GR,GE)". – Paul Sep 02 '22 at 21:30
  • I tried the following test for the Users group. Command "icacls /remove Users /t". In the directory, as a user, I still have RWX permissions to the exe file in the directory. Command "icacls /deny Users:F". Same result, I still have RWX to the file. Now really confused. – Paul Sep 02 '22 at 22:22
  • Trying more things out. For Adminisrtrators, "icacls " gives two lines "BUILTIN\Users:(I)(RX)" and "BUILTIN\Users:(I)(OI)(CI)(IO)(GR,GE)". I find this very confusing. Normally Windows is so much more user-friendly than Linux, which is why I love using it so much. But this is a rare example where Linux definitely comes out on top. – Paul Sep 02 '22 at 22:25
  • More experiments ;<). When I disable directory access with "icacls /deny Users:F", as a user I still have RWX access to the file in the directory. However, as administrator in a CMD where I tried all these previous commands, the following command fails: "cd ". – Paul Sep 02 '22 at 22:33
  • You cannot remove `(I)` inherited-from-parent entries – if inheritance is enabled, it would add them back from the parent. You need to disable inheritance on the directory and copy them as "full" access entries first. Similarly, when adding rights to the directory (didn't I tell you to stop using /deny) you want to _make_ those inheritable with the `(OI)(CI)` flags. – u1686_grawity Sep 03 '22 at 10:47
1

I think I've found the answer. Explained here

This prevents the exe-file from being deleted or modified, and grants it read/write access to its local directory.

Summary:

  • icacls directory/inheritance:d /grant:r Users:(OI)(IO)
  • icacls directory/remove:g Users /C
  • icacls directory/remove:d Users /C
  • icacls directory/grant:r Users:(RX)
  • icacls directory /deny Users:(DE)
  • cd directory
  • icacls exe-file /inheritance:d /grant:r "Users:(OI)(IO)"
  • icacls exe-file /remove:g "Users"
  • icacls exe-file /remove:d "Users"
  • icacls exe-file /grant:r "Users:(RX)"
  • icacls exe-file /deny "Users":(DE)

Not quite as simple as chmod 7555 ;<)

Paul
  • 131
  • 4