mirror of https://github.com/IoTcat/vlmcsd.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1969 lines
46 KiB
1969 lines
46 KiB
#ifndef _CRT_SECURE_NO_WARNINGS |
|
#define _CRT_SECURE_NO_WARNINGS |
|
#endif |
|
|
|
#ifndef CONFIG |
|
#define CONFIG "config.h" |
|
#endif // CONFIG |
|
#include CONFIG |
|
|
|
#if defined(USE_MSRPC) && !defined(_WIN32) && !defined(__CYGWIN__) |
|
#error Microsoft RPC is only available on Windows and Cygwin |
|
#endif |
|
|
|
#if defined(USE_MSRPC) && defined(SIMPLE_SOCKETS) |
|
#error You can only define either USE_MSRPC or SIMPLE_SOCKETS but not both |
|
#endif |
|
|
|
#if defined(NO_SOCKETS) && defined(USE_MSRPC) |
|
#error Cannot use inetd mode with Microsoft RPC |
|
#endif |
|
|
|
#ifndef _GNU_SOURCE |
|
#define _GNU_SOURCE |
|
#endif |
|
|
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include <errno.h> |
|
#include <stdint.h> |
|
|
|
#if _MSC_VER |
|
#include "wingetopt.h" |
|
#endif |
|
|
|
#ifndef _WIN32 |
|
#include <pwd.h> |
|
#include <grp.h> |
|
#include <sys/types.h> |
|
|
|
#if !defined(NO_LIMIT) && !__minix__ |
|
#include <sys/ipc.h> |
|
#if !__ANDROID__ |
|
#include <sys/shm.h> |
|
#endif // !__ANDROID__ |
|
#endif // !defined(NO_LIMIT) && !__minix__ |
|
|
|
#include <sys/wait.h> |
|
#include <unistd.h> |
|
#include <fcntl.h> |
|
#include <sys/stat.h> |
|
#ifndef NO_LIMIT |
|
#include <semaphore.h> |
|
#endif // NO_LIMIT |
|
#endif // !_WIN32 |
|
|
|
#if __APPLE__ |
|
#include <mach-o/dyld.h> |
|
#endif // __APPLE__ |
|
|
|
#if __linux__ && defined(USE_AUXV) |
|
#include <sys/auxv.h> |
|
#endif |
|
|
|
#if __FreeBSD__ |
|
#include <sys/sysctl.h> |
|
#endif |
|
|
|
#include "vlmcsd.h" |
|
// ReSharper disable CppUnusedIncludeDirective |
|
#include "endian.h" |
|
// ReSharper restore CppUnusedIncludeDirective |
|
#include "shared_globals.h" |
|
#include "output.h" |
|
#ifndef USE_MSRPC |
|
#include "network.h" |
|
#else // USE_MSRPC |
|
#include "msrpc-server.h" |
|
#endif // USE_MSRPC |
|
#include "ntservice.h" |
|
#include "helpers.h" |
|
|
|
#ifndef NO_TAP |
|
#include "wintap.h" |
|
#endif |
|
|
|
static const char* const optstring = "a:N:B:m:t:A:R:u:g:L:p:i:H:P:l:r:U:W:C:c:F:O:o:x:T:K:E:M:j:SseDdVvqkZ"; |
|
|
|
#if !defined(NO_SOCKETS) && !defined(USE_MSRPC) && !defined(SIMPLE_SOCKETS) |
|
static uint_fast8_t maxsockets = 0; |
|
|
|
#endif // !defined(NO_SOCKETS) && !defined(USE_MSRPC) && !defined(SIMPLE_SOCKETS) |
|
|
|
#ifdef _NTSERVICE |
|
static int_fast8_t installService = 0; |
|
static const char *restrict ServiceUser = NULL; |
|
static const char *restrict ServicePassword = ""; |
|
#endif |
|
|
|
#ifndef NO_PID_FILE |
|
static const char *fn_pid = NULL; |
|
#endif |
|
|
|
#ifndef NO_INI_FILE |
|
|
|
#ifdef INI_FILE |
|
static const char *fn_ini = INI_FILE; |
|
#else // !INI_FILE |
|
static const char *fn_ini = NULL; |
|
#endif // !INI_FILE |
|
|
|
#ifndef NO_TAP |
|
char* tapArgument = NULL; |
|
#endif // NO_TAP |
|
|
|
static const char* IniFileErrorMessage = ""; |
|
char* IniFileErrorBuffer = NULL; |
|
#define INIFILE_ERROR_BUFFERSIZE 256 |
|
|
|
static IniFileParameter_t IniFileParameterList[] = |
|
{ |
|
# ifndef NO_SOCKETS |
|
{ "ExitLevel", INI_PARAM_EXIT_LEVEL }, |
|
# endif // NO_SOCKETS |
|
# ifndef NO_TAP |
|
{ "VPN", INI_PARAM_VPN }, |
|
# endif // NO_TAP |
|
# ifndef NO_EXTERNAL_DATA |
|
{ "KmsData", INI_PARAM_DATA_FILE }, |
|
# endif // NO_EXTERNAL_DATA |
|
# ifndef NO_STRICT_MODES |
|
{ "WhiteListingLevel", INI_PARAM_WHITELISTING_LEVEL }, |
|
{ "CheckClientTime", INI_PARAM_CHECK_CLIENT_TIME }, |
|
# ifndef NO_CLIENT_LIST |
|
{ "StartEmpty", INI_PARAM_START_EMPTY }, |
|
{ "MaintainClients", INI_PARAM_MAINTAIN_CLIENTS }, |
|
# endif // NO_CLIENT_LIST |
|
# endif // NO_STRICT_MODES |
|
# ifndef NO_RANDOM_EPID |
|
{ "RandomizationLevel", INI_PARAM_RANDOMIZATION_LEVEL }, |
|
{ "LCID", INI_PARAM_LCID }, |
|
{ "HostBuild", INI_PARAM_HOST_BUILD }, |
|
# endif // NO_RANDOM_EPID |
|
# if !defined(NO_SOCKETS) && (defined(USE_MSRPC) || defined(SIMPLE_SOCKETS) || defined(HAVE_GETIFADDR)) |
|
{ "Port", INI_PARAM_PORT }, |
|
# endif // defined(USE_MSRPC) || defined(SIMPLE_SOCKETS) |
|
# if !defined(NO_SOCKETS) && !defined(USE_MSRPC) |
|
# ifndef SIMPLE_SOCKETS |
|
{ "Listen", INI_PARAM_LISTEN }, |
|
# endif // SIMPLE_SOCKETS |
|
# if HAVE_FREEBIND |
|
{ "FreeBind", INI_PARAM_FREEBIND }, |
|
# endif // HAVE_FREEBIND |
|
# if !defined(NO_LIMIT) && !__minix__ |
|
{ "MaxWorkers", INI_PARAM_MAX_WORKERS }, |
|
# endif // !defined(NO_LIMIT) && !__minix__ |
|
# endif // !defined(NO_SOCKETS) && !defined(USE_MSRPC) |
|
# if !defined(NO_TIMEOUT) && !__minix__ && !defined(USE_MSRPC) & !defined(USE_MSRPC) |
|
{ "ConnectionTimeout", INI_PARAM_CONNECTION_TIMEOUT }, |
|
# endif // !defined(NO_TIMEOUT) && !__minix__ && !defined(USE_MSRPC) & !defined(USE_MSRPC) |
|
# ifndef USE_MSRPC |
|
{ "DisconnectClientsImmediately", INI_PARAM_DISCONNECT_IMMEDIATELY }, |
|
# ifndef SIMPLE_RPC |
|
{ "UseNDR64", INI_PARAM_RPC_NDR64 }, |
|
{ "UseBTFN", INI_PARAM_RPC_BTFN }, |
|
# endif // !SIMPLE_RPC |
|
# endif // USE_MSRPC |
|
# ifndef NO_PID_FILE |
|
{ "PIDFile", INI_PARAM_PID_FILE }, |
|
# endif // NO_PID_FILE |
|
# ifndef NO_LOG |
|
{ "LogDateAndTime", INI_PARAM_LOG_DATE_AND_TIME }, |
|
{ "LogFile", INI_PARAM_LOG_FILE }, |
|
# ifndef NO_VERBOSE_LOG |
|
{ "LogVerbose", INI_PARAM_LOG_VERBOSE }, |
|
# endif // NO_VERBOSE_LOG |
|
# endif // NO_LOG |
|
# ifndef NO_CUSTOM_INTERVALS |
|
{"ActivationInterval", INI_PARAM_ACTIVATION_INTERVAL }, |
|
{"RenewalInterval", INI_PARAM_RENEWAL_INTERVAL }, |
|
# endif // NO_CUSTOM_INTERVALS |
|
# if !defined(NO_USER_SWITCH) && !defined(_WIN32) |
|
{ "user", INI_PARAM_UID }, |
|
{ "group", INI_PARAM_GID}, |
|
# endif // !defined(NO_USER_SWITCH) && !defined(_WIN32) |
|
# if !defined(NO_PRIVATE_IP_DETECT) |
|
{"PublicIPProtectionLevel", INI_PARAM_PUBLIC_IP_PROTECTION_LEVEL }, |
|
# endif |
|
}; |
|
|
|
#endif // NO_INI_FILE |
|
|
|
|
|
#if !defined(NO_LIMIT) && !defined (NO_SOCKETS) && !__minix__ |
|
|
|
#if !defined(USE_THREADS) && !defined(CYGWIN) && !defined(USE_MSRPC) |
|
static int shmid = -1; |
|
#endif |
|
|
|
|
|
#endif // !defined(NO_LIMIT) && !defined (NO_SOCKETS) && !__minix__ |
|
|
|
#ifndef NO_USER_SWITCH |
|
#ifndef _WIN32 |
|
|
|
static const char *uname = NULL, *gname = NULL; |
|
static gid_t gid = INVALID_GID; |
|
static uid_t uid = INVALID_UID; |
|
|
|
// Get Numeric id of user/group |
|
static char GetNumericId(gid_t *restrict id, const char *const c) |
|
{ |
|
char* endptr; |
|
gid_t temp; |
|
|
|
temp = (gid_t)strtoll(c, &endptr, 10); |
|
if (!*endptr) *id = temp; |
|
if (*endptr || temp == (gid_t)-1) errno = EINVAL; |
|
|
|
return *endptr || *id == (gid_t)-1; |
|
} |
|
|
|
|
|
// Get group id from option argument |
|
static char GetGid() |
|
{ |
|
struct group *g; |
|
|
|
if ((g = getgrnam(optarg))) |
|
gid = g->gr_gid; |
|
else |
|
return GetNumericId(&gid, optarg); |
|
|
|
return 0; |
|
} |
|
|
|
|
|
// Get user id from option argument |
|
static char GetUid() |
|
{ |
|
struct passwd *u; |
|
|
|
////PORTABILITY: Assumes uid_t and gid_t are of same size (shouldn't be a problem) |
|
if ((u = getpwnam(optarg))) |
|
uid = u->pw_uid; |
|
else |
|
return GetNumericId((gid_t*)&uid, optarg); |
|
|
|
return 0; |
|
} |
|
#endif // _WIN32 |
|
#endif //NO_USER_SWITCH |
|
|
|
#ifdef NO_HELP |
|
static __noreturn void usage() |
|
{ |
|
printerrorf("Incorrect parameters\n\n"); |
|
exit(VLMCSD_EINVAL); |
|
} |
|
#else // HELP |
|
|
|
|
|
static __noreturn void usage() |
|
{ |
|
printerrorf("vlmcsd %s\n" |
|
"\nUsage:\n" |
|
" %s [ options ]\n\n" |
|
"Where:\n" |
|
# if !defined(_WIN32) && !defined(NO_USER_SWITCH) |
|
" -u <user>\t\tset uid to <user>\n" |
|
" -g <group>\t\tset gid to <group>\n" |
|
# endif // !defined(_WIN32) && !defined(NO_USER_SWITCH) |
|
# ifndef NO_CL_PIDS |
|
" -a <csvlk>=<epid>\tuse <epid> for <csvlk>\n" |
|
# endif // NO_CL_PIDS |
|
# ifndef NO_RANDOM_EPID |
|
" -r 0|1|2\t\tset ePID randomization level (default 1)\n" |
|
" -C <LCID>\t\tuse fixed <LCID> in random ePIDs\n" |
|
" -H <build>\t\tuse fixed <build> number in random ePIDs\n" |
|
# endif // NO_RANDOM_EPID |
|
# if !defined(NO_PRIVATE_IP_DETECT) |
|
# if HAVE_GETIFADDR |
|
" -o 0|1|2|3\t\tset protection level against clients with public IP addresses (default 0)\n" |
|
# else // !HAVE_GETIFADDR |
|
# ifndef USE_MSRPC |
|
" -o 0|2\t\tset protection level against clients with public IP addresses (default 0)\n" |
|
# else // USE_MSRPC |
|
" -o 0|2\t\tset protection level against clients with public IP addresses (default 0). Limited use with MS RPC\n" |
|
# endif // USE_MSRPC |
|
# endif // !HAVE_GETIFADDR |
|
# endif // !defined(NO_PRIVATE_IP_DETECT) |
|
# ifndef NO_TAP |
|
" -O <v>[=<a>][/<c>]\tuse VPN adapter <v> with IPv4 address <a> and CIDR <c>\n" |
|
# endif |
|
# ifndef NO_SOCKETS |
|
" -x <level>\t\texit if warning <level> reached (default 0)\n" |
|
# if !defined(USE_MSRPC) && !defined(SIMPLE_SOCKETS) |
|
" -L <address>[:<port>]\tlisten on IP address <address> with optional <port>\n" |
|
" -P <port>\t\tset TCP port <port> for subsequent -L statements (default 1688)\n" |
|
# if HAVE_FREEBIND |
|
" -F0, -F1\t\tdisable/enable binding to foreign IP addresses\n" |
|
# endif // HAVE_FREEBIND |
|
# else // defined(USE_MSRPC) || defined(SIMPLE_SOCKETS) |
|
" -P <port>\t\tuse TCP port <port> (default 1688)\n" |
|
# endif // defined(USE_MSRPC) || defined(SIMPLE_SOCKETS) |
|
# if !defined(NO_LIMIT) && !__minix__ |
|
" -m <clients>\t\tHandle max. <clients> simultaneously (default no limit)\n" |
|
# endif // !defined(NO_LIMIT) && !__minix__ |
|
# ifdef _NTSERVICE |
|
" -s\t\t\tinstall vlmcsd as an NT service. Ignores -e" |
|
# ifndef _WIN32 |
|
", -f and -D" |
|
# endif // _WIN32 |
|
"\n" |
|
" -S\t\t\tremove vlmcsd service. Ignores all other options\n" |
|
" -U <username>\t\trun NT service as <username>. Must be used with -s\n" |
|
" -W <password>\t\toptional <password> for -U. Must be used with -s\n" |
|
# endif // _NTSERVICE |
|
# ifndef NO_LOG |
|
" -e\t\t\tlog to stdout\n" |
|
# endif // NO_LOG |
|
# ifndef _WIN32 // |
|
" -D\t\t\trun in foreground\n" |
|
# else // _WIN32 |
|
" -D\t\t\tdoes nothing. Provided for compatibility with POSIX versions only\n" |
|
# endif // _WIN32 |
|
# endif // NO_SOCKETS |
|
# ifndef NO_STRICT_MODES |
|
" -K 0|1|2|3\t\tset white-listing level for KMS IDs (default -K0)\n" |
|
" -c0, -c1\t\tdisable/enable client time checking (default -c0)\n" |
|
# ifndef NO_CLIENT_LIST |
|
" -M0, -M1\t\tdisable/enable maintaining clients (default -M0)\n" |
|
" -E0, -E1\t\tdisable/enable start with empty client list (default -E0, ignored if -M0)\n" |
|
# endif // !NO_CLIENT_LIST |
|
# endif // !NO_STRICT_MODES |
|
# ifndef USE_MSRPC |
|
# if !defined(NO_TIMEOUT) && !__minix__ |
|
" -t <seconds>\t\tdisconnect clients after <seconds> of inactivity (default 30)\n" |
|
# endif // !defined(NO_TIMEOUT) && !__minix__ |
|
" -d\t\t\tdisconnect clients after each request\n" |
|
" -k\t\t\tdon't disconnect clients after each request (default)\n" |
|
# ifndef SIMPLE_RPC |
|
" -N0, -N1\t\tdisable/enable NDR64\n" |
|
" -B0, -B1\t\tdisable/enable bind time feature negotiation\n" |
|
# endif // !SIMPLE_RPC |
|
# endif // USE_MSRPC |
|
# ifndef NO_PID_FILE |
|
" -p <file>\t\twrite pid to <file>\n" |
|
# endif // NO_PID_FILE |
|
# ifndef NO_INI_FILE |
|
" -i <file>\t\tuse config file <file>\n" |
|
# endif // NO_INI_FILE |
|
# ifndef NO_EXTERNAL_DATA |
|
" -j <file>\t\tuse KMS data file <file>\n" |
|
# endif // !NO_EXTERNAL_DATA |
|
# ifndef NO_CUSTOM_INTERVALS |
|
" -R <interval>\t\trenew activation every <interval> (default 1w)\n" |
|
" -A <interval>\t\tretry activation every <interval> (default 2h)\n" |
|
# endif // NO_CUSTOM_INTERVALS |
|
# ifndef NO_LOG |
|
# ifndef _WIN32 |
|
" -l syslog log to syslog\n" |
|
# endif // _WIN32 |
|
" -l <file>\t\tlog to <file>\n" |
|
" -T0, -T1\t\tdisable/enable logging with time and date (default -T1)\n" |
|
# ifndef NO_VERBOSE_LOG |
|
" -v\t\t\tlog verbose\n" |
|
" -q\t\t\tdon't log verbose (default)\n" |
|
# endif // NO_VERBOSE_LOG |
|
# endif // NO_LOG |
|
# ifndef NO_VERSION_INFORMATION |
|
" -V\t\t\tdisplay version information and exit\n" |
|
# endif // NO_VERSION_INFORMATION |
|
, |
|
Version, global_argv[0]); |
|
|
|
exit(VLMCSD_EINVAL); |
|
} |
|
#endif // HELP |
|
|
|
|
|
#ifndef NO_CUSTOM_INTERVALS |
|
#ifndef NO_INI_FILE |
|
|
|
__pure static BOOL getTimeSpanFromIniFile(DWORD* result, const char *const restrict argument) |
|
{ |
|
const DWORD val = timeSpanString2Minutes(argument); |
|
|
|
if (!val) |
|
{ |
|
IniFileErrorMessage = "Incorrect time span."; |
|
return FALSE; |
|
} |
|
|
|
*result = val; |
|
return TRUE; |
|
} |
|
|
|
#endif // NO_INI_FILE |
|
|
|
|
|
__pure static DWORD getTimeSpanFromCommandLine(const char *const restrict arg, const char optchar) |
|
{ |
|
const DWORD val = timeSpanString2Minutes(arg); |
|
|
|
if (!val) |
|
{ |
|
printerrorf("Fatal: No valid time span specified in option -%c.\n", optchar); |
|
exit(VLMCSD_EINVAL); |
|
} |
|
|
|
return val; |
|
} |
|
|
|
#endif // NO_CUSTOM_INTERVALS |
|
|
|
|
|
#if !defined(NO_INI_FILE) || !defined (NO_CL_PIDS) |
|
static __pure int isControlCharOrSlash(const char c) |
|
{ |
|
if ((unsigned char)c < '!') return TRUE; |
|
if (c == '/') return TRUE; |
|
return FALSE; |
|
} |
|
|
|
|
|
static void iniFileLineNextWord(const char **s) |
|
{ |
|
while (**s && isspace((int)**s)) (*s)++; |
|
} |
|
|
|
|
|
static BOOL setHwIdFromIniFileLine(const char **s, const uint32_t index, const uint8_t overwrite) |
|
{ |
|
iniFileLineNextWord(s); |
|
|
|
if (**s == '/') |
|
{ |
|
if (!overwrite && KmsResponseParameters[index].HwId) return TRUE; |
|
|
|
BYTE* HwId = (BYTE*)vlmcsd_malloc(sizeof(((RESPONSE_V6 *)0)->HwId)); |
|
hex2bin(HwId, *s + 1, sizeof(((RESPONSE_V6 *)0)->HwId)); |
|
KmsResponseParameters[index].HwId = HwId; |
|
} |
|
|
|
return TRUE; |
|
} |
|
|
|
|
|
static BOOL setEpidFromIniFileLine(const char **s, const uint32_t index, const char *ePidSource, const uint8_t overwrite) |
|
{ |
|
iniFileLineNextWord(s); |
|
const char *savedPosition = *s; |
|
uint_fast16_t i; |
|
|
|
for (i = 0; !isControlCharOrSlash(**s); i++) |
|
{ |
|
if (utf8_to_ucs2_char((const unsigned char*)*s, (const unsigned char**)s) == (WCHAR)~0) |
|
{ |
|
return FALSE; |
|
} |
|
} |
|
|
|
if (i < 1 || i >= PID_BUFFER_SIZE) return FALSE; |
|
if (!overwrite && KmsResponseParameters[index].Epid) return TRUE; |
|
|
|
const size_t size = *s - savedPosition + 1; |
|
|
|
char* epidbuffer = (char*)vlmcsd_malloc(size); |
|
memcpy(epidbuffer, savedPosition, size - 1); |
|
epidbuffer[size - 1] = 0; |
|
|
|
KmsResponseParameters[index].Epid = epidbuffer; |
|
|
|
#ifndef NO_LOG |
|
KmsResponseParameters[index].EpidSource = ePidSource; |
|
#endif //NO_LOG |
|
|
|
return TRUE; |
|
} |
|
#endif // !defined(NO_INI_FILE) || !defined (NO_CL_PIDS) |
|
|
|
#ifndef NO_INI_FILE |
|
static void ignoreIniFileParameter(uint_fast8_t iniFileParameterId) |
|
{ |
|
uint_fast8_t i; |
|
|
|
for (i = 0; i < vlmcsd_countof(IniFileParameterList); i++) |
|
{ |
|
if (IniFileParameterList[i].Id != iniFileParameterId) continue; |
|
IniFileParameterList[i].Id = 0; |
|
break; |
|
} |
|
} |
|
#else // NO_INI_FILE |
|
#define ignoreIniFileParameter(x) |
|
#endif // NO_INI_FILE |
|
|
|
|
|
#ifndef NO_INI_FILE |
|
static BOOL getIniFileArgumentBool(int_fast8_t *result, const char *const argument) |
|
{ |
|
IniFileErrorMessage = "Argument must be true/on/yes/1 or false/off/no/0"; |
|
return getArgumentBool(result, argument); |
|
} |
|
|
|
|
|
static BOOL getIniFileArgumentInt(unsigned int *result, const char *const argument, const unsigned int min, const unsigned int max) |
|
{ |
|
unsigned int tempResult; |
|
|
|
if (!stringToInt(argument, min, max, &tempResult)) |
|
{ |
|
vlmcsd_snprintf(IniFileErrorBuffer, INIFILE_ERROR_BUFFERSIZE, "Must be integer between %u and %u", min, max); |
|
IniFileErrorMessage = IniFileErrorBuffer; |
|
return FALSE; |
|
} |
|
|
|
*result = tempResult; |
|
return TRUE; |
|
} |
|
|
|
|
|
static BOOL setIniFileParameter(uint_fast8_t id, const char *const iniarg) |
|
{ |
|
unsigned int result; |
|
BOOL success = TRUE; |
|
switch (id) |
|
{ |
|
# ifndef NO_TAP |
|
|
|
case INI_PARAM_VPN: |
|
tapArgument = (char*)vlmcsd_strdup(iniarg); |
|
break; |
|
|
|
# endif // NO_TAP |
|
|
|
# if !defined(NO_USER_SWITCH) && !_WIN32 |
|
|
|
case INI_PARAM_GID: |
|
{ |
|
struct group *g; |
|
IniFileErrorMessage = "Invalid group id or name"; |
|
if (!(gname = vlmcsd_strdup(iniarg))) return FALSE; |
|
|
|
if ((g = getgrnam(iniarg))) |
|
gid = g->gr_gid; |
|
else |
|
success = !GetNumericId(&gid, iniarg); |
|
break; |
|
} |
|
|
|
case INI_PARAM_UID: |
|
{ |
|
struct passwd *p; |
|
IniFileErrorMessage = "Invalid user id or name"; |
|
if (!(uname = vlmcsd_strdup(iniarg))) return FALSE; |
|
|
|
if ((p = getpwnam(iniarg))) |
|
uid = p->pw_uid; |
|
else |
|
success = !GetNumericId(&uid, iniarg); |
|
break; |
|
} |
|
|
|
# endif // !defined(NO_USER_SWITCH) && !defined(_WIN32) |
|
|
|
# ifndef NO_RANDOM_EPID |
|
|
|
case INI_PARAM_LCID: |
|
success = getIniFileArgumentInt(&result, iniarg, 0, 32767); |
|
if (success) Lcid = (uint16_t)result; |
|
break; |
|
|
|
case INI_PARAM_RANDOMIZATION_LEVEL: |
|
success = getIniFileArgumentInt(&result, iniarg, 0, 2); |
|
if (success) RandomizationLevel = (int_fast8_t)result; |
|
break; |
|
|
|
case INI_PARAM_HOST_BUILD: |
|
success = getIniFileArgumentInt(&result, iniarg, 0, 65535); |
|
if (success) HostBuild = (uint16_t)result; |
|
break; |
|
|
|
# endif // NO_RANDOM_EPID |
|
|
|
# if (defined(USE_MSRPC) || defined(SIMPLE_SOCKETS) || defined(HAVE_GETIFADDR)) && !defined(NO_SOCKETS) |
|
|
|
case INI_PARAM_PORT: |
|
defaultport = vlmcsd_strdup(iniarg); |
|
break; |
|
|
|
# endif // (defined(USE_MSRPC) || defined(SIMPLE_SOCKETS) || defined(HAVE_GETIFADDR)) && !defined(NO_SOCKETS) |
|
|
|
# if !defined(NO_SOCKETS) && !defined(USE_MSRPC) && !defined(SIMPLE_SOCKETS) |
|
|
|
case INI_PARAM_LISTEN: |
|
maxsockets++; |
|
return TRUE; |
|
|
|
# endif // !defined(NO_SOCKETS) && !defined(USE_MSRPC) && !defined(SIMPLE_SOCKETS) |
|
# if !defined(NO_LIMIT) && !defined(NO_SOCKETS) && !__minix__ |
|
|
|
case INI_PARAM_MAX_WORKERS: |
|
# ifdef USE_MSRPC |
|
success = getIniFileArgumentInt(&MaxTasks, iniarg, 1, RPC_C_LISTEN_MAX_CALLS_DEFAULT); |
|
# else // !USE_MSRPC |
|
success = getIniFileArgumentInt(&MaxTasks, iniarg, 1, SEM_VALUE_MAX); |
|
# endif // !USE_MSRPC |
|
break; |
|
|
|
# endif // !defined(NO_LIMIT) && !defined(NO_SOCKETS) && !__minix__ |
|
|
|
# ifndef NO_PID_FILE |
|
|
|
case INI_PARAM_PID_FILE: |
|
fn_pid = vlmcsd_strdup(iniarg); |
|
break; |
|
|
|
# endif // NO_PID_FILE |
|
|
|
# ifndef NO_EXTERNAL_DATA |
|
|
|
case INI_PARAM_DATA_FILE: |
|
fn_data = vlmcsd_strdup(iniarg); |
|
# ifndef NO_INTERNAL_DATA |
|
ExplicitDataLoad = TRUE; |
|
# endif // NO_INTERNAL_DATA |
|
break; |
|
|
|
# endif // NO_EXTERNAL_DATA |
|
|
|
# ifndef NO_STRICT_MODES |
|
|
|
case INI_PARAM_WHITELISTING_LEVEL: |
|
success = getIniFileArgumentInt(&WhitelistingLevel, iniarg, 0, 3); |
|
break; |
|
|
|
case INI_PARAM_CHECK_CLIENT_TIME: |
|
success = getIniFileArgumentBool(&CheckClientTime, iniarg); |
|
break; |
|
|
|
# ifndef NO_CLIENT_LIST |
|
case INI_PARAM_MAINTAIN_CLIENTS: |
|
success = getIniFileArgumentBool(&MaintainClients, iniarg); |
|
break; |
|
|
|
case INI_PARAM_START_EMPTY: |
|
success = getIniFileArgumentBool(&StartEmpty, iniarg); |
|
break; |
|
|
|
# endif // NO_CLIENT_LIST |
|
# endif // !NO_STRICT_MODES |
|
|
|
|
|
# ifndef NO_LOG |
|
|
|
case INI_PARAM_LOG_FILE: |
|
fn_log = vlmcsd_strdup(iniarg); |
|
break; |
|
|
|
case INI_PARAM_LOG_DATE_AND_TIME: |
|
success = getIniFileArgumentBool(&LogDateAndTime, iniarg); |
|
break; |
|
|
|
# ifndef NO_VERBOSE_LOG |
|
case INI_PARAM_LOG_VERBOSE: |
|
success = getIniFileArgumentBool(&logverbose, iniarg); |
|
break; |
|
|
|
# endif // NO_VERBOSE_LOG |
|
# endif // NO_LOG |
|
|
|
# ifndef NO_CUSTOM_INTERVALS |
|
|
|
case INI_PARAM_ACTIVATION_INTERVAL: |
|
success = getTimeSpanFromIniFile(&VLActivationInterval, iniarg); |
|
break; |
|
|
|
case INI_PARAM_RENEWAL_INTERVAL: |
|
success = getTimeSpanFromIniFile(&VLRenewalInterval, iniarg); |
|
break; |
|
|
|
# endif // NO_CUSTOM_INTERVALS |
|
|
|
# ifndef USE_MSRPC |
|
|
|
# if !defined(NO_TIMEOUT) && !__minix__ |
|
|
|
case INI_PARAM_CONNECTION_TIMEOUT: |
|
success = getIniFileArgumentInt(&result, iniarg, 1, 600); |
|
if (success) ServerTimeout = (DWORD)result; |
|
break; |
|
|
|
# endif // !defined(NO_TIMEOUT) && !__minix__ |
|
|
|
case INI_PARAM_DISCONNECT_IMMEDIATELY: |
|
success = getIniFileArgumentBool(&DisconnectImmediately, iniarg); |
|
break; |
|
|
|
case INI_PARAM_RPC_NDR64: |
|
success = getIniFileArgumentBool(&UseServerRpcNDR64, iniarg); |
|
if (success) IsNDR64Defined = TRUE; |
|
break; |
|
|
|
case INI_PARAM_RPC_BTFN: |
|
success = getIniFileArgumentBool(&UseServerRpcBTFN, iniarg); |
|
break; |
|
|
|
# endif // USE_MSRPC |
|
|
|
# ifndef NO_SOCKETS |
|
|
|
case INI_PARAM_EXIT_LEVEL: |
|
success = getIniFileArgumentInt(&result, iniarg, 0, 1); |
|
if (success) ExitLevel = (int_fast8_t)result; |
|
break; |
|
|
|
# endif // NO_SOCKETS |
|
|
|
# if HAVE_FREEBIND |
|
|
|
case INI_PARAM_FREEBIND: |
|
success = getIniFileArgumentBool(&freebind, iniarg); |
|
break; |
|
|
|
# endif // HAVE_FREEBIND |
|
|
|
# if !defined(NO_PRIVATE_IP_DETECT) |
|
|
|
case INI_PARAM_PUBLIC_IP_PROTECTION_LEVEL: |
|
success = getIniFileArgumentInt(&PublicIPProtectionLevel, iniarg, 0, 3); |
|
|
|
# if !HAVE_GETIFADDR |
|
if (PublicIPProtectionLevel & 1) |
|
{ |
|
IniFileErrorMessage = "Must be 0 or 2"; |
|
success = FALSE; |
|
} |
|
# endif // !HAVE_GETIFADDR |
|
|
|
break; |
|
|
|
# endif // !defined(NO_PRIVATE_IP_DETECT) |
|
|
|
default: |
|
return FALSE; |
|
} |
|
|
|
return success; |
|
} |
|
|
|
|
|
static BOOL getIniFileArgument(const char **s) |
|
{ |
|
while (!isspace((int)**s) && **s != '=' && **s) (*s)++; |
|
iniFileLineNextWord(s); |
|
|
|
if (*((*s)++) != '=') |
|
{ |
|
IniFileErrorMessage = "'=' required after keyword."; |
|
return FALSE; |
|
} |
|
|
|
iniFileLineNextWord(s); |
|
|
|
if (!**s) |
|
{ |
|
IniFileErrorMessage = "missing argument after '='."; |
|
return FALSE; |
|
} |
|
|
|
return TRUE; |
|
} |
|
|
|
static char* GetNextString(char* s) |
|
{ |
|
return s + strlen(s) + 1; |
|
} |
|
|
|
static int8_t GetCsvlkIndexFromName(const char *s) |
|
{ |
|
int8_t i; |
|
|
|
for (i = 0; i < KmsData->CsvlkCount; i++) |
|
{ |
|
const char *csvlkName = GetNextString(KmsData->CsvlkData[i].EPid); |
|
|
|
if (!strncasecmp(csvlkName, s, strlen(csvlkName))) |
|
{ |
|
return i; |
|
} |
|
} |
|
|
|
return -1; |
|
} |
|
|
|
static BOOL handleIniFileEpidParameter(const char *s, uint8_t allowIniFileDirectives, const char *ePidSource) |
|
{ |
|
int_fast16_t i; |
|
|
|
if (allowIniFileDirectives) |
|
{ |
|
for (i = 0; i < (int_fast16_t)vlmcsd_countof(IniFileParameterList); i++) |
|
{ |
|
if (!strncasecmp(IniFileParameterList[i].Name, s, strlen(IniFileParameterList[i].Name))) |
|
{ |
|
return TRUE; |
|
} |
|
} |
|
} |
|
|
|
i = GetCsvlkIndexFromName(s); |
|
|
|
if (i >= 0) |
|
{ |
|
if (!getIniFileArgument(&s)) return FALSE; |
|
if (!setEpidFromIniFileLine(&s, i, ePidSource, !allowIniFileDirectives)) return FALSE; |
|
if (!setHwIdFromIniFileLine(&s, i, !allowIniFileDirectives)) return FALSE; |
|
return TRUE; |
|
} |
|
|
|
IniFileErrorMessage = "Unknown keyword."; |
|
return FALSE; |
|
} |
|
|
|
static BOOL handleIniFileParameter(const char *s) |
|
{ |
|
uint_fast8_t i; |
|
|
|
for (i = 0; i < vlmcsd_countof(IniFileParameterList); i++) |
|
{ |
|
if (strncasecmp(IniFileParameterList[i].Name, s, strlen(IniFileParameterList[i].Name))) continue; |
|
if (!IniFileParameterList[i].Id) return TRUE; |
|
if (!getIniFileArgument(&s)) return FALSE; |
|
|
|
return setIniFileParameter(IniFileParameterList[i].Id, s); |
|
} |
|
|
|
IniFileErrorMessage = NULL; |
|
return TRUE; |
|
} |
|
|
|
|
|
#if !defined(NO_SOCKETS) && !defined(SIMPLE_SOCKETS) && !defined(USE_MSRPC) |
|
static BOOL setupListeningSocketsFromIniFile(const char *s) |
|
{ |
|
if (!maxsockets) return TRUE; |
|
if (strncasecmp("Listen", s, 6)) return TRUE; |
|
if (!getIniFileArgument(&s)) return TRUE; |
|
|
|
vlmcsd_snprintf(IniFileErrorBuffer, INIFILE_ERROR_BUFFERSIZE, "Cannot listen on %s.", s); |
|
IniFileErrorMessage = IniFileErrorBuffer; |
|
return addListeningSocket(s); |
|
} |
|
#endif // !defined(NO_SOCKETS) && !defined(SIMPLE_SOCKETS) && !defined(USE_MSRPC) |
|
|
|
|
|
static BOOL readIniFile(const uint_fast8_t pass) |
|
{ |
|
char line[256]; |
|
const char *s; |
|
unsigned int lineNumber; |
|
uint_fast8_t lineParseError; |
|
|
|
FILE *restrict f; |
|
BOOL result = TRUE; |
|
|
|
if (pass == INI_FILE_PASS_2 && KmsData->MinorVer < 6) |
|
{ |
|
return TRUE; |
|
} |
|
|
|
IniFileErrorBuffer = (char*)vlmcsd_malloc(INIFILE_ERROR_BUFFERSIZE); |
|
|
|
if (!((f = fopen(fn_ini, "r")))) return FALSE; |
|
|
|
for (lineNumber = 1; (s = fgets(line, sizeof(line), f)); lineNumber++) |
|
{ |
|
line[strlen(line) - 1] = 0; |
|
|
|
iniFileLineNextWord(&s); |
|
if (*s == ';' || *s == '#' || !*s) continue; |
|
|
|
if (pass == INI_FILE_PASS_1) |
|
{ |
|
if (handleIniFileParameter(s)) continue; |
|
lineParseError = TRUE; |
|
} |
|
else if (pass == INI_FILE_PASS_2) |
|
{ |
|
if (handleIniFileEpidParameter(s, TRUE, fn_ini)) continue; |
|
lineParseError = TRUE; |
|
} |
|
# if !defined(NO_SOCKETS) && !defined(SIMPLE_SOCKETS) && !defined(USE_MSRPC) |
|
else if (pass == INI_FILE_PASS_3) |
|
{ |
|
lineParseError = !setupListeningSocketsFromIniFile(s); |
|
} |
|
else |
|
{ |
|
return FALSE; |
|
} |
|
# endif // !defined(NO_SOCKETS) && && !defined(SIMPLE_SOCKETS) && !defined(USE_MSRPC) |
|
|
|
if (lineParseError) |
|
{ |
|
printerrorf("Warning: %s line %u: \"%s\". %s\n", fn_ini, lineNumber, line, IniFileErrorMessage); |
|
continue; |
|
} |
|
} |
|
|
|
if (ferror(f)) result = FALSE; |
|
|
|
free(IniFileErrorBuffer); |
|
fclose(f); |
|
|
|
# if !defined(NO_SOCKETS) && !defined(NO_LOG) |
|
|
|
if (pass == INI_FILE_PASS_1 && !InetdMode && result) |
|
{ |
|
# ifdef _NTSERVICE |
|
if (!installService) |
|
# endif // _NTSERVICE |
|
logger("Read ini file %s\n", fn_ini); |
|
} |
|
|
|
# endif // !defined(NO_SOCKETS) && !defined(NO_LOG) |
|
|
|
return result; |
|
} |
|
#endif // NO_INI_FILE |
|
|
|
|
|
#if !defined(NO_SOCKETS) |
|
#if !defined(_WIN32) |
|
#if !defined(NO_SIGHUP) |
|
static void exec_self(char** argv) |
|
{ |
|
getExeName(); |
|
|
|
if (fn_exe != NULL) |
|
{ |
|
execv(fn_exe, argv); |
|
} |
|
else |
|
{ |
|
execvp(argv[0], argv); |
|
} |
|
} |
|
|
|
|
|
__noreturn static void HangupHandler(const int signal_unused) |
|
{ |
|
int i; |
|
int_fast8_t daemonize_protection = TRUE; |
|
CARGV argv_in = multi_argv == NULL ? global_argv : multi_argv; |
|
int argc_in = multi_argc == 0 ? global_argc : multi_argc; |
|
const char** argv_out = (const char**)vlmcsd_malloc((argc_in + 2) * sizeof(char**)); |
|
|
|
for (i = 0; i < argc_in; i++) |
|
{ |
|
if (!strcmp(argv_in[i], "-Z")) daemonize_protection = FALSE; |
|
argv_out[i] = argv_in[i]; |
|
} |
|
|
|
argv_out[argc_in] = argv_out[argc_in + 1] = NULL; |
|
if (daemonize_protection) argv_out[argc_in] = (char*) "-Z"; |
|
|
|
exec_self((char**)argv_out); |
|
int error = errno; |
|
|
|
# ifndef NO_LOG |
|
logger("Fatal: Unable to restart on SIGHUP: %s\n", strerror(error)); |
|
# endif |
|
|
|
# ifndef NO_PID_FILE |
|
if (fn_pid) unlink(fn_pid); |
|
# endif // NO_PID_FILE |
|
exit(error); |
|
} |
|
#endif // NO_SIGHUP |
|
|
|
|
|
__noreturn static void terminationHandler(const int signal_unused) |
|
{ |
|
cleanup(); |
|
exit(0); |
|
} |
|
|
|
|
|
#if defined(CHILD_HANDLER) || __minix__ |
|
static void childHandler(const int signal) |
|
{ |
|
waitpid(-1, NULL, WNOHANG); |
|
} |
|
#endif // defined(CHILD_HANDLER) || __minix__ |
|
|
|
|
|
static int daemonizeAndSetSignalAction() |
|
{ |
|
struct sigaction sa; |
|
sigemptyset(&sa.sa_mask); |
|
|
|
# ifndef NO_LOG |
|
if (!nodaemon) if (daemon(!0, logstdout)) |
|
# else // NO_LOG |
|
if (!nodaemon) if (daemon(!0, 0)) |
|
# endif // NO_LOG |
|
{ |
|
printerrorf("Fatal: Could not daemonize to background.\n"); |
|
return(errno); |
|
} |
|
|
|
if (!InetdMode) |
|
{ |
|
# ifndef USE_THREADS |
|
|
|
# if defined(CHILD_HANDLER) || __minix__ |
|
sa.sa_handler = childHandler; |
|
# else // !(defined(CHILD_HANDLER) || __minix__) |
|
sa.sa_handler = SIG_IGN; |
|
# endif // !(defined(CHILD_HANDLER) || __minix__) |
|
sa.sa_flags = SA_NOCLDWAIT; |
|
|
|
if (sigaction(SIGCHLD, &sa, NULL)) |
|
return(errno); |
|
|
|
# endif // !USE_THREADS |
|
|
|
sa.sa_handler = terminationHandler; |
|
sa.sa_flags = 0; |
|
|
|
sigaction(SIGINT, &sa, NULL); |
|
sigaction(SIGTERM, &sa, NULL); |
|
|
|
# ifndef NO_SIGHUP |
|
sa.sa_handler = HangupHandler; |
|
sa.sa_flags = SA_NODEFER; |
|
sigaction(SIGHUP, &sa, NULL); |
|
# endif // NO_SIGHUP |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
|
|
#else // _WIN32 |
|
|
|
static BOOL __stdcall terminationHandler(const DWORD fdwCtrlType) |
|
{ |
|
// What a lame substitute for Unix signal handling |
|
switch (fdwCtrlType) |
|
{ |
|
case CTRL_C_EVENT: |
|
case CTRL_CLOSE_EVENT: |
|
case CTRL_BREAK_EVENT: |
|
case CTRL_LOGOFF_EVENT: |
|
case CTRL_SHUTDOWN_EVENT: |
|
cleanup(); |
|
exit(0); |
|
default: |
|
return FALSE; |
|
} |
|
} |
|
|
|
|
|
static DWORD daemonizeAndSetSignalAction() |
|
{ |
|
if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)terminationHandler, TRUE)) |
|
{ |
|
#ifndef NO_LOG |
|
const DWORD rc = GetLastError(); |
|
logger("Warning: Could not register Windows signal handler: Error %u\n", rc); |
|
#endif // NO_LOG |
|
} |
|
|
|
return ERROR_SUCCESS; |
|
} |
|
#endif // _WIN32 |
|
#endif // !defined(NO_SOCKETS) |
|
|
|
|
|
// Workaround for Cygwin fork problem (only affects cygwin processes that are Windows services) |
|
// Best is to compile for Cygwin with threads. fork() is slow and unreliable on Cygwin |
|
#if !defined(NO_INI_FILE) || !defined(NO_LOG) || !defined(NO_CL_PIDS) || !defined(NO_EXTERNAL_DATA) |
|
__pure static char* getCommandLineArg(char *const restrict arg) |
|
{ |
|
# if !__CYGWIN__ || defined(USE_THREADS) || defined(NO_SOCKETS) |
|
return arg; |
|
# else |
|
if (!IsNTService) return arg; |
|
|
|
return vlmcsd_strdup(arg); |
|
# endif |
|
} |
|
#endif // !defined(NO_INI_FILE) || !defined(NO_LOG) || !defined(NO_CL_PIDS) || !defined(NO_EXTERNAL_DATA) |
|
|
|
|
|
static void parseGeneralArguments() { |
|
int o; |
|
|
|
for (opterr = 0; (o = getopt(global_argc, (char* const*)global_argv, (const char*)optstring)) > 0; ) switch (o) |
|
{ |
|
# if !defined(NO_SOCKETS) && !defined(NO_SIGHUP) && !defined(_WIN32) |
|
case 'Z': |
|
IsRestarted = TRUE; |
|
nodaemon = TRUE; |
|
break; |
|
# endif // !defined(NO_SOCKETS) && !defined(NO_SIGHUP) && !defined(_WIN32) |
|
|
|
# ifndef NO_TAP |
|
|
|
case 'O': |
|
ignoreIniFileParameter(INI_PARAM_VPN); |
|
tapArgument = getCommandLineArg(optarg); |
|
break; |
|
|
|
# endif // NO_TAP |
|
|
|
# ifndef NO_CL_PIDS |
|
|
|
case 'a': |
|
break; |
|
|
|
# endif // NO_CL_PIDS |
|
|
|
# ifndef NO_EXTERNAL_DATA |
|
|
|
case 'j': |
|
ignoreIniFileParameter(INI_PARAM_DATA_FILE); |
|
fn_data = getCommandLineArg(optarg); |
|
# ifndef NO_INTERNAL_DATA |
|
ExplicitDataLoad = TRUE; |
|
# endif // NO_INTERNAL_DATA |
|
break; |
|
|
|
# endif // NO_EXTERNAL_DATA |
|
|
|
# ifndef NO_SOCKETS |
|
|
|
case 'x': |
|
ignoreIniFileParameter(INI_PARAM_EXIT_LEVEL); |
|
ExitLevel = (int_fast8_t)getOptionArgumentInt((char)o, 0, 1); |
|
break; |
|
|
|
case 'P': |
|
ignoreIniFileParameter(INI_PARAM_PORT); |
|
# if !defined(SIMPLE_SOCKETS) && !defined(USE_MSRPC) |
|
ignoreIniFileParameter(INI_PARAM_LISTEN); |
|
# else |
|
defaultport = optarg; |
|
# endif // !SIMPLE_SOCKETS |
|
break; |
|
|
|
# if !defined(NO_LIMIT) && !__minix__ |
|
|
|
case 'm': |
|
# ifdef USE_MSRPC |
|
MaxTasks = getOptionArgumentInt(o, 1, RPC_C_LISTEN_MAX_CALLS_DEFAULT); |
|
# else // !USE_MSRPC |
|
MaxTasks = getOptionArgumentInt((char)o, 1, SEM_VALUE_MAX); |
|
# endif // !USE_MSRPC |
|
ignoreIniFileParameter(INI_PARAM_MAX_WORKERS); |
|
break; |
|
|
|
# endif // !defined(NO_LIMIT) && !__minix__ |
|
# endif // NO_SOCKETS |
|
|
|
# if !defined(NO_TIMEOUT) && !__minix__ && !defined(USE_MSRPC) |
|
case 't': |
|
ServerTimeout = getOptionArgumentInt((char)o, 1, 600); |
|
ignoreIniFileParameter(INI_PARAM_CONNECTION_TIMEOUT); |
|
break; |
|
# endif // !defined(NO_TIMEOUT) && !__minix__ && !defined(USE_MSRPC) |
|
|
|
# ifndef NO_PID_FILE |
|
case 'p': |
|
fn_pid = getCommandLineArg(optarg); |
|
ignoreIniFileParameter(INI_PARAM_PID_FILE); |
|
break; |
|
# endif |
|
|
|
# ifndef NO_INI_FILE |
|
case 'i': |
|
fn_ini = getCommandLineArg(optarg); |
|
if (!strcmp(fn_ini, "-")) fn_ini = NULL; |
|
break; |
|
# endif |
|
|
|
# ifndef NO_LOG |
|
|
|
case 'T': |
|
if (!getArgumentBool(&LogDateAndTime, optarg)) usage(); |
|
ignoreIniFileParameter(INI_PARAM_LOG_DATE_AND_TIME); |
|
break; |
|
|
|
case 'l': |
|
fn_log = getCommandLineArg(optarg); |
|
ignoreIniFileParameter(INI_PARAM_LOG_FILE); |
|
break; |
|
|
|
# ifndef NO_VERBOSE_LOG |
|
case 'v': |
|
case 'q': |
|
logverbose = o == 'v'; |
|
ignoreIniFileParameter(INI_PARAM_LOG_VERBOSE); |
|
break; |
|
|
|
# endif // NO_VERBOSE_LOG |
|
# endif // NO_LOG |
|
|
|
# if !defined(NO_PRIVATE_IP_DETECT) |
|
case 'o': |
|
ignoreIniFileParameter(INI_PARAM_PUBLIC_IP_PROTECTION_LEVEL); |
|
PublicIPProtectionLevel = getOptionArgumentInt((char)o, 0, 3); |
|
|
|
# if !HAVE_GETIFADDR |
|
if (PublicIPProtectionLevel & 1) usage(); |
|
# endif // !HAVE_GETIFADDR |
|
|
|
break; |
|
# endif // !defined(NO_PRIVATE_IP_DETECT) |
|
|
|
# ifndef NO_SOCKETS |
|
# if !defined(USE_MSRPC) && !defined(SIMPLE_SOCKETS) |
|
case 'L': |
|
maxsockets++; |
|
ignoreIniFileParameter(INI_PARAM_LISTEN); |
|
break; |
|
# if HAVE_FREEBIND |
|
case 'F': |
|
if (!getArgumentBool(&freebind, optarg)) usage(); |
|
ignoreIniFileParameter(INI_PARAM_FREEBIND); |
|
break; |
|
# endif // HAVE_FREEBIND |
|
# endif // !defined(USE_MSRPC) && !defined(SIMPLE_SOCKETS) |
|
|
|
# ifdef _NTSERVICE |
|
case 'U': |
|
ServiceUser = optarg; |
|
break; |
|
|
|
case 'W': |
|
ServicePassword = optarg; |
|
break; |
|
|
|
case 's': |
|
# ifndef USE_MSRPC |
|
if (InetdMode) usage(); |
|
# endif // USE_MSRPC |
|
if (!IsNTService) installService = 1; // Install |
|
break; |
|
|
|
case 'S': |
|
if (!IsNTService) installService = 2; // Remove |
|
break; |
|
# endif // _NTSERVICE |
|
|
|
# ifndef NO_STRICT_MODES |
|
|
|
case 'K': |
|
WhitelistingLevel = (int_fast8_t)getOptionArgumentInt((char)o, 0, 3); |
|
ignoreIniFileParameter(INI_PARAM_WHITELISTING_LEVEL); |
|
break; |
|
|
|
case 'c': |
|
if (!getArgumentBool(&CheckClientTime, optarg)) usage(); |
|
ignoreIniFileParameter(INI_PARAM_CHECK_CLIENT_TIME); |
|
break; |
|
|
|
# ifndef NO_CLIENT_LIST |
|
case 'E': |
|
if (!getArgumentBool(&StartEmpty, optarg)) usage(); |
|
ignoreIniFileParameter(INI_PARAM_START_EMPTY); |
|
break; |
|
|
|
case 'M': |
|
if (!getArgumentBool(&MaintainClients, optarg)) usage(); |
|
ignoreIniFileParameter(INI_PARAM_MAINTAIN_CLIENTS); |
|
break; |
|
|
|
# endif // !NO_CLIENT_LIST |
|
# endif // !NO_STRICT_MODES |
|
|
|
case 'D': |
|
# ifndef _WIN32 |
|
nodaemon = 1; |
|
# else // _WIN32 |
|
# ifdef _PEDANTIC |
|
printerrorf("Warning: Option -D has no effect in the Windows version of vlmcsd.\n"); |
|
# endif // _PEDANTIC |
|
# endif // _WIN32 |
|
break; |
|
|
|
# ifndef NO_LOG |
|
|
|
case 'e': |
|
logstdout = 1; |
|
break; |
|
|
|
# endif // NO_LOG |
|
# endif // NO_SOCKETS |
|
|
|
# ifndef NO_RANDOM_EPID |
|
case 'r': |
|
RandomizationLevel = (int_fast8_t)getOptionArgumentInt((char)o, 0, 2); |
|
ignoreIniFileParameter(INI_PARAM_RANDOMIZATION_LEVEL); |
|
break; |
|
|
|
case 'C': |
|
Lcid = (uint16_t)getOptionArgumentInt((char)o, 0, 32767); |
|
|
|
ignoreIniFileParameter(INI_PARAM_LCID); |
|
|
|
# ifdef _PEDANTIC |
|
if (!IsValidLcid(Lcid)) |
|
{ |
|
printerrorf("Warning: %s is not a valid LCID.\n", optarg); |
|
} |
|
# endif // _PEDANTIC |
|
|
|
break; |
|
|
|
case 'H': |
|
HostBuild = (uint16_t)getOptionArgumentInt((char)o, 0, 0xffff); |
|
ignoreIniFileParameter(INI_PARAM_HOST_BUILD); |
|
|
|
# ifdef _PEDANTIC |
|
if (!IsValidHostBuild(HostBuild)) |
|
{ |
|
printerrorf("Warning: %u is not a known released Windows Server build >= 2008.\n"); |
|
} |
|
# endif // _PEDANTIC |
|
|
|
break; |
|
# endif // NO_RANDOM_PID |
|
|
|
# if !defined(NO_USER_SWITCH) && !defined(_WIN32) |
|
case 'g': |
|
gname = optarg; |
|
ignoreIniFileParameter(INI_PARAM_GID); |
|
# ifndef NO_SIGHUP |
|
if (!IsRestarted) |
|
# endif // NO_SIGHUP |
|
if (GetGid()) |
|
{ |
|
printerrorf("Fatal: %s for %s failed: %s\n", "setgid", gname, strerror(errno)); |
|
exit(errno); |
|
} |
|
break; |
|
|
|
case 'u': |
|
uname = optarg; |
|
ignoreIniFileParameter(INI_PARAM_UID); |
|
# ifndef NO_SIGHUP |
|
if (!IsRestarted) |
|
# endif // NO_SIGHUP |
|
if (GetUid()) |
|
{ |
|
printerrorf("Fatal: %s for %s failed: %s\n", "setuid", uname, strerror(errno)); |
|
exit(errno); |
|
} |
|
break; |
|
# endif // NO_USER_SWITCH && !_WIN32 |
|
|
|
# ifndef NO_CUSTOM_INTERVALS |
|
case 'R': |
|
VLRenewalInterval = getTimeSpanFromCommandLine(optarg, (char)o); |
|
ignoreIniFileParameter(INI_PARAM_RENEWAL_INTERVAL); |
|
break; |
|
|
|
case 'A': |
|
VLActivationInterval = getTimeSpanFromCommandLine(optarg, (char)o); |
|
ignoreIniFileParameter(INI_PARAM_ACTIVATION_INTERVAL); |
|
break; |
|
# endif // NO_CUSTOM_INTERVALS |
|
|
|
# ifndef USE_MSRPC |
|
case 'd': |
|
case 'k': |
|
DisconnectImmediately = o == 'd'; |
|
ignoreIniFileParameter(INI_PARAM_DISCONNECT_IMMEDIATELY); |
|
break; |
|
|
|
# ifndef SIMPLE_RPC |
|
case 'N': |
|
if (!getArgumentBool(&UseServerRpcNDR64, optarg)) usage(); |
|
IsNDR64Defined = TRUE; |
|
ignoreIniFileParameter(INI_PARAM_RPC_NDR64); |
|
break; |
|
|
|
case 'B': |
|
if (!getArgumentBool(&UseServerRpcBTFN, optarg)) usage(); |
|
ignoreIniFileParameter(INI_PARAM_RPC_BTFN); |
|
break; |
|
# endif // !SIMPLE_RPC |
|
# endif // !USE_MSRPC |
|
|
|
# ifndef NO_VERSION_INFORMATION |
|
case 'V': |
|
# ifdef _NTSERVICE |
|
if (IsNTService) break; |
|
# endif |
|
# if defined(__s390__) && !defined(__zarch__) && !defined(__s390x__) |
|
printf("vlmcsd %s %i-bit\n", Version, sizeof(void*) == 4 ? 31 : (int)sizeof(void*) << 3); |
|
# else |
|
printf("vlmcsd %s %i-bit\n", Version, (int)sizeof(void*) << 3); |
|
# endif // defined(__s390__) && !defined(__zarch__) && !defined(__s390x__) |
|
printPlatform(); |
|
printCommonFlags(); |
|
printServerFlags(); |
|
exit(0); |
|
# endif // NO_VERSION_INFORMATION |
|
|
|
default: |
|
usage(); |
|
} |
|
|
|
// Do not allow non-option arguments |
|
if (optind != global_argc) |
|
usage(); |
|
|
|
# ifdef _NTSERVICE |
|
// -U and -W must be used with -s |
|
if ((ServiceUser || *ServicePassword) && installService != 1) usage(); |
|
# endif // _NTSERVICE |
|
} |
|
|
|
|
|
#if !defined(NO_PID_FILE) |
|
static void writePidFile() |
|
{ |
|
# ifndef NO_SIGHUP |
|
if (IsRestarted) return; |
|
# endif // NO_SIGHUP |
|
|
|
if (fn_pid && !InetdMode) |
|
{ |
|
FILE *file = fopen(fn_pid, "w"); |
|
|
|
if (file) |
|
{ |
|
# if _MSC_VER |
|
fprintf(file, "%u", (unsigned int)GetCurrentProcessId()); |
|
# else |
|
fprintf(file, "%u", (unsigned int)getpid()); |
|
# endif |
|
fclose(file); |
|
} |
|
|
|
# ifndef NO_LOG |
|
else |
|
{ |
|
logger("Warning: Cannot write pid file '%s'. %s.\n", fn_pid, strerror(errno)); |
|
} |
|
# endif // NO_LOG |
|
} |
|
} |
|
#else |
|
#define writePidFile() |
|
#endif // !defined(NO_PID_FILE) |
|
|
|
#if !defined(NO_SOCKETS) && !defined(USE_MSRPC) |
|
|
|
void cleanup() |
|
{ |
|
if (!InetdMode) |
|
{ |
|
# ifndef NO_CLIENT_LIST |
|
if (MaintainClients) CleanUpClientLists(); |
|
# endif // !NO_CLIENT_LIST |
|
|
|
# ifndef NO_PID_FILE |
|
if (fn_pid) vlmcsd_unlink(fn_pid); |
|
# endif // NO_PID_FILE |
|
closeAllListeningSockets(); |
|
|
|
# if !defined(NO_LIMIT) && !defined(NO_SOCKETS) && !defined(_WIN32) && !__minix__ |
|
sem_unlink("/vlmcsd"); |
|
# if !defined(USE_THREADS) && !defined(CYGWIN) |
|
if (shmid >= 0) |
|
{ |
|
if (MaxTaskSemaphore != (sem_t*)-1) shmdt(MaxTaskSemaphore); |
|
shmctl(shmid, IPC_RMID, NULL); |
|
} |
|
# endif // !defined(USE_THREADS) && !defined(CYGWIN) |
|
# endif // !defined(NO_LIMIT) && !defined(NO_SOCKETS) && !defined(_WIN32) && !__minix__ |
|
|
|
# ifndef NO_LOG |
|
logger("vlmcsd %s was shutdown\n", Version); |
|
# endif // NO_LOG |
|
} |
|
} |
|
|
|
#elif defined(USE_MSRPC) |
|
|
|
void cleanup() |
|
{ |
|
# ifndef NO_PID_FILE |
|
if (fn_pid) unlink(fn_pid); |
|
# endif // NO_PID_FILE |
|
|
|
# ifndef NO_LOG |
|
logger("vlmcsd %s was shutdown\n", Version); |
|
# endif // NO_LOG |
|
} |
|
|
|
#else // Neither Sockets nor RPC |
|
|
|
__pure void cleanup() {} |
|
|
|
#endif // Neither Sockets nor RPC |
|
|
|
|
|
#if !defined(USE_MSRPC) && !defined(NO_LIMIT) && !defined(NO_SOCKETS) && !__minix__ |
|
// Get a semaphore for limiting the maximum concurrent tasks |
|
static void allocateSemaphore(void) |
|
{ |
|
# ifdef USE_THREADS |
|
# define sharemode 0 |
|
# else |
|
# define sharemode 1 |
|
# endif |
|
|
|
# ifndef _WIN32 |
|
sem_unlink("/vlmcsd"); |
|
# endif |
|
|
|
if (MaxTasks < SEM_VALUE_MAX && !InetdMode) |
|
{ |
|
# ifndef _WIN32 |
|
|
|
# if !defined(USE_THREADS) && !defined(CYGWIN) |
|
|
|
if ((MaxTaskSemaphore = sem_open("/vlmcsd", O_CREAT /*| O_EXCL*/, 0700, MaxTasks)) == SEM_FAILED) // fails on many systems |
|
{ |
|
// We didn't get a named Semaphore (/dev/shm on Linux) so let's try our own shared page |
|
|
|
if ( |
|
(shmid = shmget(IPC_PRIVATE, sizeof(sem_t), IPC_CREAT | 0600)) < 0 || |
|
(MaxTaskSemaphore = (sem_t*)shmat(shmid, NULL, 0)) == (sem_t*)-1 || |
|
sem_init(MaxTaskSemaphore, 1, MaxTasks) < 0 |
|
) |
|
{ |
|
int errno_save = errno; |
|
if (MaxTaskSemaphore != (sem_t*)-1) shmdt(MaxTaskSemaphore); |
|
if (shmid >= 0) shmctl(shmid, IPC_RMID, NULL); |
|
printerrorf("Warning: Could not create semaphore: %s\n", vlmcsd_strerror(errno_save)); |
|
MaxTasks = SEM_VALUE_MAX; |
|
} |
|
} |
|
|
|
# else // THREADS or CYGWIN |
|
|
|
MaxTaskSemaphore = (sem_t*)vlmcsd_malloc(sizeof(sem_t)); |
|
|
|
if (sem_init(MaxTaskSemaphore, sharemode, MaxTasks) < 0) // sem_init is not implemented on Darwin (returns ENOSYS) |
|
{ |
|
free(MaxTaskSemaphore); |
|
|
|
if ((MaxTaskSemaphore = sem_open("/vlmcsd", O_CREAT /*| O_EXCL*/, 0700, MaxTasks)) == SEM_FAILED) |
|
{ |
|
printerrorf("Warning: Could not create semaphore: %s\n", vlmcsd_strerror(errno)); |
|
MaxTasks = SEM_VALUE_MAX; |
|
} |
|
} |
|
|
|
# endif // THREADS or CYGWIN |
|
|
|
# else // _WIN32 |
|
|
|
if (!((MaxTaskSemaphore = CreateSemaphoreA(NULL, MaxTasks, MaxTasks, NULL)))) |
|
{ |
|
printerrorf("Warning: Could not create semaphore: %s\n", vlmcsd_strerror(GetLastError())); |
|
MaxTasks = SEM_VALUE_MAX; |
|
} |
|
|
|
# endif // _WIN32 |
|
} |
|
} |
|
#endif // !defined(NO_LIMIT) && !defined(NO_SOCKETS) && !__minix__ |
|
|
|
|
|
#if !defined(NO_SOCKETS) && !defined(USE_MSRPC) && !defined(SIMPLE_SOCKETS) |
|
int setupListeningSockets() |
|
{ |
|
int o; |
|
# if HAVE_GETIFADDR |
|
char** privateIPList = NULL; |
|
int numPrivateIPs = 0; |
|
if (PublicIPProtectionLevel & 1) getPrivateIPAddresses(&numPrivateIPs, &privateIPList); |
|
const uint_fast8_t allocsockets = (uint_fast8_t)(maxsockets ? (maxsockets + numPrivateIPs) : ((PublicIPProtectionLevel & 1) ? numPrivateIPs : 2)); |
|
# else // !HAVE_GETIFADDR |
|
uint_fast8_t allocsockets = maxsockets ? maxsockets : 2; |
|
# endif // !HAVE_GETIFADDR |
|
|
|
SocketList = (SOCKET*)vlmcsd_malloc((size_t)allocsockets * sizeof(SOCKET)); |
|
|
|
const int_fast8_t haveIPv4Stack = checkProtocolStack(AF_INET); |
|
const int_fast8_t haveIPv6Stack = checkProtocolStack(AF_INET6); |
|
|
|
// Reset getopt since we've alread used it |
|
optReset(); |
|
|
|
for (opterr = 0; (o = getopt(global_argc, (char* const*)global_argv, (const char*)optstring)) > 0; ) switch (o) |
|
{ |
|
case 'P': |
|
defaultport = optarg; |
|
break; |
|
|
|
case 'L': |
|
addListeningSocket(optarg); |
|
break; |
|
|
|
default: |
|
break; |
|
} |
|
|
|
|
|
# ifndef NO_INI_FILE |
|
if (maxsockets && !numsockets) |
|
{ |
|
if (fn_ini && !readIniFile(INI_FILE_PASS_3)) |
|
{ |
|
# ifdef INI_FILE |
|
if (strcmp(fn_ini, INI_FILE)) |
|
# endif // INI_FILE |
|
printerrorf("Warning: Can't read %s: %s\n", fn_ini, strerror(errno)); |
|
} |
|
} |
|
# endif |
|
|
|
# if HAVE_GETIFADDR |
|
if (PublicIPProtectionLevel & 1) |
|
{ |
|
int i; |
|
for (i = 0; i < numPrivateIPs; i++) |
|
{ |
|
addListeningSocket(privateIPList[i]); |
|
free(privateIPList[i]); |
|
} |
|
|
|
free(privateIPList); |
|
} |
|
# endif // HAVE_GETIFADDR |
|
|
|
// if -L hasn't been specified on the command line, use default sockets (all IP addresses) |
|
// maxsocket results from first pass parsing the arguments |
|
if (!maxsockets) |
|
{ |
|
# if HAVE_GETIFADDR |
|
if (!(PublicIPProtectionLevel & 1) && haveIPv6Stack) addListeningSocket("::"); |
|
if (!(PublicIPProtectionLevel & 1) && haveIPv4Stack) addListeningSocket("0.0.0.0"); |
|
# else // !HAVE_GETIFADDR |
|
if (haveIPv6Stack) addListeningSocket("::"); |
|
if (haveIPv4Stack) addListeningSocket("0.0.0.0"); |
|
# endif // !HAVE_GETIFADDR |
|
} |
|
|
|
if (!numsockets) |
|
{ |
|
printerrorf("Fatal: Could not listen on any socket.\n"); |
|
return(!0); |
|
} |
|
|
|
return 0; |
|
} |
|
#endif // !defined(NO_SOCKETS) && !defined(USE_MSRPC) && !defined(SIMPLE_SOCKETS) |
|
|
|
|
|
int server_main(int argc, CARGV argv) |
|
{ |
|
global_argc = argc; |
|
global_argv = argv; |
|
|
|
# ifdef _NTSERVICE |
|
DWORD lasterror = ERROR_SUCCESS; |
|
|
|
if (!StartServiceCtrlDispatcher(NTServiceDispatchTable) && (lasterror = GetLastError()) == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) |
|
{ |
|
IsNTService = FALSE; |
|
return newmain(); |
|
} |
|
|
|
return lasterror; |
|
# else // !_NTSERVICE |
|
return newmain(); |
|
# endif // !_NTSERVICE |
|
} |
|
|
|
|
|
int newmain() |
|
{ |
|
// Initialize thread synchronization objects for Windows and Cygwin |
|
# ifdef USE_THREADS |
|
|
|
# ifndef NO_LOG |
|
// Initialize the Critical Section for proper logging |
|
# if _WIN32 || __CYGWIN__ |
|
InitializeCriticalSection(&logmutex); |
|
# endif // _WIN32 || __CYGWIN__ |
|
# endif // NO_LOG |
|
|
|
# endif // USE_THREADS |
|
|
|
# ifdef _WIN32 |
|
|
|
# ifndef USE_MSRPC |
|
WSADATA wsadata; |
|
{ |
|
// Windows Sockets must be initialized |
|
int error; |
|
if ((error = WSAStartup(0x0202, &wsadata))) |
|
{ |
|
printerrorf("Fatal: Could not initialize Windows sockets (Error: %d).\n", error); |
|
return error; |
|
} |
|
} |
|
# endif // USE_MSRPC |
|
|
|
// Windows can never daemonize |
|
//nodaemon = 1; |
|
|
|
# else // __CYGWIN__ |
|
|
|
// Do not daemonize if we are a Windows service |
|
# ifdef _NTSERVICE |
|
if (IsNTService) nodaemon = 1; |
|
# endif |
|
|
|
# endif // _WIN32 / __CYGWIN__ |
|
|
|
parseGeneralArguments(); // Does not return if an error occurs |
|
|
|
# if !defined(_WIN32) && !defined(NO_SOCKETS) && !defined(USE_MSRPC) |
|
|
|
struct stat statbuf; |
|
fstat(STDIN_FILENO, &statbuf); |
|
|
|
if (S_ISSOCK(statbuf.st_mode)) |
|
{ |
|
InetdMode = 1; |
|
# ifndef NO_CLIENT_LIST |
|
MaintainClients = FALSE; |
|
# endif // !NO_CLIENT_LIST |
|
nodaemon = 1; |
|
# ifndef SIMPLE_SOCKETS |
|
maxsockets = 0; |
|
# endif // !SIMPLE_SOCKETS |
|
# ifndef NO_LOG |
|
logstdout = 0; |
|
# endif // !NO_LOG |
|
} |
|
|
|
# endif // !defined(_WIN32) && !defined(NO_SOCKETS) && !defined(USE_MSRPC) |
|
|
|
# ifndef NO_INI_FILE |
|
|
|
if (fn_ini && !readIniFile(INI_FILE_PASS_1)) |
|
{ |
|
# ifdef INI_FILE |
|
if (strcmp(fn_ini, INI_FILE)) |
|
# endif // INI_FILE |
|
printerrorf("Warning: Can't read %s: %s\n", fn_ini, strerror(errno)); |
|
} |
|
|
|
# endif // NO_INI_FILE |
|
|
|
loadKmsData(); |
|
|
|
# if !defined(USE_MSRPC) && !defined(SIMPLE_RPC) |
|
|
|
if |
|
( |
|
!IsNDR64Defined |
|
) |
|
{ |
|
UseServerRpcNDR64 = !!KmsData->Flags & KMS_OPTIONS_USENDR64; |
|
# ifndef NO_RANDOM_EPID |
|
if (HostBuild&&RandomizationLevel) |
|
{ |
|
UseServerRpcNDR64 = HostBuild > 7601; |
|
} |
|
# endif |
|
} |
|
# endif // !defined(USE_MSRPC) && !defined(SIMPLE_RPC) |
|
|
|
# if !defined(NO_INI_FILE) || !defined(NO_CL_PIDS) |
|
if (KmsData->MinorVer < 6) |
|
{ |
|
printerrorf("Warning: Need database version 1.6 or greater to set custom ePids\n"); |
|
} |
|
# endif // !defined(NO_INI_FILE) || !defined(NO_CL_PIDS) |
|
|
|
# if !defined(NO_RANDOM_EPID) || !defined(NO_CL_PIDS) || !defined(NO_INI_FILE) |
|
KmsResponseParameters = (KmsResponseParam_t*)vlmcsd_malloc(sizeof(KmsResponseParam_t) * KmsData->CsvlkCount); |
|
memset(KmsResponseParameters, 0, sizeof(KmsResponseParam_t) * KmsData->CsvlkCount); |
|
# endif // !defined(NO_RANDOM_EPID) || !defined(NO_CL_PIDS) || !defined(NO_INI_FILE) |
|
|
|
#ifndef NO_CL_PIDS |
|
optReset(); |
|
int o; |
|
|
|
for (opterr = 0; (o = getopt(global_argc, (char* const*)global_argv, (const char*)optstring)) > 0; ) switch (o) |
|
{ |
|
case 'a': |
|
if (KmsData->MinorVer < 6 || !handleIniFileEpidParameter(optarg, FALSE, "command line")) |
|
{ |
|
usage(); |
|
} |
|
|
|
break; |
|
|
|
default: |
|
break; |
|
} |
|
|
|
#endif // NO_CL_PIDS |
|
|
|
# ifndef NO_INI_FILE |
|
|
|
if (fn_ini && !readIniFile(INI_FILE_PASS_2)) |
|
{ |
|
# ifdef INI_FILE |
|
if (strcmp(fn_ini, INI_FILE)) |
|
# endif // INI_FILE |
|
printerrorf("Warning: Can't read %s: %s\n", fn_ini, strerror(errno)); |
|
} |
|
|
|
# endif // NO_INI_FILE |
|
|
|
# ifndef NO_CLIENT_LIST |
|
if (MaintainClients) InitializeClientLists(); |
|
# endif // !NO_CLIENT_LIST |
|
|
|
# if defined(USE_MSRPC) && !defined(NO_PRIVATE_IP_DETECT) |
|
if (PublicIPProtectionLevel) |
|
{ |
|
printerrorf("Warning: Public IP address protection using MS RPC is poor. See vlmcsd.8\n"); |
|
} |
|
# endif // defined(USE_MSRPC) && !defined(NO_PRIVATE_IP_DETECT) |
|
|
|
# if !defined(NO_LIMIT) && !defined(NO_SOCKETS) && !__minix__ && !defined(USE_MSRPC) |
|
allocateSemaphore(); |
|
# endif // !defined(NO_LIMIT) && !defined(NO_SOCKETS) && __minix__ |
|
|
|
# ifdef _NTSERVICE |
|
if (installService) |
|
return NtServiceInstallation(installService, ServiceUser, ServicePassword); |
|
# endif // _NTSERVICE |
|
|
|
# ifndef NO_TAP |
|
if (tapArgument && !InetdMode) startTap(tapArgument); |
|
# endif // NO_TAP |
|
|
|
# if !defined(NO_SOCKETS) && !defined(USE_MSRPC) |
|
if (!InetdMode) |
|
{ |
|
int error; |
|
# ifdef SIMPLE_SOCKETS |
|
if ((error = listenOnAllAddresses())) return error; |
|
# else // !SIMPLE_SOCKETS |
|
if ((error = setupListeningSockets())) return error; |
|
# endif // !SIMPLE_SOCKETS |
|
} |
|
# endif // !defined(NO_SOCKETS) && !defined(USE_MSRPC) |
|
|
|
// After sockets have been set up, we may switch to a lower privileged user |
|
# if !defined(_WIN32) && !defined(NO_USER_SWITCH) |
|
|
|
# ifndef NO_SIGHUP |
|
if (!IsRestarted) |
|
{ |
|
# endif // NO_SIGHUP |
|
if (gid != INVALID_GID) |
|
{ |
|
if (setgid(gid)) |
|
{ |
|
printerrorf("Fatal: %s for %s failed: %s\n", "setgid", gname, strerror(errno)); |
|
return errno; |
|
} |
|
|
|
if (setgroups(1, &gid)) |
|
{ |
|
printerrorf("Fatal: %s for %s failed: %s\n", "setgroups", gname, strerror(errno)); |
|
return errno; |
|
} |
|
} |
|
|
|
if (uid != INVALID_UID && setuid(uid)) |
|
{ |
|
printerrorf("Fatal: %s for %s failed: %s\n", "setuid", uname, strerror(errno)); |
|
return errno; |
|
} |
|
# ifndef NO_SIGHUP |
|
} |
|
# endif // NO_SIGHUP |
|
|
|
# endif // !defined(_WIN32) && !defined(NO_USER_SWITCH) |
|
|
|
randomNumberInit(); |
|
|
|
// Randomization Level 1 means generate ePIDs at startup and use them during |
|
// the lifetime of the process. So we generate them now |
|
# ifndef NO_RANDOM_EPID |
|
if (RandomizationLevel == 1) randomPidInit(); |
|
# endif |
|
|
|
# if !defined(NO_SOCKETS) |
|
# ifdef _WIN32 |
|
if (!IsNTService) |
|
{ |
|
# endif // _WIN32 |
|
int error; |
|
if ((error = daemonizeAndSetSignalAction())) return error; |
|
# ifdef _WIN32 |
|
} |
|
# endif // _WIN32 |
|
# endif // !defined(NO_SOCKETS) |
|
|
|
writePidFile(); |
|
|
|
# if !defined(NO_LOG) && !defined(NO_SOCKETS) && !defined(USE_MSRPC) |
|
if (!InetdMode) |
|
logger("vlmcsd %s started successfully\n", Version); |
|
# endif // !defined(NO_LOG) && !defined(NO_SOCKETS) && !defined(USE_MSRPC) |
|
|
|
# if defined(_NTSERVICE) && !defined(USE_MSRPC) |
|
if (IsNTService) ReportServiceStatus(SERVICE_RUNNING, NO_ERROR, 200); |
|
# endif // defined(_NTSERVICE) && !defined(USE_MSRPC) |
|
|
|
int rc; |
|
rc = runServer(); |
|
|
|
// Clean up things and exit |
|
# ifdef _NTSERVICE |
|
if (!ServiceShutdown) |
|
# endif |
|
cleanup(); |
|
# ifdef _NTSERVICE |
|
else |
|
ReportServiceStatus(SERVICE_STOPPED, NO_ERROR, 0); |
|
# endif |
|
|
|
return rc; |
|
} |
|
|
|
|
|
#if _MSC_VER && !defined(_DEBUG)&& !MULTI_CALL_BINARY |
|
int __stdcall WinStartUp(void) |
|
{ |
|
WCHAR **szArgList; |
|
int argc; |
|
szArgList = CommandLineToArgvW(GetCommandLineW(), &argc); |
|
|
|
int i; |
|
char **argv = (char**)vlmcsd_malloc(sizeof(char*)*argc); |
|
|
|
for (i = 0; i < argc; i++) |
|
{ |
|
int size = WideCharToMultiByte(CP_UTF8, 0, szArgList[i], -1, argv[i], 0, NULL, NULL); |
|
argv[i] = (char*)vlmcsd_malloc(size); |
|
WideCharToMultiByte(CP_UTF8, 0, szArgList[i], -1, argv[i], size, NULL, NULL); |
|
} |
|
|
|
exit(server_main(argc, argv)); |
|
} |
|
#endif // _MSC_VER && !defined(_DEBUG)&& !MULTI_CALL_BINARY
|
|
|