vlmcsd.c 42 KB

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