views:

108

answers:

4

I'm modifying an old C++ program to run on Vista. It does not require Admin privileges.

I've changed the code to put logfiles in \ProgramData\MyApp\. These logfiles are written with the stdio functions (fopen, fprintf, fclose).

Here's the problem:

  1. UserA runs the program first, it creates \ProgramData\MyApp\MyLogFile.txt using CreateFile()

  2. UserB runs the program next, it tries to append to MyLogFile.txt and gets access denied.

I tried creating a null SECURITY_DESCRIPTOR and passing that to CreateFile(). That does create a file with "no permissions assigned", but it seems as if the first user to write to the file takes ownership and afterwards all the other non-admin users are out of luck.

It's important that all users share the same logfiles, but it's also important that I change as little code as possible.

Edited to add:

\ProgramData\MyApp is created by a standard Visual Studio installer. (I don't see any place to set directory security.) When it creates \MyApp it grants Users these permissions:

Read & execute  
List folder contents
Read
Special permissions

Under Advanced I see that Special permissions includes:

Create files / write data
Create folders / append data
Write attributes
Write extended attributes
+2  A: 

Probably that your application uses an installer. When the installer creates your folder "MyApp", assign read/write rights for everyone. This will probably fix your problem. There are different ways of doing this, but it depends on the type of the setup that you use.

Added custom action info.

If after install the folder does not have the required permissions you could add for example a custom action as a visual basic script on the install sequence, that will set the required permissions.

VBS Examble:

    Function SetPermissions()
        Dim strHomeFolder, strHome, strUser
        Dim intRunError, objShell, objFSO

        strHomeFolder = "C:\Test"

        Set objShell = CreateObject("Wscript.Shell")
        Set objFSO = CreateObject("Scripting.FileSystemObject")
        If objFSO.FolderExists(strHomeFolder) Then
            intRunError = objShell.Run("%COMSPEC% /c Echo Y| cacls " _
            & strHomeFolder & " /t /c /g everyone:F ", 2, True)

            If intRunError <> 0 Then
                Wscript.Echo "Error assigning permissions for user " _
                & strUser & " to home folder " & strHomeFolder
            End If
        End If

End Function
Adrian Faciu
I'm using the standard Visual Studio install project, and I have it create the directory, but I don't see anyplace to set permissions. Am I missing it?
egrunin
@egrunin On a test machine, after you install the application, does the folder have all the required permissions ?
Adrian Faciu
I edited my question to list the folder permissions after the install. `cacls` fails for me: `The trust relationship between this workstation and the primary domain failed.`
egrunin
+1  A: 

You need to add an allow rule for the user "Everyone" if that is what you truly want.

A null descriptor will defer to the directory's security if memory serves...

Spence
I tried a null descriptor, as mentioned in the post. Of course, I might be doing it wrong...
egrunin
+1  A: 

You must definetely use CreateFile. See more about security and access rights. I am sure that functions from the standard C library use CreateFile (it can't use anything else on Windows) but with default security parameters which are not helpful in your case.

I tried also to look inside SECURITY_ATTRIBUTES and SECURITY_DESCRIPTOR structures but it's not very easy to understand how to do it, though it may be a chance.

Iulian Şerbănoiu
egrunin
+1  A: 

+1 to everyone for trying, but eventually I found the answer here:

http://stackoverflow.com/questions/910528/how-to-change-the-acls-from-c

I did have to change this:

ea[0].grfAccessMode = DENY_ACCESS;

to this:

ea[0].grfAccessMode = GRANT_ACCESS;
egrunin
+1 this one should be the accepted answer
Iulian Şerbănoiu