I was dealing with a subtle issue recently involving setting access permissions using NSIS (Nullsoft Scriptable Install System). In the end, it turned out that the problem was not with NSIS at all. Rather, it was a misunderstanding on our part regarding an unexpected quirk in Windows. However, hopefully this post will help anybody who encounters a similar issue.
Our installer was supposed to enable read/write permissions for all users on certain important files and registry keys. However, some users were finding these files/keys were not accessible, and it was preventing the software from working correctly.
We eventually realised that the affected users were all running Windows 7 systems which had been setup in a language other than English. The file permissions were being set like this:
AccessControl::GrantOnFile "$INSTDIRfile.foo" "BUILTINUSERS" "GenericRead + GenericWrite"
Older versions of our installer had previously specified user group “(BU)” instead of “BUILTINUSERS”. However, the “(BU)” only works on Windows XP. As such, it had been changed to “BUILTINUSERS”, which seemed to work on Windows XP, Vista, 7, and 8.
Unfortunately, it turns out that “BUILTINUSERS” is a localised string, meaning it’s in whatever language was used when Windows was originally installed on the system. That means that specifying it in English in the installer script will fail on non-English systems. In retrospect, that’s probably very obvious to anybody who administers Microsoft systems on a daily basis, but it took us by surprise.
The correct approach is to use the newer security identifiers (SID’s), which are not localised; i.e. they are the same no matter what the original system language is. According to Microsoft’s documentation, the equivalent SID for the built-in users group is: “(S-1-5-32-545)”.
The reason we didn’t originally use that was because it’s not supported by Windows XP, which is still being used by several of our long-standing customers. Our assumption was that trying to set a file permission using an unsupported security identifier could cause installation problems.
As it happens, that’s not the case. Based on our testing, the worst that seems to happen is that the individual file permission command silently fails, and the installer moves on without any problem.
The simplest (and frankly the most obvious) way to support Windows XP and Vista onwards in a single installer is to use both types of language-independent user group identifier. For example, instead of the “BUILTINUSERS” line shown earlier, we now have these two lines:
AccessControl::GrantOnFile "$INSTDIRfile.foo" "(BU)" "GenericRead + GenericWrite" AccessControl::GrantOnFile "$INSTDIRfile.foo" "(S-1-5-32-545)" "GenericRead + GenericWrite"
So far, that appears to work correctly, supporting users on Windows XP and on Windows Vista etc.. We haven’t observed any side effects from setting the permissions twice, or from either one failing on other OS versions.