has anyone being able to share a global semaphore between different
users?
I've done the following in my dialog-based application:
HANDLE g_hSem;
BOOL CMyApp::InitInstance()
{
g_hSem = CreateSemaphore(NULL,3,3,"Global\\MyAppUniqueID");
if (g_hSem==NULL)
{
TRACE("%s\n", strerror(errno));
}
// do something
ReleaseSemaphore(g_hSem,1,NULL);
return FALSE;
}
My problem is when I use fast switching to log in as another user, and
run the same app,
the handle g_hSem is NULL, and the error is "access denied".
So I want to set a security attributes variable as the first arg of
CreateSemaphore() :
SECURITY_ATTRIBUTES SecAtt;
SecAtt.bInheritHandle=FALSE;
SecAtt.nLength=sizeof(SecAtt);
// Init the security descriptor
SetSecurityDescriptorControl( &(SecAtt.lpSecurityDescriptor),
SE_DACL_PROTECTED, 0 );
g_hSem = CreateSemaphore(&SecAtt,3,3,"Global\\MyAppUniqueID");
but when compiling I get a 'SetSecurityDescriptorControl' : undeclared
identifier message.
Anyway, is it the right path to follow?
Thanks
If the semaphore is already created, I think you need to call
OpenSemaphore() instead of CreateSemaphore().
Also, don't forget to call CloseHandle() when you're done with it.
-- David
Thanks David
The MSDN help says that if the semaphore is already created, a new
call CreateSemaphore() just returns a handle to the existing
semaphore, so it should be ok. Nevertheless, I've followed your
suggestion regarding using OpenSemaphore() rather than
CreateSemaphore() when the semaphore already exists.
I've added CloseHandle after ReleaseSemaphore.
I've made some progress:
////////////////////////////////////////////
HANDLE g_hSem=NULL;
BOOL CMyApp::InitInstance()
{
SECURITY_ATTRIBUTES SecAtt;
SECURITY_DESCRIPTOR SecDesc;
SecAtt.bInheritHandle=FALSE;
InitializeSecurityDescriptor(&SecDesc, SECURITY_DESCRIPTOR_REVISION);
SecAtt.lpSecurityDescriptor=&SecDesc;
// This should grant read/write/execute accesses to authenticated
users
ConvertStringSecurityDescriptorToSecurityDescriptor(
TEXT("(A;OICI;GRGWGX;;;AU)"),
SDDL_REVISION_1,
&(SecAtt.lpSecurityDescriptor),
NULL);
SecAtt.nLength=sizeof(SECURITY_DESCRIPTOR);
if ((g_hSem=OpenSemaphore(SEMAPHORE_ALL_ACCESS,TRUE,"Global\
\MyApp"))==NULL)
{
g_hSem = CreateSemaphore(&SecAtt,3,3,"Global\\MyApp");
}
if (g_hSem==NULL)
{
sprintf(Msg,"g_hSem : %s",strerror(errno));
AfxMessageBox(Msg);
return FALSE; // stop here
}
// Do something
ReleaseSemaphore(g_hSem,1,NULL);
CloseHandle(g_hSem);
return FALSE;
}
//////////////////////////////////////
When I run the program as user A, and fast-switch to user B and run a
second instance, the semaphore is NULL and I get an "g_hSem : Input/
Output error" error.
I feel so frustrated, because I believe I'm so close to get it to
work !!
Phil
If the error is still related to security, I'm not sure the
SECURITY_ATTRIBUTES is correct. I'm no expert at this at all, but this code
I have used to create a mutex (not semaphore) that could be accessed when
fast-user switching was invoked:
PSID pEveryoneSID = NULL;
PSECURITY_DESCRIPTOR pSD = NULL;
SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
SECURITY_ATTRIBUTES sa;
// Create a well-known SID for the Everyone group.
if(! AllocateAndInitializeSid( &SIDAuthWorld, 1,
SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0,
&pEveryoneSID) )
{
return FALSE;
}
EXPLICIT_ACCESS ea;
ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
ea.grfAccessPermissions = STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL;
ea.grfAccessMode = SET_ACCESS;
ea.grfInheritance= NO_INHERITANCE;
ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
ea.Trustee.ptstrName = (LPTSTR) pEveryoneSID;
// Create a new ACL that contains the new ACE.
PACL pACL = NULL;
dwRes = SetEntriesInAcl(1, &ea, NULL, &pACL);
if (ERROR_SUCCESS != dwRes)
{
goto Cleanup;
}
// Initialize a security descriptor.
pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR,
SECURITY_DESCRIPTOR_MIN_LENGTH);
if (pSD == NULL)
{
goto Cleanup;
}
if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
{
goto Cleanup;
}
// Add the ACL to the security descriptor.
if (!SetSecurityDescriptorDacl(pSD,
TRUE, // fDaclPresent flag
pACL,
FALSE)) // not a default DACL
{
goto Cleanup;
}
// Initialize a security attributes structure.
sa.nLength = sizeof (SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = pSD;
sa.bInheritHandle = FALSE;
// Create your semaphore using 'sa'
cleanup:
...
Hope this helps,
David
David,
It does help !! I've implemented your code, and it worked :)
Don't know what's wrong with my code, but yours work. I can share a
semaphore between users.
Thank you for sharing your expertise,
Phil
Awesome Phil, glad it's working. I think mine works because it enables
Everyone to use the semaphore. Other than everyone, it's confusing to know
what groups a resource has access to, so it's easier to enable Everyone.
That's my admittedly stupid view of security, but it's not my fault they
made it so hard for mere mortals to understand. Whether they set out to do
it or not, they designed a system where security is achieved through
obfuscation... and because it's so hard to use, actually makes the system
less secure since everyone avoids it like the plague. You can probably
clean up the code quite a bit. For example, I don't think LocalAlloc() is
needed.
-- David
You're not alone ;)
Dave
THis is carefully-specified and explicitly-documented feature of CreateSemaphore, and
therefore would not be the issue.
This is so that an app doesn't have to know if anyone else has created the semaphore.
joe
Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
On Mon, 9 Jun 2008 13:13:51 -0700, "David Ching" <d...@remove-this.dcsoft.com> wrote:
>"Phil" <pbru...@yahoo.com> wrote in message
>news:040638eb-bebf-4bcf...@k13g2000hse.googlegroups.com...
>> SECURITY_ATTRIBUTES SecAtt;
>> SECURITY_DESCRIPTOR SecDesc;
>> SecAtt.bInheritHandle=FALSE;
>> InitializeSecurityDescriptor(&SecDesc, SECURITY_DESCRIPTOR_REVISION);
>> SecAtt.lpSecurityDescriptor=&SecDesc;
>>
>> // This should grant read/write/execute accesses to authenticated
>> users
>> ConvertStringSecurityDescriptorToSecurityDescriptor(
>> TEXT("(A;OICI;GRGWGX;;;AU)"),
****
If I've decoded this properly, it means:
ace_type
A SDDL_ACCESS_ALLOWED
ace_flags
OI SDDL_OBJECT_INHERIT
CI SDDL_CONTAINER_INHERIT
rights
GR SDDL_GENERIC_READ
GW SDDL_GENERIC_WRITE
GX SDDL_GENERIC_EXECUTE
(wouldn't it have been simpler to simply use GA? Although
it is a separate bit from GR/GW/GX, the docs say it is
equivalent to specifying all three of them)
(but why execute rights on a semaphore?)
object_guid
(empty)
inherit_object_guid
(empty)
account_sid
AU SDDL_AUTHENTICATED_USERS
****
>> SDDL_REVISION_1,
>> &(SecAtt.lpSecurityDescriptor),
>> NULL);
>>
>> SecAtt.nLength=sizeof(SECURITY_DESCRIPTOR);
>> if ((g_hSem=OpenSemaphore(SEMAPHORE_ALL_ACCESS,TRUE,"Global\
>> \MyApp"))==NULL)
>> {
>> g_hSem = CreateSemaphore(&SecAtt,3,3,"Global\\MyApp");
>> }
>>
****
In the above sequence, suppose I have two sequences in thread A and B that can be
represented as o (open) and c (create), where ~ means the operation fails
if the sequences are
Ao~Bo~AcBc
Ao~Bo~BcAc
Why the OpenSemaphore call at all? Why not just CreateSemaphore? CreateSemaphore says if
the named semaphore already exists, it applies SEMAPHORE_ALL_ACCESS, which is all that is
happening here.
So what has been gained here? Note the window between open and create allows the other
thread to create it before the first thread gets to create it.
****
>
>If the error is still related to security, I'm not sure the
>SECURITY_ATTRIBUTES is correct. I'm no expert at this at all,
****
This is amazing. I've spent years avoiding learning about security, but this prompted me
to try again. How many weeks did it take you to discover this, or is there someplace it
is deducible without reading the massively complex security docs?
****
****
This is massively more complex than the first example; I'm not sure I could even create
the logical path by which these functions and values were assembled into this sequence. Is
there any reasonable reference to how these can be created?
I'd like to add something like this to my Systems Programming course, since I talk about
the \Global technique, but it is so completely incomprehensible that I'm not sure I can
safely talk about it. But before I even bother to try to understand it, I wanted to know
if you would give me permission to use this code. If you want, I would be happy to put
your name in as the creator. But it looks like it would take me several days to make
sense of this insofar as trying to explain it. (I already have another blog post in with
a reference to the creator, for integrity levels, but it is hard to explain. This is
orders of magnitude more complex!) It's a question of whether or not I have to decode
this far enough to explain it...
joe
****
>
>Hope this helps,
It was several years ago, but I think it took a day or two. I used google
to piece together a solution that gave the desired SECURITY_ATTRIBUTES,
starting with the previously known (to me) SECURITY_WORLD_SID_AUTHORITY. I
tried to learn about the intermediate Sid, EXPLICIT_ACCESS (ACE), ACL,
SECURITY_DESCRIPTOR, but to this day don't know the theory behind those
structures or why so many of them exist. I think there is a book or two
that may cover these well, but after getting this code to work I've not
needed to figure it out anymore.
> This is massively more complex than the first example; I'm not sure I
> could even create
> the logical path by which these functions and values were assembled into
> this sequence. Is
> there any reasonable reference to how these can be created?
>
It's not that complicated - you start with one data structure and use it in
the next one. Proceed linearly until you end up with the structure accepted
by the API you need. It looks hard because there are so many unfamiliar
structures and types in so short a space!
> I'd like to add something like this to my Systems Programming course,
> since I talk about
> the \Global technique, but it is so completely incomprehensible that I'm
> not sure I can
> safely talk about it. But before I even bother to try to understand it, I
> wanted to know
> if you would give me permission to use this code. If you want, I would be
> happy to put
> your name in as the creator. But it looks like it would take me several
> days to make
> sense of this insofar as trying to explain it. (I already have another
> blog post in with
> a reference to the creator, for integrity levels, but it is hard to
> explain. This is
> orders of magnitude more complex!) It's a question of whether or not I
> have to decode
> this far enough to explain it...
Thanks for asking, but I thought any code that is published here is by
definition in the public domain. Of course, please use it however you like.
Maybe one of these days you'll refer to me as someone who had some
interesting stories to tell.... ;)
-- David
There is a subtle problem with Create<object> (addressed in Vista, IIRC),
that if the object already exists, the OS will try to open it with
ALL_ACCESS, which may not be granted, though it doesn't apply to this
example. This is why it makes sense to try Open<object> first.
****
But, under the scenario I show above, the Create *would* be called twice, because both
Opens would fail.
joe