vlmcsd.c 43 KB

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