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, 510) == 0)
65  {
66  _tprintf(TEXT("Unable to install service - %s\n"), GetLastErrorText());
67  return 1;
68  }
69 
70  path[0] = TEXT('\"');
71  _tcscat(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  _tprintf(TEXT("OpenSCManager failed - %s\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  _tprintf(TEXT("%s installed.\n"), openvpn_service[i].display_name);
95  CloseServiceHandle(service);
96  --ret;
97  }
98  else
99  {
100  _tprintf(TEXT("CreateService failed - %s\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  _tprintf(TEXT("OpenSCManager failed - %s\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  _tprintf(TEXT("Service Started\n"));
129  ret = 0;
130  }
131  else
132  {
133  _tprintf(TEXT("StartService failed - %s\n"), GetLastErrorText());
134  }
135 
136  CloseServiceHandle(service);
137  }
138  else
139  {
140  _tprintf(TEXT("OpenService failed - %s\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  _tprintf(TEXT("OpenSCManager failed - %s\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  _tprintf(TEXT("OpenService failed - %s\n"), GetLastErrorText());
171  goto out;
172  }
173 
174  /* try to stop the service */
175  if (ControlService(service, SERVICE_CONTROL_STOP, &status))
176  {
177  _tprintf(TEXT("Stopping %s."), ovpn_svc->display_name);
178  Sleep(1000);
179 
180  while (QueryServiceStatus(service, &status))
181  {
182  if (status.dwCurrentState == SERVICE_STOP_PENDING)
183  {
184  _tprintf(TEXT("."));
185  Sleep(1000);
186  }
187  else
188  {
189  break;
190  }
191  }
192 
193  if (status.dwCurrentState == SERVICE_STOPPED)
194  {
195  _tprintf(TEXT("\n%s stopped.\n"), ovpn_svc->display_name);
196  }
197  else
198  {
199  _tprintf(TEXT("\n%s failed to stop.\n"), ovpn_svc->display_name);
200  }
201  }
202 
203  /* now remove the service */
204  if (DeleteService(service))
205  {
206  _tprintf(TEXT("%s removed.\n"), ovpn_svc->display_name);
207  --ret;
208  }
209  else
210  {
211  _tprintf(TEXT("DeleteService failed - %s\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  SERVICE_TABLE_ENTRY dispatchTable[] = {
229  { NULL, NULL }
230  };
231 
232  openvpn_service[0] = automatic_service;
233  openvpn_service[1] = interactive_service;
234 
235  if (argc > 1 && (*argv[1] == TEXT('-') || *argv[1] == TEXT('/')))
236  {
237  if (_tcsicmp(TEXT("install"), argv[1] + 1) == 0)
238  {
239  return CmdInstallServices();
240  }
241  else if (_tcsicmp(TEXT("remove"), argv[1] + 1) == 0)
242  {
243  return CmdRemoveServices();
244  }
245  else if (_tcsicmp(TEXT("start"), argv[1] + 1) == 0)
246  {
247  BOOL is_auto = argc < 3 || _tcsicmp(TEXT("interactive"), argv[2]) != 0;
248  return CmdStartService(is_auto ? automatic : interactive);
249  }
250  else
251  {
252  goto dispatch;
253  }
254 
255  return 0;
256  }
257 
258  /* If it doesn't match any of the above parameters
259  * the service control manager may be starting the service
260  * so we must call StartServiceCtrlDispatcher
261  */
262 dispatch:
263  _tprintf(TEXT("%s -install to install the services\n"), APPNAME);
264  _tprintf(TEXT("%s -start <name> to start a service (\"automatic\" or \"interactive\")\n"), APPNAME);
265  _tprintf(TEXT("%s -remove to remove the services\n"), APPNAME);
266  _tprintf(TEXT("\nStartServiceCtrlDispatcher being called.\n"));
267  _tprintf(TEXT("This may take several seconds. Please wait.\n"));
268 
269  if (!StartServiceCtrlDispatcher(dispatchTable))
270  {
271  MsgToEventLog(MSG_FLAGS_ERROR, TEXT("StartServiceCtrlDispatcher failed."));
272  }
273 
274  return 0;
275 }
VOID WINAPI ServiceStartAutomatic(DWORD dwArgc, LPTSTR *lpszArgv)
Definition: automatic.c:215
DWORD MsgToEventLog(DWORD flags, LPCTSTR format,...)
Definition: common.c:217
openvpn_service_t automatic_service
Definition: automatic.c:49
#define MSG_FLAGS_ERROR
Definition: service.h:43
openvpn_service_t openvpn_service[_service_max]
Definition: service.c:18
TCHAR * name
Definition: service.h:57
openvpn_service_t interactive_service
Definition: interactive.c:63
static int CmdStartService(openvpn_service_type type)
Definition: service.c:110
static int CmdRemoveServices()
Definition: service.c:149
VOID WINAPI ServiceStartInteractive(DWORD dwArgc, LPTSTR *lpszArgv)
Definition: interactive.c:1789
static SERVICE_STATUS status
Definition: automatic.c:47
static SERVICE_STATUS_HANDLE service
Definition: automatic.c:46
LPCTSTR GetLastErrorText()
Definition: common.c:188
int _tmain(int argc, TCHAR *argv[])
Definition: service.c:224
static int CmdInstallServices()
Definition: service.c:57
openvpn_service_type
Definition: service.h:49
TCHAR * display_name
Definition: service.h:58
Definition: argv.h:35
#define APPNAME
Definition: service.h:37
BOOL ReportStatusToSCMgr(SERVICE_STATUS_HANDLE service, SERVICE_STATUS *status)
Definition: service.c:22