OpenVPN
service.c
Go to the documentation of this file.
1 /*
2  * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
3  * ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
4  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
5  * PARTICULAR PURPOSE.
6  *
7  * Copyright (C) 1993 - 2000. Microsoft Corporation. All rights reserved.
8  * 2013 Heiko Hund <heiko.hund@sophos.com>
9  */
10 
11 #include "service.h"
12 
13 #include <windows.h>
14 #include <stdio.h>
15 #include <process.h>
16 
17 
19 
20 
21 BOOL
22 ReportStatusToSCMgr(SERVICE_STATUS_HANDLE service, SERVICE_STATUS *status)
23 {
24  static DWORD dwCheckPoint = 1;
25  BOOL res = TRUE;
26 
27  if (status->dwCurrentState == SERVICE_START_PENDING)
28  {
29  status->dwControlsAccepted = 0;
30  }
31  else
32  {
33  status->dwControlsAccepted = SERVICE_ACCEPT_STOP;
34  }
35 
36  if (status->dwCurrentState == SERVICE_RUNNING
37  || status->dwCurrentState == SERVICE_STOPPED)
38  {
39  status->dwCheckPoint = 0;
40  }
41  else
42  {
43  status->dwCheckPoint = dwCheckPoint++;
44  }
45 
46  /* Report the status of the service to the service control manager. */
47  res = SetServiceStatus(service, status);
48  if (!res)
49  {
50  MsgToEventLog(MSG_FLAGS_ERROR, TEXT("SetServiceStatus"));
51  }
52 
53  return res;
54 }
55 
56 static int
58 {
59  SC_HANDLE service;
60  SC_HANDLE svc_ctl_mgr;
61  TCHAR path[512];
62  int i, ret = _service_max;
63 
64  if (GetModuleFileName(NULL, path + 1, _countof(path) - 2) == 0)
65  {
66  wprintf(TEXT("Unable to install service - %ls\n"), GetLastErrorText());
67  return 1;
68  }
69 
70  path[0] = TEXT('\"');
71  wcscat_s(path, _countof(path), TEXT("\""));
72 
73  svc_ctl_mgr = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE);
74  if (svc_ctl_mgr == NULL)
75  {
76  wprintf(TEXT("OpenSCManager failed - %ls\n"), GetLastErrorText());
77  return 1;
78  }
79 
80  for (i = 0; i < _service_max; i++)
81  {
82  service = CreateService(svc_ctl_mgr,
83  openvpn_service[i].name,
84  openvpn_service[i].display_name,
85  SERVICE_QUERY_STATUS,
86  SERVICE_WIN32_SHARE_PROCESS,
87  openvpn_service[i].start_type,
88  SERVICE_ERROR_NORMAL,
89  path, NULL, NULL,
90  openvpn_service[i].dependencies,
91  NULL, NULL);
92  if (service)
93  {
94  wprintf(TEXT("%ls installed.\n"), openvpn_service[i].display_name);
95  CloseServiceHandle(service);
96  --ret;
97  }
98  else
99  {
100  wprintf(TEXT("CreateService failed - %ls\n"), GetLastErrorText());
101  }
102  }
103 
104  CloseServiceHandle(svc_ctl_mgr);
105  return ret;
106 }
107 
108 
109 static int
111 {
112  int ret = 1;
113  SC_HANDLE svc_ctl_mgr;
114  SC_HANDLE service;
115 
116  svc_ctl_mgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
117  if (svc_ctl_mgr == NULL)
118  {
119  wprintf(TEXT("OpenSCManager failed - %ls\n"), GetLastErrorText());
120  return 1;
121  }
122 
123  service = OpenService(svc_ctl_mgr, openvpn_service[type].name, SERVICE_ALL_ACCESS);
124  if (service)
125  {
126  if (StartService(service, 0, NULL))
127  {
128  wprintf(TEXT("Service Started\n"));
129  ret = 0;
130  }
131  else
132  {
133  wprintf(TEXT("StartService failed - %ls\n"), GetLastErrorText());
134  }
135 
136  CloseServiceHandle(service);
137  }
138  else
139  {
140  wprintf(TEXT("OpenService failed - %ls\n"), GetLastErrorText());
141  }
142 
143  CloseServiceHandle(svc_ctl_mgr);
144  return ret;
145 }
146 
147 
148 static int
150 {
151  SC_HANDLE service;
152  SC_HANDLE svc_ctl_mgr;
153  SERVICE_STATUS status;
154  int i, ret = _service_max;
155 
156  svc_ctl_mgr = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
157  if (svc_ctl_mgr == NULL)
158  {
159  wprintf(TEXT("OpenSCManager failed - %ls\n"), GetLastErrorText());
160  return 1;
161  }
162 
163  for (i = 0; i < _service_max; i++)
164  {
165  openvpn_service_t *ovpn_svc = &openvpn_service[i];
166  service = OpenService(svc_ctl_mgr, ovpn_svc->name,
167  DELETE | SERVICE_STOP | SERVICE_QUERY_STATUS);
168  if (service == NULL)
169  {
170  wprintf(TEXT("OpenService failed - %ls\n"), GetLastErrorText());
171  goto out;
172  }
173 
174  /* try to stop the service */
175  if (ControlService(service, SERVICE_CONTROL_STOP, &status))
176  {
177  wprintf(TEXT("Stopping %ls."), ovpn_svc->display_name);
178  Sleep(1000);
179 
180  while (QueryServiceStatus(service, &status))
181  {
182  if (status.dwCurrentState == SERVICE_STOP_PENDING)
183  {
184  wprintf(TEXT("."));
185  Sleep(1000);
186  }
187  else
188  {
189  break;
190  }
191  }
192 
193  if (status.dwCurrentState == SERVICE_STOPPED)
194  {
195  wprintf(TEXT("\n%ls stopped.\n"), ovpn_svc->display_name);
196  }
197  else
198  {
199  wprintf(TEXT("\n%ls failed to stop.\n"), ovpn_svc->display_name);
200  }
201  }
202 
203  /* now remove the service */
204  if (DeleteService(service))
205  {
206  wprintf(TEXT("%ls removed.\n"), ovpn_svc->display_name);
207  --ret;
208  }
209  else
210  {
211  wprintf(TEXT("DeleteService failed - %ls\n"), GetLastErrorText());
212  }
213 
214  CloseServiceHandle(service);
215  }
216 
217 out:
218  CloseServiceHandle(svc_ctl_mgr);
219  return ret;
220 }
221 
222 
223 int
224 _tmain(int argc, TCHAR *argv[])
225 {
226  /*
227  * Interactive service (as a SERVICE_WIN32_SHARE_PROCESS)
228  * This is the default.
229  */
230  const SERVICE_TABLE_ENTRY dispatchTable_shared[] = {
232  { NULL, NULL }
233  };
234 
235  /* Interactive service only (as a SERVICE_WIN32_OWN_PROCESS) */
236  const SERVICE_TABLE_ENTRY dispatchTable_interactive[] = {
237  { TEXT(""), ServiceStartInteractiveOwn },
238  { NULL, NULL }
239  };
240 
241  const SERVICE_TABLE_ENTRY *dispatchTable = dispatchTable_shared;
242 
243  openvpn_service[interactive] = interactive_service;
244 
245  for (int i = 1; i < argc; i++)
246  {
247  if (*argv[i] == TEXT('-') || *argv[i] == TEXT('/'))
248  {
249  if (_wcsicmp(TEXT("install"), argv[i] + 1) == 0)
250  {
251  return CmdInstallServices();
252  }
253  else if (_wcsicmp(TEXT("remove"), argv[i] + 1) == 0)
254  {
255  return CmdRemoveServices();
256  }
257  else if (_wcsicmp(TEXT("start"), argv[i] + 1) == 0)
258  {
260  }
261  else if (argc > i + 2 && _wcsicmp(TEXT("instance"), argv[i] + 1) == 0)
262  {
263  if (_wcsicmp(TEXT("interactive"), argv[i+1]) == 0)
264  {
265  dispatchTable = dispatchTable_interactive;
266  service_instance = argv[i + 2];
267  i += 2;
268  }
269  else
270  {
271  MsgToEventLog(M_ERR, L"Invalid argument to -instance <%s>. Service not started.", argv[i+1]);
272  return 1;
273  }
274  }
275  else
276  {
277  wprintf(TEXT("%ls -install to install the interactive service\n"), APPNAME);
278  wprintf(TEXT("%ls -start [name] to start the service (name = \"interactive\" is optional)\n"), APPNAME);
279  wprintf(TEXT("%ls -remove to remove the service\n"), APPNAME);
280 
281  wprintf(TEXT("\nService run-time parameters:\n"));
282  wprintf(TEXT("-instance interactive <id>\n")
283  TEXT(" Runs the service as an alternate instance.\n")
284  TEXT(" The service settings will be loaded from\n")
285  TEXT(" HKLM\\Software\\" PACKAGE_NAME "<id> registry key, and the service will accept\n")
286  TEXT(" requests on \\\\.\\pipe\\" PACKAGE "<id>\\service named pipe.\n"));
287 
288  return 0;
289  }
290  }
291  }
292 
293  /* If it doesn't match any of the above parameters
294  * the service control manager may be starting the service
295  * so we must call StartServiceCtrlDispatcher
296  */
297  wprintf(TEXT("\nStartServiceCtrlDispatcher being called.\n"));
298  wprintf(TEXT("This may take several seconds. Please wait.\n"));
299 
300  if (!StartServiceCtrlDispatcher(dispatchTable))
301  {
302  MsgToEventLog(MSG_FLAGS_ERROR, TEXT("StartServiceCtrlDispatcher failed."));
303  }
304 
305  return 0;
306 }
DWORD MsgToEventLog(DWORD flags, LPCTSTR format,...)
Definition: common.c:245
LPCTSTR service_instance
Definition: common.c:27
#define MSG_FLAGS_ERROR
Definition: service.h:49
openvpn_service_t openvpn_service[_service_max]
Definition: service.c:18
TCHAR * name
Definition: service.h:62
openvpn_service_t interactive_service
Definition: interactive.c:64
static int CmdStartService(openvpn_service_type type)
Definition: service.c:110
#define PACKAGE_NAME
Definition: config.h:730
static int CmdRemoveServices()
Definition: service.c:149
VOID WINAPI ServiceStartInteractive(DWORD dwArgc, LPTSTR *lpszArgv)
Definition: interactive.c:2080
static SERVICE_STATUS_HANDLE service
Definition: interactive.c:55
LPCTSTR GetLastErrorText()
Definition: common.c:214
int _tmain(int argc, TCHAR *argv[])
Definition: service.c:224
static int CmdInstallServices()
Definition: service.c:57
openvpn_service_type
Definition: service.h:55
#define M_ERR
Definition: error.h:114
VOID WINAPI ServiceStartInteractiveOwn(DWORD dwArgc, LPTSTR *lpszArgv)
Definition: interactive.c:2072
TCHAR * display_name
Definition: service.h:63
#define PACKAGE
Definition: config.h:724
Definition: argv.h:35
static SERVICE_STATUS status
Definition: interactive.c:56
#define APPNAME
Definition: service.h:43
BOOL ReportStatusToSCMgr(SERVICE_STATUS_HANDLE service, SERVICE_STATUS *status)
Definition: service.c:22