2025-11-28 00:35:46 +09:00

373 lines
12 KiB
C

/*--------------------------------------------------------------------------
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (C) Microsoft Corporation. All rights reserved.
MODULE: simple.c
PURPOSE: Implements the body of the service.
The default behavior is to open a
named pipe, \\.\pipe\simple, and read
from it. It then modifies the data and
writes it back to the pipe.
FUNCTIONS:
ServiceStart(DWORD dwArgc, LPTSTR *lpszArgv);
ServiceStop( );
COMMENTS: The functions implemented in simple.c are
prototyped in service.h
--------------------------------------------------------------------------*/
#include <windows.h>
#include <sddl.h>
#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#include <tchar.h>
#include "service.h"
#include <strsafe.h>
// this event is signalled when the
// service should end
//
HANDLE hServerStopEvent = NULL;
// CreateMyDACL
// Creates a security descriptor containing the
// desired DACL. This function uses SDDL to make Deny and Allow ACEs.
//
// Parameter:
// SECURITY_ATTRIBUTES * pSA
// Address to a SECURITY_ATTRIBUTES structure. It is the caller's
// responsibility to properly initialize the structure, and to free
// the structure's lpSecurityDescriptor member when done (by calling
// the LocalFree function).
//
// Return value:
// FALSE if the address to the structure is NULL.
// Otherwise, this function returns the value from the
// ConvertStringSecurityDescriptorToSecurityDescriptor function.
BOOL CreateMyDACL(SECURITY_ATTRIBUTES * pSA)
{
// Define the SDDL for the DACL. This example sets
// the following access:
// Built-in guests are denied all access.
// Anonymous Logon is denied all access.
// Authenticated Users are allowed read/write/execute access.
// Administrators are allowed full control.
// Modify these values as needed to generate the proper
// DACL for your application.
TCHAR * szSD = "D:" // Discretionary ACL
"(D;OICI;GA;;;BG)" // Deny access to Built-in Guests
"(D;OICI;GA;;;AN)" // Deny access to Anonymous Logon
"(A;OICI;GRGWGX;;;AU)" // Allow read/write/execute to Authenticated Users
"(A;OICI;GA;;;BA)"; // Allow full control to Administrators
if (NULL == pSA)
return FALSE;
return ConvertStringSecurityDescriptorToSecurityDescriptor(
szSD,
SDDL_REVISION_1,
&(pSA->lpSecurityDescriptor),
NULL);
}
//
// FUNCTION: ServiceStart
//
// PURPOSE: Actual code of the service that does the work.
//
// PARAMETERS:
// dwArgc - number of command line arguments
// lpszArgv - array of command line arguments
//
// RETURN VALUE:
// none
//
// COMMENTS:
// The default behavior is to open a
// named pipe, \\.\pipe\simple, and read
// from it. It the modifies the data and
// writes it back to the pipe. The service
// stops when hServerStopEvent is signalled
//
VOID ServiceStart (DWORD dwArgc, LPTSTR *lpszArgv)
{
HANDLE hPipe = INVALID_HANDLE_VALUE;
HANDLE hEvents[2] = {NULL, NULL};
OVERLAPPED os;
PSECURITY_DESCRIPTOR pSD = NULL;
SECURITY_ATTRIBUTES sa;
TCHAR szIn[80];
TCHAR szOut[ (sizeof(szIn) / sizeof(TCHAR) ) + 100];
LPTSTR lpszPipeName = TEXT("\\\\.\\pipe\\simple");
BOOL bRet;
DWORD cbRead;
DWORD cbWritten;
DWORD dwWait;
UINT ndx;
///////////////////////////////////////////////////
//
// Service initialization
//
// report the status to the service control manager.
//
if (!ReportStatusToSCMgr(
SERVICE_START_PENDING, // service state
NO_ERROR, // exit code
3000)) // wait hint
goto cleanup;
// create the event object. The control handler function signals
// this event when it receives the "stop" control code.
//
hServerStopEvent = CreateEvent(
NULL, // no security attributes
TRUE, // manual reset event
FALSE, // not-signalled
NULL); // no name
if ( hServerStopEvent == NULL)
goto cleanup;
hEvents[0] = hServerStopEvent;
// report the status to the service control manager.
//
if (!ReportStatusToSCMgr(
SERVICE_START_PENDING, // service state
NO_ERROR, // exit code
3000)) // wait hint
goto cleanup;
// create the event object object use in overlapped i/o
//
hEvents[1] = CreateEvent(
NULL, // no security attributes
TRUE, // manual reset event
FALSE, // not-signalled
NULL); // no name
if ( hEvents[1] == NULL)
goto cleanup;
// report the status to the service control manager.
//
if (!ReportStatusToSCMgr(
SERVICE_START_PENDING, // service state
NO_ERROR, // exit code
3000)) // wait hint
goto cleanup;
// create a security descriptor that allows anyone to write to
// the pipe...
//
pSD = (PSECURITY_DESCRIPTOR) malloc( SECURITY_DESCRIPTOR_MIN_LENGTH );
if (pSD == NULL)
goto cleanup;
if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
goto cleanup;
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = pSD;
if(!CreateMyDACL(&sa) )
{
// DACL creation FAILED!!
return;
}
// report the status to the service control manager.
//
if (!ReportStatusToSCMgr(
SERVICE_START_PENDING, // service state
NO_ERROR, // exit code
3000)) // wait hint
goto cleanup;
// allow user tp define pipe name
for ( ndx = 1; ndx < dwArgc-1; ndx++ )
{
if ( ( (*(lpszArgv[ndx]) == TEXT('-')) ||
(*(lpszArgv[ndx]) == TEXT('/')) ) &&
(!_tcsicmp( TEXT("pipe"), lpszArgv[ndx]+1 ) && ((ndx + 1) < dwArgc)) )
{
lpszPipeName = lpszArgv[++ndx];
}
}
// open our named pipe...
//
hPipe = CreateNamedPipe(
lpszPipeName , // name of pipe
FILE_FLAG_OVERLAPPED |
PIPE_ACCESS_DUPLEX, // pipe open mode
PIPE_TYPE_MESSAGE |
PIPE_READMODE_MESSAGE |
PIPE_WAIT, // pipe IO type
1, // number of instances
0, // size of outbuf (0 == allocate as necessary)
0, // size of inbuf
1000, // default time-out value
&sa); // security attributes
if (hPipe == INVALID_HANDLE_VALUE)
{
AddToMessageLog(TEXT("Unable to create named pipe"));
goto cleanup;
}
// report the status to the service control manager.
//
if (!ReportStatusToSCMgr(
SERVICE_RUNNING, // service state
NO_ERROR, // exit code
0)) // wait hint
goto cleanup;
//
// End of initialization
//
////////////////////////////////////////////////////////
////////////////////////////////////////////////////////
//
// Service is now running, perform work until shutdown
//
for(;;)
{
// init the overlapped structure
//
memset( &os, 0, sizeof(OVERLAPPED) );
os.hEvent = hEvents[1];
ResetEvent( hEvents[1] );
// wait for a connection...
//
ConnectNamedPipe(hPipe, &os);
if ( GetLastError() == ERROR_IO_PENDING )
{
dwWait = WaitForMultipleObjects( 2, hEvents, FALSE, INFINITE );
if ( dwWait != WAIT_OBJECT_0+1 ) // not overlapped i/o event - error occurred,
break; // or server stop signaled
}
// init the overlapped structure
//
memset( &os, 0, sizeof(OVERLAPPED) );
os.hEvent = hEvents[1];
ResetEvent( hEvents[1] );
// Set the buffer to all NULLs otherwise we get leftover characters
memset(szIn, '\0', sizeof(szIn));
// grab whatever's coming through the pipe...
//
bRet = ReadFile(
hPipe, // file to read from
szIn, // address of input buffer
sizeof(szIn), // number of bytes to read
&cbRead, // number of bytes read
&os); // overlapped stuff, not needed
if ( !bRet && ( GetLastError() == ERROR_IO_PENDING ) )
{
dwWait = WaitForMultipleObjects( 2, hEvents, FALSE, INFINITE );
if ( dwWait != WAIT_OBJECT_0+1 ) // not overlapped i/o event - error occurred,
break; // or server stop signaled
}
// munge the string
//
StringCchPrintf(szOut, sizeof(szOut),TEXT("Hello! [%s]"), szIn);
// init the overlapped structure
//
memset( &os, 0, sizeof(OVERLAPPED) );
os.hEvent = hEvents[1];
ResetEvent( hEvents[1] );
// send it back out...
//
bRet = WriteFile(
hPipe, // file to write to
szOut, // address of output buffer
sizeof(szOut), // number of bytes to write
&cbWritten, // number of bytes written
&os); // overlapped stuff, not needed
if ( !bRet && ( GetLastError() == ERROR_IO_PENDING ) )
{
dwWait = WaitForMultipleObjects( 2, hEvents, FALSE, INFINITE );
if ( dwWait != WAIT_OBJECT_0+1 ) // not overlapped i/o event - error occurred,
break; // or server stop signaled
}
// drop the connection...
//
DisconnectNamedPipe(hPipe);
}
cleanup:
if (hPipe != INVALID_HANDLE_VALUE )
CloseHandle(hPipe);
if (hServerStopEvent)
CloseHandle(hServerStopEvent);
if (hEvents[1]) // overlapped i/o event
CloseHandle(hEvents[1]);
if ( pSD )
free( pSD );
}
//
// FUNCTION: ServiceStop
//
// PURPOSE: Stops the service
//
// PARAMETERS:
// none
//
// RETURN VALUE:
// none
//
// COMMENTS:
// If a ServiceStop procedure is going to
// take longer than 3 seconds to execute,
// it should spawn a thread to execute the
// stop code, and return. Otherwise, the
// ServiceControlManager will believe that
// the service has stopped responding.
//
VOID ServiceStop()
{
if ( hServerStopEvent )
SetEvent(hServerStopEvent);
}