modified: myjupyterlab.sh
[GalaxyCodeBases.git] / etc / Windows / vlmcsd_old_vancepym / vlmcsd.c
blob63ef423ec2b8b2db1a22a7c6808bbae699680307
1 #ifndef CONFIG
2 #define CONFIG "config.h"
3 #endif // CONFIG
4 #include CONFIG
6 #if defined(USE_MSRPC) && !defined(_WIN32) && !defined(__CYGWIN__)
7 #error Microsoft RPC is only available on Windows and Cygwin
8 #endif
10 #if defined(NO_SOCKETS) && defined(USE_MSRPC)
11 #error Cannot use inetd mode with Microsoft RPC
12 #endif
14 #ifndef _GNU_SOURCE
15 #define _GNU_SOURCE
16 #endif
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <stdint.h>
24 #ifndef _WIN32
25 #include <pwd.h>
26 #include <grp.h>
27 #include <sys/types.h>
29 #if !defined(NO_LIMIT) && !__minix__
30 #include <sys/ipc.h>
31 #if !__ANDROID__
32 #include <sys/shm.h>
33 #else // __ANDROID__
34 #include <sys/syscall.h>
35 #endif // __ANDROID__
36 #endif // !defined(NO_LIMIT) && !__minix__
38 #include <sys/wait.h>
39 #include <unistd.h>
40 #include <fcntl.h>
41 #include <sys/stat.h>
42 #include <semaphore.h>
43 #endif // !_WIN32
45 #if __APPLE__
46 #include <mach-o/dyld.h>
47 #endif // __APPLE__
49 #if __linux__ && defined(USE_AUXV)
50 #include <sys/auxv.h>
51 #endif
53 #if __FreeBSD__
54 #include <sys/sysctl.h>
55 #endif
57 #include "vlmcsd.h"
58 #include "endian.h"
59 #include "shared_globals.h"
60 #include "output.h"
61 #ifndef USE_MSRPC
62 #include "network.h"
63 #else // USE_MSRPC
64 #include "msrpc-server.h"
65 #endif // USE_MSRPC
66 #include "ntservice.h"
67 #include "helpers.h"
70 static const char* const optstring = "N:B:m:t:w:0:3:H:A:R:u:g:L:p:i:P:l:r:U:W:C:SsfeDd46VvIdqkZ";
72 #if !defined(NO_SOCKETS)
73 #if !defined(USE_MSRPC)
74 static uint_fast8_t maxsockets = 0;
75 static int_fast8_t haveIPv6Stack = 0;
76 static int_fast8_t haveIPv4Stack = 0;
77 static int_fast8_t v6required = 0;
78 static int_fast8_t v4required = 0;
79 #endif // !defined(USE_MSRPC)
80 #endif // !defined(NO_SOCKETS)
82 #ifdef _NTSERVICE
83 static int_fast8_t installService = 0;
84 static const char *restrict ServiceUser = NULL;
85 static const char *restrict ServicePassword = "";
86 #endif
88 #ifndef NO_PID_FILE
89 static const char *fn_pid = NULL;
90 #endif
92 #ifndef NO_INI_FILE
94 #ifdef INI_FILE
95 static const char *fn_ini = INI_FILE;
96 #else // !INI_FILE
97 static const char *fn_ini = NULL;
98 #endif // !INI_FILE
100 static const char* IniFileErrorMessage = "";
101 char* IniFileErrorBuffer = NULL;
102 #define INIFILE_ERROR_BUFFERSIZE 256
104 static IniFileParameter_t IniFileParameterList[] =
106 # ifndef NO_RANDOM_EPID
107 { "RandomizationLevel", INI_PARAM_RANDOMIZATION_LEVEL },
108 { "LCID", INI_PARAM_LCID },
109 # endif // NO_RANDOM_EPID
110 # ifdef USE_MSRPC
111 { "Port", INI_PARAM_PORT },
112 # endif // USE_MSRPC
113 # if !defined(NO_SOCKETS) && !defined(USE_MSRPC)
114 { "Listen", INI_PARAM_LISTEN },
115 # if !defined(NO_LIMIT) && !__minix__
116 { "MaxWorkers", INI_PARAM_MAX_WORKERS },
117 # endif // !defined(NO_LIMIT) && !__minix__
118 # endif // !defined(NO_SOCKETS) && !defined(USE_MSRPC)
119 # if !defined(NO_TIMEOUT) && !__minix__ && !defined(USE_MSRPC) & !defined(USE_MSRPC)
120 { "ConnectionTimeout", INI_PARAM_CONNECTION_TIMEOUT },
121 # endif // !defined(NO_TIMEOUT) && !__minix__ && !defined(USE_MSRPC) & !defined(USE_MSRPC)
122 # ifndef USE_MSRPC
123 { "DisconnectClientsImmediately", INI_PARAM_DISCONNECT_IMMEDIATELY },
124 { "UseNDR64", INI_PARAM_RPC_NDR64 },
125 { "UseBTFN", INI_PARAM_RPC_BTFN },
126 # endif // USE_MSRPC
127 # ifndef NO_PID_FILE
128 { "PIDFile", INI_PARAM_PID_FILE },
129 # endif // NO_PID_FILE
130 # ifndef NO_LOG
131 { "LogFile", INI_PARAM_LOG_FILE },
132 # ifndef NO_VERBOSE_LOG
133 { "LogVerbose", INI_PARAM_LOG_VERBOSE },
134 # endif // NO_VERBOSE_LOG
135 # endif // NO_LOG
136 # ifndef NO_CUSTOM_INTERVALS
137 {"ActivationInterval", INI_PARAM_ACTIVATION_INTERVAL },
138 {"RenewalInterval", INI_PARAM_RENEWAL_INTERVAL },
139 # endif // NO_CUSTOM_INTERVALS
140 # if !defined(NO_USER_SWITCH) && !defined(_WIN32)
141 { "user", INI_PARAM_UID },
142 { "group", INI_PARAM_GID},
143 # endif // !defined(NO_USER_SWITCH) && !defined(_WIN32)
146 #endif // NO_INI_FILE
149 #if !defined(NO_LIMIT) && !defined (NO_SOCKETS) && !__minix__
151 #if !defined(USE_THREADS) && !defined(CYGWIN) && !defined(USE_MSRPC)
152 static int shmid = -1;
153 #endif
155 #if __ANDROID__ && !defined(USE_THREADS) // Bionic does not wrap these syscalls (willingly because Google fears, developers don't know how to use it)
157 #ifdef __NR_shmget
158 static int shmget(key_t key, size_t size, int shmflg)
160 return syscall(__NR_shmget, key, size, shmflg);
162 #endif // __NR_shmget
164 #ifdef __NR_shmat
165 static void *shmat(int shmid, const void *shmaddr, int shmflg)
167 return (void *)syscall(__NR_shmat, shmid, shmaddr, shmflg);
169 #endif // __NR_shmat
171 #ifdef __NR_shmdt
172 static int shmdt(const void *shmaddr)
174 return syscall(__NR_shmdt, shmaddr);
176 #endif // __NR_shmdt
178 #ifdef __NR_shmctl
179 static int shmctl(int shmid, int cmd, /*struct shmid_ds*/void *buf)
181 return syscall(__NR_shmctl, shmid, cmd, buf);
183 #endif // __NR_shmctl
185 #endif // __ANDROID__ && !defined(USE_THREADS)
187 #endif // !defined(NO_LIMIT) && !defined (NO_SOCKETS) && !__minix__
189 #ifndef NO_USER_SWITCH
190 #ifndef _WIN32
192 static const char *uname = NULL, *gname = NULL;
193 static gid_t gid = INVALID_GID;
194 static uid_t uid = INVALID_UID;
196 // Get Numeric id of user/group
197 static char GetNumericId(gid_t *restrict id, const char *const c)
199 char* endptr;
200 gid_t temp;
202 temp = (gid_t)strtoll(c, &endptr, 10);
204 if (!*endptr) *id = temp;
206 return *endptr;
210 // Get group id from option argument
211 static char GetGid()
213 struct group *g;
215 if ((g = getgrnam(optarg)))
216 gid = g->gr_gid;
217 else
218 return GetNumericId(&gid, optarg);
220 return 0;
224 // Get user id from option argument
225 static char GetUid()
227 struct passwd *u;
229 ////PORTABILITY: Assumes uid_t and gid_t are of same size (shouldn't be a problem)
230 if ((u = getpwnam(optarg)))
231 uid = u->pw_uid;
232 else
233 return GetNumericId((gid_t*)&uid, optarg);
235 return 0;
237 #endif // _WIN32
238 #endif //NO_USER_SWITCH
240 #ifdef NO_HELP
241 static __noreturn void usage()
243 printerrorf("Incorrect parameters\n\n");
244 exit(!0);
246 #else // HELP
249 static __noreturn void usage()
251 printerrorf("vlmcsd %s\n"
252 "\nUsage:\n"
253 " %s [ options ]\n\n"
254 "Where:\n"
255 #ifndef NO_CL_PIDS
256 " -w <ePID> always use <ePID> for Windows\n"
257 " -0 <ePID> always use <ePID> for Office2010\n"
258 " -3 <ePID> always use <ePID> for Office2013\n"
259 " -H <HwId> always use hardware Id <HwId>\n"
260 #endif // NO_CL_PIDS
261 #if !defined(_WIN32) && !defined(NO_USER_SWITCH)
262 " -u <user> set uid to <user>\n"
263 " -g <group> set gid to <group>\n"
264 #endif // !defined(_WIN32) && !defined(NO_USER_SWITCH)
265 #ifndef NO_RANDOM_EPID
266 " -r 0|1|2\t\tset ePID randomization level (default 1)\n"
267 " -C <LCID>\t\tuse fixed <LCID> in random ePIDs\n"
268 #endif // NO_RANDOM_EPID
269 #ifndef NO_SOCKETS
270 #ifndef USE_MSRPC
271 " -4\t\t\tuse IPv4\n"
272 " -6\t\t\tuse IPv6\n"
273 " -L <address>[:<port>]\tlisten on IP address <address> with optional <port>\n"
274 " -P <port>\t\tset TCP port <port> for subsequent -L statements (default 1688)\n"
275 #else // USE_MSRPC
276 " -P <port>\t\tuse TCP port <port> (default 1688)\n"
277 #endif // USE_MSRPC
278 #if !defined(NO_LIMIT) && !__minix__
279 " -m <clients>\t\tHandle max. <clients> simultaneously (default no limit)\n"
280 #endif // !defined(NO_LIMIT) && !__minix__
281 #ifdef _NTSERVICE
282 " -s install vlmcsd as an NT service. Ignores -e"
283 #ifndef _WIN32
284 ", -f and -D"
285 #endif // _WIN32
286 "\n"
287 " -S remove vlmcsd service. Ignores all other options\n"
288 " -U <username> run NT service as <username>. Must be used with -s\n"
289 " -W <password> optional <password> for -U. Must be used with -s\n"
290 #endif // _NTSERVICE
291 #ifndef NO_LOG
292 " -e log to stdout\n"
293 #endif // NO_LOG
294 #ifndef _WIN32 //
295 " -D run in foreground\n"
296 " -f run in foreground"
297 #ifndef NO_LOG
298 " and log to stdout"
299 #endif // NO_LOG
300 "\n"
301 #endif // _WIN32
302 #endif // NO_SOCKETS
303 #ifndef USE_MSRPC
304 #if !defined(NO_TIMEOUT) && !__minix__
305 " -t <seconds>\t\tdisconnect clients after <seconds> of inactivity (default 30)\n"
306 #endif // !defined(NO_TIMEOUT) && !__minix__
307 " -d\t\t\tdisconnect clients after each request\n"
308 " -k\t\t\tdon't disconnect clients after each request (default)\n"
309 " -N0, -N1\t\tdisable/enable NDR64\n"
310 " -B0, -B1\t\tdisable/enable bind time feature negotiation\n"
311 #endif // USE_MSRPC
312 #ifndef NO_PID_FILE
313 " -p <file> write pid to <file>\n"
314 #endif // NO_PID_FILE
315 #ifndef NO_INI_FILE
316 " -i <file>\t\tuse config file <file>\n"
317 #endif // NO_INI_FILE
318 #ifndef NO_CUSTOM_INTERVALS
319 " -R <interval> renew activation every <interval> (default 1w)\n"
320 " -A <interval> retry activation every <interval> (default 2h)\n"
321 #endif // NO_CUSTOM_INTERVALS
322 #ifndef NO_LOG
323 #ifndef _WIN32
324 " -l syslog log to syslog\n"
325 #endif // _WIN32
326 " -l <file> log to <file>\n"
327 #ifndef NO_VERBOSE_LOG
328 " -v\t\t\tlog verbose\n"
329 " -q\t\t\tdon't log verbose (default)\n"
330 #endif // NO_VERBOSE_LOG
331 #endif // NO_LOG
332 " -V display version information and exit"
333 "\n",
334 Version, global_argv[0]);
336 exit(!0);
338 #endif // HELP
341 #ifndef NO_CUSTOM_INTERVALS
343 // Convert time span strings (e.g. "2h", "5w") to minutes
344 __pure static DWORD timeSpanString2Minutes(const char *const restrict argument)
346 char *unitId;
348 long long val = strtoll(argument, &unitId, 10);
350 switch(toupper((int)*unitId))
352 case 0:
353 case 'M':
354 break;
355 case 'H':
356 val *= 60;
357 break;
358 case 'D':
359 val *= 60 * 24;
360 break;
361 case 'W':
362 val *= 60 * 24 * 7;
363 break;
364 case 'S':
365 val /= 60;
366 break;
367 default:
368 return 0;
371 if (val < 1) val = 1;
372 if (val > UINT_MAX) val = UINT_MAX;
374 return (DWORD)val;
378 #ifndef NO_INI_FILE
379 __pure static BOOL getTimeSpanFromIniFile(DWORD* result, const char *const restrict argument)
381 DWORD val = timeSpanString2Minutes(argument);
382 if (!val)
384 IniFileErrorMessage = "Incorrect time span.";
385 return FALSE;
388 *result = val;
389 return TRUE;
391 #endif // NO_INI_FILE
394 __pure static DWORD getTimeSpanFromCommandLine(const char *const restrict optarg, const char optchar)
396 long long val = timeSpanString2Minutes(optarg);
398 if (!val)
400 printerrorf("Fatal: No valid time span specified in option -%c.\n", optchar);
401 exit (!0);
404 return (DWORD)val;
407 #endif // NO_CUSTOM_INTERVALS
410 #ifndef NO_INI_FILE
411 static void ignoreIniFileParameter(uint_fast8_t iniFileParameterId)
413 uint_fast8_t i;
415 for (i = 0; i < _countof(IniFileParameterList); i++)
417 if (IniFileParameterList[i].Id != iniFileParameterId) continue;
418 IniFileParameterList[i].Id = 0;
419 break;
422 #else // NO_INI_FILE
423 #define ignoreIniFileParameter(x)
424 #endif // NO_INI_FILE
427 #ifndef NO_INI_FILE
428 static BOOL getIniFileArgumentBool(int_fast8_t *result, const char *const argument)
430 IniFileErrorMessage = "Argument must be true/on/yes/1 or false/off/no/0";
431 return getArgumentBool(result, argument);
435 static BOOL getIniFileArgumentInt(unsigned int *result, const char *const argument, const unsigned int min, const unsigned int max)
437 unsigned int tempResult;
439 if (!stringToInt(argument, min, max, &tempResult))
441 snprintf(IniFileErrorBuffer, INIFILE_ERROR_BUFFERSIZE, "Must be integer between %u and %u", min, max);
442 IniFileErrorMessage = IniFileErrorBuffer;
443 return FALSE;
446 *result = tempResult;
447 return TRUE;
451 static char* allocateStringArgument(const char *const argument)
453 char* result = (char*)vlmcsd_malloc(strlen(argument) + 1);
454 strcpy(result, argument);
455 return result;
459 static BOOL setIniFileParameter(uint_fast8_t id, const char *const iniarg)
461 unsigned int result;
462 BOOL success = TRUE;
464 switch(id)
466 # if !defined(NO_USER_SWITCH) && !defined(_WIN32)
468 case INI_PARAM_GID:
470 struct group *g;
471 IniFileErrorMessage = "Invalid group id or name";
472 if (!(gname = allocateStringArgument(iniarg))) return FALSE;
474 if ((g = getgrnam(iniarg)))
475 gid = g->gr_gid;
476 else
477 success = !GetNumericId(&gid, iniarg);
478 break;
481 case INI_PARAM_UID:
483 struct passwd *p;
484 IniFileErrorMessage = "Invalid user id or name";
485 if (!(uname = allocateStringArgument(iniarg))) return FALSE;
487 if ((p = getpwnam(iniarg)))
488 uid = p->pw_uid;
489 else
490 success = !GetNumericId(&uid, iniarg);
491 break;
494 # endif // !defined(NO_USER_SWITCH) && !defined(_WIN32)
496 # ifndef NO_RANDOM_EPID
498 case INI_PARAM_LCID:
499 success = getIniFileArgumentInt(&result, iniarg, 0, 32767);
500 if (success) Lcid = (uint16_t)result;
501 break;
503 case INI_PARAM_RANDOMIZATION_LEVEL:
504 success = getIniFileArgumentInt(&result, iniarg, 0, 2);
505 if (success) RandomizationLevel = (int_fast8_t)result;
506 break;
508 # endif // NO_RANDOM_EPID
510 # ifdef USE_MSRPC
512 case INI_PARAM_PORT:
513 defaultport = allocateStringArgument(iniarg);
514 break;
516 # endif // USE_MSRPC
518 # if !defined(NO_SOCKETS) && !defined(USE_MSRPC)
520 case INI_PARAM_LISTEN:
521 maxsockets++;
522 return TRUE;
524 # if !defined(NO_LIMIT) && !__minix__
526 case INI_PARAM_MAX_WORKERS:
527 # ifdef USE_MSRPC
528 success = getIniFileArgumentInt(&MaxTasks, iniarg, 1, RPC_C_LISTEN_MAX_CALLS_DEFAULT);
529 # else // !USE_MSRPC
530 success = getIniFileArgumentInt(&MaxTasks, iniarg, 1, SEM_VALUE_MAX);
531 # endif // !USE_MSRPC
532 break;
534 # endif // !defined(NO_LIMIT) && !__minix__
535 # endif // NO_SOCKETS
537 # ifndef NO_PID_FILE
539 case INI_PARAM_PID_FILE:
540 fn_pid = allocateStringArgument(iniarg);
541 break;
543 # endif // NO_PID_FILE
545 # ifndef NO_LOG
547 case INI_PARAM_LOG_FILE:
548 fn_log = allocateStringArgument(iniarg);
549 break;
551 # ifndef NO_VERBOSE_LOG
552 case INI_PARAM_LOG_VERBOSE:
553 success = getIniFileArgumentBool(&logverbose, iniarg);
554 break;
556 # endif // NO_VERBOSE_LOG
557 # endif // NO_LOG
559 # ifndef NO_CUSTOM_INTERVALS
561 case INI_PARAM_ACTIVATION_INTERVAL:
562 success = getTimeSpanFromIniFile(&VLActivationInterval, iniarg);
563 break;
565 case INI_PARAM_RENEWAL_INTERVAL:
566 success = getTimeSpanFromIniFile(&VLRenewalInterval, iniarg);
567 break;
569 # endif // NO_CUSTOM_INTERVALS
571 # ifndef USE_MSRPC
573 # if !defined(NO_TIMEOUT) && !__minix__
575 case INI_PARAM_CONNECTION_TIMEOUT:
576 success = getIniFileArgumentInt(&result, iniarg, 1, 600);
577 if (success) ServerTimeout = (DWORD)result;
578 break;
580 # endif // !defined(NO_TIMEOUT) && !__minix__
582 case INI_PARAM_DISCONNECT_IMMEDIATELY:
583 success = getIniFileArgumentBool(&DisconnectImmediately, iniarg);
584 break;
586 case INI_PARAM_RPC_NDR64:
587 success = getIniFileArgumentBool(&UseRpcNDR64, iniarg);
588 break;
590 case INI_PARAM_RPC_BTFN:
591 success = getIniFileArgumentBool(&UseRpcBTFN, iniarg);
592 break;
594 # endif // USE_MSRPC
596 default:
597 return FALSE;
600 return success;
604 static __pure int isControlCharOrSlash(const char c)
606 if ((unsigned char)c < '!') return !0;
607 if (c == '/') return !0;
608 return 0;
612 static void iniFileLineNextWord(const char **s)
614 while ( **s && isspace((int)**s) ) (*s)++;
618 static BOOL setHwIdFromIniFileLine(const char **s, const ProdListIndex_t index)
620 iniFileLineNextWord(s);
622 if (**s == '/')
624 if (KmsResponseParameters[index].HwId) return TRUE;
626 BYTE* HwId = (BYTE*)vlmcsd_malloc(sizeof(((RESPONSE_V6 *)0)->HwId));
627 hex2bin(HwId, *s + 1, sizeof(((RESPONSE_V6 *)0)->HwId));
628 KmsResponseParameters[index].HwId = HwId;
631 return TRUE;
635 static BOOL checkGuidInIniFileLine(const char **s, ProdListIndex_t *const index)
637 GUID AppGuid;
639 if (!string2Uuid(*s, &AppGuid)) return FALSE;
641 (*s) += GUID_STRING_LENGTH;
642 getProductNameHE(&AppGuid, AppList, index);
644 if (*index > getAppListSize() - 2)
646 IniFileErrorMessage = "Unknown App Guid.";
647 return FALSE;
650 iniFileLineNextWord(s);
651 if ( *(*s)++ != '=' ) return FALSE;
653 return TRUE;
657 static BOOL setEpidFromIniFileLine(const char **s, const ProdListIndex_t index)
659 iniFileLineNextWord(s);
660 const char *savedPosition = *s;
661 uint_fast16_t i;
663 for (i = 0; !isControlCharOrSlash(**s); i++)
665 if (utf8_to_ucs2_char((const unsigned char*)*s, (const unsigned char**)s) == (WCHAR)~0)
667 return FALSE;
671 if (i < 1 || i >= PID_BUFFER_SIZE) return FALSE;
672 if (KmsResponseParameters[index].Epid) return TRUE;
674 size_t size = *s - savedPosition + 1;
676 char* epidbuffer = (char*)vlmcsd_malloc(size);
677 memcpy(epidbuffer, savedPosition, size - 1);
678 epidbuffer[size - 1] = 0;
680 KmsResponseParameters[index].Epid = epidbuffer;
682 #ifndef NO_LOG
683 KmsResponseParameters[index].EpidSource = fn_ini;
684 #endif //NO_LOG
686 return TRUE;
690 static BOOL getIniFileArgument(const char **s)
692 while (!isspace((int)**s) && **s != '=' && **s) (*s)++;
693 iniFileLineNextWord(s);
695 if (*((*s)++) != '=')
697 IniFileErrorMessage = "'=' required after keyword.";
698 return FALSE;
701 iniFileLineNextWord(s);
703 if (!**s)
705 IniFileErrorMessage = "missing argument after '='.";
706 return FALSE;
709 return TRUE;
713 static BOOL handleIniFileParameter(const char *s)
715 uint_fast8_t i;
717 for (i = 0; i < _countof(IniFileParameterList); i++)
719 if (strncasecmp(IniFileParameterList[i].Name, s, strlen(IniFileParameterList[i].Name))) continue;
720 if (!IniFileParameterList[i].Id) return TRUE;
722 if (!getIniFileArgument(&s)) return FALSE;
724 return setIniFileParameter(IniFileParameterList[i].Id, s);
727 IniFileErrorMessage = "Unknown keyword.";
728 return FALSE;
732 #if !defined(NO_SOCKETS) && !defined(USE_MSRPC)
733 static BOOL setupListeningSocketsFromIniFile(const char *s)
735 if (!maxsockets) return TRUE;
736 if (strncasecmp("Listen", s, 6)) return TRUE;
737 if (!getIniFileArgument(&s)) return TRUE;
739 snprintf(IniFileErrorBuffer, INIFILE_ERROR_BUFFERSIZE, "Cannot listen on %s.", s);
740 IniFileErrorMessage = IniFileErrorBuffer;
741 return addListeningSocket(s);
743 #endif // !defined(NO_SOCKETS) && !defined(USE_MSRPC)
746 static BOOL readIniFile(const uint_fast8_t pass)
748 char line[256];
749 const char *s;
750 ProdListIndex_t appIndex;
751 unsigned int lineNumber;
752 uint_fast8_t lineParseError;
754 FILE *restrict f;
755 BOOL result = TRUE;
757 IniFileErrorBuffer = (char*)vlmcsd_malloc(INIFILE_ERROR_BUFFERSIZE);
759 if ( !(f = fopen(fn_ini, "r") )) return FALSE;
761 for (lineNumber = 1; (s = fgets(line, sizeof(line), f)); lineNumber++)
763 line[strlen(line) - 1] = 0;
765 iniFileLineNextWord(&s);
766 if (*s == ';' || *s == '#' || !*s) continue;
768 # ifndef NO_SOCKETS
769 if (pass == INI_FILE_PASS_1)
770 # endif // NO_SOCKETS
772 if (handleIniFileParameter(s)) continue;
774 lineParseError = !checkGuidInIniFileLine(&s, &appIndex) ||
775 !setEpidFromIniFileLine(&s, appIndex) ||
776 !setHwIdFromIniFileLine(&s, appIndex);
778 # if !defined(NO_SOCKETS) && !defined(USE_MSRPC)
779 else if (pass == INI_FILE_PASS_2)
781 lineParseError = !setupListeningSocketsFromIniFile(s);
783 else
785 return FALSE;
787 # endif // NO_SOCKETS
789 if (lineParseError)
791 printerrorf("Warning: %s line %u: \"%s\". %s\n", fn_ini, lineNumber, line, IniFileErrorMessage);
792 continue;
796 if (ferror(f)) result = FALSE;
798 free(IniFileErrorBuffer);
799 fclose(f);
801 # if !defined(NO_SOCKETS) && !defined(NO_LOG)
803 if (pass == INI_FILE_PASS_1 && !InetdMode && result)
805 # ifdef _NTSERVICE
806 if (!installService)
807 # endif // _NTSERVICE
808 logger("Read ini file %s\n", fn_ini);
811 # endif // !defined(NO_SOCKETS) && !defined(NO_LOG)
813 return result;
815 #endif // NO_INI_FILE
818 #if !defined(NO_SOCKETS)
819 #if !defined(_WIN32)
820 #if !defined(NO_SIGHUP)
821 static void exec_self(char** argv)
823 # if __linux__ && defined(USE_AUXV)
825 char *execname_ptr = (char*)getauxval(AT_EXECFN);
826 if (execname_ptr) execv(execname_ptr, argv);
828 # elif (__linux__ || __CYGWIN__) && !defined(NO_PROCFS)
830 execv(realpath("/proc/self/exe", NULL), argv);
832 # elif (__FreeBSD__) && !defined(NO_PROCFS)
834 int mib[4];
835 mib[0] = CTL_KERN;
836 mib[1] = KERN_PROC;
837 mib[2] = KERN_PROC_PATHNAME;
838 mib[3] = -1;
839 char path[PATH_MAX + 1];
840 size_t cb = sizeof(path);
841 if (!sysctl(mib, 4, path, &cb, NULL, 0)) execv(path, argv);
843 # elif (__DragonFly__) && !defined(NO_PROCFS)
845 execv(realpath("/proc/curproc/file", NULL), argv);
847 # elif __NetBSD__ && !defined(NO_PROCFS)
849 execv(realpath("/proc/curproc/exe", NULL), argv);
851 # elif __sun__
853 const char* exename = getexecname();
854 if (exename) execv(exename, argv);
856 # elif __APPLE__
858 char path[PATH_MAX + 1];
859 uint32_t size = sizeof(path);
860 if (_NSGetExecutablePath(path, &size) == 0) execv(path, argv);
862 # else
864 execvp(argv[0], argv);
866 # endif
870 static void HangupHandler(const int signal_unused)
872 int i;
873 int_fast8_t daemonize_protection = TRUE;
874 CARGV argv_in = multi_argv == NULL ? global_argv : multi_argv;
875 int argc_in = multi_argc == 0 ? global_argc : multi_argc;
876 const char** argv_out = (const char**)vlmcsd_malloc((argc_in + 2) * sizeof(char**));
878 for (i = 0; i < argc_in; i++)
880 if (!strcmp(argv_in[i], "-Z")) daemonize_protection = FALSE;
881 argv_out[i] = argv_in[i];
884 argv_out[argc_in] = argv_out[argc_in + 1] = NULL;
885 if (daemonize_protection) argv_out[argc_in] = (char*) "-Z";
887 exec_self((char**)argv_out);
889 # ifndef NO_LOG
890 logger("Fatal: Unable to restart on SIGHUP: %s\n", strerror(errno));
891 # endif
893 # ifndef NO_PID_FILE
894 if (fn_pid) unlink(fn_pid);
895 # endif // NO_PID_FILE
896 exit(errno);
898 #endif // NO_SIGHUP
901 static void terminationHandler(const int signal_unused)
903 cleanup();
904 exit(0);
908 #if defined(CHILD_HANDLER) || __minix__
909 static void childHandler(const int signal)
911 waitpid(-1, NULL, WNOHANG);
913 #endif // defined(CHILD_HANDLER) || __minix__
916 static int daemonizeAndSetSignalAction()
918 struct sigaction sa;
919 sigemptyset(&sa.sa_mask);
921 # ifndef NO_LOG
922 if ( !nodaemon) if (daemon(!0, logstdout))
923 # else // NO_LOG
924 if ( !nodaemon) if (daemon(!0, 0))
925 # endif // NO_LOG
927 printerrorf("Fatal: Could not daemonize to background.\n");
928 return(errno);
931 if (!InetdMode)
933 # ifndef USE_THREADS
935 # if defined(CHILD_HANDLER) || __minix__
936 sa.sa_handler = childHandler;
937 # else // !(defined(CHILD_HANDLER) || __minix__)
938 sa.sa_handler = SIG_IGN;
939 # endif // !(defined(CHILD_HANDLER) || __minix__)
940 sa.sa_flags = SA_NOCLDWAIT;
942 if (sigaction(SIGCHLD, &sa, NULL))
943 return(errno);
945 # endif // !USE_THREADS
947 sa.sa_handler = terminationHandler;
948 sa.sa_flags = 0;
950 sigaction(SIGINT, &sa, NULL);
951 sigaction(SIGTERM, &sa, NULL);
953 # ifndef NO_SIGHUP
954 sa.sa_handler = HangupHandler;
955 sa.sa_flags = SA_NODEFER;
956 sigaction(SIGHUP, &sa, NULL);
957 # endif // NO_SIGHUP
960 return 0;
964 #else // _WIN32
966 static BOOL terminationHandler(const DWORD fdwCtrlType)
968 // What a lame substitute for Unix signal handling
969 switch(fdwCtrlType)
971 case CTRL_C_EVENT:
972 case CTRL_CLOSE_EVENT:
973 case CTRL_BREAK_EVENT:
974 case CTRL_LOGOFF_EVENT:
975 case CTRL_SHUTDOWN_EVENT:
976 cleanup();
977 exit(0);
978 default:
979 return FALSE;
984 static DWORD daemonizeAndSetSignalAction()
986 if(!SetConsoleCtrlHandler( (PHANDLER_ROUTINE) terminationHandler, TRUE ))
988 #ifndef NO_LOG
989 DWORD rc = GetLastError();
990 logger("Warning: Could not register Windows signal handler: Error %u\n", rc);
991 #endif // NO_LOG
994 return ERROR_SUCCESS;
996 #endif // _WIN32
997 #endif // !defined(NO_SOCKETS)
1000 // Workaround for Cygwin fork bug (only affects cygwin processes that are Windows services)
1001 // Best is to compile for Cygwin with threads. fork() is slow and unreliable on Cygwin
1002 #if !defined(NO_INI_FILE) || !defined(NO_LOG) || !defined(NO_CL_PIDS)
1003 __pure static char* getCommandLineArg(char *const restrict optarg)
1005 #if !defined (__CYGWIN__) || defined(USE_THREADS) || defined(NO_SOCKETS)
1006 return optarg;
1007 #else
1008 if (!IsNTService) return optarg;
1010 return allocateStringArgument(optarg);
1011 #endif
1013 #endif // !defined(NO_INI_FILE) || !defined(NO_LOG) || !defined(NO_CL_PIDS)
1016 static void parseGeneralArguments() {
1017 int o;
1019 #ifndef NO_CL_PIDS
1020 BYTE* HwId;
1021 #endif // NO_CL_PIDS
1023 for (opterr = 0; ( o = getopt(global_argc, (char* const*)global_argv, optstring) ) > 0; ) switch (o)
1025 #if !defined(NO_SOCKETS) && !defined(NO_SIGHUP) && !defined(_WIN32)
1026 case 'Z':
1027 IsRestarted = TRUE;
1028 nodaemon = TRUE;
1029 break;
1030 #endif // !defined(NO_SOCKETS) && !defined(NO_SIGHUP) && !defined(_WIN32)
1032 #ifndef NO_CL_PIDS
1033 case 'w':
1034 KmsResponseParameters[APP_ID_WINDOWS].Epid = getCommandLineArg(optarg);
1035 #ifndef NO_LOG
1036 KmsResponseParameters[APP_ID_WINDOWS].EpidSource = "command line";
1037 #endif // NO_LOG
1038 break;
1040 case '0':
1041 KmsResponseParameters[APP_ID_OFFICE2010].Epid = getCommandLineArg(optarg);
1042 #ifndef NO_LOG
1043 KmsResponseParameters[APP_ID_OFFICE2010].EpidSource = "command line";
1044 #endif // NO_LOG
1045 break;
1047 case '3':
1048 KmsResponseParameters[APP_ID_OFFICE2013].Epid = getCommandLineArg(optarg);
1049 #ifndef NO_LOG
1050 KmsResponseParameters[APP_ID_OFFICE2013].EpidSource = "command line";
1051 #endif // NO_LOG
1052 break;
1054 case 'H':
1055 HwId = (BYTE*)vlmcsd_malloc(sizeof(((RESPONSE_V6 *)0)->HwId));
1057 hex2bin(HwId, optarg, sizeof(((RESPONSE_V6 *)0)->HwId));
1059 KmsResponseParameters[APP_ID_WINDOWS].HwId = HwId;
1060 KmsResponseParameters[APP_ID_OFFICE2010].HwId = HwId;
1061 KmsResponseParameters[APP_ID_OFFICE2013].HwId = HwId;
1062 break;
1063 #endif // NO_CL_PIDS
1065 #ifndef NO_SOCKETS
1067 #ifndef USE_MSRPC
1068 case '4':
1069 case '6':
1070 case 'P':
1071 ignoreIniFileParameter(INI_PARAM_LISTEN);
1072 break;
1073 #else // USE_MSRPC
1074 case 'P':
1075 defaultport = optarg;
1076 ignoreIniFileParameter(INI_PARAM_PORT);
1077 break;
1078 #endif // USE_MSRPC
1080 #if !defined(NO_LIMIT) && !__minix__
1082 case 'm':
1083 #ifdef USE_MSRPC
1084 MaxTasks = getOptionArgumentInt(o, 1, RPC_C_LISTEN_MAX_CALLS_DEFAULT);
1085 #else // !USE_MSRPC
1086 MaxTasks = getOptionArgumentInt(o, 1, SEM_VALUE_MAX);
1087 #endif // !USE_MSRPC
1088 ignoreIniFileParameter(INI_PARAM_MAX_WORKERS);
1089 break;
1091 #endif // !defined(NO_LIMIT) && !__minix__
1092 #endif // NO_SOCKETS
1094 #if !defined(NO_TIMEOUT) && !__minix__ && !defined(USE_MSRPC)
1095 case 't':
1096 ServerTimeout = getOptionArgumentInt(o, 1, 600);
1097 ignoreIniFileParameter(INI_PARAM_CONNECTION_TIMEOUT);
1098 break;
1099 #endif // !defined(NO_TIMEOUT) && !__minix__ && !defined(USE_MSRPC)
1101 #ifndef NO_PID_FILE
1102 case 'p':
1103 fn_pid = getCommandLineArg(optarg);
1104 ignoreIniFileParameter(INI_PARAM_PID_FILE);
1105 break;
1106 #endif
1108 #ifndef NO_INI_FILE
1109 case 'i':
1110 fn_ini = getCommandLineArg(optarg);
1111 if (!strcmp(fn_ini, "-")) fn_ini = NULL;
1112 break;
1113 #endif
1115 #ifndef NO_LOG
1116 case 'l':
1117 fn_log = getCommandLineArg(optarg);
1118 ignoreIniFileParameter(INI_PARAM_LOG_FILE);
1119 break;
1121 #ifndef NO_VERBOSE_LOG
1122 case 'v':
1123 case 'q':
1124 logverbose = o == 'v';
1125 ignoreIniFileParameter(INI_PARAM_LOG_VERBOSE);
1126 break;
1128 #endif // NO_VERBOSE_LOG
1129 #endif // NO_LOG
1131 #ifndef NO_SOCKETS
1132 #ifndef USE_MSRPC
1133 case 'L':
1134 maxsockets++;
1135 ignoreIniFileParameter(INI_PARAM_LISTEN);
1136 break;
1137 #endif // USE_MSRPC
1139 case 'f':
1140 nodaemon = 1;
1141 #ifndef NO_LOG
1142 logstdout = 1;
1143 #endif
1144 break;
1146 #ifdef _NTSERVICE
1147 case 'U':
1148 ServiceUser = optarg;
1149 break;
1151 case 'W':
1152 ServicePassword = optarg;
1153 break;
1155 case 's':
1156 #ifndef USE_MSRPC
1157 if (InetdMode) usage();
1158 #endif // USE_MSRPC
1159 if (!IsNTService) installService = 1; // Install
1160 break;
1162 case 'S':
1163 if (!IsNTService) installService = 2; // Remove
1164 break;
1165 #endif // _NTSERVICE
1167 case 'D':
1168 nodaemon = 1;
1169 break;
1171 #ifndef NO_LOG
1172 case 'e':
1173 logstdout = 1;
1174 break;
1175 #endif // NO_LOG
1176 #endif // NO_SOCKETS
1178 #ifndef _WIN32
1179 case 'I': // Backward compatibility with svn681 and earlier
1180 break;
1181 #endif // _WIN32
1183 #ifndef NO_RANDOM_EPID
1184 case 'r':
1185 RandomizationLevel = (int_fast8_t)getOptionArgumentInt(o, 0, 2);
1186 ignoreIniFileParameter(INI_PARAM_RANDOMIZATION_LEVEL);
1187 break;
1189 case 'C':
1190 Lcid = (uint16_t)getOptionArgumentInt(o, 0, 32767);
1192 ignoreIniFileParameter(INI_PARAM_LCID);
1194 #ifdef _PEDANTIC
1195 if (!IsValidLcid(Lcid))
1197 printerrorf("Warning: %s is not a valid LCID.\n", optarg);
1199 #endif // _PEDANTIC
1201 break;
1202 #endif // NO_RANDOM_PID
1204 #if !defined(NO_USER_SWITCH) && !defined(_WIN32)
1205 case 'g':
1206 gname = optarg;
1207 ignoreIniFileParameter(INI_PARAM_GID);
1208 #ifndef NO_SIGHUP
1209 if (!IsRestarted)
1210 #endif // NO_SIGHUP
1211 if (GetGid())
1213 printerrorf("Fatal: setgid for %s failed.\n", optarg);
1214 exit(!0);
1216 break;
1218 case 'u':
1219 uname = optarg;
1220 ignoreIniFileParameter(INI_PARAM_UID);
1221 #ifndef NO_SIGHUP
1222 if (!IsRestarted)
1223 #endif // NO_SIGHUP
1224 if (GetUid())
1226 printerrorf("Fatal: setuid for %s failed.\n", optarg);
1227 exit(!0);
1229 break;
1230 #endif // NO_USER_SWITCH && !_WIN32
1232 #ifndef NO_CUSTOM_INTERVALS
1233 case 'R':
1234 VLRenewalInterval = getTimeSpanFromCommandLine(optarg, o);
1235 ignoreIniFileParameter(INI_PARAM_RENEWAL_INTERVAL);
1236 break;
1238 case 'A':
1239 VLActivationInterval = getTimeSpanFromCommandLine(optarg, o);
1240 ignoreIniFileParameter(INI_PARAM_ACTIVATION_INTERVAL);
1241 break;
1242 #endif
1244 #ifndef USE_MSRPC
1245 case 'd':
1246 case 'k':
1247 DisconnectImmediately = o == 'd';
1248 ignoreIniFileParameter(INI_PARAM_DISCONNECT_IMMEDIATELY);
1249 break;
1251 case 'N':
1252 if (!getArgumentBool(&UseRpcNDR64, optarg)) usage();
1253 ignoreIniFileParameter(INI_PARAM_RPC_NDR64);
1254 break;
1256 case 'B':
1257 if (!getArgumentBool(&UseRpcBTFN, optarg)) usage();
1258 ignoreIniFileParameter(INI_PARAM_RPC_BTFN);
1259 break;
1260 #endif // !USE_MSRPC
1262 case 'V':
1263 #ifdef _NTSERVICE
1264 if (IsNTService) break;
1265 #endif
1266 printf("vlmcsd %s\n", Version);
1267 exit(0);
1269 default:
1270 usage();
1273 // Do not allow non-option arguments
1274 if (optind != global_argc)
1275 usage();
1277 #ifdef _NTSERVICE
1278 // -U and -W must be used with -s
1279 if ((ServiceUser || *ServicePassword) && installService != 1) usage();
1280 #endif // _NTSERVICE
1284 #ifndef NO_PID_FILE
1285 static void writePidFile()
1287 # ifndef NO_SIGHUP
1288 if (IsRestarted) return;
1289 # endif // NO_SIGHUP
1291 if (fn_pid && !InetdMode)
1293 FILE *_f = fopen(fn_pid, "w");
1295 if ( _f )
1297 fprintf(_f, "%u", (uint32_t)getpid());
1298 fclose(_f);
1301 #ifndef NO_LOG
1302 else
1304 logger("Warning: Cannot write pid file '%s'. %s.\n", fn_pid, strerror(errno));
1306 #endif // NO_LOG
1309 #else
1310 #define writePidFile(x)
1311 #endif // NO_PID_FILE
1313 #if !defined(NO_SOCKETS) && !defined(USE_MSRPC)
1315 void cleanup()
1318 if (!InetdMode)
1320 #ifndef NO_PID_FILE
1321 if (fn_pid) unlink(fn_pid);
1322 #endif // NO_PID_FILE
1323 closeAllListeningSockets();
1325 #if !defined(NO_LIMIT) && !defined(NO_SOCKETS) && !defined(_WIN32) && !__minix__
1326 sem_unlink("/vlmcsd");
1327 #if !defined(USE_THREADS) && !defined(CYGWIN)
1328 if (shmid >= 0)
1330 if (Semaphore != (sem_t*)-1) shmdt(Semaphore);
1331 shmctl(shmid, IPC_RMID, NULL);
1333 #endif // !defined(USE_THREADS) && !defined(CYGWIN)
1334 #endif // !defined(NO_LIMIT) && !defined(NO_SOCKETS) && !defined(_WIN32) && !__minix__
1336 #ifndef NO_LOG
1337 logger("vlmcsd %s was shutdown\n", Version);
1338 #endif // NO_LOG
1343 #elif defined(USE_MSRPC)
1345 void cleanup()
1347 # ifndef NO_PID_FILE
1348 if (fn_pid) unlink(fn_pid);
1349 # endif // NO_PID_FILE
1351 # ifndef NO_LOG
1352 logger("vlmcsd %s was shutdown\n", Version);
1353 # endif // NO_LOG
1356 #else // Neither Sockets nor RPC
1358 __pure void cleanup() {}
1360 #endif // Neither Sockets nor RPC
1363 #if !defined(USE_MSRPC) && !defined(NO_LIMIT) && !defined(NO_SOCKETS) && !__minix__
1364 // Get a semaphore for limiting the maximum concurrent tasks
1365 static void allocateSemaphore(void)
1367 #ifdef USE_THREADS
1368 #define sharemode 0
1369 #else
1370 #define sharemode 1
1371 #endif
1373 #ifndef _WIN32
1374 sem_unlink("/vlmcsd");
1375 #endif
1377 if(MaxTasks < SEM_VALUE_MAX && !InetdMode)
1379 #ifndef _WIN32
1381 #if !defined(USE_THREADS) && !defined(CYGWIN)
1383 if ((Semaphore = sem_open("/vlmcsd", O_CREAT /*| O_EXCL*/, 0700, MaxTasks)) == SEM_FAILED) // fails on many systems
1385 // We didn't get a named Semaphore (/dev/shm on Linux) so let's try our own shared page
1387 if (
1388 ( shmid = shmget(IPC_PRIVATE, sizeof(sem_t), IPC_CREAT | 0600) ) < 0 ||
1389 ( Semaphore = (sem_t*)shmat(shmid, NULL, 0) ) == (sem_t*)-1 ||
1390 sem_init(Semaphore, 1, MaxTasks) < 0
1393 int errno_save = errno;
1394 if (Semaphore != (sem_t*)-1) shmdt(Semaphore);
1395 if (shmid >= 0) shmctl(shmid, IPC_RMID, NULL);
1396 printerrorf("Warning: Could not create semaphore: %s\n", vlmcsd_strerror(errno_save));
1397 MaxTasks = SEM_VALUE_MAX;
1401 #else // THREADS or CYGWIN
1403 Semaphore = (sem_t*)vlmcsd_malloc(sizeof(sem_t));
1405 if (sem_init(Semaphore, sharemode, MaxTasks) < 0) // sem_init is not implemented on Darwin (returns ENOSYS)
1407 free(Semaphore);
1409 if ((Semaphore = sem_open("/vlmcsd", O_CREAT /*| O_EXCL*/, 0700, MaxTasks)) == SEM_FAILED)
1411 printerrorf("Warning: Could not create semaphore: %s\n", vlmcsd_strerror(errno));
1412 MaxTasks = SEM_VALUE_MAX;
1416 #endif // THREADS or CYGWIN
1418 #else // _WIN32
1420 if (!(Semaphore = CreateSemaphoreA(NULL, MaxTasks, MaxTasks, NULL)))
1422 printerrorf("Warning: Could not create semaphore: %s\n", vlmcsd_strerror(GetLastError()));
1423 MaxTasks = SEM_VALUE_MAX;
1426 #endif // _WIN32
1429 #endif // !defined(NO_LIMIT) && !defined(NO_SOCKETS) && !__minix__
1432 #if !defined(NO_SOCKETS) && !defined(USE_MSRPC)
1433 int setupListeningSockets()
1435 int o;
1436 uint_fast8_t allocsockets = maxsockets ? maxsockets : 2;
1438 SocketList = (SOCKET*)vlmcsd_malloc((size_t)allocsockets * sizeof(SOCKET));
1440 haveIPv4Stack = checkProtocolStack(AF_INET);
1441 haveIPv6Stack = checkProtocolStack(AF_INET6);
1443 // Reset getopt since we've alread used it
1444 optReset();
1446 for (opterr = 0; ( o = getopt(global_argc, (char* const*)global_argv, optstring) ) > 0; ) switch (o)
1448 case '4':
1450 if (!haveIPv4Stack)
1452 printerrorf("Fatal: Your system does not support %s.\n", cIPv4);
1453 return !0;
1455 v4required = 1;
1456 break;
1458 case '6':
1460 if (!haveIPv6Stack)
1462 printerrorf("Fatal: Your system does not support %s.\n", cIPv6);
1463 return !0;
1465 v6required = 1;
1466 break;
1468 case 'L':
1470 addListeningSocket(optarg);
1471 break;
1473 case 'P':
1475 defaultport = optarg;
1476 break;
1478 default:
1480 break;
1484 # ifndef NO_INI_FILE
1485 if (maxsockets && !numsockets)
1487 if (fn_ini && !readIniFile(INI_FILE_PASS_2))
1489 #ifdef INI_FILE
1490 if (strcmp(fn_ini, INI_FILE))
1491 #endif // INI_FILE
1492 printerrorf("Warning: Can't read %s: %s\n", fn_ini, strerror(errno));
1495 # endif
1497 // if -L hasn't been specified on the command line, use default sockets (all IP addresses)
1498 // maxsocket results from first pass parsing the arguments
1499 if (!maxsockets)
1501 if (haveIPv6Stack && (v6required || !v4required)) addListeningSocket("::");
1502 if (haveIPv4Stack && (v4required || !v6required)) addListeningSocket("0.0.0.0");
1505 if (!numsockets)
1507 printerrorf("Fatal: Could not listen on any socket.\n");
1508 return(!0);
1511 return 0;
1513 #endif // !defined(NO_SOCKETS) && !defined(USE_MSRPC)
1516 int server_main(int argc, CARGV argv)
1518 #if !defined(_NTSERVICE) && !defined(NO_SOCKETS)
1519 int error;
1520 #endif // !defined(_NTSERVICE) && !defined(NO_SOCKETS)
1522 // Initialize ePID / HwId parameters
1523 memset(KmsResponseParameters, 0, sizeof(KmsResponseParameters));
1525 global_argc = argc;
1526 global_argv = argv;
1528 #ifdef _NTSERVICE // #endif is in newmain()
1529 DWORD lasterror = ERROR_SUCCESS;
1531 if (!StartServiceCtrlDispatcher(NTServiceDispatchTable) && (lasterror = GetLastError()) == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
1533 IsNTService = FALSE;
1534 return newmain();
1537 return lasterror;
1541 int newmain()
1543 int error;
1545 // Initialize thread synchronization objects for Windows and Cygwin
1546 #ifdef USE_THREADS
1548 #ifndef NO_LOG
1549 // Initialize the Critical Section for proper logging
1550 InitializeCriticalSection(&logmutex);
1551 #endif // NO_LOG
1553 #endif // USE_THREADS
1555 #ifdef _WIN32
1557 #ifndef USE_MSRPC
1558 // Windows Sockets must be initialized
1559 WSADATA wsadata;
1561 if ((error = WSAStartup(0x0202, &wsadata)))
1563 printerrorf("Fatal: Could not initialize Windows sockets (Error: %d).\n", error);
1564 return error;
1566 #endif // USE_MSRPC
1568 // Windows can never daemonize
1569 nodaemon = 1;
1571 #else // __CYGWIN__
1573 // Do not daemonize if we are a Windows service
1574 if (IsNTService) nodaemon = 1;
1576 #endif // _WIN32 / __CYGWIN__
1577 #endif // _NTSERVICE ( #ifdef is main(int argc, CARGV argv) )
1579 parseGeneralArguments(); // Does not return if an error occurs
1581 #if !defined(_WIN32) && !defined(NO_SOCKETS) && !defined(USE_MSRPC)
1582 struct stat statbuf;
1583 fstat(STDIN_FILENO, &statbuf);
1584 if (S_ISSOCK(statbuf.st_mode))
1586 InetdMode = 1;
1587 nodaemon = 1;
1588 maxsockets = 0;
1589 #ifndef NO_LOG
1590 logstdout = 0;
1591 #endif // NO_LOG
1593 #endif // !defined(_WIN32) && !defined(NO_SOCKETS) && !defined(USE_MSRPC)
1595 #ifndef NO_INI_FILE
1596 if (fn_ini && !readIniFile(INI_FILE_PASS_1))
1598 #ifdef INI_FILE
1599 if (strcmp(fn_ini, INI_FILE))
1600 #endif // INI_FILE
1601 printerrorf("Warning: Can't read %s: %s\n", fn_ini, strerror(errno));
1603 #endif // NO_INI_FILE
1605 #if !defined(NO_LIMIT) && !defined(NO_SOCKETS) && !__minix__ && !defined(USE_MSRPC)
1606 allocateSemaphore();
1607 #endif // !defined(NO_LIMIT) && !defined(NO_SOCKETS) && __minix__
1609 #ifdef _NTSERVICE
1610 if (installService)
1611 return NtServiceInstallation(installService, ServiceUser, ServicePassword);
1612 #endif // _NTSERVICE
1614 #if !defined(NO_SOCKETS) && !defined(USE_MSRPC)
1615 if (!InetdMode)
1617 if ((error = setupListeningSockets())) return error;
1619 #endif // NO_SOCKETS
1621 // After sockets have been set up, we may switch to a lower privileged user
1622 #if !defined(_WIN32) && !defined(NO_USER_SWITCH)
1624 #ifndef NO_SIGHUP
1625 if (!IsRestarted)
1627 #endif // NO_SIGHUP
1628 if (gid != INVALID_GID && setgid(gid))
1630 printerrorf("Fatal: setgid for %s failed.\n", gname);
1631 return !0;
1634 if (uid != INVALID_UID && setuid(uid))
1636 printerrorf("Fatal: setuid for %s failed.\n", uname);
1637 return !0;
1639 #ifndef NO_SIGHUP
1641 #endif // NO_SIGHUP
1643 #endif // !defined(_WIN32) && !defined(NO_USER_SWITCH)
1645 randomNumberInit();
1647 // Randomization Level 1 means generate ePIDs at startup and use them during
1648 // the lifetime of the process. So we generate them now
1649 #ifndef NO_RANDOM_EPID
1650 if (RandomizationLevel == 1) randomPidInit();
1651 #endif
1653 #if !defined(NO_SOCKETS)
1654 #ifdef _WIN32
1655 if (!IsNTService)
1656 #endif // _WIN32
1657 if ((error = daemonizeAndSetSignalAction())) return error;
1658 #endif // !defined(NO_SOCKETS)
1660 writePidFile();
1662 #if !defined(NO_LOG) && !defined(NO_SOCKETS) && !defined(USE_MSRPC)
1663 if (!InetdMode)
1664 logger("vlmcsd %s started successfully\n", Version);
1665 #endif // !defined(NO_LOG) && !defined(NO_SOCKETS) && !defined(USE_MSRPC)
1667 #if defined(_NTSERVICE) && !defined(USE_MSRPC)
1668 if (IsNTService) ReportServiceStatus(SERVICE_RUNNING, NO_ERROR, 200);
1669 #endif // defined(_NTSERVICE) && !defined(USE_MSRPC)
1671 int rc;
1672 rc = runServer();
1674 // Clean up things and exit
1675 #ifdef _NTSERVICE
1676 if (!ServiceShutdown)
1677 #endif
1678 cleanup();
1679 #ifdef _NTSERVICE
1680 else
1681 ReportServiceStatus(SERVICE_STOPPED, NO_ERROR, 0);
1682 #endif
1684 return rc;