~hudson-ubuntu/+junk/windows-remote-command

« back to all changes in this revision

Viewing changes to service/Service.cpp

  • Committer: James Page
  • Date: 2010-12-06 10:47:32 UTC
  • Revision ID: james.page@canonical.com-20101206104732-nctfskg5ky3vinf4
Initial release

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
   Copyright (c) 2006 Talha Tariq [ talha.tariq@gmail.com ] 
 
3
   All rights are reserved.
 
4
 
 
5
   Permission to use, copy, modify, and distribute this software 
 
6
   for any purpose and without any fee is hereby granted, 
 
7
   provided this notice is included in its entirety in the 
 
8
   documentation and in the source files.
 
9
  
 
10
   This software and any related documentation is provided "as is" 
 
11
   without any warranty of any kind, either express or implied, 
 
12
   including, without limitation, the implied warranties of 
 
13
   merchantibility or fitness for a particular purpose. The entire 
 
14
   risk arising out of use or performance of the software remains 
 
15
   with you. 
 
16
   
 
17
*/
 
18
#include <windows.h>
 
19
#include <tchar.h>
 
20
#include <stdio.h>
 
21
#include <stdlib.h>
 
22
#include <winsvc.h>
 
23
#include <process.h>
 
24
#include "RemComSvc.h"
 
25
#include "../RemCom.h"
 
26
 
 
27
SERVICE_STATUS          ServiceStatus; 
 
28
SERVICE_STATUS_HANDLE   ServiceStatusHandle; 
 
29
 
 
30
HANDLE hStopServiceEvent = NULL;
 
31
 
 
32
VOID  WINAPI RemComStart (DWORD argc, LPTSTR *argv); // prototype for the starting point of the service
 
33
VOID  WINAPI RemComCtrlHandler (DWORD opcode); // prototype for the control handler callback function of the service
 
34
DWORD IsService( BOOL& );
 
35
void CommunicationPoolThread(PVOID);
 
36
 
 
37
 
 
38
int _tmain( int, LPTSTR* )
 
39
{
 
40
   SERVICE_TABLE_ENTRY DispatchTable[] = { 
 
41
        { SERVICENAME,  RemComStart }, 
 
42
        { NULL, NULL } }; 
 
43
 
 
44
   BOOL bService = TRUE;
 
45
   
 
46
   // This process should be a service :)
 
47
   IsService( bService );
 
48
   if ( !bService ) {
 
49
      // _tprintf( _T("A service Cannot be started directly.\n") );
 
50
           CommunicationPoolThread(NULL);
 
51
   }
 
52
 
 
53
   // Start service
 
54
   return StartServiceCtrlDispatcher( DispatchTable);
 
55
}
 
56
 
 
57
// Deletes service
 
58
void DeleteSvc()
 
59
{
 
60
   // Open service manager
 
61
   SC_HANDLE hSCM = ::OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS);
 
62
 
 
63
   if (hSCM == NULL)
 
64
      return;
 
65
 
 
66
   // OPen service
 
67
   SC_HANDLE hService = ::OpenService( hSCM, SERVICENAME, SERVICE_ALL_ACCESS );
 
68
 
 
69
   if (hService == NULL)
 
70
   {
 
71
      ::CloseServiceHandle(hSCM);
 
72
      return;
 
73
   }
 
74
 
 
75
   // Deletes service from service database
 
76
   DeleteService( hService );
 
77
 
 
78
   // Stop the service
 
79
   ServiceStatus.dwCurrentState       = SERVICE_STOPPED; 
 
80
   ServiceStatus.dwCheckPoint         = 0; 
 
81
   ServiceStatus.dwWaitHint           = 0; 
 
82
   ServiceStatus.dwWin32ExitCode      = 0; 
 
83
   ServiceStatus.dwServiceSpecificExitCode = 0; 
 
84
   SetServiceStatus (ServiceStatusHandle, &ServiceStatus); 
 
85
 
 
86
   ::CloseServiceHandle(hService);
 
87
   ::CloseServiceHandle(hSCM);
 
88
}
 
89
 
 
90
// Start service
 
91
VOID WINAPI RemComStart (DWORD, LPTSTR* ) 
 
92
{
 
93
   DWORD status = 0; 
 
94
   DWORD specificError = 0;
 
95
 
 
96
   // Prepare the ServiceStatus structure that will be used for the
 
97
   // comunication with SCM(Service Control Manager).
 
98
   // If you fully under stand the members of this structure, feel
 
99
   // free to change these values :o)
 
100
   ServiceStatus.dwServiceType        = SERVICE_WIN32; 
 
101
   ServiceStatus.dwCurrentState       = SERVICE_START_PENDING; 
 
102
   ServiceStatus.dwControlsAccepted   = SERVICE_ACCEPT_STOP; 
 
103
   ServiceStatus.dwWin32ExitCode      = 0; 
 
104
   ServiceStatus.dwServiceSpecificExitCode = 0; 
 
105
   ServiceStatus.dwCheckPoint         = 0; 
 
106
   ServiceStatus.dwWaitHint           = 0; 
 
107
 
 
108
   // Here we register the control handler for our service.
 
109
   // We tell the SCM about a call back function that SCM will
 
110
   // call when user tries to Start, Stop or Pause your service.
 
111
   ServiceStatusHandle = RegisterServiceCtrlHandler( 
 
112
         TEXT("Service"), RemComCtrlHandler ); 
 
113
 
 
114
   if (ServiceStatusHandle == (SERVICE_STATUS_HANDLE)0) 
 
115
      return; 
 
116
   
 
117
   // Handle error condition 
 
118
   if (status != NO_ERROR) 
 
119
   { 
 
120
      ServiceStatus.dwCurrentState       = SERVICE_STOPPED; 
 
121
      ServiceStatus.dwCheckPoint         = 0; 
 
122
      ServiceStatus.dwWaitHint           = 0; 
 
123
      ServiceStatus.dwWin32ExitCode      = status; 
 
124
      ServiceStatus.dwServiceSpecificExitCode = specificError; 
 
125
 
 
126
      SetServiceStatus (ServiceStatusHandle, &ServiceStatus); 
 
127
      return; 
 
128
   } 
 
129
 
 
130
   // Initialization complete - report running status. 
 
131
   ServiceStatus.dwCurrentState       = SERVICE_RUNNING; 
 
132
   ServiceStatus.dwCheckPoint         = 0; 
 
133
   ServiceStatus.dwWaitHint           = 0; 
 
134
 
 
135
   if (!SetServiceStatus (ServiceStatusHandle, &ServiceStatus)) 
 
136
      status = GetLastError(); 
 
137
   else
 
138
   {
 
139
      // Start the main thread
 
140
      hStopServiceEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
 
141
      _beginthread( _ServiceMain, 0, NULL );
 
142
   }
 
143
 
 
144
   return; 
 
145
 
146
 
 
147
// Service Ctrl handler
 
148
VOID WINAPI RemComCtrlHandler (DWORD Opcode) 
 
149
 
150
    DWORD status; 
 
151
        
 
152
    switch(Opcode) 
 
153
    { 
 
154
        case SERVICE_CONTROL_STOP: 
 
155
            // Signal the event to stop the main thread
 
156
            SetEvent( hStopServiceEvent );
 
157
 
 
158
            ServiceStatus.dwWin32ExitCode = 0; 
 
159
            ServiceStatus.dwCurrentState  = SERVICE_STOPPED; 
 
160
            ServiceStatus.dwCheckPoint    = 0; 
 
161
            ServiceStatus.dwWaitHint      = 0; 
 
162
 
 
163
            if (!SetServiceStatus (ServiceStatusHandle, 
 
164
                &ServiceStatus))
 
165
            { 
 
166
                status = GetLastError(); 
 
167
            } 
 
168
                        return; 
 
169
 
 
170
        case SERVICE_CONTROL_INTERROGATE: 
 
171
        // Fall through to send current status. 
 
172
            break; 
 
173
    } 
 
174
 
 
175
    // Send current status. 
 
176
    if (!SetServiceStatus (ServiceStatusHandle,  &ServiceStatus)) 
 
177
    { 
 
178
        status = GetLastError(); 
 
179
    } 
 
180
    return; 
 
181
}
 
182
 
 
183
// This process is a service or is not ?
 
184
DWORD IsService( BOOL& isService )
 
185
{
 
186
   DWORD pID = GetCurrentProcessId(); 
 
187
        HANDLE hProcessToken = NULL;
 
188
        DWORD groupLength = 50;
 
189
        PTOKEN_GROUPS groupInfo = NULL;
 
190
 
 
191
        SID_IDENTIFIER_AUTHORITY siaNt = SECURITY_NT_AUTHORITY;
 
192
        PSID pInteractiveSid = NULL;
 
193
        PSID pServiceSid = NULL;
 
194
 
 
195
        DWORD dwRet = NO_ERROR;
 
196
    
 
197
    // reset flags
 
198
        BOOL isInteractive = FALSE;
 
199
        isService = FALSE;
 
200
 
 
201
        DWORD ndx;
 
202
 
 
203
        HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pID );
 
204
 
 
205
        // open the token
 
206
        if (!::OpenProcessToken( hProcess, TOKEN_QUERY, &hProcessToken) )
 
207
        {
 
208
                dwRet = ::GetLastError();
 
209
                goto closedown;
 
210
        }
 
211
 
 
212
        // allocate a buffer of default size
 
213
        groupInfo = (PTOKEN_GROUPS)::LocalAlloc(0, groupLength);
 
214
        if (groupInfo == NULL)
 
215
        {
 
216
                dwRet = ::GetLastError();
 
217
                goto closedown;
 
218
        }
 
219
 
 
220
        // try to get the info
 
221
        if (!::GetTokenInformation(hProcessToken, TokenGroups,
 
222
                groupInfo, groupLength, &groupLength))
 
223
        {
 
224
                // if buffer was too small, allocate to proper size, otherwise error
 
225
                if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER)
 
226
                {
 
227
                        dwRet = ::GetLastError();
 
228
                        goto closedown;
 
229
                }
 
230
 
 
231
                ::LocalFree(groupInfo);
 
232
 
 
233
                groupInfo = (PTOKEN_GROUPS)::LocalAlloc(0, groupLength);
 
234
                if (groupInfo == NULL)
 
235
                {
 
236
                        dwRet = ::GetLastError();
 
237
                        goto closedown;
 
238
                }
 
239
 
 
240
                if (!GetTokenInformation(hProcessToken, TokenGroups,
 
241
                        groupInfo, groupLength, &groupLength))
 
242
                {
 
243
                        dwRet = ::GetLastError();
 
244
                        goto closedown;
 
245
                }
 
246
        }
 
247
 
 
248
        // create comparison sids
 
249
        if (!AllocateAndInitializeSid(&siaNt, 1, SECURITY_INTERACTIVE_RID,
 
250
                0, 0, 0, 0, 0, 0, 0, &pInteractiveSid))
 
251
        {
 
252
                dwRet = ::GetLastError();
 
253
                goto closedown;
 
254
        }
 
255
 
 
256
        if (!AllocateAndInitializeSid(&siaNt, 1, SECURITY_SERVICE_RID,
 
257
                0, 0, 0, 0, 0, 0, 0, &pServiceSid))
 
258
        {
 
259
                dwRet = ::GetLastError();
 
260
                goto closedown;
 
261
        }
 
262
 
 
263
        // try to match sids
 
264
        for (ndx = 0; ndx < groupInfo->GroupCount ; ndx += 1)
 
265
        {
 
266
                SID_AND_ATTRIBUTES sanda = groupInfo->Groups[ndx];
 
267
                PSID pSid = sanda.Sid;
 
268
 
 
269
                if (::EqualSid(pSid, pInteractiveSid))
 
270
                {
 
271
                        isInteractive = TRUE;
 
272
                        isService = FALSE;
 
273
                        break;
 
274
                }
 
275
                else if (::EqualSid(pSid, pServiceSid))
 
276
                {
 
277
                        isService = TRUE;
 
278
                        isInteractive = FALSE;
 
279
                        break;
 
280
                }
 
281
        }
 
282
 
 
283
   if ( !( isService || isInteractive ) )
 
284
                isService = TRUE;
 
285
        
 
286
closedown:
 
287
                if ( pServiceSid )
 
288
                        ::FreeSid( pServiceSid );
 
289
 
 
290
                if ( pInteractiveSid )
 
291
                        ::FreeSid( pInteractiveSid );
 
292
 
 
293
                if ( groupInfo )
 
294
                        ::LocalFree( groupInfo );
 
295
 
 
296
                if ( hProcessToken )
 
297
                        ::CloseHandle( hProcessToken );
 
298
 
 
299
                if ( hProcess )
 
300
                        ::CloseHandle( hProcess );
 
301
 
 
302
        return dwRet;
 
303
}