vlmcsd.c 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785
  1. #ifndef CONFIG
  2. #define CONFIG "config.h"
  3. #endif // CONFIG
  4. #include CONFIG
  5. #if defined(USE_MSRPC) && !defined(_WIN32) && !defined(__CYGWIN__)
  6. #error Microsoft RPC is only available on Windows and Cygwin
  7. #endif
  8. #if defined(USE_MSRPC) && defined(SIMPLE_SOCKETS)
  9. #error You can only define either USE_MSRPC or SIMPLE_SOCKETS but not both
  10. #endif
  11. #if defined(NO_SOCKETS) && defined(USE_MSRPC)
  12. #error Cannot use inetd mode with Microsoft RPC
  13. #endif
  14. #ifndef _GNU_SOURCE
  15. #define _GNU_SOURCE
  16. #endif
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <errno.h>
  21. #include <stdint.h>
  22. #ifndef _WIN32
  23. #include <pwd.h>
  24. #include <grp.h>
  25. #include <sys/types.h>
  26. #if !defined(NO_LIMIT) && !__minix__
  27. #include <sys/ipc.h>
  28. #if !__ANDROID__
  29. #include <sys/shm.h>
  30. #else // __ANDROID__
  31. #include <sys/syscall.h>
  32. #endif // __ANDROID__
  33. #endif // !defined(NO_LIMIT) && !__minix__
  34. #include <sys/wait.h>
  35. #include <unistd.h>
  36. #include <fcntl.h>
  37. #include <sys/stat.h>
  38. #ifndef NO_LIMIT
  39. #include <semaphore.h>
  40. #endif // NO_LIMIT
  41. #endif // !_WIN32
  42. #if __APPLE__
  43. #include <mach-o/dyld.h>
  44. #endif // __APPLE__
  45. #if __linux__ && defined(USE_AUXV)
  46. #include <sys/auxv.h>
  47. #endif
  48. #if __FreeBSD__
  49. #include <sys/sysctl.h>
  50. #endif
  51. #include "vlmcsd.h"
  52. #include "endian.h"
  53. #include "shared_globals.h"
  54. #include "output.h"
  55. #ifndef USE_MSRPC
  56. #include "network.h"
  57. #else // USE_MSRPC
  58. #include "msrpc-server.h"
  59. #endif // USE_MSRPC
  60. #include "ntservice.h"
  61. #include "helpers.h"
  62. static const char* const optstring = "N:B:m:t:w:0:3:H:A:R:u:g:L:p:i:P:l:r:U:W:C:F:o:T:SseDdVvqkZ";
  63. #if !defined(NO_SOCKETS) && !defined(USE_MSRPC) && !defined(SIMPLE_SOCKETS)
  64. static uint_fast8_t maxsockets = 0;
  65. #endif // !defined(NO_SOCKETS) && !defined(USE_MSRPC) && !defined(SIMPLE_SOCKETS)
  66. #ifdef _NTSERVICE
  67. static int_fast8_t installService = 0;
  68. static const char *restrict ServiceUser = NULL;
  69. static const char *restrict ServicePassword = "";
  70. #endif
  71. #ifndef NO_PID_FILE
  72. static const char *fn_pid = NULL;
  73. #endif
  74. #ifndef NO_INI_FILE
  75. #ifdef INI_FILE
  76. static const char *fn_ini = INI_FILE;
  77. #else // !INI_FILE
  78. static const char *fn_ini = NULL;
  79. #endif // !INI_FILE
  80. static const char* IniFileErrorMessage = "";
  81. char* IniFileErrorBuffer = NULL;
  82. #define INIFILE_ERROR_BUFFERSIZE 256
  83. static IniFileParameter_t IniFileParameterList[] =
  84. {
  85. # ifndef NO_RANDOM_EPID
  86. { "RandomizationLevel", INI_PARAM_RANDOMIZATION_LEVEL },
  87. { "LCID", INI_PARAM_LCID },
  88. # endif // NO_RANDOM_EPID
  89. # if !defined(NO_SOCKETS) && (defined(USE_MSRPC) || defined(SIMPLE_SOCKETS) || defined(HAVE_GETIFADDR))
  90. { "Port", INI_PARAM_PORT },
  91. # endif // defined(USE_MSRPC) || defined(SIMPLE_SOCKETS)
  92. # if !defined(NO_SOCKETS) && !defined(USE_MSRPC)
  93. # ifndef SIMPLE_SOCKETS
  94. { "Listen", INI_PARAM_LISTEN },
  95. # endif // SIMPLE_SOCKETS
  96. # if HAVE_FREEBIND
  97. { "FreeBind", INI_PARAM_FREEBIND },
  98. # endif // HAVE_FREEBIND
  99. # if !defined(NO_LIMIT) && !__minix__
  100. { "MaxWorkers", INI_PARAM_MAX_WORKERS },
  101. # endif // !defined(NO_LIMIT) && !__minix__
  102. # endif // !defined(NO_SOCKETS) && !defined(USE_MSRPC)
  103. # if !defined(NO_TIMEOUT) && !__minix__ && !defined(USE_MSRPC) & !defined(USE_MSRPC)
  104. { "ConnectionTimeout", INI_PARAM_CONNECTION_TIMEOUT },
  105. # endif // !defined(NO_TIMEOUT) && !__minix__ && !defined(USE_MSRPC) & !defined(USE_MSRPC)
  106. # ifndef USE_MSRPC
  107. { "DisconnectClientsImmediately", INI_PARAM_DISCONNECT_IMMEDIATELY },
  108. { "UseNDR64", INI_PARAM_RPC_NDR64 },
  109. { "UseBTFN", INI_PARAM_RPC_BTFN },
  110. # endif // USE_MSRPC
  111. # ifndef NO_PID_FILE
  112. { "PIDFile", INI_PARAM_PID_FILE },
  113. # endif // NO_PID_FILE
  114. # ifndef NO_LOG
  115. { "LogDateAndTime", INI_PARAM_LOG_DATE_AND_TIME },
  116. { "LogFile", INI_PARAM_LOG_FILE },
  117. # ifndef NO_VERBOSE_LOG
  118. { "LogVerbose", INI_PARAM_LOG_VERBOSE },
  119. # endif // NO_VERBOSE_LOG
  120. # endif // NO_LOG
  121. # ifndef NO_CUSTOM_INTERVALS
  122. {"ActivationInterval", INI_PARAM_ACTIVATION_INTERVAL },
  123. {"RenewalInterval", INI_PARAM_RENEWAL_INTERVAL },
  124. # endif // NO_CUSTOM_INTERVALS
  125. # if !defined(NO_USER_SWITCH) && !defined(_WIN32)
  126. { "user", INI_PARAM_UID },
  127. { "group", INI_PARAM_GID},
  128. # endif // !defined(NO_USER_SWITCH) && !defined(_WIN32)
  129. # if !defined(NO_PRIVATE_IP_DETECT)
  130. {"PublicIPProtectionLevel", INI_PARAM_PUBLIC_IP_PROTECTION_LEVEL },
  131. # endif
  132. };
  133. #endif // NO_INI_FILE
  134. #if !defined(NO_LIMIT) && !defined (NO_SOCKETS) && !__minix__
  135. #if !defined(USE_THREADS) && !defined(CYGWIN) && !defined(USE_MSRPC)
  136. static int shmid = -1;
  137. #endif
  138. #if __ANDROID__ && !defined(USE_THREADS) // Bionic does not wrap these syscalls (willingly because Google fears, developers don't know how to use it)
  139. #ifdef __NR_shmget
  140. static int shmget(key_t key, size_t size, int shmflg)
  141. {
  142. return syscall(__NR_shmget, key, size, shmflg);
  143. }
  144. #endif // __NR_shmget
  145. #ifdef __NR_shmat
  146. static void *shmat(int shmid, const void *shmaddr, int shmflg)
  147. {
  148. return (void *)syscall(__NR_shmat, shmid, shmaddr, shmflg);
  149. }
  150. #endif // __NR_shmat
  151. #ifdef __NR_shmdt
  152. static int shmdt(const void *shmaddr)
  153. {
  154. return syscall(__NR_shmdt, shmaddr);
  155. }
  156. #endif // __NR_shmdt
  157. #ifdef __NR_shmctl
  158. static int shmctl(int shmid, int cmd, /*struct shmid_ds*/void *buf)
  159. {
  160. return syscall(__NR_shmctl, shmid, cmd, buf);
  161. }
  162. #endif // __NR_shmctl
  163. #endif // __ANDROID__ && !defined(USE_THREADS)
  164. #endif // !defined(NO_LIMIT) && !defined (NO_SOCKETS) && !__minix__
  165. #ifndef NO_USER_SWITCH
  166. #ifndef _WIN32
  167. static const char *uname = NULL, *gname = NULL;
  168. static gid_t gid = INVALID_GID;
  169. static uid_t uid = INVALID_UID;
  170. // Get Numeric id of user/group
  171. static char GetNumericId(gid_t *restrict id, const char *const c)
  172. {
  173. char* endptr;
  174. gid_t temp;
  175. temp = (gid_t)strtoll(c, &endptr, 10);
  176. if (!*endptr) *id = temp;
  177. if (*endptr || temp == (gid_t)-1) errno = EINVAL;
  178. return *endptr || *id == (gid_t)-1;
  179. }
  180. // Get group id from option argument
  181. static char GetGid()
  182. {
  183. struct group *g;
  184. if ((g = getgrnam(optarg)))
  185. gid = g->gr_gid;
  186. else
  187. return GetNumericId(&gid, optarg);
  188. return 0;
  189. }
  190. // Get user id from option argument
  191. static char GetUid()
  192. {
  193. struct passwd *u;
  194. ////PORTABILITY: Assumes uid_t and gid_t are of same size (shouldn't be a problem)
  195. if ((u = getpwnam(optarg)))
  196. uid = u->pw_uid;
  197. else
  198. return GetNumericId((gid_t*)&uid, optarg);
  199. return 0;
  200. }
  201. #endif // _WIN32
  202. #endif //NO_USER_SWITCH
  203. #ifdef NO_HELP
  204. static __noreturn void usage()
  205. {
  206. printerrorf("Incorrect parameters\n\n");
  207. exit(!0);
  208. }
  209. #else // HELP
  210. static __noreturn void usage()
  211. {
  212. printerrorf("vlmcsd %s\n"
  213. "\nUsage:\n"
  214. " %s [ options ]\n\n"
  215. "Where:\n"
  216. #ifndef NO_CL_PIDS
  217. " -w <ePID> always use <ePID> for Windows\n"
  218. " -0 <ePID> always use <ePID> for Office2010\n"
  219. " -3 <ePID> always use <ePID> for Office2013\n"
  220. " -H <HwId> always use hardware Id <HwId>\n"
  221. #endif // NO_CL_PIDS
  222. #if !defined(_WIN32) && !defined(NO_USER_SWITCH)
  223. " -u <user> set uid to <user>\n"
  224. " -g <group> set gid to <group>\n"
  225. #endif // !defined(_WIN32) && !defined(NO_USER_SWITCH)
  226. #ifndef NO_RANDOM_EPID
  227. " -r 0|1|2\t\tset ePID randomization level (default 1)\n"
  228. " -C <LCID>\t\tuse fixed <LCID> in random ePIDs\n"
  229. #endif // NO_RANDOM_EPID
  230. #if !defined(NO_PRIVATE_IP_DETECT)
  231. #if HAVE_GETIFADDR
  232. " -o 0|1|2|3\t\tset protection level against clients with public IP addresses (default 0)\n"
  233. #else // !HAVE_GETIFADDR
  234. #ifndef USE_MSRPC
  235. " -o 0|2\t\tset protection level against clients with public IP addresses (default 0)\n"
  236. #else // USE_MSRPC
  237. " -o 0|2\t\tset protection level against clients with public IP addresses (default 0). Limited use with MS RPC\n"
  238. #endif // USE_MSRPC
  239. #endif // !HAVE_GETIFADDR
  240. #endif // !defined(NO_PRIVATE_IP_DETECT)
  241. #ifndef NO_SOCKETS
  242. #if !defined(USE_MSRPC) && !defined(SIMPLE_SOCKETS)
  243. " -L <address>[:<port>]\tlisten on IP address <address> with optional <port>\n"
  244. " -P <port>\t\tset TCP port <port> for subsequent -L statements (default 1688)\n"
  245. #if HAVE_FREEBIND
  246. " -F0, -F1\t\tdisable/enable binding to foreign IP addresses\n"
  247. #endif // HAVE_FREEBIND
  248. #else // defined(USE_MSRPC) || defined(SIMPLE_SOCKETS)
  249. " -P <port>\t\tuse TCP port <port> (default 1688)\n"
  250. #endif // defined(USE_MSRPC) || defined(SIMPLE_SOCKETS)
  251. #if !defined(NO_LIMIT) && !__minix__
  252. " -m <clients>\t\tHandle max. <clients> simultaneously (default no limit)\n"
  253. #endif // !defined(NO_LIMIT) && !__minix__
  254. #ifdef _NTSERVICE
  255. " -s install vlmcsd as an NT service. Ignores -e"
  256. #ifndef _WIN32
  257. ", -f and -D"
  258. #endif // _WIN32
  259. "\n"
  260. " -S remove vlmcsd service. Ignores all other options\n"
  261. " -U <username> run NT service as <username>. Must be used with -s\n"
  262. " -W <password> optional <password> for -U. Must be used with -s\n"
  263. #endif // _NTSERVICE
  264. #ifndef NO_LOG
  265. " -e log to stdout\n"
  266. #endif // NO_LOG
  267. #ifndef _WIN32 //
  268. " -D run in foreground\n"
  269. #else // _WIN32
  270. " -D does nothing. Provided for compatibility with POSIX versions only\n"
  271. #endif // _WIN32
  272. #endif // NO_SOCKETS
  273. #ifndef USE_MSRPC
  274. #if !defined(NO_TIMEOUT) && !__minix__
  275. " -t <seconds>\t\tdisconnect clients after <seconds> of inactivity (default 30)\n"
  276. #endif // !defined(NO_TIMEOUT) && !__minix__
  277. " -d\t\t\tdisconnect clients after each request\n"
  278. " -k\t\t\tdon't disconnect clients after each request (default)\n"
  279. " -N0, -N1\t\tdisable/enable NDR64\n"
  280. " -B0, -B1\t\tdisable/enable bind time feature negotiation\n"
  281. #endif // USE_MSRPC
  282. #ifndef NO_PID_FILE
  283. " -p <file> write pid to <file>\n"
  284. #endif // NO_PID_FILE
  285. #ifndef NO_INI_FILE
  286. " -i <file>\t\tuse config file <file>\n"
  287. #endif // NO_INI_FILE
  288. #ifndef NO_CUSTOM_INTERVALS
  289. " -R <interval> renew activation every <interval> (default 1w)\n"
  290. " -A <interval> retry activation every <interval> (default 2h)\n"
  291. #endif // NO_CUSTOM_INTERVALS
  292. #ifndef NO_LOG
  293. #ifndef _WIN32
  294. " -l syslog log to syslog\n"
  295. #endif // _WIN32
  296. " -l <file> log to <file>\n"
  297. " -T0, -T1\t\tdisable/enable logging with time and date (default -T1)\n"
  298. #ifndef NO_VERBOSE_LOG
  299. " -v\t\t\tlog verbose\n"
  300. " -q\t\t\tdon't log verbose (default)\n"
  301. #endif // NO_VERBOSE_LOG
  302. #endif // NO_LOG
  303. #ifndef NO_VERSION_INFORMATION
  304. " -V display version information and exit\n"
  305. #endif // NO_VERSION_INFORMATION
  306. ,
  307. Version, global_argv[0]);
  308. exit(!0);
  309. }
  310. #endif // HELP
  311. #ifndef NO_CUSTOM_INTERVALS
  312. // Convert time span strings (e.g. "2h", "5w") to minutes
  313. __pure static DWORD timeSpanString2Minutes(const char *const restrict argument)
  314. {
  315. char *unitId;
  316. long long val = strtoll(argument, &unitId, 10);
  317. switch(toupper((int)*unitId))
  318. {
  319. case 0:
  320. case 'M':
  321. break;
  322. case 'H':
  323. val *= 60;
  324. break;
  325. case 'D':
  326. val *= 60 * 24;
  327. break;
  328. case 'W':
  329. val *= 60 * 24 * 7;
  330. break;
  331. case 'S':
  332. val /= 60;
  333. break;
  334. default:
  335. return 0;
  336. }
  337. if (val < 1) val = 1;
  338. if (val > UINT_MAX) val = UINT_MAX;
  339. return (DWORD)val;
  340. }
  341. #ifndef NO_INI_FILE
  342. __pure static BOOL getTimeSpanFromIniFile(DWORD* result, const char *const restrict argument)
  343. {
  344. DWORD val = timeSpanString2Minutes(argument);
  345. if (!val)
  346. {
  347. IniFileErrorMessage = "Incorrect time span.";
  348. return FALSE;
  349. }
  350. *result = val;
  351. return TRUE;
  352. }
  353. #endif // NO_INI_FILE
  354. __pure static DWORD getTimeSpanFromCommandLine(const char *const restrict optarg, const char optchar)
  355. {
  356. long long val = timeSpanString2Minutes(optarg);
  357. if (!val)
  358. {
  359. printerrorf("Fatal: No valid time span specified in option -%c.\n", optchar);
  360. exit (!0);
  361. }
  362. return (DWORD)val;
  363. }
  364. #endif // NO_CUSTOM_INTERVALS
  365. #ifndef NO_INI_FILE
  366. static void ignoreIniFileParameter(uint_fast8_t iniFileParameterId)
  367. {
  368. uint_fast8_t i;
  369. for (i = 0; i < _countof(IniFileParameterList); i++)
  370. {
  371. if (IniFileParameterList[i].Id != iniFileParameterId) continue;
  372. IniFileParameterList[i].Id = 0;
  373. break;
  374. }
  375. }
  376. #else // NO_INI_FILE
  377. #define ignoreIniFileParameter(x)
  378. #endif // NO_INI_FILE
  379. #ifndef NO_INI_FILE
  380. static BOOL getIniFileArgumentBool(int_fast8_t *result, const char *const argument)
  381. {
  382. IniFileErrorMessage = "Argument must be true/on/yes/1 or false/off/no/0";
  383. return getArgumentBool(result, argument);
  384. }
  385. static BOOL getIniFileArgumentInt(unsigned int *result, const char *const argument, const unsigned int min, const unsigned int max)
  386. {
  387. unsigned int tempResult;
  388. if (!stringToInt(argument, min, max, &tempResult))
  389. {
  390. snprintf(IniFileErrorBuffer, INIFILE_ERROR_BUFFERSIZE, "Must be integer between %u and %u", min, max);
  391. IniFileErrorMessage = IniFileErrorBuffer;
  392. return FALSE;
  393. }
  394. *result = tempResult;
  395. return TRUE;
  396. }
  397. static char* allocateStringArgument(const char *const argument)
  398. {
  399. char* result = (char*)vlmcsd_malloc(strlen(argument) + 1);
  400. strcpy(result, argument);
  401. return result;
  402. }
  403. static BOOL setIniFileParameter(uint_fast8_t id, const char *const iniarg)
  404. {
  405. unsigned int result;
  406. BOOL success = TRUE;
  407. switch(id)
  408. {
  409. # if !defined(NO_USER_SWITCH) && !defined(_WIN32)
  410. case INI_PARAM_GID:
  411. {
  412. struct group *g;
  413. IniFileErrorMessage = "Invalid group id or name";
  414. if (!(gname = allocateStringArgument(iniarg))) return FALSE;
  415. if ((g = getgrnam(iniarg)))
  416. gid = g->gr_gid;
  417. else
  418. success = !GetNumericId(&gid, iniarg);
  419. break;
  420. }
  421. case INI_PARAM_UID:
  422. {
  423. struct passwd *p;
  424. IniFileErrorMessage = "Invalid user id or name";
  425. if (!(uname = allocateStringArgument(iniarg))) return FALSE;
  426. if ((p = getpwnam(iniarg)))
  427. uid = p->pw_uid;
  428. else
  429. success = !GetNumericId(&uid, iniarg);
  430. break;
  431. }
  432. # endif // !defined(NO_USER_SWITCH) && !defined(_WIN32)
  433. # ifndef NO_RANDOM_EPID
  434. case INI_PARAM_LCID:
  435. success = getIniFileArgumentInt(&result, iniarg, 0, 32767);
  436. if (success) Lcid = (uint16_t)result;
  437. break;
  438. case INI_PARAM_RANDOMIZATION_LEVEL:
  439. success = getIniFileArgumentInt(&result, iniarg, 0, 2);
  440. if (success) RandomizationLevel = (int_fast8_t)result;
  441. break;
  442. # endif // NO_RANDOM_EPID
  443. # if (defined(USE_MSRPC) || defined(SIMPLE_SOCKETS) || defined(HAVE_GETIFADDR)) && !defined(NO_SOCKETS)
  444. case INI_PARAM_PORT:
  445. defaultport = allocateStringArgument(iniarg);
  446. break;
  447. # endif // (defined(USE_MSRPC) || defined(SIMPLE_SOCKETS) || defined(HAVE_GETIFADDR)) && !defined(NO_SOCKETS)
  448. # if !defined(NO_SOCKETS) && !defined(USE_MSRPC) && !defined(SIMPLE_SOCKETS)
  449. case INI_PARAM_LISTEN:
  450. maxsockets++;
  451. return TRUE;
  452. # endif // !defined(NO_SOCKETS) && !defined(USE_MSRPC) && !defined(SIMPLE_SOCKETS)
  453. # if !defined(NO_LIMIT) && !defined(NO_SOCKETS) && !__minix__
  454. case INI_PARAM_MAX_WORKERS:
  455. # ifdef USE_MSRPC
  456. success = getIniFileArgumentInt(&MaxTasks, iniarg, 1, RPC_C_LISTEN_MAX_CALLS_DEFAULT);
  457. # else // !USE_MSRPC
  458. success = getIniFileArgumentInt(&MaxTasks, iniarg, 1, SEM_VALUE_MAX);
  459. # endif // !USE_MSRPC
  460. break;
  461. # endif // !defined(NO_LIMIT) && !defined(NO_SOCKETS) && !__minix__
  462. # ifndef NO_PID_FILE
  463. case INI_PARAM_PID_FILE:
  464. fn_pid = allocateStringArgument(iniarg);
  465. break;
  466. # endif // NO_PID_FILE
  467. # ifndef NO_LOG
  468. case INI_PARAM_LOG_FILE:
  469. fn_log = allocateStringArgument(iniarg);
  470. break;
  471. case INI_PARAM_LOG_DATE_AND_TIME:
  472. success = getIniFileArgumentBool(&LogDateAndTime, iniarg);
  473. break;
  474. # ifndef NO_VERBOSE_LOG
  475. case INI_PARAM_LOG_VERBOSE:
  476. success = getIniFileArgumentBool(&logverbose, iniarg);
  477. break;
  478. # endif // NO_VERBOSE_LOG
  479. # endif // NO_LOG
  480. # ifndef NO_CUSTOM_INTERVALS
  481. case INI_PARAM_ACTIVATION_INTERVAL:
  482. success = getTimeSpanFromIniFile(&VLActivationInterval, iniarg);
  483. break;
  484. case INI_PARAM_RENEWAL_INTERVAL:
  485. success = getTimeSpanFromIniFile(&VLRenewalInterval, iniarg);
  486. break;
  487. # endif // NO_CUSTOM_INTERVALS
  488. # ifndef USE_MSRPC
  489. # if !defined(NO_TIMEOUT) && !__minix__
  490. case INI_PARAM_CONNECTION_TIMEOUT:
  491. success = getIniFileArgumentInt(&result, iniarg, 1, 600);
  492. if (success) ServerTimeout = (DWORD)result;
  493. break;
  494. # endif // !defined(NO_TIMEOUT) && !__minix__
  495. case INI_PARAM_DISCONNECT_IMMEDIATELY:
  496. success = getIniFileArgumentBool(&DisconnectImmediately, iniarg);
  497. break;
  498. case INI_PARAM_RPC_NDR64:
  499. success = getIniFileArgumentBool(&UseRpcNDR64, iniarg);
  500. break;
  501. case INI_PARAM_RPC_BTFN:
  502. success = getIniFileArgumentBool(&UseRpcBTFN, iniarg);
  503. break;
  504. # endif // USE_MSRPC
  505. # if HAVE_FREEBIND
  506. case INI_PARAM_FREEBIND:
  507. success = getIniFileArgumentBool(&freebind, iniarg);
  508. break;
  509. # endif // HAVE_FREEBIND
  510. # if !defined(NO_PRIVATE_IP_DETECT)
  511. case INI_PARAM_PUBLIC_IP_PROTECTION_LEVEL:
  512. success = getIniFileArgumentInt(&PublicIPProtectionLevel, iniarg, 0, 3);
  513. # if !HAVE_GETIFADDR
  514. if (PublicIPProtectionLevel & 1)
  515. {
  516. IniFileErrorMessage = "Must be 0 or 2";
  517. success = FALSE;
  518. }
  519. # endif // !HAVE_GETIFADDR
  520. break;
  521. # endif // !defined(NO_PRIVATE_IP_DETECT)
  522. default:
  523. return FALSE;
  524. }
  525. return success;
  526. }
  527. static __pure int isControlCharOrSlash(const char c)
  528. {
  529. if ((unsigned char)c < '!') return !0;
  530. if (c == '/') return !0;
  531. return 0;
  532. }
  533. static void iniFileLineNextWord(const char **s)
  534. {
  535. while ( **s && isspace((int)**s) ) (*s)++;
  536. }
  537. static BOOL setHwIdFromIniFileLine(const char **s, const ProdListIndex_t index)
  538. {
  539. iniFileLineNextWord(s);
  540. if (**s == '/')
  541. {
  542. if (KmsResponseParameters[index].HwId) return TRUE;
  543. BYTE* HwId = (BYTE*)vlmcsd_malloc(sizeof(((RESPONSE_V6 *)0)->HwId));
  544. hex2bin(HwId, *s + 1, sizeof(((RESPONSE_V6 *)0)->HwId));
  545. KmsResponseParameters[index].HwId = HwId;
  546. }
  547. return TRUE;
  548. }
  549. static BOOL checkGuidInIniFileLine(const char **s, ProdListIndex_t *const index)
  550. {
  551. GUID AppGuid;
  552. if (!string2Uuid(*s, &AppGuid)) return FALSE;
  553. (*s) += GUID_STRING_LENGTH;
  554. getProductNameHE(&AppGuid, AppList, index);
  555. if (*index > getAppListSize() - 2)
  556. {
  557. IniFileErrorMessage = "Unknown App Guid.";
  558. return FALSE;
  559. }
  560. iniFileLineNextWord(s);
  561. if ( *(*s)++ != '=' ) return FALSE;
  562. return TRUE;
  563. }
  564. static BOOL setEpidFromIniFileLine(const char **s, const ProdListIndex_t index)
  565. {
  566. iniFileLineNextWord(s);
  567. const char *savedPosition = *s;
  568. uint_fast16_t i;
  569. for (i = 0; !isControlCharOrSlash(**s); i++)
  570. {
  571. if (utf8_to_ucs2_char((const unsigned char*)*s, (const unsigned char**)s) == (WCHAR)~0)
  572. {
  573. return FALSE;
  574. }
  575. }
  576. if (i < 1 || i >= PID_BUFFER_SIZE) return FALSE;
  577. if (KmsResponseParameters[index].Epid) return TRUE;
  578. size_t size = *s - savedPosition + 1;
  579. char* epidbuffer = (char*)vlmcsd_malloc(size);
  580. memcpy(epidbuffer, savedPosition, size - 1);
  581. epidbuffer[size - 1] = 0;
  582. KmsResponseParameters[index].Epid = epidbuffer;
  583. #ifndef NO_LOG
  584. KmsResponseParameters[index].EpidSource = fn_ini;
  585. #endif //NO_LOG
  586. return TRUE;
  587. }
  588. static BOOL getIniFileArgument(const char **s)
  589. {
  590. while (!isspace((int)**s) && **s != '=' && **s) (*s)++;
  591. iniFileLineNextWord(s);
  592. if (*((*s)++) != '=')
  593. {
  594. IniFileErrorMessage = "'=' required after keyword.";
  595. return FALSE;
  596. }
  597. iniFileLineNextWord(s);
  598. if (!**s)
  599. {
  600. IniFileErrorMessage = "missing argument after '='.";
  601. return FALSE;
  602. }
  603. return TRUE;
  604. }
  605. static BOOL handleIniFileParameter(const char *s)
  606. {
  607. uint_fast8_t i;
  608. for (i = 0; i < _countof(IniFileParameterList); i++)
  609. {
  610. if (strncasecmp(IniFileParameterList[i].Name, s, strlen(IniFileParameterList[i].Name))) continue;
  611. if (!IniFileParameterList[i].Id) return TRUE;
  612. if (!getIniFileArgument(&s)) return FALSE;
  613. return setIniFileParameter(IniFileParameterList[i].Id, s);
  614. }
  615. IniFileErrorMessage = "Unknown keyword.";
  616. return FALSE;
  617. }
  618. #if !defined(NO_SOCKETS) && !defined(SIMPLE_SOCKETS) && !defined(USE_MSRPC)
  619. static BOOL setupListeningSocketsFromIniFile(const char *s)
  620. {
  621. if (!maxsockets) return TRUE;
  622. if (strncasecmp("Listen", s, 6)) return TRUE;
  623. if (!getIniFileArgument(&s)) return TRUE;
  624. snprintf(IniFileErrorBuffer, INIFILE_ERROR_BUFFERSIZE, "Cannot listen on %s.", s);
  625. IniFileErrorMessage = IniFileErrorBuffer;
  626. return addListeningSocket(s);
  627. }
  628. #endif // !defined(NO_SOCKETS) && !defined(SIMPLE_SOCKETS) && !defined(USE_MSRPC)
  629. static BOOL readIniFile(const uint_fast8_t pass)
  630. {
  631. char line[256];
  632. const char *s;
  633. ProdListIndex_t appIndex;
  634. unsigned int lineNumber;
  635. uint_fast8_t lineParseError;
  636. FILE *restrict f;
  637. BOOL result = TRUE;
  638. IniFileErrorBuffer = (char*)vlmcsd_malloc(INIFILE_ERROR_BUFFERSIZE);
  639. if ( !(f = fopen(fn_ini, "r") )) return FALSE;
  640. for (lineNumber = 1; (s = fgets(line, sizeof(line), f)); lineNumber++)
  641. {
  642. line[strlen(line) - 1] = 0;
  643. iniFileLineNextWord(&s);
  644. if (*s == ';' || *s == '#' || !*s) continue;
  645. # ifndef NO_SOCKETS
  646. if (pass == INI_FILE_PASS_1)
  647. # endif // NO_SOCKETS
  648. {
  649. if (handleIniFileParameter(s)) continue;
  650. lineParseError = !checkGuidInIniFileLine(&s, &appIndex) ||
  651. !setEpidFromIniFileLine(&s, appIndex) ||
  652. !setHwIdFromIniFileLine(&s, appIndex);
  653. }
  654. # if !defined(NO_SOCKETS) && !defined(SIMPLE_SOCKETS) && !defined(USE_MSRPC)
  655. else if (pass == INI_FILE_PASS_2)
  656. {
  657. lineParseError = !setupListeningSocketsFromIniFile(s);
  658. }
  659. else
  660. {
  661. return FALSE;
  662. }
  663. # endif // !defined(NO_SOCKETS) && && !defined(SIMPLE_SOCKETS) && !defined(USE_MSRPC)
  664. if (lineParseError)
  665. {
  666. printerrorf("Warning: %s line %u: \"%s\". %s\n", fn_ini, lineNumber, line, IniFileErrorMessage);
  667. continue;
  668. }
  669. }
  670. if (ferror(f)) result = FALSE;
  671. free(IniFileErrorBuffer);
  672. fclose(f);
  673. # if !defined(NO_SOCKETS) && !defined(NO_LOG)
  674. if (pass == INI_FILE_PASS_1 && !InetdMode && result)
  675. {
  676. # ifdef _NTSERVICE
  677. if (!installService)
  678. # endif // _NTSERVICE
  679. logger("Read ini file %s\n", fn_ini);
  680. }
  681. # endif // !defined(NO_SOCKETS) && !defined(NO_LOG)
  682. return result;
  683. }
  684. #endif // NO_INI_FILE
  685. #if !defined(NO_SOCKETS)
  686. #if !defined(_WIN32)
  687. #if !defined(NO_SIGHUP)
  688. static void exec_self(char** argv)
  689. {
  690. # if __linux__ && defined(USE_AUXV)
  691. char *execname_ptr = (char*)getauxval(AT_EXECFN);
  692. if (execname_ptr) execv(execname_ptr, argv);
  693. # elif (__linux__ || __CYGWIN__) && !defined(NO_PROCFS)
  694. execv(realpath("/proc/self/exe", NULL), argv);
  695. # elif (__FreeBSD__) && !defined(NO_PROCFS)
  696. int mib[4];
  697. mib[0] = CTL_KERN;
  698. mib[1] = KERN_PROC;
  699. mib[2] = KERN_PROC_PATHNAME;
  700. mib[3] = -1;
  701. char path[PATH_MAX + 1];
  702. size_t cb = sizeof(path);
  703. if (!sysctl(mib, 4, path, &cb, NULL, 0)) execv(path, argv);
  704. # elif (__DragonFly__) && !defined(NO_PROCFS)
  705. execv(realpath("/proc/curproc/file", NULL), argv);
  706. # elif __NetBSD__ && !defined(NO_PROCFS)
  707. execv(realpath("/proc/curproc/exe", NULL), argv);
  708. # elif __sun__
  709. const char* exename = getexecname();
  710. if (exename) execv(exename, argv);
  711. # elif __APPLE__
  712. char path[PATH_MAX + 1];
  713. uint32_t size = sizeof(path);
  714. if (_NSGetExecutablePath(path, &size) == 0) execv(path, argv);
  715. # else
  716. execvp(argv[0], argv);
  717. # endif
  718. }
  719. static void HangupHandler(const int signal_unused)
  720. {
  721. int i;
  722. int_fast8_t daemonize_protection = TRUE;
  723. CARGV argv_in = multi_argv == NULL ? global_argv : multi_argv;
  724. int argc_in = multi_argc == 0 ? global_argc : multi_argc;
  725. const char** argv_out = (const char**)vlmcsd_malloc((argc_in + 2) * sizeof(char**));
  726. for (i = 0; i < argc_in; i++)
  727. {
  728. if (!strcmp(argv_in[i], "-Z")) daemonize_protection = FALSE;
  729. argv_out[i] = argv_in[i];
  730. }
  731. argv_out[argc_in] = argv_out[argc_in + 1] = NULL;
  732. if (daemonize_protection) argv_out[argc_in] = (char*) "-Z";
  733. exec_self((char**)argv_out);
  734. # ifndef NO_LOG
  735. logger("Fatal: Unable to restart on SIGHUP: %s\n", strerror(errno));
  736. # endif
  737. # ifndef NO_PID_FILE
  738. if (fn_pid) unlink(fn_pid);
  739. # endif // NO_PID_FILE
  740. exit(errno);
  741. }
  742. #endif // NO_SIGHUP
  743. static void terminationHandler(const int signal_unused)
  744. {
  745. cleanup();
  746. exit(0);
  747. }
  748. #if defined(CHILD_HANDLER) || __minix__
  749. static void childHandler(const int signal)
  750. {
  751. waitpid(-1, NULL, WNOHANG);
  752. }
  753. #endif // defined(CHILD_HANDLER) || __minix__
  754. static int daemonizeAndSetSignalAction()
  755. {
  756. struct sigaction sa;
  757. sigemptyset(&sa.sa_mask);
  758. # ifndef NO_LOG
  759. if ( !nodaemon) if (daemon(!0, logstdout))
  760. # else // NO_LOG
  761. if ( !nodaemon) if (daemon(!0, 0))
  762. # endif // NO_LOG
  763. {
  764. printerrorf("Fatal: Could not daemonize to background.\n");
  765. return(errno);
  766. }
  767. if (!InetdMode)
  768. {
  769. # ifndef USE_THREADS
  770. # if defined(CHILD_HANDLER) || __minix__
  771. sa.sa_handler = childHandler;
  772. # else // !(defined(CHILD_HANDLER) || __minix__)
  773. sa.sa_handler = SIG_IGN;
  774. # endif // !(defined(CHILD_HANDLER) || __minix__)
  775. sa.sa_flags = SA_NOCLDWAIT;
  776. if (sigaction(SIGCHLD, &sa, NULL))
  777. return(errno);
  778. # endif // !USE_THREADS
  779. sa.sa_handler = terminationHandler;
  780. sa.sa_flags = 0;
  781. sigaction(SIGINT, &sa, NULL);
  782. sigaction(SIGTERM, &sa, NULL);
  783. # ifndef NO_SIGHUP
  784. sa.sa_handler = HangupHandler;
  785. sa.sa_flags = SA_NODEFER;
  786. sigaction(SIGHUP, &sa, NULL);
  787. # endif // NO_SIGHUP
  788. }
  789. return 0;
  790. }
  791. #else // _WIN32
  792. static BOOL terminationHandler(const DWORD fdwCtrlType)
  793. {
  794. // What a lame substitute for Unix signal handling
  795. switch(fdwCtrlType)
  796. {
  797. case CTRL_C_EVENT:
  798. case CTRL_CLOSE_EVENT:
  799. case CTRL_BREAK_EVENT:
  800. case CTRL_LOGOFF_EVENT:
  801. case CTRL_SHUTDOWN_EVENT:
  802. cleanup();
  803. exit(0);
  804. default:
  805. return FALSE;
  806. }
  807. }
  808. static DWORD daemonizeAndSetSignalAction()
  809. {
  810. if(!SetConsoleCtrlHandler( (PHANDLER_ROUTINE) terminationHandler, TRUE ))
  811. {
  812. #ifndef NO_LOG
  813. DWORD rc = GetLastError();
  814. logger("Warning: Could not register Windows signal handler: Error %u\n", rc);
  815. #endif // NO_LOG
  816. }
  817. return ERROR_SUCCESS;
  818. }
  819. #endif // _WIN32
  820. #endif // !defined(NO_SOCKETS)
  821. // Workaround for Cygwin fork bug (only affects cygwin processes that are Windows services)
  822. // Best is to compile for Cygwin with threads. fork() is slow and unreliable on Cygwin
  823. #if !defined(NO_INI_FILE) || !defined(NO_LOG) || !defined(NO_CL_PIDS)
  824. __pure static char* getCommandLineArg(char *const restrict optarg)
  825. {
  826. #if !defined (__CYGWIN__) || defined(USE_THREADS) || defined(NO_SOCKETS)
  827. return optarg;
  828. #else
  829. if (!IsNTService) return optarg;
  830. return allocateStringArgument(optarg);
  831. #endif
  832. }
  833. #endif // !defined(NO_INI_FILE) || !defined(NO_LOG) || !defined(NO_CL_PIDS)
  834. static void parseGeneralArguments() {
  835. int o;
  836. #ifndef NO_CL_PIDS
  837. BYTE* HwId;
  838. #endif // NO_CL_PIDS
  839. for (opterr = 0; ( o = getopt(global_argc, (char* const*)global_argv, optstring) ) > 0; ) switch (o)
  840. {
  841. #if !defined(NO_SOCKETS) && !defined(NO_SIGHUP) && !defined(_WIN32)
  842. case 'Z':
  843. IsRestarted = TRUE;
  844. nodaemon = TRUE;
  845. break;
  846. #endif // !defined(NO_SOCKETS) && !defined(NO_SIGHUP) && !defined(_WIN32)
  847. #ifndef NO_CL_PIDS
  848. case 'w':
  849. KmsResponseParameters[APP_ID_WINDOWS].Epid = getCommandLineArg(optarg);
  850. #ifndef NO_LOG
  851. KmsResponseParameters[APP_ID_WINDOWS].EpidSource = "command line";
  852. #endif // NO_LOG
  853. break;
  854. case '0':
  855. KmsResponseParameters[APP_ID_OFFICE2010].Epid = getCommandLineArg(optarg);
  856. #ifndef NO_LOG
  857. KmsResponseParameters[APP_ID_OFFICE2010].EpidSource = "command line";
  858. #endif // NO_LOG
  859. break;
  860. case '3':
  861. KmsResponseParameters[APP_ID_OFFICE2013].Epid = getCommandLineArg(optarg);
  862. #ifndef NO_LOG
  863. KmsResponseParameters[APP_ID_OFFICE2013].EpidSource = "command line";
  864. #endif // NO_LOG
  865. break;
  866. case 'H':
  867. HwId = (BYTE*)vlmcsd_malloc(sizeof(((RESPONSE_V6 *)0)->HwId));
  868. hex2bin(HwId, optarg, sizeof(((RESPONSE_V6 *)0)->HwId));
  869. KmsResponseParameters[APP_ID_WINDOWS].HwId = HwId;
  870. KmsResponseParameters[APP_ID_OFFICE2010].HwId = HwId;
  871. KmsResponseParameters[APP_ID_OFFICE2013].HwId = HwId;
  872. break;
  873. #endif // NO_CL_PIDS
  874. #ifndef NO_SOCKETS
  875. case 'P':
  876. ignoreIniFileParameter(INI_PARAM_PORT);
  877. #if !defined(SIMPLE_SOCKETS) && !defined(USE_MSRPC)
  878. ignoreIniFileParameter(INI_PARAM_LISTEN);
  879. #else
  880. defaultport = optarg;
  881. #endif // !SIMPLE_SOCKETS
  882. break;
  883. #if !defined(NO_LIMIT) && !__minix__
  884. case 'm':
  885. #ifdef USE_MSRPC
  886. MaxTasks = getOptionArgumentInt(o, 1, RPC_C_LISTEN_MAX_CALLS_DEFAULT);
  887. #else // !USE_MSRPC
  888. MaxTasks = getOptionArgumentInt(o, 1, SEM_VALUE_MAX);
  889. #endif // !USE_MSRPC
  890. ignoreIniFileParameter(INI_PARAM_MAX_WORKERS);
  891. break;
  892. #endif // !defined(NO_LIMIT) && !__minix__
  893. #endif // NO_SOCKETS
  894. #if !defined(NO_TIMEOUT) && !__minix__ && !defined(USE_MSRPC)
  895. case 't':
  896. ServerTimeout = getOptionArgumentInt(o, 1, 600);
  897. ignoreIniFileParameter(INI_PARAM_CONNECTION_TIMEOUT);
  898. break;
  899. #endif // !defined(NO_TIMEOUT) && !__minix__ && !defined(USE_MSRPC)
  900. #ifndef NO_PID_FILE
  901. case 'p':
  902. fn_pid = getCommandLineArg(optarg);
  903. ignoreIniFileParameter(INI_PARAM_PID_FILE);
  904. break;
  905. #endif
  906. #ifndef NO_INI_FILE
  907. case 'i':
  908. fn_ini = getCommandLineArg(optarg);
  909. if (!strcmp(fn_ini, "-")) fn_ini = NULL;
  910. break;
  911. #endif
  912. #ifndef NO_LOG
  913. case 'T':
  914. if (!getArgumentBool(&LogDateAndTime, optarg)) usage();
  915. ignoreIniFileParameter(INI_PARAM_LOG_DATE_AND_TIME);
  916. break;
  917. case 'l':
  918. fn_log = getCommandLineArg(optarg);
  919. ignoreIniFileParameter(INI_PARAM_LOG_FILE);
  920. break;
  921. #ifndef NO_VERBOSE_LOG
  922. case 'v':
  923. case 'q':
  924. logverbose = o == 'v';
  925. ignoreIniFileParameter(INI_PARAM_LOG_VERBOSE);
  926. break;
  927. #endif // NO_VERBOSE_LOG
  928. #endif // NO_LOG
  929. #if !defined(NO_PRIVATE_IP_DETECT)
  930. case 'o':
  931. ignoreIniFileParameter(INI_PARAM_PUBLIC_IP_PROTECTION_LEVEL);
  932. PublicIPProtectionLevel = getOptionArgumentInt(o, 0, 3);
  933. #if !HAVE_GETIFADDR
  934. if (PublicIPProtectionLevel & 1) usage();
  935. #endif // !HAVE_GETIFADDR
  936. break;
  937. #endif // !defined(NO_PRIVATE_IP_DETECT)
  938. #ifndef NO_SOCKETS
  939. #if !defined(USE_MSRPC) && !defined(SIMPLE_SOCKETS)
  940. case 'L':
  941. maxsockets++;
  942. ignoreIniFileParameter(INI_PARAM_LISTEN);
  943. break;
  944. #if HAVE_FREEBIND
  945. case 'F':
  946. if (!getArgumentBool(&freebind, optarg)) usage();
  947. ignoreIniFileParameter(INI_PARAM_FREEBIND);
  948. break;
  949. #endif // HAVE_FREEBIND
  950. #endif // !defined(USE_MSRPC) && !defined(SIMPLE_SOCKETS)
  951. #ifdef _NTSERVICE
  952. case 'U':
  953. ServiceUser = optarg;
  954. break;
  955. case 'W':
  956. ServicePassword = optarg;
  957. break;
  958. case 's':
  959. #ifndef USE_MSRPC
  960. if (InetdMode) usage();
  961. #endif // USE_MSRPC
  962. if (!IsNTService) installService = 1; // Install
  963. break;
  964. case 'S':
  965. if (!IsNTService) installService = 2; // Remove
  966. break;
  967. #endif // _NTSERVICE
  968. case 'D':
  969. #ifndef _WIN32
  970. nodaemon = 1;
  971. #else // _WIN32
  972. #ifdef _PEDANTIC
  973. printerrorf("Warning: Option -D has no effect in the Windows version of vlmcsd.\n");
  974. #endif // _PEDANTIC
  975. #endif // _WIN32
  976. break;
  977. #ifndef NO_LOG
  978. case 'e':
  979. logstdout = 1;
  980. break;
  981. #endif // NO_LOG
  982. #endif // NO_SOCKETS
  983. #ifndef NO_RANDOM_EPID
  984. case 'r':
  985. RandomizationLevel = (int_fast8_t)getOptionArgumentInt(o, 0, 2);
  986. ignoreIniFileParameter(INI_PARAM_RANDOMIZATION_LEVEL);
  987. break;
  988. case 'C':
  989. Lcid = (uint16_t)getOptionArgumentInt(o, 0, 32767);
  990. ignoreIniFileParameter(INI_PARAM_LCID);
  991. #ifdef _PEDANTIC
  992. if (!IsValidLcid(Lcid))
  993. {
  994. printerrorf("Warning: %s is not a valid LCID.\n", optarg);
  995. }
  996. #endif // _PEDANTIC
  997. break;
  998. #endif // NO_RANDOM_PID
  999. #if !defined(NO_USER_SWITCH) && !defined(_WIN32)
  1000. case 'g':
  1001. gname = optarg;
  1002. ignoreIniFileParameter(INI_PARAM_GID);
  1003. #ifndef NO_SIGHUP
  1004. if (!IsRestarted)
  1005. #endif // NO_SIGHUP
  1006. if (GetGid())
  1007. {
  1008. printerrorf("Fatal: %s for %s failed: %s\n", "setgid", gname, strerror(errno));
  1009. exit(errno);
  1010. }
  1011. break;
  1012. case 'u':
  1013. uname = optarg;
  1014. ignoreIniFileParameter(INI_PARAM_UID);
  1015. #ifndef NO_SIGHUP
  1016. if (!IsRestarted)
  1017. #endif // NO_SIGHUP
  1018. if (GetUid())
  1019. {
  1020. printerrorf("Fatal: %s for %s failed: %s\n", "setuid", uname, strerror(errno));
  1021. exit(errno);
  1022. }
  1023. break;
  1024. #endif // NO_USER_SWITCH && !_WIN32
  1025. #ifndef NO_CUSTOM_INTERVALS
  1026. case 'R':
  1027. VLRenewalInterval = getTimeSpanFromCommandLine(optarg, o);
  1028. ignoreIniFileParameter(INI_PARAM_RENEWAL_INTERVAL);
  1029. break;
  1030. case 'A':
  1031. VLActivationInterval = getTimeSpanFromCommandLine(optarg, o);
  1032. ignoreIniFileParameter(INI_PARAM_ACTIVATION_INTERVAL);
  1033. break;
  1034. #endif
  1035. #ifndef USE_MSRPC
  1036. case 'd':
  1037. case 'k':
  1038. DisconnectImmediately = o == 'd';
  1039. ignoreIniFileParameter(INI_PARAM_DISCONNECT_IMMEDIATELY);
  1040. break;
  1041. case 'N':
  1042. if (!getArgumentBool(&UseRpcNDR64, optarg)) usage();
  1043. ignoreIniFileParameter(INI_PARAM_RPC_NDR64);
  1044. break;
  1045. case 'B':
  1046. if (!getArgumentBool(&UseRpcBTFN, optarg)) usage();
  1047. ignoreIniFileParameter(INI_PARAM_RPC_BTFN);
  1048. break;
  1049. #endif // !USE_MSRPC
  1050. #ifndef NO_VERSION_INFORMATION
  1051. case 'V':
  1052. #ifdef _NTSERVICE
  1053. if (IsNTService) break;
  1054. #endif
  1055. #if defined(__s390__) && !defined(__zarch__) && !defined(__s390x__)
  1056. printf("vlmcsd %s %i-bit\n", Version, sizeof(void*) == 4 ? 31 : (int)sizeof(void*) << 3);
  1057. #else
  1058. printf("vlmcsd %s %i-bit\n", Version, (int)sizeof(void*) << 3);
  1059. #endif // defined(__s390__) && !defined(__zarch__) && !defined(__s390x__)
  1060. printPlatform();
  1061. printCommonFlags();
  1062. printServerFlags();
  1063. exit(0);
  1064. #endif // NO_VERSION_INFORMATION
  1065. default:
  1066. usage();
  1067. }
  1068. // Do not allow non-option arguments
  1069. if (optind != global_argc)
  1070. usage();
  1071. #ifdef _NTSERVICE
  1072. // -U and -W must be used with -s
  1073. if ((ServiceUser || *ServicePassword) && installService != 1) usage();
  1074. #endif // _NTSERVICE
  1075. }
  1076. #ifndef NO_PID_FILE
  1077. static void writePidFile()
  1078. {
  1079. # ifndef NO_SIGHUP
  1080. if (IsRestarted) return;
  1081. # endif // NO_SIGHUP
  1082. if (fn_pid && !InetdMode)
  1083. {
  1084. FILE *_f = fopen(fn_pid, "w");
  1085. if ( _f )
  1086. {
  1087. fprintf(_f, "%u", (uint32_t)getpid());
  1088. fclose(_f);
  1089. }
  1090. #ifndef NO_LOG
  1091. else
  1092. {
  1093. logger("Warning: Cannot write pid file '%s'. %s.\n", fn_pid, strerror(errno));
  1094. }
  1095. #endif // NO_LOG
  1096. }
  1097. }
  1098. #else
  1099. #define writePidFile(x)
  1100. #endif // NO_PID_FILE
  1101. #if !defined(NO_SOCKETS) && !defined(USE_MSRPC)
  1102. void cleanup()
  1103. {
  1104. if (!InetdMode)
  1105. {
  1106. #ifndef NO_PID_FILE
  1107. if (fn_pid) unlink(fn_pid);
  1108. #endif // NO_PID_FILE
  1109. closeAllListeningSockets();
  1110. #if !defined(NO_LIMIT) && !defined(NO_SOCKETS) && !defined(_WIN32) && !__minix__
  1111. sem_unlink("/vlmcsd");
  1112. #if !defined(USE_THREADS) && !defined(CYGWIN)
  1113. if (shmid >= 0)
  1114. {
  1115. if (Semaphore != (sem_t*)-1) shmdt(Semaphore);
  1116. shmctl(shmid, IPC_RMID, NULL);
  1117. }
  1118. #endif // !defined(USE_THREADS) && !defined(CYGWIN)
  1119. #endif // !defined(NO_LIMIT) && !defined(NO_SOCKETS) && !defined(_WIN32) && !__minix__
  1120. #ifndef NO_LOG
  1121. logger("vlmcsd %s was shutdown\n", Version);
  1122. #endif // NO_LOG
  1123. }
  1124. }
  1125. #elif defined(USE_MSRPC)
  1126. void cleanup()
  1127. {
  1128. # ifndef NO_PID_FILE
  1129. if (fn_pid) unlink(fn_pid);
  1130. # endif // NO_PID_FILE
  1131. # ifndef NO_LOG
  1132. logger("vlmcsd %s was shutdown\n", Version);
  1133. # endif // NO_LOG
  1134. }
  1135. #else // Neither Sockets nor RPC
  1136. __pure void cleanup() {}
  1137. #endif // Neither Sockets nor RPC
  1138. #if !defined(USE_MSRPC) && !defined(NO_LIMIT) && !defined(NO_SOCKETS) && !__minix__
  1139. // Get a semaphore for limiting the maximum concurrent tasks
  1140. static void allocateSemaphore(void)
  1141. {
  1142. #ifdef USE_THREADS
  1143. #define sharemode 0
  1144. #else
  1145. #define sharemode 1
  1146. #endif
  1147. #ifndef _WIN32
  1148. sem_unlink("/vlmcsd");
  1149. #endif
  1150. if(MaxTasks < SEM_VALUE_MAX && !InetdMode)
  1151. {
  1152. #ifndef _WIN32
  1153. #if !defined(USE_THREADS) && !defined(CYGWIN)
  1154. if ((Semaphore = sem_open("/vlmcsd", O_CREAT /*| O_EXCL*/, 0700, MaxTasks)) == SEM_FAILED) // fails on many systems
  1155. {
  1156. // We didn't get a named Semaphore (/dev/shm on Linux) so let's try our own shared page
  1157. if (
  1158. ( shmid = shmget(IPC_PRIVATE, sizeof(sem_t), IPC_CREAT | 0600) ) < 0 ||
  1159. ( Semaphore = (sem_t*)shmat(shmid, NULL, 0) ) == (sem_t*)-1 ||
  1160. sem_init(Semaphore, 1, MaxTasks) < 0
  1161. )
  1162. {
  1163. int errno_save = errno;
  1164. if (Semaphore != (sem_t*)-1) shmdt(Semaphore);
  1165. if (shmid >= 0) shmctl(shmid, IPC_RMID, NULL);
  1166. printerrorf("Warning: Could not create semaphore: %s\n", vlmcsd_strerror(errno_save));
  1167. MaxTasks = SEM_VALUE_MAX;
  1168. }
  1169. }
  1170. #else // THREADS or CYGWIN
  1171. Semaphore = (sem_t*)vlmcsd_malloc(sizeof(sem_t));
  1172. if (sem_init(Semaphore, sharemode, MaxTasks) < 0) // sem_init is not implemented on Darwin (returns ENOSYS)
  1173. {
  1174. free(Semaphore);
  1175. if ((Semaphore = sem_open("/vlmcsd", O_CREAT /*| O_EXCL*/, 0700, MaxTasks)) == SEM_FAILED)
  1176. {
  1177. printerrorf("Warning: Could not create semaphore: %s\n", vlmcsd_strerror(errno));
  1178. MaxTasks = SEM_VALUE_MAX;
  1179. }
  1180. }
  1181. #endif // THREADS or CYGWIN
  1182. #else // _WIN32
  1183. if (!(Semaphore = CreateSemaphoreA(NULL, MaxTasks, MaxTasks, NULL)))
  1184. {
  1185. printerrorf("Warning: Could not create semaphore: %s\n", vlmcsd_strerror(GetLastError()));
  1186. MaxTasks = SEM_VALUE_MAX;
  1187. }
  1188. #endif // _WIN32
  1189. }
  1190. }
  1191. #endif // !defined(NO_LIMIT) && !defined(NO_SOCKETS) && !__minix__
  1192. #if !defined(NO_SOCKETS) && !defined(USE_MSRPC) && !defined(SIMPLE_SOCKETS)
  1193. int setupListeningSockets()
  1194. {
  1195. int o;
  1196. # if HAVE_GETIFADDR
  1197. char** privateIPList;
  1198. int numPrivateIPs = 0;
  1199. if (PublicIPProtectionLevel & 1) getPrivateIPAddresses(&numPrivateIPs, &privateIPList);
  1200. uint_fast8_t allocsockets = maxsockets ? (maxsockets + numPrivateIPs) : ((PublicIPProtectionLevel & 1) ? numPrivateIPs : 2);
  1201. # else // !HAVE_GETIFADDR
  1202. uint_fast8_t allocsockets = maxsockets ? maxsockets : 2;
  1203. # endif // !HAVE_GETIFADDR
  1204. SocketList = (SOCKET*)vlmcsd_malloc((size_t)allocsockets * sizeof(SOCKET));
  1205. int_fast8_t haveIPv4Stack = checkProtocolStack(AF_INET);
  1206. int_fast8_t haveIPv6Stack = checkProtocolStack(AF_INET6);
  1207. // Reset getopt since we've alread used it
  1208. optReset();
  1209. for (opterr = 0; ( o = getopt(global_argc, (char* const*)global_argv, optstring) ) > 0; ) switch (o)
  1210. {
  1211. case 'P':
  1212. defaultport = optarg;
  1213. break;
  1214. case 'L':
  1215. addListeningSocket(optarg);
  1216. break;
  1217. default:
  1218. break;
  1219. }
  1220. # ifndef NO_INI_FILE
  1221. if (maxsockets && !numsockets)
  1222. {
  1223. if (fn_ini && !readIniFile(INI_FILE_PASS_2))
  1224. {
  1225. #ifdef INI_FILE
  1226. if (strcmp(fn_ini, INI_FILE))
  1227. #endif // INI_FILE
  1228. printerrorf("Warning: Can't read %s: %s\n", fn_ini, strerror(errno));
  1229. }
  1230. }
  1231. # endif
  1232. # if HAVE_GETIFADDR
  1233. if (PublicIPProtectionLevel & 1)
  1234. {
  1235. int i;
  1236. for (i = 0; i < numPrivateIPs; i++)
  1237. {
  1238. addListeningSocket(privateIPList[i]);
  1239. free(privateIPList[i]);
  1240. }
  1241. free(privateIPList);
  1242. }
  1243. # endif // HAVE_GETIFADDR
  1244. // if -L hasn't been specified on the command line, use default sockets (all IP addresses)
  1245. // maxsocket results from first pass parsing the arguments
  1246. if (!maxsockets)
  1247. {
  1248. # if HAVE_GETIFADDR
  1249. if (!(PublicIPProtectionLevel & 1) && haveIPv6Stack) addListeningSocket("::");
  1250. if (!(PublicIPProtectionLevel & 1) && haveIPv4Stack) addListeningSocket("0.0.0.0");
  1251. # else // !HAVE_GETIFADDR
  1252. if (haveIPv6Stack) addListeningSocket("::");
  1253. if (haveIPv4Stack) addListeningSocket("0.0.0.0");
  1254. # endif // !HAVE_GETIFADDR
  1255. }
  1256. if (!numsockets)
  1257. {
  1258. printerrorf("Fatal: Could not listen on any socket.\n");
  1259. return(!0);
  1260. }
  1261. return 0;
  1262. }
  1263. #endif // !defined(NO_SOCKETS) && !defined(USE_MSRPC) && !defined(SIMPLE_SOCKETS)
  1264. int server_main(int argc, CARGV argv)
  1265. {
  1266. #if !defined(_NTSERVICE) && !defined(NO_SOCKETS)
  1267. int error;
  1268. #endif // !defined(_NTSERVICE) && !defined(NO_SOCKETS)
  1269. // Initialize ePID / HwId parameters
  1270. memset(KmsResponseParameters, 0, sizeof(KmsResponseParameters));
  1271. global_argc = argc;
  1272. global_argv = argv;
  1273. #ifdef _NTSERVICE // #endif is in newmain()
  1274. DWORD lasterror = ERROR_SUCCESS;
  1275. if (!StartServiceCtrlDispatcher(NTServiceDispatchTable) && (lasterror = GetLastError()) == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
  1276. {
  1277. IsNTService = FALSE;
  1278. return newmain();
  1279. }
  1280. return lasterror;
  1281. }
  1282. int newmain()
  1283. {
  1284. int error;
  1285. // Initialize thread synchronization objects for Windows and Cygwin
  1286. #ifdef USE_THREADS
  1287. #ifndef NO_LOG
  1288. // Initialize the Critical Section for proper logging
  1289. InitializeCriticalSection(&logmutex);
  1290. #endif // NO_LOG
  1291. #endif // USE_THREADS
  1292. #ifdef _WIN32
  1293. #ifndef USE_MSRPC
  1294. // Windows Sockets must be initialized
  1295. WSADATA wsadata;
  1296. if ((error = WSAStartup(0x0202, &wsadata)))
  1297. {
  1298. printerrorf("Fatal: Could not initialize Windows sockets (Error: %d).\n", error);
  1299. return error;
  1300. }
  1301. #endif // USE_MSRPC
  1302. // Windows can never daemonize
  1303. //nodaemon = 1;
  1304. #else // __CYGWIN__
  1305. // Do not daemonize if we are a Windows service
  1306. if (IsNTService) nodaemon = 1;
  1307. #endif // _WIN32 / __CYGWIN__
  1308. #endif // _NTSERVICE ( #ifdef is main(int argc, CARGV argv) )
  1309. parseGeneralArguments(); // Does not return if an error occurs
  1310. #if !defined(_WIN32) && !defined(NO_SOCKETS) && !defined(USE_MSRPC)
  1311. struct stat statbuf;
  1312. fstat(STDIN_FILENO, &statbuf);
  1313. if (S_ISSOCK(statbuf.st_mode))
  1314. {
  1315. InetdMode = 1;
  1316. nodaemon = 1;
  1317. #ifndef SIMPLE_SOCKETS
  1318. maxsockets = 0;
  1319. #endif // SIMPLE_SOCKETS
  1320. #ifndef NO_LOG
  1321. logstdout = 0;
  1322. #endif // NO_LOG
  1323. }
  1324. #endif // !defined(_WIN32) && !defined(NO_SOCKETS) && !defined(USE_MSRPC)
  1325. #ifndef NO_INI_FILE
  1326. if (fn_ini && !readIniFile(INI_FILE_PASS_1))
  1327. {
  1328. #ifdef INI_FILE
  1329. if (strcmp(fn_ini, INI_FILE))
  1330. #endif // INI_FILE
  1331. printerrorf("Warning: Can't read %s: %s\n", fn_ini, strerror(errno));
  1332. }
  1333. #endif // NO_INI_FILE
  1334. #if defined(USE_MSRPC) && !defined(NO_PRIVATE_IP_DETECT)
  1335. if (PublicIPProtectionLevel)
  1336. {
  1337. printerrorf("Warning: Public IP address protection using MS RPC is poor. See vlmcsd.8\n");
  1338. }
  1339. #endif // defined(USE_MSRPC) && !defined(NO_PRIVATE_IP_DETECT)
  1340. #if !defined(NO_LIMIT) && !defined(NO_SOCKETS) && !__minix__ && !defined(USE_MSRPC)
  1341. allocateSemaphore();
  1342. #endif // !defined(NO_LIMIT) && !defined(NO_SOCKETS) && __minix__
  1343. #ifdef _NTSERVICE
  1344. if (installService)
  1345. return NtServiceInstallation(installService, ServiceUser, ServicePassword);
  1346. #endif // _NTSERVICE
  1347. #if !defined(NO_SOCKETS) && !defined(USE_MSRPC)
  1348. if (!InetdMode)
  1349. {
  1350. #ifdef SIMPLE_SOCKETS
  1351. if ((error = listenOnAllAddresses())) return error;
  1352. #else // !SIMPLE_SOCKETS
  1353. if ((error = setupListeningSockets())) return error;
  1354. #endif // !SIMPLE_SOCKETS
  1355. }
  1356. #endif // !defined(NO_SOCKETS) && !defined(USE_MSRPC)
  1357. // After sockets have been set up, we may switch to a lower privileged user
  1358. #if !defined(_WIN32) && !defined(NO_USER_SWITCH)
  1359. #ifndef NO_SIGHUP
  1360. if (!IsRestarted)
  1361. {
  1362. #endif // NO_SIGHUP
  1363. if (gid != INVALID_GID)
  1364. {
  1365. if (setgid(gid))
  1366. {
  1367. printerrorf("Fatal: %s for %s failed: %s\n", "setgid", gname, strerror(errno));
  1368. return errno;
  1369. }
  1370. if (setgroups(1, &gid))
  1371. {
  1372. printerrorf("Fatal: %s for %s failed: %s\n", "setgroups", gname, strerror(errno));
  1373. return errno;
  1374. }
  1375. }
  1376. if (uid != INVALID_UID && setuid(uid))
  1377. {
  1378. printerrorf("Fatal: %s for %s failed: %s\n", "setuid", uname, strerror(errno));
  1379. return errno;
  1380. }
  1381. #ifndef NO_SIGHUP
  1382. }
  1383. #endif // NO_SIGHUP
  1384. #endif // !defined(_WIN32) && !defined(NO_USER_SWITCH)
  1385. randomNumberInit();
  1386. // Randomization Level 1 means generate ePIDs at startup and use them during
  1387. // the lifetime of the process. So we generate them now
  1388. #ifndef NO_RANDOM_EPID
  1389. if (RandomizationLevel == 1) randomPidInit();
  1390. #endif
  1391. #if !defined(NO_SOCKETS)
  1392. #ifdef _WIN32
  1393. if (!IsNTService)
  1394. #endif // _WIN32
  1395. if ((error = daemonizeAndSetSignalAction())) return error;
  1396. #endif // !defined(NO_SOCKETS)
  1397. writePidFile();
  1398. #if !defined(NO_LOG) && !defined(NO_SOCKETS) && !defined(USE_MSRPC)
  1399. if (!InetdMode)
  1400. logger("vlmcsd %s started successfully\n", Version);
  1401. #endif // !defined(NO_LOG) && !defined(NO_SOCKETS) && !defined(USE_MSRPC)
  1402. #if defined(_NTSERVICE) && !defined(USE_MSRPC)
  1403. if (IsNTService) ReportServiceStatus(SERVICE_RUNNING, NO_ERROR, 200);
  1404. #endif // defined(_NTSERVICE) && !defined(USE_MSRPC)
  1405. int rc;
  1406. rc = runServer();
  1407. // Clean up things and exit
  1408. #ifdef _NTSERVICE
  1409. if (!ServiceShutdown)
  1410. #endif
  1411. cleanup();
  1412. #ifdef _NTSERVICE
  1413. else
  1414. ReportServiceStatus(SERVICE_STOPPED, NO_ERROR, 0);
  1415. #endif
  1416. return rc;
  1417. }