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
21BOOL
22ReportStatusToSCMgr(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
56static 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
109static 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
148static 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
217out:
218 CloseServiceHandle(svc_ctl_mgr);
219 return ret;
220}
221
222
223int
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
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\\") TEXT(PACKAGE_NAME) TEXT("<id> registry key, and the service will accept\n")
286 TEXT(" requests on \\\\.\\pipe\\") TEXT(PACKAGE) TEXT("<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}
LPCTSTR GetLastErrorText(void)
Definition common.c:184
DWORD MsgToEventLog(DWORD flags, LPCTSTR format,...)
Definition common.c:215
LPCTSTR service_instance
Definition common.c:27
static SERVICE_STATUS status
Definition interactive.c:53
openvpn_service_t interactive_service
Definition interactive.c:61
VOID WINAPI ServiceStartInteractiveOwn(DWORD dwArgc, LPTSTR *lpszArgv)
VOID WINAPI ServiceStartInteractive(DWORD dwArgc, LPTSTR *lpszArgv)
static SERVICE_STATUS_HANDLE service
Definition interactive.c:52
#define M_ERR
Definition error.h:105
static int CmdStartService(openvpn_service_type type)
Definition service.c:110
static int CmdInstallServices(void)
Definition service.c:57
static int CmdRemoveServices(void)
Definition service.c:149
BOOL ReportStatusToSCMgr(SERVICE_STATUS_HANDLE service, SERVICE_STATUS *status)
Definition service.c:22
int _tmain(int argc, TCHAR *argv[])
Definition service.c:224
openvpn_service_t openvpn_service[_service_max]
Definition service.c:18
#define APPNAME
Definition service.h:42
#define MSG_FLAGS_ERROR
Definition service.h:48
openvpn_service_type
Definition service.h:54
@ _service_max
Definition service.h:56
@ interactive
Definition service.h:55
Definition argv.h:35
TCHAR * display_name
Definition service.h:62