win: allow OpenVPN service account to use any command-line options

Since 2.7, OpenVPN service (used to start persistent connections)
runs under limited virtual service account NT SERVICE\OpenVPNService.

Since it should be able to use all command-line options
and cannot be made member of "OpenVPN Administrators" group,
it has to be handled separately.

Change-Id: I44d308301dfb7c22600d8632a553288f52b3068f
Signed-off-by: Lev Stipakov <lev@openvpn.net>
This commit is contained in:
Lev Stipakov 2025-03-12 13:35:56 +02:00
parent 99b35c3783
commit f89d00a3a8
5 changed files with 26 additions and 9 deletions

View file

@ -130,6 +130,14 @@ GetOpenvpnSettings(settings_t *s)
{
goto out;
}
error = GetRegString(key, TEXT("ovpn_service_user"), s->ovpn_service_user,
sizeof(s->ovpn_service_user), OVPN_SERVICE_USER);
if (error != ERROR_SUCCESS)
{
goto out;
}
/* set process priority */
if (!_wcsicmp(priority, TEXT("IDLE_PRIORITY_CLASS")))
{

View file

@ -2497,7 +2497,7 @@ RunOpenvpn(LPVOID p)
* OR user is authorized to run any config.
*/
if (!ValidateOptions(pipe, sud.directory, sud.options, errmsg, _countof(errmsg))
&& !IsAuthorizedUser(ovpn_user->User.Sid, imp_token, settings.ovpn_admin_group))
&& !IsAuthorizedUser(ovpn_user->User.Sid, imp_token, settings.ovpn_admin_group, settings.ovpn_service_user))
{
ReturnError(pipe, ERROR_STARTUP_DATA, errmsg, 1, &exit_event);
goto out;

View file

@ -71,6 +71,7 @@ typedef struct {
TCHAR ext_string[16];
TCHAR log_dir[MAX_PATH];
TCHAR ovpn_admin_group[MAX_NAME];
TCHAR ovpn_service_user[MAX_NAME];
DWORD priority;
BOOL append;
} settings_t;

View file

@ -140,12 +140,8 @@ GetBuiltinAdminGroupName(WCHAR *name, DWORD nlen)
return b;
}
/*
* Check whether user is a member of Administrators group or
* the group specified in ovpn_admin_group
*/
BOOL
IsAuthorizedUser(PSID sid, const HANDLE token, const WCHAR *ovpn_admin_group)
IsAuthorizedUser(PSID sid, const HANDLE token, const WCHAR *ovpn_admin_group, const WCHAR *ovpn_service_user)
{
const WCHAR *admin_group[2];
WCHAR username[MAX_NAME];
@ -164,6 +160,12 @@ IsAuthorizedUser(PSID sid, const HANDLE token, const WCHAR *ovpn_admin_group)
domain[0] = '\0';
}
/* is this service account? */
if ((wcscmp(username, ovpn_service_user) == 0) && (wcscmp(domain, TEXT("NT SERVICE")) == 0))
{
return TRUE;
}
if (GetBuiltinAdminGroupName(sysadmin_group, _countof(sysadmin_group)))
{
admin_group[0] = sysadmin_group;

View file

@ -29,11 +29,17 @@
/* Authorized groups who can use any options and config locations */
#define SYSTEM_ADMIN_GROUP TEXT("Administrators")
#define OVPN_ADMIN_GROUP TEXT("OpenVPN Administrators")
/* The last one may be reset in registry: HKLM\Software\OpenVPN\ovpn_admin_group */
#define OVPN_ADMIN_GROUP TEXT("OpenVPN Administrators") /* may be set in HKLM\Software\OpenVPN\ovpn_admin_group */
#define OVPN_SERVICE_USER TEXT("OpenVPNService") /* may be set in HKLM\Software\OpenVPN\ovpn_service_user */
/*
* Check whether user is a member of Administrators group or
* the group specified in ovpn_admin_group or
* OpenVPN Virtual Service Account user
*/
BOOL
IsAuthorizedUser(PSID sid, const HANDLE token, const WCHAR *ovpn_admin_group);
IsAuthorizedUser(PSID sid, const HANDLE token, const WCHAR *ovpn_admin_group, const WCHAR *ovpn_service_user);
BOOL
CheckOption(const WCHAR *workdir, int narg, WCHAR *argv[], const settings_t *s);