Blame

cab3e6 Samuli Seppänen 2025-02-27 13:36:39 1
# OpenVPN Interactive Service Notes
2
3
## Introduction
4
5
OpenVPN Interactive Service, also known as "iservice" or
6
"OpenVPNServiceInteractive", is a Windows system service which allows
7
unprivileged openvpn.exe process to do certain privileged operations, such as
8
adding routes. This removes the need to always run OpenVPN as administrator,
9
which was the case for a long time, and continues to be the case for OpenVPN
10
2.3.x.
11
12
The 2.4.x release and git "master" versions of OpenVPN contain the Interactive
13
Service code and OpenVPN-GUI is setup to use it by default. Starting from
14
version 2.4.0, OpenVPN-GUI is expected to be started as user (do not right-click
15
and "run as administrator" or do not set the shortcut to run as administrator).
16
This ensures that OpenVPN and the GUI run with limited privileges.
17
18
## How It Works
19
20
Here is a brief explanation of how the Interactive Service works, based on
21
`Gert's email`_ to openvpn-devel mailing list. The example user, *joe*, is not
22
an administrator, and does not have any other extra privileges.
23
24
- OpenVPN-GUI runs as user *joe*.
25
- Interactive Service runs as a local Windows service with maximum privileges.
26
- OpenVPN-GUI connects to the Interactive Service and asks it to "run
27
openvpn.exe with the given command line options".
28
- Interactive Service starts openvpn.exe process as user *joe*, and keeps a
29
service pipe between Interactive Service and openvpn.exe.
30
- When openvpn.exe wants to perform any operation that require elevation (e.g.
31
ipconfig, route, configure DNS), it sends a request over the service pipe to
32
the Interactive Service, which will then execute it (and clean up should
33
openvpn.exe crash).
34
- `--up` scripts are run by openvpn.exe itself, which is running as user
35
*joe*, all privileges are nicely in place.
36
- Scripts run by the GUI will run as user *joe*, so that automated tasks like
37
mapping of drives work as expected.
38
39
This avoids the use of scripts for privilege escalation (as was possible by
40
running an `--up` script from openvpn.exe which is run as administrator).
41
42
43
## Client-Service Communication
44
45
### Connecting
46
47
The client (OpenVPN GUI) and the Interactive Service communicate using a named
48
message pipe. By default, the service provides the `\\.\pipe\openvpn\service`
49
named pipe.
50
51
The client connects to the pipe for read/write and sets the pipe state to
52
`PIPE_READMODE_MESSAGE`:
53
54
HANDLE pipe = CreateFile(_T("\\\\.\\pipe\\openvpn\\service"),
55
GENERIC_READ | GENERIC_WRITE,
56
0,
57
NULL,
58
OPEN_EXISTING,
59
FILE_FLAG_OVERLAPPED,
60
NULL);
61
62
if (pipe == INVALID_HANDLE_VALUE)
63
{
64
// Error
65
}
66
67
DWORD dwMode = PIPE_READMODE_MESSAGE;
68
if (!SetNamedPipeHandleState(pipe, &dwMode, NULL, NULL)
69
{
70
// Error
71
}
72
73
74
### openvpn.exe Startup
75
76
After the client is connected to the service, the client must send a startup
77
message to have the service start the openvpn.exe process. The startup message
78
is comprised of three UTF-16 strings delimited by U0000 zero characters:
79
80
startupmsg = workingdir WZERO openvpnoptions WZERO stdin WZERO
81
82
workingdir = WSTRING
83
openvpnoptions = WSTRING
84
stdin = WSTRING
85
86
WSTRING = *WCHAR
87
WCHAR = %x0001-FFFF
88
WZERO = %x0000
89
90
`workingdir`
91
92
Represents the folder openvpn.exe process should be started in.
93
94
`openvpnoptions`
95
96
String contains `--config` and other OpenVPN command line options, without
97
the `argv[0]` executable name ("openvpn" or "openvpn.exe"). When there is
98
only one option specified, the `--config` option is assumed and the option
99
is the configuration filename.
100
101
Note that the interactive service validates the options. OpenVPN
102
configuration file must reside in the configuration folder defined by
103
`config_dir` registry value. The configuration file can also reside in any
104
subfolder of the configuration folder. For all other folders the invoking
105
user must be a member of local Administrators group, or a member of the group
106
defined by `ovpn_admin_group` registry value ("OpenVPN Administrators" by
107
default).
108
109
`stdin`
110
111
The content of the `stdin` string is sent to the openvpn.exe process to its
112
stdin stream after it starts.
113
114
When a `--management ... stdin` option is present, the openvpn.exe process
115
will prompt for the management interface password on start. In this case, the
116
`stdin` must contain the password appended with an LF (U000A) to simulate
117
the [Enter] key after the password is "typed" in.
118
119
The openvpn.exe's stdout is redirected to `NUL`. Should the client require
120
openvpn.exe's stdout, one should specify `--log` option.
121
122
The message must be written in a single `riteFile()` call.
123
124
Example:
125
126
// Prepare the message.
127
size_t msg_len =
128
wcslen(workingdir) + 1 +
129
wcslen(options ) + 1 +
130
wcslen(manage_pwd) + 1;
131
wchar_t *msg_data = (wchar_t*)malloc(msg_len*sizeof(wchar_t));
132
_snwprintf(msg_data, msg_len, L"%s%c%s%c%s",
133
workingdir, L'\0',
134
options, L'\0',
135
manage_pwd)
136
137
// Send the message.
138
DWORD dwBytesWritten;
139
if (!WriteFile(pipe,
140
msg_data,
141
msg_len*sizeof(wchar_t),
142
&dwBytesWritten,
143
NULL))
144
{
145
// Error
146
}
147
148
// Sanitize memory, since the stdin component of the message
149
// contains the management interface password.
150
SecureZeroMemory(msg_data, msg_len*sizeof(wchar_t));
151
free(msg_data);
152
153
### openvpn.exe Process ID
154
155
After receiving the startup message, the Interactive Service validates the user
156
and specified options before launching the openvpn.exe process.
157
158
The Interactive Service replies with a process ID message. The process ID
159
message is comprised of three UTF-16 strings delimited by LFs (U000A):
160
161
pidmsg = L"0x00000000" WLF L"0x" pid WLF L"Process ID"
162
163
pid = 8*8WHEXDIG
164
165
WHEXDIG = WDIGIT / L"A" / L"B" / L"C" / L"D" / L"E" / L"F"
166
WDIGIT = %x0030-0039
167
WLF = %x000a
168
169
`pid`
170
171
A UTF-16 eight-character hexadecimal process ID of the openvpn.exe process
172
the Interactive Service launched on client's behalf.
173
174
175
### openvpn.exe Monitoring and Termination
176
177
After the openvpn.exe process is launched, the client can disconnect the pipe to
178
the interactive service. However, it should monitor the openvpn.exe process
179
itself. OpenVPN Management Interface is recommended for this.
180
181
The client may choose to stay connected to the pipe. When the openvpn.exe
182
process terminates, the service disconnects the pipe. Should the openvpn.exe
183
process terminate with an error, the service sends an error message to the
184
client before disconnecting the pipe.
185
186
Note that Interactive Service terminates all child openvpn.exe processes when
187
the service is stopped or restarted. This allows a graceful elevation-required
188
clean-up (e.g. restore ipconfig, route, DNS).
189
190
### Error Messages
191
192
In case of an error, the Interactive Service sends an error message to the
193
client. Error messages are comprised of three UTF-16 strings delimited by LFs
194
(U000A):
195
196
errmsg = L"0x" errnum WLF func WLF msg
197
198
errnum = 8*8WHEXDIG
199
func = WSTRING
200
msg = WSTRING
201
202
`errnum`
203
204
A UTF-16 eight-character hexadecimal error code. Typically, it is one of the
205
Win32 error codes returned by `GetLastError()`.
206
207
However, it can be one of the Interactive Service specific error codes:
208
209
===================== ==========
210
Error Code
211
===================== ==========
212
ERROR_OPENVPN_STARTUP 0x20000000
213
ERROR_STARTUP_DATA 0x20000001
214
ERROR_MESSAGE_DATA 0x20000002
215
ERROR_MESSAGE_TYPE 0x20000003
216
===================== ==========
217
218
`func`
219
220
The name of the function call that failed or an error description.
221
222
`msg`
223
224
The error description returned by a `FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, 0, errnum, ...)` call.
225
226
227
## Interactive Service Configuration
228
229
The Interactive Service settings are read from the
230
`HKEY_LOCAL_MACHINE\SOFTWARE\OpenVPN` registry key by default.
231
232
All the following registry values are of the `REG_SZ` type:
233
234
*Default*
235
236
Installation folder (required, hereinafter `install_dir`)
237
238
`exe_path`
239
240
The absolute path to the openvpn.exe binary; defaults to `install_dir "\bin\openvpn.exe"`.
241
242
`config_dir`
243
244
The path to the configuration folder; defaults to `install_dir "\config"`.
245
246
`priority`
247
248
openvpn.exe process priority; one of the following strings:
249
250
* "IDLE_PRIORITY_CLASS"
251
* "BELOW_NORMAL_PRIORITY_CLASS"
252
* "NORMAL_PRIORITY_CLASS"(default)
253
* "ABOVE_NORMAL_PRIORITY_CLASS"
254
* "HIGH_PRIORITY_CLASS"
255
256
`ovpn_admin_group`
257
258
The name of the local group, whose members are authorized to use the Interactive Service unrestricted; defaults to `"OpenVPN Administrators"`
259
260
## Multiple Interactive Service Instances
261
262
OpenVPN 2.4.5 extended the Interactive Service to support multiple side-by-side
263
running instances. This allows clients to use different Interactive Service
264
versions with different settings and/or openvpn.exe binary version on the same
265
computer.
266
267
OpenVPN installs the default Interactive Service instance only. The default
268
instance is used by OpenVPN GUI client and also provides backward compatibility.
269
270
### Installing a Non-default Interactive Service Instance
271
272
1. Choose a unique instance name. For example: "$v2.5-test". The instance nameis appended to the default registry path and service name. We choose to start it with a dollar "$" sign analogous to Microsoft SQL Server instance naming scheme. However, this is not imperative. Appending the name to the registry path and service name also implies the name cannot contain characters not allowed in Windows paths: "<", ">", double quote etc.
273
1. Create an `HKEY_LOCAL_MACHINE\SOFTWARE\OpenVPN$v2.5-test` registry key and configure the Interactive Service instance configuration appropriately. This allows using slightly or completely different settings from the default instance. See the `Interactive Service Configuration` section for the list of registry values.
274
1. Create and start the instance's Windows service from an elevated command prompt:
275
```
276
sc create "OpenVPNServiceInteractive$v2.5-test" \
277
start= auto \
278
binPath= "<path to openvpnserv.exe> -instance interactive $v2.5-test" \
279
depend= tap0901/Dhcp \
280
DisplayName= "OpenVPN Interactive Service (v2.5-test)"
281
282
sc start "OpenVPNServiceInteractive$v2.5-test"
283
```
284
This allows using the same or a different version of openvpnserv.exe than the
285
default instance. Note the space after "=" character in `sc` command line options.
286
287
4. Set your OpenVPN client to connect to the `\\.\pipe\openvpn$v2.5-test\service`. This allows the client to select a different installed Interactive Service instance at run-time, thus allowing different OpenVPN settings and versions. At the time writing, the OpenVPN GUI client supports connecting to the default Interactive Service instance only.
288
289
Gert's email: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg00097.html