vlmcsd.c 42 KB

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