Browse code

Remove automatic service

This has been replaced by openvpnserv2 since 2.4.0 and we have
stopped setting up this service in the installer since 2.5.0.

Get rid of the unused code. The mechanics of supporting multiple
services with the same executable is retained for possible future use.

For backwards compatibility, the command line option -instance
is unchanged as "-instance <name> id" although <name>="interactive"
is the only supported value now.

Signed-off-by: Selva Nair <selva.nair@gmail.com>
Acked-by: Lev Stipakov <lstipakov@gmail.com>
Message-Id: <1616991798-7179-1-git-send-email-selva.nair@gmail.com>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg21890.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>

Selva Nair authored on 2021/03/29 13:23:18
Showing 6 changed files
... ...
@@ -31,7 +31,6 @@ endif
31 31
 
32 32
 openvpnserv_SOURCES = \
33 33
         common.c \
34
-	automatic.c \
35 34
 	interactive.c \
36 35
 	service.c service.h \
37 36
 	validate.c validate.h \
38 37
deleted file mode 100644
... ...
@@ -1,434 +0,0 @@
1
-/*
2
- *  OpenVPN -- An application to securely tunnel IP networks
3
- *             over a single TCP/UDP port, with support for SSL/TLS-based
4
- *             session authentication and key exchange,
5
- *             packet encryption, packet authentication, and
6
- *             packet compression.
7
- *
8
- *  Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
9
- *
10
- *  This program is free software; you can redistribute it and/or modify
11
- *  it under the terms of the GNU General Public License version 2
12
- *  as published by the Free Software Foundation.
13
- *
14
- *  This program is distributed in the hope that it will be useful,
15
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
- *  GNU General Public License for more details.
18
- *
19
- *  You should have received a copy of the GNU General Public License along
20
- *  with this program; if not, write to the Free Software Foundation, Inc.,
21
- *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
- */
23
-
24
-/*
25
- * This program allows one or more OpenVPN processes to be started
26
- * as a service.  To build, you must get the service sample from the
27
- * Platform SDK and replace Simple.c with this file.
28
- *
29
- * You should also apply service.patch to
30
- * service.c and service.h from the Platform SDK service sample.
31
- *
32
- * This code is designed to be built with the mingw compiler.
33
- */
34
-
35
-#include "service.h"
36
-
37
-#include <stdio.h>
38
-#include <stdarg.h>
39
-#include <stdbool.h>
40
-#include <process.h>
41
-
42
-static SERVICE_STATUS_HANDLE service;
43
-static SERVICE_STATUS status = { .dwServiceType = SERVICE_WIN32_SHARE_PROCESS };
44
-
45
-openvpn_service_t automatic_service = {
46
-    automatic,
47
-    TEXT(PACKAGE_NAME "ServiceLegacy"),
48
-    TEXT(PACKAGE_NAME " Legacy Service"),
49
-    TEXT(SERVICE_DEPENDENCIES),
50
-    SERVICE_DEMAND_START
51
-};
52
-
53
-struct security_attributes
54
-{
55
-    SECURITY_ATTRIBUTES sa;
56
-    SECURITY_DESCRIPTOR sd;
57
-};
58
-
59
-static HANDLE exit_event = NULL;
60
-
61
-/* clear an object */
62
-#define CLEAR(x) memset(&(x), 0, sizeof(x))
63
-
64
-
65
-bool
66
-init_security_attributes_allow_all(struct security_attributes *obj)
67
-{
68
-    CLEAR(*obj);
69
-
70
-    obj->sa.nLength = sizeof(SECURITY_ATTRIBUTES);
71
-    obj->sa.lpSecurityDescriptor = &obj->sd;
72
-    obj->sa.bInheritHandle = TRUE;
73
-    if (!InitializeSecurityDescriptor(&obj->sd, SECURITY_DESCRIPTOR_REVISION))
74
-    {
75
-        return false;
76
-    }
77
-    if (!SetSecurityDescriptorDacl(&obj->sd, TRUE, NULL, FALSE))
78
-    {
79
-        return false;
80
-    }
81
-    return true;
82
-}
83
-
84
-HANDLE
85
-create_event(LPCTSTR name, bool allow_all, bool initial_state, bool manual_reset)
86
-{
87
-    if (allow_all)
88
-    {
89
-        struct security_attributes sa;
90
-        if (!init_security_attributes_allow_all(&sa))
91
-        {
92
-            return NULL;
93
-        }
94
-        return CreateEvent(&sa.sa, (BOOL)manual_reset, (BOOL)initial_state, name);
95
-    }
96
-    else
97
-    {
98
-        return CreateEvent(NULL, (BOOL)manual_reset, (BOOL)initial_state, name);
99
-    }
100
-}
101
-
102
-void
103
-close_if_open(HANDLE h)
104
-{
105
-    if (h != NULL)
106
-    {
107
-        CloseHandle(h);
108
-    }
109
-}
110
-
111
-static bool
112
-match(const WIN32_FIND_DATA *find, LPCTSTR ext)
113
-{
114
-    if (find->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
115
-    {
116
-        return false;
117
-    }
118
-
119
-    if (*ext == TEXT('\0'))
120
-    {
121
-        return true;
122
-    }
123
-
124
-    /* find the pointer to that last '.' in filename and match ext against the rest */
125
-
126
-    const TCHAR *p = _tcsrchr(find->cFileName, TEXT('.'));
127
-    return p && p != find->cFileName && _tcsicmp(p + 1, ext) == 0;
128
-}
129
-
130
-/*
131
- * Modify the extension on a filename.
132
- */
133
-static bool
134
-modext(LPTSTR dest, size_t size, LPCTSTR src, LPCTSTR newext)
135
-{
136
-    size_t i;
137
-
138
-    if (size > 0 && (_tcslen(src) + 1) <= size)
139
-    {
140
-        _tcscpy_s(dest, size, src);
141
-        dest [size - 1] = TEXT('\0');
142
-        i = _tcslen(dest);
143
-        while (i-- > 0)
144
-        {
145
-            if (dest[i] == TEXT('\\'))
146
-            {
147
-                break;
148
-            }
149
-            if (dest[i] == TEXT('.'))
150
-            {
151
-                dest[i] = TEXT('\0');
152
-                break;
153
-            }
154
-        }
155
-        if (_tcslen(dest) + _tcslen(newext) + 2 <= size)
156
-        {
157
-            _tcscat_s(dest, size, TEXT("."));
158
-            _tcscat_s(dest, size, newext);
159
-            return true;
160
-        }
161
-        dest[0] = TEXT('\0');
162
-    }
163
-    return false;
164
-}
165
-
166
-static DWORD WINAPI
167
-ServiceCtrlAutomatic(DWORD ctrl_code, DWORD event, LPVOID data, LPVOID ctx)
168
-{
169
-    SERVICE_STATUS *status = ctx;
170
-    switch (ctrl_code)
171
-    {
172
-        case SERVICE_CONTROL_STOP:
173
-            status->dwCurrentState = SERVICE_STOP_PENDING;
174
-            ReportStatusToSCMgr(service, status);
175
-            if (exit_event)
176
-            {
177
-                SetEvent(exit_event);
178
-            }
179
-            return NO_ERROR;
180
-
181
-        case SERVICE_CONTROL_INTERROGATE:
182
-            return NO_ERROR;
183
-
184
-        default:
185
-            return ERROR_CALL_NOT_IMPLEMENTED;
186
-    }
187
-}
188
-
189
-
190
-VOID WINAPI
191
-ServiceStartAutomaticOwn(DWORD dwArgc, LPTSTR *lpszArgv)
192
-{
193
-    status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
194
-    ServiceStartAutomatic(dwArgc, lpszArgv);
195
-}
196
-
197
-
198
-VOID WINAPI
199
-ServiceStartAutomatic(DWORD dwArgc, LPTSTR *lpszArgv)
200
-{
201
-    DWORD error = NO_ERROR;
202
-    settings_t settings;
203
-    TCHAR event_name[256];
204
-
205
-    service = RegisterServiceCtrlHandlerEx(automatic_service.name, ServiceCtrlAutomatic, &status);
206
-    if (!service)
207
-    {
208
-        return;
209
-    }
210
-
211
-    status.dwCurrentState = SERVICE_START_PENDING;
212
-    status.dwServiceSpecificExitCode = NO_ERROR;
213
-    status.dwWin32ExitCode = NO_ERROR;
214
-    status.dwWaitHint = 3000;
215
-
216
-    if (!ReportStatusToSCMgr(service, &status))
217
-    {
218
-        MsgToEventLog(M_ERR, TEXT("ReportStatusToSCMgr #1 failed"));
219
-        goto finish;
220
-    }
221
-
222
-    /*
223
-     * Create our exit event
224
-     * This event is initially created in the non-signaled
225
-     * state.  It will transition to the signaled state when
226
-     * we have received a terminate signal from the Service
227
-     * Control Manager which will cause an asynchronous call
228
-     * of ServiceStop below.
229
-     */
230
-
231
-    openvpn_sntprintf(event_name, _countof(event_name), TEXT(PACKAGE "%s_exit_1"), service_instance);
232
-    exit_event = create_event(event_name, false, false, true);
233
-    if (!exit_event)
234
-    {
235
-        MsgToEventLog(M_ERR, TEXT("CreateEvent failed"));
236
-        goto finish;
237
-    }
238
-
239
-    /*
240
-     * If exit event is already signaled, it means we were not
241
-     * shut down properly.
242
-     */
243
-    if (WaitForSingleObject(exit_event, 0) != WAIT_TIMEOUT)
244
-    {
245
-        MsgToEventLog(M_ERR, TEXT("Exit event is already signaled -- we were not shut down properly"));
246
-        goto finish;
247
-    }
248
-
249
-    if (!ReportStatusToSCMgr(service, &status))
250
-    {
251
-        MsgToEventLog(M_ERR, TEXT("ReportStatusToSCMgr #2 failed"));
252
-        goto finish;
253
-    }
254
-
255
-    /*
256
-     * Read info from registry in key HKLM\SOFTWARE\OpenVPN
257
-     */
258
-    error = GetOpenvpnSettings(&settings);
259
-    if (error != ERROR_SUCCESS)
260
-    {
261
-        goto finish;
262
-    }
263
-
264
-    /*
265
-     * Instantiate an OpenVPN process for each configuration
266
-     * file found.
267
-     */
268
-    {
269
-        WIN32_FIND_DATA find_obj;
270
-        HANDLE find_handle;
271
-        BOOL more_files;
272
-        TCHAR find_string[MAX_PATH];
273
-
274
-        openvpn_sntprintf(find_string, _countof(find_string), TEXT("%s\\*"), settings.config_dir);
275
-
276
-        find_handle = FindFirstFile(find_string, &find_obj);
277
-        if (find_handle == INVALID_HANDLE_VALUE)
278
-        {
279
-            MsgToEventLog(M_ERR, TEXT("Cannot get configuration file list using: %s"), find_string);
280
-            goto finish;
281
-        }
282
-
283
-        /*
284
-         * Loop over each config file
285
-         */
286
-        do
287
-        {
288
-            HANDLE log_handle = NULL;
289
-            STARTUPINFO start_info;
290
-            PROCESS_INFORMATION proc_info;
291
-            struct security_attributes sa;
292
-            TCHAR log_file[MAX_PATH];
293
-            TCHAR log_path[MAX_PATH];
294
-            TCHAR command_line[256];
295
-
296
-            CLEAR(start_info);
297
-            CLEAR(proc_info);
298
-            CLEAR(sa);
299
-
300
-            if (!ReportStatusToSCMgr(service, &status))
301
-            {
302
-                MsgToEventLog(M_ERR, TEXT("ReportStatusToSCMgr #3 failed"));
303
-                FindClose(find_handle);
304
-                goto finish;
305
-            }
306
-
307
-            /* does file have the correct type and extension? */
308
-            if (match(&find_obj, settings.ext_string))
309
-            {
310
-                /* get log file pathname */
311
-                if (!modext(log_file, _countof(log_file), find_obj.cFileName, TEXT("log")))
312
-                {
313
-                    MsgToEventLog(M_ERR, TEXT("Cannot construct logfile name based on: %s"), find_obj.cFileName);
314
-                    FindClose(find_handle);
315
-                    goto finish;
316
-                }
317
-                openvpn_sntprintf(log_path, _countof(log_path),
318
-                                  TEXT("%s\\%s"), settings.log_dir, log_file);
319
-
320
-                /* construct command line */
321
-                openvpn_sntprintf(command_line, _countof(command_line), TEXT("openvpn --service \"" PACKAGE "%s_exit_1\" 1 --config \"%s\""),
322
-                                  service_instance,
323
-                                  find_obj.cFileName);
324
-
325
-                /* Make security attributes struct for logfile handle so it can
326
-                 * be inherited. */
327
-                if (!init_security_attributes_allow_all(&sa))
328
-                {
329
-                    error = MsgToEventLog(M_SYSERR, TEXT("InitializeSecurityDescriptor start_" PACKAGE " failed"));
330
-                    goto finish;
331
-                }
332
-
333
-                /* open logfile as stdout/stderr for soon-to-be-spawned subprocess */
334
-                log_handle = CreateFile(log_path,
335
-                                        GENERIC_WRITE,
336
-                                        FILE_SHARE_READ,
337
-                                        &sa.sa,
338
-                                        settings.append ? OPEN_ALWAYS : CREATE_ALWAYS,
339
-                                        FILE_ATTRIBUTE_NORMAL,
340
-                                        NULL);
341
-
342
-                if (log_handle == INVALID_HANDLE_VALUE)
343
-                {
344
-                    error = MsgToEventLog(M_SYSERR, TEXT("Cannot open logfile: %s"), log_path);
345
-                    FindClose(find_handle);
346
-                    goto finish;
347
-                }
348
-
349
-                /* append to logfile? */
350
-                if (settings.append)
351
-                {
352
-                    if (SetFilePointer(log_handle, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER)
353
-                    {
354
-                        error = MsgToEventLog(M_SYSERR, TEXT("Cannot seek to end of logfile: %s"), log_path);
355
-                        FindClose(find_handle);
356
-                        goto finish;
357
-                    }
358
-                }
359
-
360
-                /* fill in STARTUPINFO struct */
361
-                GetStartupInfo(&start_info);
362
-                start_info.cb = sizeof(start_info);
363
-                start_info.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
364
-                start_info.wShowWindow = SW_HIDE;
365
-                start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
366
-                start_info.hStdOutput = start_info.hStdError = log_handle;
367
-
368
-                /* create an OpenVPN process for one config file */
369
-                if (!CreateProcess(settings.exe_path,
370
-                                   command_line,
371
-                                   NULL,
372
-                                   NULL,
373
-                                   TRUE,
374
-                                   settings.priority | CREATE_NEW_CONSOLE,
375
-                                   NULL,
376
-                                   settings.config_dir,
377
-                                   &start_info,
378
-                                   &proc_info))
379
-                {
380
-                    error = MsgToEventLog(M_SYSERR, TEXT("CreateProcess failed, exe='%s' cmdline='%s' dir='%s'"),
381
-                                          settings.exe_path,
382
-                                          command_line,
383
-                                          settings.config_dir);
384
-
385
-                    FindClose(find_handle);
386
-                    CloseHandle(log_handle);
387
-                    goto finish;
388
-                }
389
-
390
-                /* close unneeded handles */
391
-                Sleep(1000); /* try to prevent race if we close logfile
392
-                              * handle before child process DUPs it */
393
-                if (!CloseHandle(proc_info.hProcess)
394
-                    || !CloseHandle(proc_info.hThread)
395
-                    || !CloseHandle(log_handle))
396
-                {
397
-                    error = MsgToEventLog(M_SYSERR, TEXT("CloseHandle failed"));
398
-                    goto finish;
399
-                }
400
-            }
401
-
402
-            /* more files to process? */
403
-            more_files = FindNextFile(find_handle, &find_obj);
404
-
405
-        } while (more_files);
406
-
407
-        FindClose(find_handle);
408
-    }
409
-
410
-    /* we are now fully started */
411
-    status.dwCurrentState = SERVICE_RUNNING;
412
-    status.dwWaitHint = 0;
413
-    if (!ReportStatusToSCMgr(service, &status))
414
-    {
415
-        MsgToEventLog(M_ERR, TEXT("ReportStatusToSCMgr SERVICE_RUNNING failed"));
416
-        goto finish;
417
-    }
418
-
419
-    /* wait for our shutdown signal */
420
-    if (WaitForSingleObject(exit_event, INFINITE) != WAIT_OBJECT_0)
421
-    {
422
-        MsgToEventLog(M_ERR, TEXT("wait for shutdown signal failed"));
423
-    }
424
-
425
-finish:
426
-    if (exit_event)
427
-    {
428
-        CloseHandle(exit_event);
429
-    }
430
-
431
-    status.dwCurrentState = SERVICE_STOPPED;
432
-    status.dwWin32ExitCode = error;
433
-    ReportStatusToSCMgr(service, &status);
434
-}
... ...
@@ -115,7 +115,6 @@
115 115
     </Link>
116 116
   </ItemDefinitionGroup>
117 117
   <ItemGroup>
118
-    <ClCompile Include="automatic.c" />
119 118
     <ClCompile Include="common.c" />
120 119
     <ClCompile Include="interactive.c" />
121 120
     <ClCompile Include="service.c" />
... ...
@@ -18,9 +18,6 @@
18 18
     <ClCompile Include="service.c">
19 19
       <Filter>Source Files</Filter>
20 20
     </ClCompile>
21
-    <ClCompile Include="automatic.c">
22
-      <Filter>Source Files</Filter>
23
-    </ClCompile>
24 21
     <ClCompile Include="common.c">
25 22
       <Filter>Source Files</Filter>
26 23
     </ClCompile>
... ...
@@ -224,21 +224,14 @@ int
224 224
 _tmain(int argc, TCHAR *argv[])
225 225
 {
226 226
     /*
227
-     * Automatic + Interactive service (as a SERVICE_WIN32_SHARE_PROCESS)
227
+     * Interactive service (as a SERVICE_WIN32_SHARE_PROCESS)
228 228
      * This is the default.
229 229
      */
230 230
     const SERVICE_TABLE_ENTRY dispatchTable_shared[] = {
231
-        { automatic_service.name, ServiceStartAutomatic },
232 231
         { interactive_service.name, ServiceStartInteractive },
233 232
         { NULL, NULL }
234 233
     };
235 234
 
236
-    /* Automatic service only (as a SERVICE_WIN32_OWN_PROCESS) */
237
-    const SERVICE_TABLE_ENTRY dispatchTable_automatic[] = {
238
-        { TEXT(""), ServiceStartAutomaticOwn },
239
-        { NULL, NULL }
240
-    };
241
-
242 235
     /* Interactive service only (as a SERVICE_WIN32_OWN_PROCESS) */
243 236
     const SERVICE_TABLE_ENTRY dispatchTable_interactive[] = {
244 237
         { TEXT(""), ServiceStartInteractiveOwn },
... ...
@@ -247,8 +240,7 @@ _tmain(int argc, TCHAR *argv[])
247 247
 
248 248
     const SERVICE_TABLE_ENTRY *dispatchTable = dispatchTable_shared;
249 249
 
250
-    openvpn_service[0] = automatic_service;
251
-    openvpn_service[1] = interactive_service;
250
+    openvpn_service[interactive] = interactive_service;
252 251
 
253 252
     for (int i = 1; i < argc; i++)
254 253
     {
... ...
@@ -264,29 +256,33 @@ _tmain(int argc, TCHAR *argv[])
264 264
             }
265 265
             else if (_tcsicmp(TEXT("start"), argv[i] + 1) == 0)
266 266
             {
267
-                BOOL is_auto = argc < i + 2 || _tcsicmp(TEXT("interactive"), argv[i + 1]) != 0;
268
-                return CmdStartService(is_auto ? automatic : interactive);
267
+                return CmdStartService(interactive);
269 268
             }
270 269
             else if (argc > i + 2 && _tcsicmp(TEXT("instance"), argv[i] + 1) == 0)
271 270
             {
272
-                dispatchTable = _tcsicmp(TEXT("interactive"), argv[i + 1]) != 0 ?
273
-                                dispatchTable_automatic :
274
-                                dispatchTable_interactive;
275
-
276
-                service_instance = argv[i + 2];
277
-                i += 2;
271
+                if (_tcsicmp(TEXT("interactive"), argv[i+1]) == 0)
272
+                {
273
+                    dispatchTable = dispatchTable_interactive;
274
+                    service_instance = argv[i + 2];
275
+                    i += 2;
276
+                }
277
+                else
278
+                {
279
+                    MsgToEventLog(M_ERR, L"Invalid argument to -instance <%s>. Service not started.", argv[i+1]);
280
+                    return 1;
281
+                }
278 282
             }
279 283
             else
280 284
             {
281
-                _tprintf(TEXT("%s -install        to install the services\n"), APPNAME);
282
-                _tprintf(TEXT("%s -start <name>   to start a service (\"automatic\" or \"interactive\")\n"), APPNAME);
283
-                _tprintf(TEXT("%s -remove         to remove the services\n"), APPNAME);
285
+                _tprintf(TEXT("%s -install        to install the interactive service\n"), APPNAME);
286
+                _tprintf(TEXT("%s -start [name]   to start the service (name = \"interactive\" is optional)\n"), APPNAME);
287
+                _tprintf(TEXT("%s -remove         to remove the service\n"), APPNAME);
284 288
 
285 289
                 _tprintf(TEXT("\nService run-time parameters:\n"));
286
-                _tprintf(TEXT("-instance <name> <id>\n")
287
-                         TEXT("   Runs the service as an alternate instance. <name> can be \"automatic\" or\n")
288
-                         TEXT("   \"interactive\". The service settings will be loaded from\n")
289
-                         TEXT("   HKLM\\Software\\" PACKAGE_NAME "<id> registry key, and the interactive service will accept\n")
290
+                _tprintf(TEXT("-instance interactive <id>\n")
291
+                         TEXT("   Runs the service as an alternate instance.\n")
292
+                         TEXT("   The service settings will be loaded from\n")
293
+                         TEXT("   HKLM\\Software\\" PACKAGE_NAME "<id> registry key, and the service will accept\n")
290 294
                          TEXT("   requests on \\\\.\\pipe\\" PACKAGE "<id>\\service named pipe.\n"));
291 295
 
292 296
                 return 0;
... ...
@@ -48,7 +48,6 @@
48 48
 #define M_ERR     (MSG_FLAGS_ERROR)                    /* error */
49 49
 
50 50
 typedef enum {
51
-    automatic,
52 51
     interactive,
53 52
     _service_max
54 53
 } openvpn_service_type;
... ...
@@ -72,14 +71,9 @@ typedef struct {
72 72
     BOOL append;
73 73
 } settings_t;
74 74
 
75
-extern openvpn_service_t automatic_service;
76 75
 extern openvpn_service_t interactive_service;
77 76
 extern LPCTSTR service_instance;
78 77
 
79
-VOID WINAPI ServiceStartAutomaticOwn(DWORD argc, LPTSTR *argv);
80
-
81
-VOID WINAPI ServiceStartAutomatic(DWORD argc, LPTSTR *argv);
82
-
83 78
 VOID WINAPI ServiceStartInteractiveOwn(DWORD argc, LPTSTR *argv);
84 79
 
85 80
 VOID WINAPI ServiceStartInteractive(DWORD argc, LPTSTR *argv);