Discussion:
Win32 alternative for _access() C library function? _access() seems broken..
(too old to reply)
Greg Ercolano
2005-04-11 06:15:11 UTC
Permalink
Is there a WIN32 function similar to the _access() C library
function?

I need an alternative to _access(), because _access() appears
to be broken; it's saying files are writeable when they're not..
(see '** BAD ** below). The environment is Win2K with a VC.NET 7.0
compiler.

I guess I should report this as a security bug to MS.

Meanwhile, I'm hoping that there's a similar Win32 function
that actually works for detect r/w access for files *and directories*.

In my real app (not shown) needs to check for access problems
with files and directories before actually opening or creating files.

I'm not sure I see an equivalent for _access() in Win32.

-------------------------------------------------------------------------------------
C:\temp>type check-bar.c <-- view test program
// Simple program to test access() function
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include <errno.h>
#include <string.h>
main()
{
// ACCESS TEST
if ( _access("bar", 6) == 0 ) { printf("access() says bar is OK to r/w. (NO IT'S NOT!)\n"); }
else { perror("_access(bar,6) NOT writable (EXPECT THIS), reason:"); }

// OPEN TEST
{
int fd = _open("bar", O_WRONLY|O_APPEND);
if ( fd == -1 ) { perror("open(bar) fails, as we expect"); }
else { printf("open(bar) OK\n"); close(fd); }
}
}

C:\temp>cl check-bar.c <-- compile it
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.00.9466 for 80x86
Copyright (C) Microsoft Corporation 1984-2001. All rights reserved.
[..]
/out:check-bar.exe
check-bar.obj

C:\temp>.\check-bar.exe <-- run it
access() says bar is OK to r/w. (NO IT'S NOT!) <-- ** BAD **
open(bar) fails, as we expect: Permission denied <-- OK

C:\temp>echo > bar <-- OK: verify we have NO access..
Access is denied. <-- OK: expect this, we can't access file

C:\temp>echo %USERNAME% <-- OK: Reason: we are 'barney'..
barney
^^^^^^

C:\temp>cacls bar <-- OK: ..and file is accessable..
C:\temp\bar GENEVA\fred:F <-- OK: only to 'fred'
^^^^
----------------------------------------------------------------------------------
Sten Westerback
2005-04-11 12:14:55 UTC
Permalink
Post by Greg Ercolano
Is there a WIN32 function similar to the _access() C library
function?
I need an alternative to _access(), because _access() appears
to be broken; it's saying files are writeable when they're not..
(see '** BAD ** below). The environment is Win2K with a VC.NET 7.0
compiler.
I guess I should report this as a security bug to MS.
Meanwhile, I'm hoping that there's a similar Win32 function
that actually works for detect r/w access for files *and directories*.
In my real app (not shown) needs to check for access problems
with files and directories before actually opening or creating files.
I'm not sure I see an equivalent for _access() in Win32.
--------------------------------------------------------------------------
-----------
Post by Greg Ercolano
C:\temp>type check-bar.c <-- view test program
// Simple program to test access() function
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include <errno.h>
#include <string.h>
main()
{
// ACCESS TEST
if ( _access("bar", 6) == 0 ) { printf("access() says bar is OK to
r/w. (NO IT'S NOT!)\n"); }
Post by Greg Ercolano
else { perror("_access(bar,6) NOT writable
(EXPECT THIS), reason:"); }
Post by Greg Ercolano
// OPEN TEST
{
int fd = _open("bar", O_WRONLY|O_APPEND);
if ( fd == -1 ) { perror("open(bar) fails, as we expect"); }
else { printf("open(bar) OK\n"); close(fd); }
}
}
C:\temp>cl check-bar.c <-- compile it
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.00.9466 for 80x86
Copyright (C) Microsoft Corporation 1984-2001. All rights reserved.
[..]
/out:check-bar.exe
check-bar.obj
C:\temp>.\check-bar.exe <-- run it
access() says bar is OK to r/w. (NO IT'S NOT!) <-- ** BAD **
open(bar) fails, as we expect: Permission denied <-- OK
C:\temp>echo > bar <-- OK: verify we have NO access..
Access is denied. <-- OK: expect this, we can't access file
C:\temp>echo %USERNAME% <-- OK: Reason: we are 'barney'..
barney
^^^^^^
C:\temp>cacls bar <-- OK: ..and file is accessable..
C:\temp\bar GENEVA\fred:F <-- OK: only to 'fred'
^^^^
First of all.. are you sure you are accessing the correct bar ? :=)
That is, are you sure you haven't got another "bar" file in the
default folder used by the process than the one you think you are
testing.

Anyway, to test using WINAPI, CreateFile() is the easiest way.
You could also read the fields security descriptor yourself and
analyse it to find out what access you have. But why not just
find out what access you have by accessing...

- Sten
Greg Ercolano
2005-04-13 01:53:36 UTC
Permalink
[..]
I'm hoping that there's a similar Win32 function (to _access())
that actually works for detect r/w access for files *and directories*.
[..] my real app (not shown) needs to check for access problems
with files and directories before actually opening or creating files.
[..] are you sure you haven't got another "bar" file in the
default folder
Yes, quite sure.

After posting here, and doing more tests, I was convinced _access()
was broken enough to phone it in to Microsoft as a bug, and they
confirmed it today.
Anyway, to test using WINAPI, CreateFile() is the easiest way.
Hmm, but then I'm modifying the file system.

This is why I'm using _access(); a non-intrusive write access test.

In my situation, other apps are constantly reading/creating
files in the target directory at all times, and I can't risk race
conditions with those apps (I don't have control over their code).

Regarding testing /existing/ files for write access, Microsoft
recommended using the following workaround:

fopen("bar", "r+")

..which will apparently test for write access in a non-intrusive
way for an exsiting file.

Trouble is that won't work for checking directory write access..
the incedent is still open.
You could also read the fields security descriptor yourself and
analyse it to find out what access you have.
That sounds like the correct solution, but the question is
what function(s) should I be looking at to test for access.
I'm not very familiar with the WinAPI with respect to security stuff.

Testing for access involves 1) getting the file|dir attributes,
2) getting the user attributes, 3) comparing the two in a reliable
manner for a test.

I imagine the only clean way to do the above is a single Win32 function
that does all three. Doing those separately in my app would only be
prone to error, if the underlying security system is enhanced.

This is the reason _access() is so useful; it hides the
security internals from the app.
But why not just find out what access you have by accessing...
Needs to be non-intrusive.
Ralf Buschmann
2005-04-13 09:23:16 UTC
Permalink
Post by Greg Ercolano
But why not just find out what access you have by accessing...
Needs to be non-intrusive.
Try AccessCheck() API.
--
Ralf.
Greg Ercolano
2005-04-13 15:47:13 UTC
Permalink
Post by Ralf Buschmann
Post by Greg Ercolano
But why not just find out what access you have by accessing...
Needs to be non-intrusive.
Try AccessCheck() API.
Much thanks.. that looks like the right direction.

Will follow up with a code snippet if I figure it out..
r***@pen_fact.com
2005-04-13 19:35:02 UTC
Permalink
On Tue, 12 Apr 2005 18:53:36 -0700, Greg Ercolano <***@3dsite.com>
wrote:

clip
Post by Greg Ercolano
Regarding testing /existing/ files for write access, Microsoft
fopen("bar", "r+")
..which will apparently test for write access in a non-intrusive
way for an exsiting file.
I'm glad someone gave you a lead on a real solution. But I'm still
curious about this workaround. I'm under the impression that Microsoft
uses CreateFile in its implementation of fopen. So I don't see how
using fopen has any advantages over using CreateFile directly.


clip

-----------------------------------------
To reply to me, remove the underscores (_) from my email address (and please indicate which newsgroup and message).

Robert E. Zaret, eMVP
PenFact, Inc.
500 Harrison Ave., Suite 3R
Boston, MA 02118
www.penfact.com
Greg Ercolano
2005-04-13 20:15:58 UTC
Permalink
Post by r***@pen_fact.com
I'm glad someone gave you a lead on a real solution. But I'm still
curious about this workaround. I'm under the impression that Microsoft
uses CreateFile in its implementation of fopen. So I don't see how
using fopen has any advantages over using CreateFile directly.
Microsoft came back this morning with a more complete response
(below) as a workaround for the half broken _access() function.
FYI:

-------------------------------------------------------------- snip
//Function : CheckAccess( LPCTSTR fname, int mode)
//Returns : 0 when the access is present, -1 when access is not available
//Desc : This function can be used as a substitue for _access. The paramters are the same as in _access()
//fname - file/directory whose access is to be checked
//mode - mode to be checked, pass the code corresponding to the access test required.
// 0 - Test existence
// 2 - Write access
// 4 - Read access
// 6 - Read & Write access.
//
int CheckAccess(LPCTSTR fname, int mode)
{
DWORD dwAccess;
if (mode == 0)
return _access(fname, mode); //access would do when we want to check the existence alone.

if (mode == 2)
dwAccess = GENERIC_WRITE;
else if (mode == 4)
dwAccess = GENERIC_READ;
else if (mode == 6)
dwAccess = GENERIC_READ | GENERIC_WRITE;

HANDLE hFile = 0;
hFile = CreateFile(fname,
dwAccess,
FILE_SHARE_READ|FILE_SHARE_WRITE, // share for reading and writing
NULL, // no security
OPEN_EXISTING, // existing file only
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS,
NULL); // no attr. template

if (hFile == INVALID_HANDLE_VALUE)
{ return(-1); }
CloseHandle(hFile);
return(0);
}
-------------------------------------------------------------- snip

I tested it with files and dirs that had read only, write only,
and r/w ACLs, and it all seemed to work fine.

And their solution does in fact use CreateFile(), and it
does indeed work unintrusively for both files AND directories.
(Note they actually use _access() to do the existence check,
but use CreateFile() for everything else)

This workaround was a pleasant surprise in that it was /simple/..
under one page.

All my other encounters with the WINAPI have been generally
very painful (CreateProcess(), registry functions, PDH lib..)
with pages of structures in structures, and calls with zillions
of flags, and very little intuitiveness or readability.

So I'm definitely going to use this approach, thus avoiding
a descent into the security subsystem via AccessCheck().
[I did some investigation into that this morning, and all
I can say is I'm glad I won't have to go there..]


PS. The case was closed with the above solution solving my problem,
and an internal bug report was generated towards the _access()
function.. so maybe it'll be fixed in a future release of the compiler.
Greg Ercolano
2012-09-20 12:55:23 UTC
Permalink
Post by Greg Ercolano
PS. The case was closed with the above solution solving my problem,
and an internal bug report was generated towards the _access()
function.. so maybe it'll be fixed in a future release of the compiler.
It is now 2012, 7 years later.. following up to this old thread
which can be seen here:
https://groups.google.com/forum/?fromgroups=#!topic/comp.os.ms-windows.programmer.win32/sGozH_cHVuY

Just did the same test with VS 2010 + Windows 7 to see if MS
ever fixed the bug I logged with them back in 2005 through their
support line.

Looks like this bug still exists, so seems MS never did fix it.

-------------------------------------------------------------------------
C:\temp>echo %date% %time%
Thu 09/20/2012 5:46:36.31

C:\temp>ver
Microsoft Windows [Version 6.1.7600]

C:\temp>dir
Volume in drive C has no label.
Volume Serial Number is 348A-1965

Directory of C:\temp

09/20/2012 05:44 AM <DIR> .
09/20/2012 05:44 AM <DIR> ..
09/20/2012 05:25 AM 607 foo.c
1 File(s) 607 bytes
2 Dir(s) 54,282,874,880 bytes free

C:\temp>echo > bar # create 'bar'

C:\temp>echo %USERNAME% # see who I am
erco

C:\temp>cacls bar /e /d erco # remove my write access to bar
processed file: C:\temp\bar

C:\temp>echo >> bar # verify no write access
Access is denied.

C:\temp>type foo.c
// Simple program to test access() function
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include <errno.h>
#include <string.h>
main()
{
// ACCESS TEST
if ( _access("bar", 6) == 0 )
{ printf("access() says bar is OK to r/w. (NO IT'S NOT!)\n"); }
else
{ perror("_access(bar,6) NOT writable (EXPECT THIS), reason:"); }

// OPEN TEST
{
int fd = _open("bar", O_WRONLY|O_APPEND);
if ( fd == -1 ) { perror("open(bar) fails, as we expect"); }
else { printf("open(bar) OK\n"); close(fd); }
}
}

C:\temp>cl foo.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.

foo.c
Microsoft (R) Incremental Linker Version 10.00.30319.01
Copyright (C) Microsoft Corporation. All rights reserved.

/out:foo.exe
foo.obj

C:\temp>.\foo.exe
access() says bar is OK to r/w. (NO IT'S NOT!) <-- still broken
open(bar) fails, as we expect: Permission denied
-------------------------------------------------------------------------
Lucian Wischik
2005-04-13 21:25:50 UTC
Permalink
Post by Greg Ercolano
Post by Sten Westerback
Anyway, to test using WINAPI, CreateFile() is the easiest way.
Hmm, but then I'm modifying the file system.
I don't think you can deduce that.
"CreateFile" is just the name that they happened to use for a
super-function that does everything. It can create files, or open
existing files, or do hardware interaction, or lots of stuff. It
doesn't have to modify the FS at all.

--
Lucian
Greg Ercolano
2005-04-15 16:25:37 UTC
Permalink
Post by Lucian Wischik
Post by Greg Ercolano
Post by Sten Westerback
Anyway, to test using WINAPI, CreateFile() is the easiest way.
Hmm, but then I'm modifying the file system.
I don't think you can deduce that.
"CreateFile" is just the name that they happened to use for a
super-function that does everything. It can create files, or open
existing files, or do hardware interaction, or lots of stuff. It
doesn't have to modify the FS at all.
Yes, you're right.

Indeed, Microsoft's code workaround (posted by me elsewhere in this thread)
uses CreateFile() to do the non-intrusive 'access checks'.

I thought OpenFile() would be the 'super function' if anything was,
but apparently that's been obsoleted by CreateFile(). *head spins*

Anyway, thanks for all the pointers.
a***@gmail.com
2018-06-15 04:32:54 UTC
Permalink
Post by Greg Ercolano
Is there a WIN32 function similar to the _access() C library
function?
I need an alternative to _access(), because _access() appears
to be broken; it's saying files are writeable when they're not..
(see '** BAD ** below). The environment is Win2K with a VC.NET 7.0
compiler.
I guess I should report this as a security bug to MS.
Meanwhile, I'm hoping that there's a similar Win32 function
that actually works for detect r/w access for files *and directories*.
In my real app (not shown) needs to check for access problems
with files and directories before actually opening or creating files.
I'm not sure I see an equivalent for _access() in Win32.
-------------------------------------------------------------------------------------
C:\temp>type check-bar.c <-- view test program
// Simple program to test access() function
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include <errno.h>
#include <string.h>
main()
{
// ACCESS TEST
if ( _access("bar", 6) == 0 ) { printf("access() says bar is OK to r/w. (NO IT'S NOT!)\n"); }
else { perror("_access(bar,6) NOT writable (EXPECT THIS), reason:"); }
// OPEN TEST
{
int fd = _open("bar", O_WRONLY|O_APPEND);
if ( fd == -1 ) { perror("open(bar) fails, as we expect"); }
else { printf("open(bar) OK\n"); close(fd); }
}
}
C:\temp>cl check-bar.c <-- compile it
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.00.9466 for 80x86
Copyright (C) Microsoft Corporation 1984-2001. All rights reserved.
[..]
/out:check-bar.exe
check-bar.obj
C:\temp>.\check-bar.exe <-- run it
access() says bar is OK to r/w. (NO IT'S NOT!) <-- ** BAD **
open(bar) fails, as we expect: Permission denied <-- OK
C:\temp>echo > bar <-- OK: verify we have NO access..
Access is denied. <-- OK: expect this, we can't access file
C:\temp>echo %USERNAME% <-- OK: Reason: we are 'barney'..
barney
^^^^^^
C:\temp>cacls bar <-- OK: ..and file is accessable..
C:\temp\bar GENEVA\fred:F <-- OK: only to 'fred'
^^^^
----------------------------------------------------------------------------------
Hi Greg Ercolano,
i was today working on my project of windows i found the _access is buggy for read and write operation so u said try the CheckAccess method but there is no method exist alternative to _access plz resolve my query
Thanks in advance.
Auric__
2018-06-15 07:12:47 UTC
Permalink
LOOK ^^^^^^^^^^^^^^^^^^^^^^
[snip]
Post by a***@gmail.com
Hi Greg Ercolano,
i was today working on my project of windows i found the _access is
buggy for read and write operation so u said try the CheckAccess method
but there is no method exist alternative to _access plz resolve my query
Thanks in advance.
Greg posted his original message ***THIRTEEN YEARS AGO***. His last post in
this thread was almost SIX YEARS AGO.
--
Bandring is fleeing from the dreaded Malevolent Moose.
Loading...