You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@subversion.apache.org by ja...@binarycoder.net on 2013/09/28 20:00:59 UTC

Respecting inherited Windows file permissions on file create

In a working copy, different directories may require different Windows
permissions (access control lists). For example, some might contain
code or data to be accessed by Windows services. Concretely, the
Windows service might be a web server and the directory might contain
HTML files. For convenience in this reproduction, assume the service
runs as "LOCAL SERVICE", an account that comes with Windows. Of
special note (but not shown in the following example), different
portions of the working copy may require different permissions. For
example, this might be because there are several different Windows
services involved. For illustration, let's call the working copy root
wc and a directory requiring the permissions wc\a.

I don't expect (or event want) svn to store Windows permission
information in its repository, but I find it undesirable that svn
"arbitrarily" interferes with any manually applied permissions,
particularly file permissions inherited from parent directories. svn
seems to get itself into trouble when it performs what to the user is
logically a file "create" through a physical file "move". This is
because Windows has potentially surprising behavior in this case where
it does not recalculate the inherited permissions on the file according
to its new parent directory. This may appear to be an OS bug in the
MoveFile/MoveFileEx API, but Microsoft blogger Raymond Chen does an
excellent job explaining how things got to be this way (related to
Windows "hard link" support!). The blog post is: "Moving a file does
not recalculate inherited permissions" at
http://blogs.msdn.com/b/oldnewthing/archive/2006/08/24/717181.aspx.

Raymond Chen describes a solution: After performing the
MoveFile/MoveFileEx, to "... recalculate [the file's access control
entries] from the destination's inheritable properties ... [c]all the
SetNamedSecurityInfo function, specifying that you want an empty,
unprotected DACL." The reason I think this would be the correct
handling is because the move is an implementation detail. The fix
causes the permissions to end up to what they would have been had
CreateFile been used instead of MoveFile. The follow shows how to
reproduce. The call to icacls /reset is analogous to
SetNamedSecurityInfo with a NULL DACL.

The impact of this problem is that I have to follow svn update or
revert operations below directories with inheritable access control
entries with calls to the console command icacls /reset, even though
the directory tree structure where the permissions are actually
assigned was not changed by the svn operation. In practice, this is not
lightning fast because I cannot trust the permissions in the subtree
and recursively reset everything in the the working copy followed by
re-assigning the permissions from scratch which on Windows is
proportional to the number of files in the working copy.

mkdir C:\FIXME
cd /D C:\FIXME
svnadmin create repos
svn co file:///C:/FIXME/repos wc

mkdir wc\a
svn add wc\a

@rem Grant "LOCAL SERVICE" (which exists on all Windows systems) read
@rem and execute to directory a. Specify as inheritable to descendent
@rem objects, both (files) (OI) and containers (subdirectories) (CI).

icacls wc\a /grant "LOCAL SERVICE:(OI)(CI)(RX)"

@rem Create file a.txt in directory a.
@rem Display its ACL to verify that it has the above access, applied by
@rem inheritance as indicated with (I).

echo This is a.txt > wc\a\a.txt
svn add wc\a\a.txt

icacls wc\a\a.txt
@rem wc\a\a.txt NT AUTHORITY\LOCAL SERVICE:(I)(RX)
@rem            BUILTIN\Administrators:(I)(F)
@rem            NT AUTHORITY\SYSTEM:(I)(F)
@rem            BUILTIN\Users:(I)(RX)
@rem            NT AUTHORITY\Authenticated Users:(I)(M)

svn ci wc -m Test

@rem Show what happens when svn "creates" a file in that directory.
@rem The problem is it really does a move so does not follow the same
@rem rules as the echo command above. Expect to see
@rem "NT AUTHORITY\LOCAL SERVICE:(I)(RX)" but do not see it.

del wc\a\a.txt
svn up wc
@rem Updating 'wc':
@rem Restored 'wc\a\a.txt'
@rem At revision 1.
icacls wc\a\a.txt
@rem wc\a\a.txt BUILTIN\Administrators:(I)(F)
@rem            NT AUTHORITY\SYSTEM:(I)(F)
@rem            BUILTIN\Users:(I)(RX)
@rem            NT AUTHORITY\Authenticated Users:(I)(M)

@rem Showing how to manually fix the permissions on the file.
@rem Using icalcs /reset on a file will remove all permissions on the
@ file and reset them according to inheritance rules.

icacls wc\a\a.txt /reset
icacls wc\a\a.txt
@rem wc\a\a.txt NT AUTHORITY\LOCAL SERVICE:(I)(RX)
@rem            BUILTIN\Administrators:(I)(F)
@rem            NT AUTHORITY\SYSTEM:(I)(F)
@rem            BUILTIN\Users:(I)(RX)
@rem            NT AUTHORITY\Authenticated Users:(I)(M)


Re: Respecting inherited Windows file permissions on file create

Posted by Ivan Zhakov <iv...@visualsvn.com>.
On 28 September 2013 22:00,  <ja...@binarycoder.net> wrote:
> In a working copy, different directories may require different Windows
> permissions (access control lists). For example, some might contain
> code or data to be accessed by Windows services. Concretely, the
> Windows service might be a web server and the directory might contain
> HTML files. For convenience in this reproduction, assume the service
> runs as "LOCAL SERVICE", an account that comes with Windows. Of
> special note (but not shown in the following example), different
> portions of the working copy may require different permissions. For
> example, this might be because there are several different Windows
> services involved. For illustration, let's call the working copy root
> wc and a directory requiring the permissions wc\a.
>
> I don't expect (or event want) svn to store Windows permission
> information in its repository, but I find it undesirable that svn
> "arbitrarily" interferes with any manually applied permissions,
> particularly file permissions inherited from parent directories. svn
> seems to get itself into trouble when it performs what to the user is
> logically a file "create" through a physical file "move". This is
> because Windows has potentially surprising behavior in this case where
> it does not recalculate the inherited permissions on the file according
> to its new parent directory. This may appear to be an OS bug in the
> MoveFile/MoveFileEx API, but Microsoft blogger Raymond Chen does an
> excellent job explaining how things got to be this way (related to
> Windows "hard link" support!). The blog post is: "Moving a file does
> not recalculate inherited permissions" at
> http://blogs.msdn.com/b/oldnewthing/archive/2006/08/24/717181.aspx.
>
> Raymond Chen describes a solution: After performing the
> MoveFile/MoveFileEx, to "... recalculate [the file's access control
> entries] from the destination's inheritable properties ... [c]all the
> SetNamedSecurityInfo function, specifying that you want an empty,
> unprotected DACL." The reason I think this would be the correct
> handling is because the move is an implementation detail. The fix
> causes the permissions to end up to what they would have been had
> CreateFile been used instead of MoveFile. The follow shows how to
> reproduce. The call to icacls /reset is analogous to
> SetNamedSecurityInfo with a NULL DACL.
>
I see two possible solutions for this problem:
1. Use hTemplate argument in CreateFile call when temporary file is created
2. Created temporary file along original file to be replaced instead
of .svn/tmp in working copy root

Option (1) is hard to because APR abstraction, while (2) should be
easier but solve only problem when file itself doesn't have specific
permissions.

-- 
Ivan Zhakov
CTO | VisualSVN | http://www.visualsvn.com