vlmcsd.c 38 KB

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