• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/openvpn/src/openvpnserv/
1/*---------------------------------------------------------------------------
2THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
3ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
4TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
5PARTICULAR PURPOSE.
6
7Copyright (C) 1993 - 2000.  Microsoft Corporation.  All rights reserved.
8
9MODULE:   service.c
10
11PURPOSE:  Implements functions required by all Windows NT services
12
13FUNCTIONS:
14  main(int argc, char **argv);
15  service_ctrl(DWORD dwCtrlCode);
16  service_main(DWORD dwArgc, LPTSTR *lpszArgv);
17  CmdInstallService();
18  CmdRemoveService();
19  CmdStartService();
20  CmdDebugService(int argc, char **argv);
21  ControlHandler ( DWORD dwCtrlType );
22  GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize );
23
24---------------------------------------------------------------------------*/
25
26#ifdef HAVE_CONFIG_H
27#include "config.h"
28#elif defined(_MSC_VER)
29#include "config-msvc.h"
30#endif
31#include <windows.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <process.h>
35#include <tchar.h>
36
37#include "service.h"
38
39// internal variables
40SERVICE_STATUS          ssStatus;       // current status of the service
41SERVICE_STATUS_HANDLE   sshStatusHandle;
42DWORD                   dwErr = 0;
43BOOL                    bDebug = FALSE;
44TCHAR                   szErr[256];
45
46// internal function prototypes
47VOID WINAPI service_ctrl(DWORD dwCtrlCode);
48VOID WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv);
49int CmdInstallService();
50int CmdRemoveService();
51int CmdStartService();
52VOID CmdDebugService(int argc, char **argv);
53BOOL WINAPI ControlHandler ( DWORD dwCtrlType );
54LPTSTR GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize );
55
56//
57//  FUNCTION: main
58//
59//  PURPOSE: entrypoint for service
60//
61//  PARAMETERS:
62//    argc - number of command line arguments
63//    argv - array of command line arguments
64//
65//  RETURN VALUE:
66//    none
67//
68//  COMMENTS:
69//    main() either performs the command line task, or
70//    call StartServiceCtrlDispatcher to register the
71//    main service thread.  When the this call returns,
72//    the service has stopped, so exit.
73//
74int __cdecl main(int argc, char **argv)
75{
76   SERVICE_TABLE_ENTRY dispatchTable[] =
77   {
78      { TEXT(SZSERVICENAME), (LPSERVICE_MAIN_FUNCTION)service_main},
79      { NULL, NULL}
80   };
81
82   if ( (argc > 1) &&
83        ((*argv[1] == '-') || (*argv[1] == '/')) )
84   {
85      if ( _stricmp( "install", argv[1]+1 ) == 0 )
86      {
87         return CmdInstallService();
88      }
89      else if ( _stricmp( "remove", argv[1]+1 ) == 0 )
90      {
91         return CmdRemoveService();
92      }
93	  else if ( _stricmp( "start", argv[1]+1 ) == 0)
94	  {
95		  return CmdStartService();
96      }
97      else if ( _stricmp( "debug", argv[1]+1 ) == 0 )
98      {
99         bDebug = TRUE;
100         CmdDebugService(argc, argv);
101      }
102      else
103      {
104         goto dispatch;
105      }
106      return 0;
107   }
108
109   // if it doesn't match any of the above parameters
110   // the service control manager may be starting the service
111   // so we must call StartServiceCtrlDispatcher
112   dispatch:
113   // this is just to be friendly
114   printf( "%s -install          to install the service\n", SZAPPNAME );
115   printf( "%s -start			 to start the service\n", SZAPPNAME );
116   printf( "%s -remove           to remove the service\n", SZAPPNAME );
117   printf( "%s -debug <params>   to run as a console app for debugging\n", SZAPPNAME );
118   printf( "\nStartServiceCtrlDispatcher being called.\n" );
119   printf( "This may take several seconds.  Please wait.\n" );
120
121   if (!StartServiceCtrlDispatcher(dispatchTable))
122      AddToMessageLog(MSG_FLAGS_ERROR, TEXT("StartServiceCtrlDispatcher failed."));
123
124   return 0;
125}
126
127
128
129//
130//  FUNCTION: service_main
131//
132//  PURPOSE: To perform actual initialization of the service
133//
134//  PARAMETERS:
135//    dwArgc   - number of command line arguments
136//    lpszArgv - array of command line arguments
137//
138//  RETURN VALUE:
139//    none
140//
141//  COMMENTS:
142//    This routine performs the service initialization and then calls
143//    the user defined ServiceStart() routine to perform majority
144//    of the work.
145//
146void WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv)
147{
148
149   // register our service control handler:
150   //
151   sshStatusHandle = RegisterServiceCtrlHandler( TEXT(SZSERVICENAME), service_ctrl);
152
153   if (!sshStatusHandle)
154      goto cleanup;
155
156   // SERVICE_STATUS members that don't change in example
157   //
158   ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
159   ssStatus.dwServiceSpecificExitCode = 0;
160
161
162   // report the status to the service control manager.
163   //
164   if (!ReportStatusToSCMgr(
165                           SERVICE_START_PENDING, // service state
166                           NO_ERROR,              // exit code
167                           3000))                 // wait hint
168      goto cleanup;
169
170
171   ServiceStart( dwArgc, lpszArgv );
172
173   cleanup:
174
175   // try to report the stopped status to the service control manager.
176   //
177   if (sshStatusHandle)
178      (VOID)ReportStatusToSCMgr(
179                               SERVICE_STOPPED,
180                               dwErr,
181                               0);
182
183   return;
184}
185
186
187
188//
189//  FUNCTION: service_ctrl
190//
191//  PURPOSE: This function is called by the SCM whenever
192//           ControlService() is called on this service.
193//
194//  PARAMETERS:
195//    dwCtrlCode - type of control requested
196//
197//  RETURN VALUE:
198//    none
199//
200//  COMMENTS:
201//
202VOID WINAPI service_ctrl(DWORD dwCtrlCode)
203{
204   // Handle the requested control code.
205   //
206   switch (dwCtrlCode)
207   {
208   // Stop the service.
209   //
210   // SERVICE_STOP_PENDING should be reported before
211   // setting the Stop Event - hServerStopEvent - in
212   // ServiceStop().  This avoids a race condition
213   // which may result in a 1053 - The Service did not respond...
214   // error.
215   case SERVICE_CONTROL_STOP:
216      ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 0);
217      ServiceStop();
218      return;
219
220      // Update the service status.
221      //
222   case SERVICE_CONTROL_INTERROGATE:
223      break;
224
225      // invalid control code
226      //
227   default:
228      break;
229
230   }
231
232   ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0);
233}
234
235
236
237//
238//  FUNCTION: ReportStatusToSCMgr()
239//
240//  PURPOSE: Sets the current status of the service and
241//           reports it to the Service Control Manager
242//
243//  PARAMETERS:
244//    dwCurrentState - the state of the service
245//    dwWin32ExitCode - error code to report
246//    dwWaitHint - worst case estimate to next checkpoint
247//
248//  RETURN VALUE:
249//    TRUE  - success
250//    FALSE - failure
251//
252//  COMMENTS:
253//
254BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
255                         DWORD dwWin32ExitCode,
256                         DWORD dwWaitHint)
257{
258   static DWORD dwCheckPoint = 1;
259   BOOL fResult = TRUE;
260
261
262   if ( !bDebug ) // when debugging we don't report to the SCM
263   {
264      if (dwCurrentState == SERVICE_START_PENDING)
265         ssStatus.dwControlsAccepted = 0;
266      else
267         ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
268
269      ssStatus.dwCurrentState = dwCurrentState;
270      ssStatus.dwWin32ExitCode = dwWin32ExitCode;
271      ssStatus.dwWaitHint = dwWaitHint;
272
273      if ( ( dwCurrentState == SERVICE_RUNNING ) ||
274           ( dwCurrentState == SERVICE_STOPPED ) )
275         ssStatus.dwCheckPoint = 0;
276      else
277         ssStatus.dwCheckPoint = dwCheckPoint++;
278
279
280      // Report the status of the service to the service control manager.
281      //
282      if (!(fResult = SetServiceStatus( sshStatusHandle, &ssStatus)))
283      {
284         AddToMessageLog(MSG_FLAGS_ERROR, TEXT("SetServiceStatus"));
285      }
286   }
287   return fResult;
288}
289
290
291
292//
293//  FUNCTION: AddToMessageLog(LPTSTR lpszMsg)
294//
295//  PURPOSE: Allows any thread to log an error message
296//
297//  PARAMETERS:
298//    lpszMsg - text for message
299//
300//  RETURN VALUE:
301//    none
302//
303//  COMMENTS:
304//
305void AddToMessageLog(DWORD flags, LPTSTR lpszMsg)
306{
307   TCHAR szMsg [(sizeof(SZSERVICENAME) / sizeof(TCHAR)) + 100 ];
308   HANDLE  hEventSource;
309   LPCSTR  lpszStrings[2];
310
311   if ( !bDebug )
312   {
313     if (flags & MSG_FLAGS_SYS_CODE)
314      dwErr = GetLastError();
315     else
316       dwErr = 0;
317
318      // Use event logging to log the error.
319      //
320      hEventSource = RegisterEventSource(NULL, TEXT(SZSERVICENAME));
321
322      _stprintf(szMsg, TEXT("%s error: %d"), TEXT(SZSERVICENAME), (int)dwErr);
323      lpszStrings[0] = szMsg;
324      lpszStrings[1] = lpszMsg;
325
326      if (hEventSource != NULL)
327      {
328         ReportEvent(hEventSource, // handle of event source
329		     // event type
330                     (flags & MSG_FLAGS_ERROR)
331		       ? EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE,
332                     0,                    // event category
333                     0,                    // event ID
334                     NULL,                 // current user's SID
335                     2,                    // strings in lpszStrings
336                     0,                    // no bytes of raw data
337                     lpszStrings,          // array of error strings
338                     NULL);                // no raw data
339
340         (VOID) DeregisterEventSource(hEventSource);
341      }
342   }
343}
344
345void ResetError (void)
346{
347  dwErr = 0;
348}
349
350///////////////////////////////////////////////////////////////////
351//
352//  The following code handles service installation and removal
353//
354
355
356//
357//  FUNCTION: CmdInstallService()
358//
359//  PURPOSE: Installs the service
360//
361//  PARAMETERS:
362//    none
363//
364//  RETURN VALUE:
365//    0 if success
366//
367//  COMMENTS:
368//
369int CmdInstallService()
370{
371   SC_HANDLE   schService;
372   SC_HANDLE   schSCManager;
373
374   TCHAR szPath[512];
375
376   int ret = 0;
377
378   if ( GetModuleFileName( NULL, szPath+1, 510 ) == 0 )
379   {
380      _tprintf(TEXT("Unable to install %s - %s\n"), TEXT(SZSERVICEDISPLAYNAME), GetLastErrorText(szErr, 256));
381      return 1;
382   }
383   szPath[0] = '\"';
384   strcat(szPath, "\"");
385
386   schSCManager = OpenSCManager(
387                               NULL,                   // machine (NULL == local)
388                               NULL,                   // database (NULL == default)
389                               SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE  // access required
390                               );
391   if ( schSCManager )
392   {
393      schService = CreateService(
394                                schSCManager,               // SCManager database
395                                TEXT(SZSERVICENAME),        // name of service
396                                TEXT(SZSERVICEDISPLAYNAME), // name to display
397                                SERVICE_QUERY_STATUS,         // desired access
398                                SERVICE_WIN32_OWN_PROCESS,  // service type
399				SERVICE_DEMAND_START,        // start type -- alternative: SERVICE_AUTO_START
400                                SERVICE_ERROR_NORMAL,       // error control type
401                                szPath,                     // service's binary
402                                NULL,                       // no load ordering group
403                                NULL,                       // no tag identifier
404                                TEXT(SZDEPENDENCIES),       // dependencies
405                                NULL,                       // LocalSystem account
406                                NULL);                      // no password
407
408      if ( schService )
409      {
410         _tprintf(TEXT("%s installed.\n"), TEXT(SZSERVICEDISPLAYNAME) );
411         CloseServiceHandle(schService);
412      }
413      else
414      {
415         _tprintf(TEXT("CreateService failed - %s\n"), GetLastErrorText(szErr, 256));
416	 ret = 1;
417      }
418
419      CloseServiceHandle(schSCManager);
420   }
421   else
422     {
423      _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
424       ret = 1;
425     }
426   return ret;
427}
428
429//
430//  FUNCTION: CmdStartService()
431//
432//  PURPOSE: Start the service
433//
434//  PARAMETERS:
435//    none
436//
437//  RETURN VALUE:
438//    0 if success
439//
440//  COMMENTS:
441
442int CmdStartService()
443{
444  int ret = 0;
445
446  SC_HANDLE schSCManager;
447  SC_HANDLE schService;
448
449
450    // Open a handle to the SC Manager database.
451    schSCManager = OpenSCManager(
452       NULL,                    // local machine
453       NULL,                    // ServicesActive database
454       SC_MANAGER_ALL_ACCESS);  // full access rights
455
456    if (NULL == schSCManager) {
457       _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
458       ret = 1;
459    }
460
461    schService = OpenService(
462        schSCManager,          // SCM database
463        SZSERVICENAME,         // service name
464        SERVICE_ALL_ACCESS);
465
466    if (schService == NULL) {
467      _tprintf(TEXT("OpenService failed - %s\n"), GetLastErrorText(szErr,256));
468       ret = 1;
469    }
470
471    if (!StartService(
472            schService,  // handle to service
473            0,           // number of arguments
474            NULL) )      // no arguments
475    {
476      _tprintf(TEXT("StartService failed - %s\n"), GetLastErrorText(szErr,256));
477       ret = 1;
478    }
479    else
480	{
481		_tprintf(TEXT("Service Started\n"));
482       ret = 0;
483	}
484    CloseServiceHandle(schService);
485    CloseServiceHandle(schSCManager);
486    return ret;
487}
488
489//
490//  FUNCTION: CmdRemoveService()
491//
492//  PURPOSE: Stops and removes the service
493//
494//  PARAMETERS:
495//    none
496//
497//  RETURN VALUE:
498//    0 if success
499//
500//  COMMENTS:
501//
502int CmdRemoveService()
503{
504   SC_HANDLE   schService;
505   SC_HANDLE   schSCManager;
506
507   int ret = 0;
508
509   schSCManager = OpenSCManager(
510                               NULL,                   // machine (NULL == local)
511                               NULL,                   // database (NULL == default)
512                               SC_MANAGER_CONNECT   // access required
513                               );
514   if ( schSCManager )
515   {
516      schService = OpenService(schSCManager, TEXT(SZSERVICENAME), DELETE | SERVICE_STOP | SERVICE_QUERY_STATUS);
517
518      if (schService)
519      {
520         // try to stop the service
521         if ( ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus ) )
522         {
523            _tprintf(TEXT("Stopping %s."), TEXT(SZSERVICEDISPLAYNAME));
524            Sleep( 1000 );
525
526            while ( QueryServiceStatus( schService, &ssStatus ) )
527            {
528               if ( ssStatus.dwCurrentState == SERVICE_STOP_PENDING )
529               {
530                  _tprintf(TEXT("."));
531                  Sleep( 1000 );
532               }
533               else
534                  break;
535            }
536
537            if ( ssStatus.dwCurrentState == SERVICE_STOPPED )
538               _tprintf(TEXT("\n%s stopped.\n"), TEXT(SZSERVICEDISPLAYNAME) );
539            else
540	      {
541               _tprintf(TEXT("\n%s failed to stop.\n"), TEXT(SZSERVICEDISPLAYNAME) );
542		ret = 1;
543	      }
544
545         }
546
547         // now remove the service
548         if ( DeleteService(schService) )
549            _tprintf(TEXT("%s removed.\n"), TEXT(SZSERVICEDISPLAYNAME) );
550         else
551	   {
552            _tprintf(TEXT("DeleteService failed - %s\n"), GetLastErrorText(szErr,256));
553	     ret = 1;
554	   }
555
556
557         CloseServiceHandle(schService);
558      }
559      else
560	{
561         _tprintf(TEXT("OpenService failed - %s\n"), GetLastErrorText(szErr,256));
562	  ret = 1;
563	}
564
565      CloseServiceHandle(schSCManager);
566   }
567   else
568     {
569      _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
570       ret = 1;
571     }
572   return ret;
573}
574
575
576
577
578///////////////////////////////////////////////////////////////////
579//
580//  The following code is for running the service as a console app
581//
582
583
584//
585//  FUNCTION: CmdDebugService(int argc, char ** argv)
586//
587//  PURPOSE: Runs the service as a console application
588//
589//  PARAMETERS:
590//    argc - number of command line arguments
591//    argv - array of command line arguments
592//
593//  RETURN VALUE:
594//    none
595//
596//  COMMENTS:
597//
598void CmdDebugService(int argc, char ** argv)
599{
600   DWORD dwArgc;
601   LPTSTR *lpszArgv;
602
603#ifdef UNICODE
604   lpszArgv = CommandLineToArgvW(GetCommandLineW(), &(dwArgc) );
605   if (NULL == lpszArgv)
606   {
607       // CommandLineToArvW failed!!
608       _tprintf(TEXT("CmdDebugService CommandLineToArgvW returned NULL\n"));
609       return;
610   }
611#else
612   dwArgc   = (DWORD) argc;
613   lpszArgv = argv;
614#endif
615
616   _tprintf(TEXT("Debugging %s.\n"), TEXT(SZSERVICEDISPLAYNAME));
617
618   SetConsoleCtrlHandler( ControlHandler, TRUE );
619
620   ServiceStart( dwArgc, lpszArgv );
621
622#ifdef UNICODE
623// Must free memory allocated for arguments
624
625   GlobalFree(lpszArgv);
626#endif // UNICODE
627
628}
629
630
631//
632//  FUNCTION: ControlHandler ( DWORD dwCtrlType )
633//
634//  PURPOSE: Handled console control events
635//
636//  PARAMETERS:
637//    dwCtrlType - type of control event
638//
639//  RETURN VALUE:
640//    True - handled
641//    False - unhandled
642//
643//  COMMENTS:
644//
645BOOL WINAPI ControlHandler ( DWORD dwCtrlType )
646{
647   switch ( dwCtrlType )
648   {
649   case CTRL_BREAK_EVENT:  // use Ctrl+C or Ctrl+Break to simulate
650   case CTRL_C_EVENT:      // SERVICE_CONTROL_STOP in debug mode
651      _tprintf(TEXT("Stopping %s.\n"), TEXT(SZSERVICEDISPLAYNAME));
652      ServiceStop();
653      return TRUE;
654      break;
655
656   }
657   return FALSE;
658}
659
660//
661//  FUNCTION: GetLastErrorText
662//
663//  PURPOSE: copies error message text to string
664//
665//  PARAMETERS:
666//    lpszBuf - destination buffer
667//    dwSize - size of buffer
668//
669//  RETURN VALUE:
670//    destination buffer
671//
672//  COMMENTS:
673//
674LPTSTR GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize )
675{
676   DWORD dwRet;
677   LPTSTR lpszTemp = NULL;
678
679   dwRet = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY,
680                          NULL,
681                          GetLastError(),
682                          LANG_NEUTRAL,
683                          (LPTSTR)&lpszTemp,
684                          0,
685                          NULL );
686
687   // supplied buffer is not long enough
688   if ( !dwRet || ( (long)dwSize < (long)dwRet+14 ) )
689      lpszBuf[0] = TEXT('\0');
690   else
691   {
692      lpszTemp[lstrlen(lpszTemp)-2] = TEXT('\0');  //remove cr and newline character
693      _stprintf( lpszBuf, TEXT("%s (0x%x)"), lpszTemp, (int)GetLastError() );
694   }
695
696   if ( lpszTemp )
697      LocalFree((HLOCAL) lpszTemp );
698
699   return lpszBuf;
700}
701