Hem
Hem

Reputation: 739

CreateMutex -- "Access is denied"

The following code works without any problem sometimes and at other times it throws "Access is denied" error. The behavior is not consistent.

_hMutex = CreateMutex(NULL, FALSE, MutexName);
    if (_hMutex == NULL) 
{
  throw MY_ERROR(GetLastError(), L"Error creating mutex handle");
}

I run my standalone executable which has this code, do the operation and exit. It is not a multithreaded application. I logon with the same user credential every time I run this.

Could you help me resolve this?

Thanks, Hem

Upvotes: 3

Views: 7983

Answers (4)

David Gausmann
David Gausmann

Reputation: 1718

Today I had a similar issue, but with different sessions. The mutex is named and has the prefix Global\. When one application created the named global mutex no other application of different user accounts was allowed to synchronize with the same mutex. CreateMutex always returned the error ERROR_ACCESS_DENIED. OpenMutex succeeded, but the mutex couldn't be used for synchronization.

The solution is that each application must access the global mutex with CreateMutexEx (with only SYNCHRONIZE requested) AND you must specify the SecurityAttributes. The default SecurityAttributes disallows sharing between user accounts.

A working code looks like:

HANDLE hMutex;
{
    DWORD dwRes, dwDisposition;
    PSID pEveryoneSID = NULL;
    PACL pACL = NULL;
    PSECURITY_DESCRIPTOR pSD = NULL;
    EXPLICIT_ACCESS ea[1];
    SID_IDENTIFIER_AUTHORITY SIDAuthWorld =
            SECURITY_WORLD_SID_AUTHORITY;
    SECURITY_ATTRIBUTES sa;
    LONG lRes;

    // Create a well-known SID for the Everyone group.
    if(!AllocateAndInitializeSid(&SIDAuthWorld, 1,
                     SECURITY_WORLD_RID,
                     0, 0, 0, 0, 0, 0, 0,
                     &pEveryoneSID))
    {
        _tprintf(_T("AllocateAndInitializeSid Error %u\n"), GetLastError());
        goto Cleanup;
    }

    // Initialize an EXPLICIT_ACCESS structure for an ACE.
    // The ACE will allow Everyone read access to the key.
    ZeroMemory(&ea, 1 * sizeof(EXPLICIT_ACCESS));
    ea[0].grfAccessPermissions = SYNCHRONIZE;
    ea[0].grfAccessMode = SET_ACCESS;
    ea[0].grfInheritance= NO_INHERITANCE;
    ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
    ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
    ea[0].Trustee.ptstrName  = (LPTSTR) pEveryoneSID;
    
    // Create a new ACL that contains the new ACEs.
    dwRes = SetEntriesInAcl(1, ea, NULL, &pACL);
    if (ERROR_SUCCESS != dwRes) 
    {
        _tprintf(_T("SetEntriesInAcl Error %u\n"), GetLastError());
        goto Cleanup;
    }

    // Initialize a security descriptor.  
    pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, 
                             SECURITY_DESCRIPTOR_MIN_LENGTH); 
    if (NULL == pSD) 
    { 
        _tprintf(_T("LocalAlloc Error %u\n"), GetLastError());
        goto Cleanup; 
    } 
 
    if (!InitializeSecurityDescriptor(pSD,
            SECURITY_DESCRIPTOR_REVISION)) 
    {  
        _tprintf(_T("InitializeSecurityDescriptor Error %u\n"),
                                GetLastError());
        goto Cleanup; 
    } 
 
    // Add the ACL to the security descriptor. 
    if (!SetSecurityDescriptorDacl(pSD, 
            TRUE,     // bDaclPresent flag   
            pACL, 
            FALSE))   // not a default DACL 
    {  
        _tprintf(_T("SetSecurityDescriptorDacl Error %u\n"),
                GetLastError());
        goto Cleanup; 
    } 

    // Initialize a security attributes structure.
    sa.nLength = sizeof (SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = pSD;
    sa.bInheritHandle = FALSE;

    hMutex = CreateMutexExW(&sa, L"Global\\MyNamedMutex", 0, SYNCHRONIZE);

Cleanup:

    if (pEveryoneSID) 
        FreeSid(pEveryoneSID);
    if (pAdminSID) 
        FreeSid(pAdminSID);
    if (pACL) 
        LocalFree(pACL);
    if (pSD) 
        LocalFree(pSD);
}

// Do something with hMutex
WaitForSingleObject(hMutex, INFINITE);

CloseHandle(hMutex);

Source links:

Upvotes: 2

Hem
Hem

Reputation: 739

I found it finally. There is a service that runs with system account that creates the mutex and an exe run by user trying to access it. It was due to the permission.

Upvotes: 0

Ram
Ram

Reputation: 3143

If the mutex is a named mutex, and the object existed before this function call, the return value is a handle to the existing object, GetLastError returns ERROR_ALREADY_EXISTS, bInitialOwner is ignored, and the calling thread is not granted ownership.

However, if the caller has limited access rights, the function will fail with ERROR_ACCESS_DENIED and the caller should use the OpenMutex function.

MSDN

Upvotes: 3

Adam Wright
Adam Wright

Reputation: 49386

This is probably because a mutex with MutexName already exists. You're creating the mutex with default security descriptor, which (depending on how you're using this mutex) may not permit other uses of it.

For more, see MSDN. A useful snippet:

If the mutex is a named mutex and the object existed before this function call, [elided], if the caller has limited access rights, the function will fail with ERROR_ACCESS_DENIED and the caller should use the OpenMutex function.

Upvotes: 1

Related Questions