WIX: Giving Permissions to a folder

27,203

Solution 1

I had this exact same issue and talked to Rob M about it. I was going to do Christian G's answer (https://stackoverflow.com/a/5296967/18475), but Rob suggested using WixQueryOsWellKnownSID (http://wix.sourceforge.net/manual-wix3/osinfo.htm) to get around non en-US locales.

In the .wxs file you add the following:

<PropertyRef Id="WIX_ACCOUNT_LOCALSYSTEM" />
<PropertyRef Id="WIX_ACCOUNT_USERS" />

And further down in the .wxs file where you want to apply the permissions it's just like this:

<Permission GenericAll="yes" User="[WIX_ACCOUNT_LOCALSYSTEM]" />
<Permission GenericRead="yes" GenericExecute="yes" User="[WIX_ACCOUNT_USERS]" />

Now when you run light, you just need to link WixUtilExtension.

light -ext WiXUtilExtension ...

NOTE: Depending on your version of WiX, this may not be fully supported. If it doesn't work for you, there may be other options you can use to translate SIDs.

Solution 2

Use the following code to accomplish this without a custom action. I've verified this works (also on child folders). Also the User Everyone is mapped on localized windows operating systems.

<CreateFolder>
      <Permission User="Everyone" GenericAll="yes" ChangePermission="yes"/>
</CreateFolder>

Solution 3

Another option would be to have a simple CA that will just translate a msi property that contains the SID to the actual name of the group from the localized OS. The CA doesn't have to be deferred and it's not doing the actual work of setting the permissions.

Below is a sample of CA that reads the value of PROPERTY_TO_BE_TRANSLATED msi property and translates the msi property indicated by it. In this way you can run the CA to translate different msi properties.

 [CustomAction]
  public static ActionResult TranslateSidToName(Session session)
  {
     var property = session["PROPERTY_TO_BE_TRANSLATED"];
     if (String.IsNullOrEmpty(property))
     {
        session.Log("The {0} property that should say what property to translate is empty", translateSidProperty);
        return ActionResult.Failure;
     }
     var sid = session[property];
     if (String.IsNullOrEmpty(sid))
     {
        session.Log("The {0} property that should contain the SID to translate is empty", property);
        return ActionResult.Failure;
     }
     try
     {
        // convert the user sid to a domain\name
        var account = new SecurityIdentifier(sid).Translate(typeof(NTAccount)).ToString();
        session[property] = account;
        session.Log("The {0} property translated from {1} SID to {2}", property, sid, account);
     }
     catch (Exception e)
     {
        session.Log("Exception getting the name for the {0} sid. Message: {1}", sid, e.Message);
        return ActionResult.Failure;
     }
     return ActionResult.Success;
  }

In WiX you define the properties to be translated using the SID for the accounts:

  <Property Id="AdminAccount" Value="S-1-5-32-544" />
  <Property Id="EveryoneAccount" Value="S-1-1-0" />

Create the CA that will set the PROPERTY_TO_BE_TRANSLATED property and then call the CA doing the translation:

<CustomAction Id="TranslateAdmin_SetProperty" Property="PROPERTY_TO_BE_TRANSLATED" Value="AdminAccount"/>
<CustomAction Id="TranslateAdmin" BinaryKey="CommonCustomActions" DllEntry="TranslateSidToName" Impersonate="no" />
<CustomAction Id="TranslateEveryone_SetProperty" Property="PROPERTY_TO_BE_TRANSLATED" Value="EveryoneAccount" />
<CustomAction Id="TranslateEveryone" BinaryKey="CommonCustomActions" DllEntry="TranslateSidToName" Impersonate="no" />

Don't forget to use the msi properties when setting the permissions:

<CreateFolder>                
   <Permission GenericAll="yes" User="[AdminAccount]" />
   <Permission GenericRead="yes" GenericExecute="yes" User="[EveryoneAccount]" />
</CreateFolder>

Finally, schedule the CA before CreateFolder

 <InstallExecuteSequence>
   <Custom Action='TranslateAdmin_SetProperty' Before='TranslateAdmin' />
  <Custom Action='TranslateAdmin' Before='CreateFolders' />
  <Custom Action='TranslateEveryone_SetProperty' Before='TranslateEveryone' />
  <Custom Action='TranslateEveryone' Before='CreateFolders' />
  </InstallExecuteSequence>

In this way the CA is doing only some simple work, leaving the setting of permissions to the WiX element.

Solution 4

As the <Permission> element clears the inheritance of permissions from parent folders, you could try using a single <Permission> element for users "Everyone" or "Administrators" followed by <util:PermissionEx> elements to set permissions for user names that are not supported by the <Permission> element, for example:

<Permission User="Everyone" GenericRead="no" />
<util:PermissionEx User="Users" Domain="[LOCAL_MACHINE_NAME]" GenericRead="yes" Read="yes" GenericExecute="yes" ChangePermission="yes" />

It is not needed to explicitly set permission for SYSTEM, as these are added automatically by the installer.

Solution 5

you need to implement deferred custom action for changing permissions. c# custom action example:

[CustomAction]
public static ActionResult SetFolderPermission(Session session)
{
     string folder = session.CustomActionData["Folder"].Trim('\"');
     string sid = session.CustomActionData["SID"].Trim('\"');
     System.Security.Principal.SecurityIdentifier sidID =  new System.Security.Principal.SecurityIdentifier(sid);

     System.Security.AccessControl.DirectorySecurity ds = System.IO.Directory.GetAccessControl(folder);
     ds.AddAccessRule(new System.Security.AccessControl.FileSystemAccessRule(sidID 
                , System.Security.AccessControl.FileSystemRights.Write
                , System.Security.AccessControl.InheritanceFlags.ObjectInherit
                , System.Security.AccessControl.PropagationFlags.NoPropagateInherit
                , System.Security.AccessControl.AccessControlType.Allow));
     System.IO.Directory.SetAccessControl(folder , ds);

     return ActionResult.Success;
}

you may port that on C++, custom action must be deferred - than you must access your session properties by CustomActionData

Share:
27,203
Hila
Author by

Hila

Updated on August 02, 2020

Comments

  • Hila
    Hila almost 4 years

    I've read all related topics and haven't found a full answer to my problem.

    I would like to give full permissions to SYSTEM and Read & Execute permissions to Users group to a folder under Program Files. Nothing more, nothing less.

    I know there are 3 ways to give permissions to a folder using WIX, none of them are really good for me and I'll explain why:

    1) Regular Permission element:

        <CreateFolder Directory="Test">
          <Permission User="SYSTEM" GenericAll="yes"/>
          <Permission User="Users" Domain="[LOCAL_MACHINE_NAME]" 
          GenericRead="yes" Read="yes" GenericExecute="yes" ChangePermission="yes"/>
        </CreateFolder>
    

    Problem: It fails on foreign OS since it doesn't knows the "Users" keyword. I tried it with SID as well. Beside that I need to place the Permission element under each file in the Test directory (but if this was the only case, I would have managed)

    2) WixUtilsExtension PermissionEx element:

        <CreateFolder Directory="Test">
          <util:PermissionEx User="SYSTEM" GenericAll="yes"/>
          <util:PermissionEx User="Users" Domain="[LOCAL_MACHINE_NAME]" 
          GenericRead="yes" Read="yes" GenericExecute="yes" ChangePermission="yes"/>
        </CreateFolder>
    

    Problem: The folder also keeps the default permissions of the Program Files folder. I can not allow that.

    3) PermissionEx with Sddl:

    Problem: This element is only available when installing with MSI 5.0. I'm using installer 3.01.

    I'll be happy to get any solution, including solutions with custom actions...

  • ferventcoder
    ferventcoder almost 10 years
    Be warned, I think we needed to back this out for some reason.
  • Papa Mufflon
    Papa Mufflon almost 9 years
    This does not work for me. [WIX_ACCOUNT_USERS] will be resolved to "BUILTIN\Users" and grants the permission to a user called "BUILTIN".
  • Papa Mufflon
    Papa Mufflon almost 9 years
    The aforementioned behavior is only true if you set the permissions in a merge module! Using [WIX_ACCOUNT_USERS] in a WiX project and not in a WiX merge module sets the permissions for the user group correctly.
  • ferventcoder
    ferventcoder almost 9 years
    Thanks for the followup! We ended up backing this out.
  • ferventcoder
    ferventcoder almost 9 years
    Why the downvotes? Still technically a correct answer if you are on the right versions of WiX. We backed it out b/c we were on an earlier version of WiX and the support isn't quite all there.
  • ferventcoder
    ferventcoder almost 9 years
    FWIW, we went with the actual SIDs IIRC. Much more deterministic.
  • Papa Mufflon
    Papa Mufflon almost 9 years
    Inserting the SIDs instead of the user or group name into the User-value did not work --> error. I tried to unvote my downvote, but I cannot unvote until the answer gets edited :/
  • ferventcoder
    ferventcoder almost 9 years
    Ah right on - I believe passing SIDs requires something different. We didn't need to use SIDs because the accounts we use are localized, not all of them are - if you look at this post (scroll past the accepted answer) you will see translate SID: social.msdn.microsoft.com/Forums/vstudio/en-US/…
  • John
    John over 8 years
    This will not work for non-US Eng locales, because "Everyone" must be localized.
  • Blake Niemyjski
    Blake Niemyjski over 8 years
    I haven't had any problems reported and we deploy to all cultures. How did you fix it?