views:

1783

answers:

9

I am creating an appcation on Vista,which include a service and a Console application .Both running in same user account

In service i am creating an event and waits for that event.In console application i am opening the same event (problem starts here) and calling SetEvent function. I can not open the event (getting error 5,Access is denied) in the console application.I searched in the net and saw something about integrity level (I am not sure that the problem is related to integrity level).Its telling that service and applicaation got differnt integrity levels.

here is the part of the code,where IPC occures

service

DWORD
WINAPI IpcThread(LPVOID lpParam)
{
HANDLE ghRequestEvent = NULL ;

ghRequestEvent = CreateEvent(NULL, FALSE,
FALSE, "Global\\Event1") ; //creating the event

if(NULL == ghRequestEvent)
{
//error
}
while(1)
{
WaitForSingleObject(ghRequestEvent, INFINITE) //waiting for the event
//here some action related to event
}
}

Console Application

Here in application ,opening the event and seting the event

unsigned int
event_notification()
{
HANDLE ghRequestEvent = NULL ;



 ghRequestEvent = OpenEvent(SYNCHRONIZE|EVENT_MODIFY_STATE, FALSE, "Global\\Event1") ;

if(NULL == ghRequestEvent)
{
//error
}
SetEvent(ghRequestEvent) ;
}

I am running both application (serivce and console application) with administrative privilege (i logged in as Administraor and running the console application by right clicking and using the option "run as administrator") .

The error i am getting in console application (where i am opening the event) is error no 5(Access is denied. ) .

So it will be very helpfull if you tell how to do the IPC between a service and an application in Vista

Thanks in advance

Navaneeth

+3  A: 

Are the service and the application running as the same user with different integrity levels, or are they running as different users?

If it is the former, then this article from MSDN which talks about integrity levels might help. They have some sample code for lowering the integrity level of a file. I'm not sure that this could be relevant for an event though.

#include <sddl.h>
#include <AccCtrl.h>
#include <Aclapi.h>

void SetLowLabelToFile()
{
  // The LABEL_SECURITY_INFORMATION SDDL SACL to be set for low integrity 
  #define LOW_INTEGRITY_SDDL_SACL_W L"S:(ML;;NW;;;LW)"
  DWORD dwErr = ERROR_SUCCESS;
  PSECURITY_DESCRIPTOR pSD = NULL;    

  PACL pSacl = NULL; // not allocated
  BOOL fSaclPresent = FALSE;
  BOOL fSaclDefaulted = FALSE;
  LPCWSTR pwszFileName = L"Sample.txt";

  if (ConvertStringSecurityDescriptorToSecurityDescriptorW(
         LOW_INTEGRITY_SDDL_SACL_W, SDDL_REVISION_1, &pSD;, NULL)) 
  {
    if (GetSecurityDescriptorSacl(pSD, &fSaclPresent;, &pSacl;, 
         &fSaclDefaulted;))
    {
      // Note that psidOwner, psidGroup, and pDacl are 
      // all NULL and set the new LABEL_SECURITY_INFORMATION
      dwErr = SetNamedSecurityInfoW((LPWSTR) pwszFileName, 
                 SE_FILE_OBJECT, LABEL_SECURITY_INFORMATION, 
                 NULL, NULL, NULL, pSacl);
    }
    LocalFree(pSD);
  }
}

If it is the latter you might look at this link which suggests creating a NULL ACL and associating it with the object (in the example it is a named pipe, but the approach is similar for an event I'm sure:

BYTE sd[SECURITY_DESCRIPTOR_MIN_LENGTH];
SECURITY_ATTRIBUTES sa;

sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = &sd;

InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, TRUE, (PACL) 0, FALSE);

CreateNamedPipe(..., &sa);
1800 INFORMATION
i ma running as same user .
Navaneeth
Where can you get a description of the LOW_INTEGRITY_SDDL_SACL_W string used above? I've only seen it used in sample code, never formally defined.
Clay
The security descriptor definition language (SDDL) is defined here http://msdn.microsoft.com/en-us/library/aa379567(VS.85).aspx
1800 INFORMATION
A: 

First, it is important to conceptually understand what is required. Once that is understood we can take it from there.

On the server, it should look something similar to:

{
   HANDLE hEvent;
   hEvent = CreateEvent(null, true, false, TEXT("MyEvent"));
   while (1)
   {
       WaitForSingleObject (hEvent);
       ResetEvent (hEvent);
       /* Do something -- start */
       /* Processing 1 */
       /* Processing 2 */
       /* Do something -- end */
   }
}

On the client:

{
   HANDLE hEvent;
   hEvent = OpenEvent(0, false, TEXT("MyEvent"));
   SetEvent (hEvent);
}

Several points to note:

  • ResetEvent should be as early as possible, right after WaitForSingleObject or WaitForMultipleObjects. If multiple clients are using the server and first client's processing takes time, second client might set the event and it might not be caught while server processes the first request.
  • You should implement some mechanism that would notify the client that server finished processing.
  • Before doing any win32 service mumbo-jumbo, have server running as simple application. This will eliminate any security-related problems.
Ignas Limanauskas
You shoulds use an auto reset event (second parameter to CreateEvent is false) rather than worrying about the race condition you describe
1800 INFORMATION
+1  A: 

I notice that you are creating the object in the "Global" namespace but are trying to open it in a local namespace. Does adding "Global\" to the name in the open call help?

Also, in the //error area, is there anything there to let you know it wasn't created?

Jere.Jones
A: 

Thanks Mr. Jere .Jones for helping me.i used "Global" in both application(please see the updated code).For error checking in the service i am using a file ,where i am writing all errors. In the application i am printing the error(its a console application).

The error i am getting in console application (where i am opening the event) is error no 5(Access is denied. ) .

Navaneeth
A: 

@Navaneeth:

Excellent feedback. Since your error is Access Denied, then I would change the desired access from EVENT_ALL_ACCESS, which you really don't need, to

(SYNCHRONIZE | EVENT_MODIFY_STATE)

SYNCHRONIZE lets you wait on the event and EVENT_MODIFY_STATE lets you call SetEvent, ResetEvent and PulseEvent.

It is possible that you might need more access, but that is highly unusual.

Jere.Jones
A: 

"1800 INFORMATION" is right - this is a UIPI issue; don't use Events in new code anyways, the event signal can be lost if the target blocking on the event happens to be in user-mode APC code when it is fired. The canonical way in Win32 to write a service/application is to use RPC calls to cross the UIPI boundary.

Paul Betts
A: 

Thank you Mr.Jere.Jones

I have tried that way aloso ( SYNCHRONIZE | EVENT_MODIFY_STATE , please see the updated code and information i added above ,which include how i am running the applications ),i am getting the same error 5. :(

Navaneeth
A: 

According to "1800 INFORMATION" and Mr. Paul Betts information, i made a sample application which include a service and console application(please see the code bellow).

I am running both application (serivce and console application) with administrative privilege (i logged in as Administraor and running the console application by right clicking and using the option "run as administrator") .

The error i am getting in console application (where i am opening the event) is error no 5(Access is denied. ) .

Service

DWORD WINAPI Ipcthread(LPVOID lpParam)

{
    #define LOW_INTEGRITY_SDDL_SACL_W TEXT("S:(ML;;NW;;;LW)")

    HANDLE ghTestEvent;
    PSECURITY_DESCRIPTOR pSD = NULL;
    PACL pSacl     = NULL; // not allocated
    BOOL fSaclPresent     = FALSE;
    BOOL fSaclDefaulted   = FALSE;


    TCHAR buf[50];
    DWORD err;




    //for error checking ,write all errors to this file

    hFile = CreateFile( TEXT("D:\\eventerror.txt"),
         GENERIC_WRITE,
         FILE_SHARE_READ,
         NULL,
         CREATE_ALWAYS,
         FILE_ATTRIBUTE_NORMAL,
         NULL);

    ghTestEvent  = CreateEvent(NULL,FALSE,FALSE,TEXT("Global\\sampleEvent"));

    if(ghTestEvent == NULL)
    {
     wsprintf(buf,TEXT("CreateEvent failed %d"),GetLastError());
     WriteFile(hFile,buf,sizeof(buf),NULL,NULL);
     RtlZeroMemory(buf,sizeof(buf));
     goto Cleanup;
    }




    if (!ConvertStringSecurityDescriptorToSecurityDescriptor(
         LOW_INTEGRITY_SDDL_SACL_W, SDDL_REVISION_1, &pSD, NULL)) 
     {
     wsprintf(buf,TEXT("ConvertStringSecurityDescriptorToSecurityDescriptor failed %d"),
                     GetLastError());
     WriteFile(hFile,buf,sizeof(buf),NULL,NULL);
     RtlZeroMemory(buf,sizeof(buf));
     goto Cleanup;  

     }
     if (!GetSecurityDescriptorSacl(pSD, &fSaclPresent, &pSacl, 
      &fSaclDefaulted))
     {
      wsprintf(buf,TEXT("GetSecurityDescriptorSacl failed %d"),GetLastError());
      WriteFile(hFile,buf,sizeof(buf),NULL,NULL);
      RtlZeroMemory(buf,sizeof(buf));
      goto Cleanup;
     }

      // Note that psidOwner, psidGroup, and pDacl are 
      // all NULL and set the new LABEL_SECURITY_INFORMATION
       err = SetNamedSecurityInfo(TEXT( "Global\\sampleEvent"), 
             SE_KERNEL_OBJECT, LABEL_SECURITY_INFORMATION, 
                      NULL, NULL, NULL, pSacl);
       if( err != ERROR_SUCCESS)
       {
      wsprintf(buf,TEXT("SetNamedSecurityInfo failed %d"),err);
      WriteFile(hFile,buf,sizeof(buf),NULL,NULL);
      RtlZeroMemory(buf,sizeof(buf));
      goto Cleanup;
       }

        LocalFree(pSD);


    err = WaitForSingleObject(ghTestEvent,INFINITE);

    if( err == WAIT_FAILED)
    {
     wsprintf(buf, TEXT("WaitForSingleObject failed %d"),GetLastError());
     WriteFile(hFile,buf,sizeof(buf),NULL,NULL);
     RtlZeroMemory(buf,sizeof(buf));
     goto Cleanup;
    }
    wsprintf(buf, TEXT("WaitForSingleObject Success:Got the event") );
    WriteFile(hFile,buf,sizeof(buf),NULL,NULL);
    RtlZeroMemory(buf,sizeof(buf));


Cleanup:
CloseHandle(hFile);
return err;
}

Console Application

int main()
{

    HANDLE ghEvent;
    BOOL res;

    ghEvent = OpenEvent( SYNCHRONIZE|EVENT_MODIFY_STATE  , FALSE, TEXT("Global\\sampleEvent"));

    if (ghEvent == NULL)
    {
     printf("error on opening the event %d ",GetLastError());
     getchar(); 
     return 1;

    }

    res = SetEvent(ghEvent);

    if(!res)
    {
     printf("SetEvent failed,%d",GetLastError());
     getchar();
     return 1;

    }
    printf("SetEvent success\n");
    return 0;

}
Navaneeth
A: 

Could it be the acl in the event? have you tried granting access to everyone?