1

I have been all over google and back trying to figure this out. Let me tell you the problem and then tell/show you what I'm trying to do to fix said problem. So the problem is that I install the program I wrote to another computer with only 1 account (the built in Admin account). I then create a new standard user, and run the program with this new user. As long as I don't make any changes to the config file (an xml file located in CommonApplicationData) through my program there is no problem. However if I do make a change then my program crashes with a AccessDenied exception. The first time I encountered it I just went to the folder and tried to create a new text file so I started searching high and low why I was getting this error. Now if i log in as admin delete the config file, then log in as the standard user and run the program, the config file gets recreated and now my user has read/write access to the file. So my question is, how can I do that from the get go?

What I've tried is by using NUnit I wrote a test that creates the config file in the exact same location as it would if my program were to run it. And assert that I can read and write from it, passes. Where it gets strange is if I create the folder with specific security options set (code below) as the standard user then my admin account no longer as the ability to read or write to the file.

    [TestFixtureSetUp]
    public void Setup()
    {
        xmlPath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "MyCompany\\MyProgram");
        xmlFileLocation = System.IO.Path.Combine(xmlPath, "MyConfig.xml");
        fileInfo = new FileInfo(xmlFileLocation);
    }
    [Test]
    public void TestCreateNewFolder()
    {
        Assert.IsFalse(fileInfo.Directory.Exists);
        Console.WriteLine("Creating new directory:{0}", fileInfo.DirectoryName);
        Console.WriteLine("Directory.FullName:{0}", fileInfo.Directory.FullName);

        SecurityIdentifier sid = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
        NTAccount acct = sid.Translate(typeof(NTAccount)) as NTAccount;
        string strEveryoneAccount = acct.ToString();

        FileSystemAccessRule everyOne = new FileSystemAccessRule(strEveryoneAccount, FileSystemRights.FullControl, AccessControlType.Allow);
        DirectorySecurity dirSecurity = new DirectorySecurity(fileInfo.DirectoryName, AccessControlSections.Group);
        dirSecurity.AddAccessRule(everyOne);

        fileInfo.Directory.Create(dirSecurity);
    }

I'm getting super frustrated because this seems like such a trivial thing. "As admin mark this new folder/subfolder/files as FullControl by Everyone" so that any new user created before or after can read and write to this file. Where am I going wrong?

Robert Snyder
  • 2,399
  • 4
  • 33
  • 65
  • We're using the same approach in our projects, and it seems to me that if the subfolder in CommonApplicationData is created by an installer (for instance to install files with default values), then the application get AccessDenied in the folder. But if the folder is created by the application then it works properly. Anyway, I've solved it by adding a step in the installation script that (as you mention) grants Full access to Everyone. – Daniel Persson Mar 11 '14 at 20:32
  • @DanielPersson I'm using WIX as my installer, but it does not create the config files/folders, the application does. I would be curious though if I should do that. Problem is my current installer doesn't know about that folder so when I uninstall those folders would still be there.. Would it update the security for it? – Robert Snyder Mar 11 '14 at 20:36
  • No, the security would have to be updated through a command I think (see my answer). – Daniel Persson Mar 11 '14 at 20:47
  • 2
    The assumption that the default install of Windows allows one user to overwrite the files of another is just flawed. Undiagnosable data loss is just not a standard feature of an operating system ;) – Hans Passant Mar 11 '14 at 21:33

2 Answers2

1

When we want to grant full control to a folder, which we do to get around this issue, we use the following command. You should be able to run that from Wix:

icacls.exe "C:\ProgramData\MyCompany\MyApplication" /grant Users:(OI) (CI)F
Daniel Persson
  • 2,171
  • 1
  • 17
  • 24
0

I took the idea that Daniel Persson suggested and looked up the equivalent call in WIX which ends up being Permission EX. In Directory.wxs (the same file I put the Fragment for my INSTALLFOLDER I added another directory like so

        <!--Directory for Config file-->
        <Directory Id="CommonAppDataFolder">
            <Directory Id="commonAppDataMyCompany" Name="MyCompany"/>
        </Directory>

Next I created a new file called Permissions.wxs

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
     xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
    <Fragment>
        <ComponentGroup Id="ProductPermissions">
            <Component Id="INS_COMP" DiskId="1" Guid="{YOUR-GUID}"  Directory="INSTALLFOLDER">
                <CreateFolder Directory="INSTALLFOLDER">
                    <util:PermissionEx User="Users" GenericAll="yes"/>
                </CreateFolder>
            </Component>
            <Component Id="CMN_APP" DiskId="1" Guid="{YOUR-GUID}"  Directory="commonAppDataMyCompany">
                <CreateFolder Directory="commonAppDataMyCompany">
                    <util:PermissionEx User="Users" GenericAll="yes"/>
                </CreateFolder>
            </Component>
        </ComponentGroup>
    </Fragment>
</Wix>

last thing to do was to reference that new component group.

    <!--Features to add to cab file-->
    <Feature Id="ProductFeature" Title="Keymon Setup" Level="1">
        <ComponentGroupRef Id="ProductComponents" />
        <ComponentGroupRef Id="ProductContentComponents" />
        <ComponentGroupRef Id="RegistrySetings" />
        <ComponentGroupRef Id="ProductPermissions"/>
        <ComponentRef Id="ApplicationShortcut"/>
    </Feature>

There we go, now my both my common app data folder has inherited permisisions, and so does my INSTALL folder, which is something our IT department was having people do. Now they shouldn't have to do that anymore :)

Robert Snyder
  • 2,399
  • 4
  • 33
  • 65