_access () vs. AccessCheck () for FILE_GENERIC_WRITE fails
unless world writeable
Brian Leair
bleair at opnet.com
Fri Aug 22 18:28:46 GMT 2003
I have a function whose job is to determine if a pathname has write
permissions. I'm using a code fragment that is based off of this URL
support.microsoft.com/default.aspx?scid=kb;en-us;Q171273
My function uses AccessCheck () and it works correctly for local files, and
for windows files shares. When the files comes from a samba mounted drive
the function always returns false unless world-write permission is set on
the unix file.
I have four files
-r--r--r-- 1 opnet mil3 3 Aug 21 18:06 ronly
-rw-rw-r-- 1 opnet mil3 3 Aug 21 18:06 group
-rw-r--r-- 1 opnet mil3 3 Aug 21 18:05 owner
-rw-rw-rw- 1 opnet mil3 3 Aug 21 18:06 world
My function only returns true for the last file. Using SWAT, I believe that
I am accessing the samba mount as the correct owner and group. I can open a
command window and I can actually write to all files except the ronly file.
My function also calls to _access () to test for write permissions for
files. This secondary check for file write access does return the status
that I expect for NFS and Samba filesystem.
For windows filesystem you have to call AccessCheck () first because the
ACLs take precedence. Most of the time my function is working with files
that are on Winodws file shares.
Curiously, NFS always returns success for the AccessCheck and the _access
() indicates the real permissions.
Is there an alternate Win32 API that I should be using? Why is Samba
mapping the world permission bits to the windows ACL?
Is there a samba option that controls which set of bits are mapped to the ACL?
Thanks for any help.
Brian Leair
OPNET Development
----------------------------------------------------------------------------
--------------------
windows console application to test file access
#include <stdlib.h>
#include <stdio.h>
#include <io.h> /* for _open(), _access() */
#define STRICT /*
perform extra type-checking */
#undef FSHIFT /*
avoid a warning */
#include <windows.h> /* for the
Win32 functions */
#include <wtypes.h>
/* WinSock version */
#define WSVERS MAKEWORD(2,0)
int
oe_file_access_core (const char *path);
int
main (int argc, char * argv [])
{
char file_name [1024];
sprintf (file_name, "O:\\samba_testing\\test_file");
while (1)
{
printf ("Enter pathname to test ['quit' to end]: ");
scanf ("%s", file_name);
if (strcmp ("quit", file_name) == 0)
break;
printf ("\nTesting access to file %s.\n", file_name);
if (oe_file_access_core (file_name) == 1)
{
printf ("file %s has write permissions.\n",
file_name);
}
else
{
printf ("file %s does not have write
permissions.\n", file_name);
}
}
return (0);
}
int
oe_file_access_core (const char *path)
{
PSECURITY_DESCRIPTOR pSD;
DWORD nLength;
HANDLE hToken;
PRIVILEGE_SET PrivilegeSet;
DWORD PrivSetSize = sizeof
(PRIVILEGE_SET);
DWORD DesiredAccess =
FILE_WRITE_DATA;
GENERIC_MAPPING GenericMapping;
DWORD GrantedAccess;
BOOL bAccessGranted;
if (_access (path, /* F_OK = */ 0) == -1)
{
// File doesn't exist.
printf ("File %s doesn't exist.\n", path);
return (0);
}
/* Allocated memory to store current user's the security
descriptor. */
GetFileSecurity (path, OWNER_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
NULL, 0, &nLength);
pSD = (PSECURITY_DESCRIPTOR)
HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, nLength);
if (pSD == NULL)
{
printf ( "Unable to allocate memory to store security
descriptor.");
return (0);
}
/* Obtain the security descriptor. */
if (!GetFileSecurity (path, OWNER_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
pSD, nLength, &nLength))
{
printf ("Unable to obtain security descriptor.");
return (0);
}
/* Perform security impersonation of the user and open */
/* the resulting thread token. */
if (!ImpersonateSelf (SecurityImpersonation))
{
printf ("Unable to perform security impersonation.");
return (0);
}
if (!OpenThreadToken (GetCurrentThread (), TOKEN_DUPLICATE |
TOKEN_QUERY, FALSE, &hToken))
{
printf ( "Unable to get current thread's token.");
return (0);
}
RevertToSelf ();
memset (&GenericMapping, 0x00, sizeof (GENERIC_MAPPING));
// We want to test for write permissions
DesiredAccess = FILE_WRITE_DATA | FILE_APPEND_DATA;
GenericMapping.GenericWrite = FILE_GENERIC_WRITE;
MapGenericMask (&DesiredAccess, &GenericMapping);
/* Perform access check using the token. */
if (!AccessCheck (pSD, hToken, DesiredAccess, &GenericMapping,
&PrivilegeSet, &PrivSetSize, &GrantedAccess,
&bAccessGranted))
{
printf ("Unable to perform access check.");
return (0);
}
/* Clean up. */
HeapFree (GetProcessHeap (), 0, pSD);
CloseHandle (hToken);
/* For a directory, the securities is all we need to check. */
/* For a file, however, we also need to check the attributes */
/* to see that the read-only attribute is not set for write mode. */
/* This is what the _access function does. */
// if (is_dir (path))
// return (bAccessGranted);
// else
// return ((bAccessGranted) && (_access(path, 2) != -1));
if (_access (path, 2) == -1)
{
printf (" Note, NO write permissions via _access ().\n");
}
else
{
printf (" Note, write permissions via _access ().\n");
}
return (bAccessGranted);
}
More information about the samba-technical
mailing list