_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


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)

oe_file_access_core (const char *path);
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)
                 printf ("\nTesting access to file %s.\n", file_name);
                 if (oe_file_access_core (file_name) == 1)
                         printf ("file %s has write permissions.\n", 
                         printf ("file %s does not have write 
permissions.\n", file_name);
         return (0);
oe_file_access_core (const char *path)
         DWORD                                   nLength;
         HANDLE                                  hToken;
         PRIVILEGE_SET                   PrivilegeSet;
         DWORD                                   PrivSetSize = sizeof 
         DWORD                                   DesiredAccess = 
         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 |
                 NULL, 0, &nLength);
                 HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, nLength);
         if (pSD == NULL)
                 printf ( "Unable to allocate memory to store security 
                 return (0);
         /* Obtain the security descriptor. */
         if (!GetFileSecurity (path, OWNER_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 | 
                 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,
                 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");
                 printf ("  Note, write permissions via _access ().\n");
         return (bAccessGranted);

More information about the samba-technical mailing list