fix for non-unicode build
[public/netxms.git] / src / agent / core / nxagentd.cpp
1 /*
2 ** NetXMS multiplatform core agent
3 ** Copyright (C) 2003-2016 Victor Kirhenshtein
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 **
19 ** File: nxagentd.cpp
20 **
21 **/
22
23 #include "nxagentd.h"
24
25 #if defined(_WIN32)
26 #include <shlobj.h>
27 #include <conio.h>
28 #else
29 #include <signal.h>
30 #include <sys/wait.h>
31 #endif
32
33 #if HAVE_LOCALE_H
34 #include <locale.h>
35 #endif
36
37 #if HAVE_SYS_UTSNAME_H
38 #include <sys/utsname.h>
39 #endif
40
41 #if HAVE_SYS_SYSCTL_H
42 #include <sys/sysctl.h>
43 #endif
44
45 #ifdef _WITH_ENCRYPTION
46 #include <openssl/ssl.h>
47 #endif
48
49 #if HAVE_GRP_H
50 #include <grp.h>
51 #endif
52
53 #if HAVE_PWD_H
54 #include <pwd.h>
55 #endif
56
57 /**
58 * Externals
59 */
60 THREAD_RESULT THREAD_CALL ListenerThread(void *);
61 THREAD_RESULT THREAD_CALL SessionWatchdog(void *);
62 THREAD_RESULT THREAD_CALL TrapSender(void *);
63 THREAD_RESULT THREAD_CALL MasterAgentListener(void *arg);
64 THREAD_RESULT THREAD_CALL SNMPTrapReceiver(void *);
65 THREAD_RESULT THREAD_CALL SNMPTrapSender(void *);
66 THREAD_RESULT THREAD_CALL SyslogReceiver(void *);
67 THREAD_RESULT THREAD_CALL SyslogSender(void *);
68 THREAD_RESULT THREAD_CALL TunnelManager(void *);
69
70 void ShutdownTrapSender();
71 void ShutdownSNMPTrapSender();
72
73 void ShutdownSyslogSender();
74
75 void StartLocalDataCollector();
76 void ShutdownLocalDataCollector();
77
78 void StartWatchdog();
79 void StopWatchdog();
80 int WatchdogMain(DWORD pid);
81
82 void InitSessionList();
83 void DestroySessionList();
84
85 BOOL RegisterOnServer(const TCHAR *pszServer);
86
87 void UpdatePolicyInventory();
88
89 void ParseTunnelList(TCHAR *list);
90
91 #if !defined(_WIN32)
92 void InitStaticSubagents();
93 #endif
94
95 #ifdef _WIN32
96 extern TCHAR g_windowsServiceName[];
97 extern TCHAR g_windowsServiceDisplayName[];
98 #endif
99
100 void LIBNXAGENT_EXPORTABLE InitSubAgentAPI(void (* writeLog)(int, int, const TCHAR *),
101 void (* sendTrap1)(UINT32, const TCHAR *, const char *, va_list),
102 void (* sendTrap2)(UINT32, const TCHAR *, int, TCHAR **),
103 bool (* enumerateSessions)(EnumerationCallbackResult (*)(AbstractCommSession *, void *), void*),
104 AbstractCommSession *(* findServerSession)(UINT64),
105 bool (* sendFile)(void *, UINT32, const TCHAR *, long),
106 bool (* pushData)(const TCHAR *, const TCHAR *, UINT32, time_t),
107 DB_HANDLE (* getLocalDatabaseHandle)(),
108 CONDITION shutdownCondition, const TCHAR *dataDirectory);
109
110 /**
111 * Messages generated by mc.pl (for UNIX version only)
112 */
113 #ifndef _WIN32
114 extern unsigned int g_dwNumMessages;
115 extern const TCHAR *g_szMessages[];
116 #endif
117
118 /**
119 * Valid options for getopt()
120 */
121 #if defined(_WIN32)
122 #define VALID_OPTIONS "c:CdD:e:EfhHiIKM:n:N:P:r:RsSUvX:W:Z:"
123 #else
124 #define VALID_OPTIONS "c:CdD:fg:hKM:p:P:r:u:vX:W:Z:"
125 #endif
126
127 /**
128 * Actions
129 */
130 #define ACTION_NONE 0
131 #define ACTION_RUN_AGENT 1
132 #define ACTION_INSTALL_SERVICE 2
133 #define ACTION_REMOVE_SERVICE 3
134 #define ACTION_START_SERVICE 4
135 #define ACTION_STOP_SERVICE 5
136 #define ACTION_CHECK_CONFIG 6
137 #define ACTION_INSTALL_EVENT_SOURCE 7
138 #define ACTION_REMOVE_EVENT_SOURCE 8
139 #define ACTION_CREATE_CONFIG 9
140 #define ACTION_HELP 10
141 #define ACTION_RUN_WATCHDOG 11
142 #define ACTION_SHUTDOWN_EXT_AGENTS 12
143
144 /**
145 * Global variables
146 */
147 UINT32 g_dwFlags = AF_ENABLE_ACTIONS | AF_ENABLE_AUTOLOAD;
148 UINT32 g_failFlags = 0;
149 TCHAR g_szLogFile[MAX_PATH] = AGENT_DEFAULT_LOG;
150 TCHAR g_szSharedSecret[MAX_SECRET_LENGTH] = _T("admin");
151 TCHAR g_szConfigFile[MAX_PATH] = AGENT_DEFAULT_CONFIG;
152 TCHAR g_szFileStore[MAX_PATH] = AGENT_DEFAULT_FILE_STORE;
153 TCHAR g_szDataDirectory[MAX_PATH] = AGENT_DEFAULT_DATA_DIR;
154 TCHAR g_szPlatformSuffix[MAX_PSUFFIX_LENGTH] = _T("");
155 TCHAR g_szConfigServer[MAX_DB_STRING] = _T("not_set");
156 TCHAR g_szRegistrar[MAX_DB_STRING] = _T("not_set");
157 TCHAR g_szListenAddress[MAX_PATH] = _T("*");
158 TCHAR g_szConfigIncludeDir[MAX_PATH] = AGENT_DEFAULT_CONFIG_D;
159 TCHAR g_szConfigPolicyDir[MAX_PATH] = AGENT_DEFAULT_CONFIG_D;
160 TCHAR g_szLogParserDirectory[MAX_PATH] = _T("");
161 TCHAR g_masterAgent[MAX_PATH] = _T("not_set");
162 TCHAR g_szSNMPTrapListenAddress[MAX_PATH] = _T("*");
163 UINT16 g_wListenPort = AGENT_LISTEN_PORT;
164 ObjectArray<ServerInfo> g_serverList(8, 8, true);
165 UINT32 g_dwServerCount = 0;
166 UINT32 g_dwExecTimeout = 2000; // External process execution timeout in milliseconds
167 UINT32 g_dwSNMPTimeout = 1500;
168 time_t g_tmAgentStartTime;
169 UINT32 g_dwStartupDelay = 0;
170 UINT32 g_dwMaxSessions = 32;
171 UINT32 g_dwSNMPTrapPort = 162;
172 UINT32 g_longRunningQueryThreshold = 250;
173 UINT32 g_dcReconciliationBlockSize = 1024;
174 UINT32 g_dcReconciliationTimeout = 15000;
175 UINT32 g_dcMaxCollectorPoolSize = 64;
176 UINT32 g_zoneId = 0;
177 UINT16 g_syslogListenPort = 514;
178 #ifdef _WIN32
179 UINT16 g_sessionAgentPort = 28180;
180 #else
181 UINT16 g_sessionAgentPort = 0;
182 #endif
183 Config *g_config = NULL;
184 #ifdef _WIN32
185 UINT32 g_dwIdleTimeout = 60; // Session idle timeout
186 #else
187 UINT32 g_dwIdleTimeout = 120; // Session idle timeout
188 #endif
189
190 #if !defined(_WIN32)
191 TCHAR g_szPidFile[MAX_PATH] = _T("/var/run/nxagentd.pid");
192 #endif
193
194 /**
195 * Static variables
196 */
197 static TCHAR *m_pszActionList = NULL;
198 static TCHAR *m_pszShellActionList = NULL;
199 static TCHAR *m_pszServerList = NULL;
200 static TCHAR *m_pszControlServerList = NULL;
201 static TCHAR *m_pszMasterServerList = NULL;
202 static TCHAR *m_pszSubagentList = NULL;
203 static TCHAR *m_pszExtParamList = NULL;
204 static TCHAR *m_pszExtListsList = NULL;
205 static TCHAR *m_pszShExtParamList = NULL;
206 static TCHAR *m_pszParamProviderList = NULL;
207 static TCHAR *m_pszExtSubagentList = NULL;
208 static TCHAR *m_pszAppAgentList = NULL;
209 static TCHAR *s_serverConnectionList = NULL;
210 static UINT32 s_enabledCiphers = 0xFFFF;
211 static THREAD s_sessionWatchdogThread = INVALID_THREAD_HANDLE;
212 static THREAD s_listenerThread = INVALID_THREAD_HANDLE;
213 static THREAD s_eventSenderThread = INVALID_THREAD_HANDLE;
214 static THREAD s_snmpTrapReceiverThread = INVALID_THREAD_HANDLE;
215 static THREAD s_snmpTrapSenderThread = INVALID_THREAD_HANDLE;
216 static THREAD s_syslogReceiverThread = INVALID_THREAD_HANDLE;
217 static THREAD s_syslogSenderThread = INVALID_THREAD_HANDLE;
218 static THREAD s_masterAgentListenerThread = INVALID_THREAD_HANDLE;
219 static THREAD s_tunnelManagerThread = INVALID_THREAD_HANDLE;
220 static TCHAR s_processToWaitFor[MAX_PATH] = _T("");
221 static TCHAR s_dumpDir[MAX_PATH] = _T("C:\\");
222 static UINT64 s_maxLogSize = 16384 * 1024;
223 static UINT32 s_logHistorySize = 4;
224 static UINT32 s_logRotationMode = NXLOG_ROTATION_BY_SIZE;
225 static TCHAR s_dailyLogFileSuffix[64] = _T("");
226 static TCHAR s_executableName[MAX_PATH];
227 static UINT32 s_debugLevel = (UINT32)NXCONFIG_UNINITIALIZED_VALUE;
228
229 static CONDITION s_subAgentsStopCondition = INVALID_CONDITION_HANDLE;
230 #if defined(_WIN32)
231 static CONDITION s_shutdownCondition = INVALID_CONDITION_HANDLE;
232 #endif
233
234 #if !defined(_WIN32)
235 static pid_t s_pid;
236 #endif
237
238 /**
239 * Configuration file template
240 */
241 static NX_CFG_TEMPLATE m_cfgTemplate[] =
242 {
243 { _T("Action"), CT_STRING_LIST, '\n', 0, 0, 0, &m_pszActionList, NULL },
244 { _T("ActionShellExec"), CT_STRING_LIST, '\n', 0, 0, 0, &m_pszShellActionList, NULL },
245 { _T("AppAgent"), CT_STRING_LIST, '\n', 0, 0, 0, &m_pszAppAgentList, NULL },
246 { _T("BackgroundLogWriter"), CT_BOOLEAN, 0, 0, AF_BACKGROUND_LOG_WRITER, 0, &g_dwFlags, NULL },
247 { _T("ControlServers"), CT_STRING_LIST, ',', 0, 0, 0, &m_pszControlServerList, NULL },
248 { _T("CreateCrashDumps"), CT_BOOLEAN, 0, 0, AF_CATCH_EXCEPTIONS, 0, &g_dwFlags, NULL },
249 { _T("DataCollectionThreadPoolSize"), CT_LONG, 0, 0, 0, 0, &g_dcMaxCollectorPoolSize, NULL },
250 { _T("DataDirectory"), CT_STRING, 0, 0, MAX_PATH, 0, g_szDataDirectory, NULL },
251 { _T("DataReconciliationBlockSize"), CT_LONG, 0, 0, 0, 0, &g_dcReconciliationBlockSize, NULL },
252 { _T("DataReconciliationTimeout"), CT_LONG, 0, 0, 0, 0, &g_dcReconciliationTimeout, NULL },
253 { _T("DailyLogFileSuffix"), CT_STRING, 0, 0, 64, 0, s_dailyLogFileSuffix, NULL },
254 { _T("DebugLevel"), CT_LONG, 0, 0, 0, 0, &s_debugLevel, &s_debugLevel },
255 { _T("DisableIPv4"), CT_BOOLEAN, 0, 0, AF_DISABLE_IPV4, 0, &g_dwFlags, NULL },
256 { _T("DisableIPv6"), CT_BOOLEAN, 0, 0, AF_DISABLE_IPV6, 0, &g_dwFlags, NULL },
257 { _T("DumpDirectory"), CT_STRING, 0, 0, MAX_PATH, 0, s_dumpDir, NULL },
258 { _T("EnableActions"), CT_BOOLEAN, 0, 0, AF_ENABLE_ACTIONS, 0, &g_dwFlags, NULL },
259 { _T("EnabledCiphers"), CT_LONG, 0, 0, 0, 0, &s_enabledCiphers, NULL },
260 { _T("EnableControlConnector"), CT_BOOLEAN, 0, 0, AF_ENABLE_CONTROL_CONNECTOR, 0, &g_dwFlags, NULL },
261 { _T("EnableProxy"), CT_BOOLEAN, 0, 0, AF_ENABLE_PROXY, 0, &g_dwFlags, NULL },
262 { _T("EnableSNMPProxy"), CT_BOOLEAN, 0, 0, AF_ENABLE_SNMP_PROXY, 0, &g_dwFlags, NULL },
263 { _T("EnableSNMPTrapProxy"), CT_BOOLEAN, 0, 0, AF_ENABLE_SNMP_TRAP_PROXY, 0, &g_dwFlags, NULL },
264 { _T("EnableSyslogProxy"), CT_BOOLEAN, 0, 0, AF_ENABLE_SYSLOG_PROXY, 0, &g_dwFlags, NULL },
265 { _T("EnableSubagentAutoload"), CT_BOOLEAN, 0, 0, AF_ENABLE_AUTOLOAD, 0, &g_dwFlags, NULL },
266 { _T("EnableWatchdog"), CT_BOOLEAN, 0, 0, AF_ENABLE_WATCHDOG, 0, &g_dwFlags, NULL },
267 { _T("EncryptedSharedSecret"), CT_STRING, 0, 0, MAX_SECRET_LENGTH, 0, g_szSharedSecret, NULL },
268 { _T("ExecTimeout"), CT_LONG, 0, 0, 0, 0, &g_dwExecTimeout, NULL },
269 { _T("ExternalList"), CT_STRING_LIST, '\n', 0, 0, 0, &m_pszExtListsList, NULL },
270 { _T("ExternalMasterAgent"), CT_STRING, 0, 0, MAX_PATH, 0, g_masterAgent, NULL },
271 { _T("ExternalParameter"), CT_STRING_LIST, '\n', 0, 0, 0, &m_pszExtParamList, NULL },
272 { _T("ExternalParameterShellExec"), CT_STRING_LIST, '\n', 0, 0, 0, &m_pszShExtParamList, NULL },
273 { _T("ExternalParametersProvider"), CT_STRING_LIST, '\n', 0, 0, 0, &m_pszParamProviderList, NULL },
274 { _T("ExternalSubagent"), CT_STRING_LIST, '\n', 0, 0, 0, &m_pszExtSubagentList, NULL },
275 { _T("FileStore"), CT_STRING, 0, 0, MAX_PATH, 0, g_szFileStore, NULL },
276 { _T("FullCrashDumps"), CT_BOOLEAN, 0, 0, AF_WRITE_FULL_DUMP, 0, &g_dwFlags, NULL },
277 { _T("ListenAddress"), CT_STRING, 0, 0, MAX_PATH, 0, g_szListenAddress, NULL },
278 { _T("ListenPort"), CT_WORD, 0, 0, 0, 0, &g_wListenPort, NULL },
279 { _T("LogFile"), CT_STRING, 0, 0, MAX_PATH, 0, g_szLogFile, NULL },
280 { _T("LogHistorySize"), CT_LONG, 0, 0, 0, 0, &s_logHistorySize, NULL },
281 { _T("LogRotationMode"), CT_LONG, 0, 0, 0, 0, &s_logRotationMode, NULL },
282 { _T("LogUnresolvedSymbols"), CT_BOOLEAN, 0, 0, AF_LOG_UNRESOLVED_SYMBOLS, 0, &g_dwFlags, NULL },
283 { _T("LongRunningQueryThreshold"), CT_LONG, 0, 0, 0, 0, &g_longRunningQueryThreshold, NULL },
284 { _T("MasterServers"), CT_STRING_LIST, ',', 0, 0, 0, &m_pszMasterServerList, NULL },
285 { _T("MaxLogSize"), CT_SIZE_BYTES, 0, 0, 0, 0, &s_maxLogSize, NULL },
286 { _T("MaxSessions"), CT_LONG, 0, 0, 0, 0, &g_dwMaxSessions, NULL },
287 { _T("PlatformSuffix"), CT_STRING, 0, 0, MAX_PSUFFIX_LENGTH, 0, g_szPlatformSuffix, NULL },
288 { _T("RequireAuthentication"), CT_BOOLEAN, 0, 0, AF_REQUIRE_AUTH, 0, &g_dwFlags, NULL },
289 { _T("RequireEncryption"), CT_BOOLEAN, 0, 0, AF_REQUIRE_ENCRYPTION, 0, &g_dwFlags, NULL },
290 { _T("ServerConnection"), CT_STRING_LIST, '\n', 0, 0, 0, &s_serverConnectionList, NULL },
291 { _T("Servers"), CT_STRING_LIST, ',', 0, 0, 0, &m_pszServerList, NULL },
292 { _T("SessionIdleTimeout"), CT_LONG, 0, 0, 0, 0, &g_dwIdleTimeout, NULL },
293 { _T("SessionAgentPort"), CT_WORD, 0, 0, 0, 0, &g_sessionAgentPort, NULL },
294 { _T("SharedSecret"), CT_STRING, 0, 0, MAX_SECRET_LENGTH, 0, g_szSharedSecret, NULL },
295 { _T("SNMPTimeout"), CT_LONG, 0, 0, 0, 0, &g_dwSNMPTimeout, NULL },
296 { _T("SNMPTrapListenAddress"), CT_STRING, 0, 0, MAX_PATH, 0, &g_szSNMPTrapListenAddress, NULL },
297 { _T("SNMPTrapPort"), CT_LONG, 0, 0, 0, 0, &g_dwSNMPTrapPort, NULL },
298 { _T("StartupDelay"), CT_LONG, 0, 0, 0, 0, &g_dwStartupDelay, NULL },
299 { _T("SubAgent"), CT_STRING_LIST, '\n', 0, 0, 0, &m_pszSubagentList, NULL },
300 { _T("SyslogListenPort"), CT_WORD, 0, 0, 0, 0, &g_syslogListenPort, NULL },
301 { _T("TimeOut"), CT_IGNORE, 0, 0, 0, 0, NULL, NULL },
302 { _T("WaitForProcess"), CT_STRING, 0, 0, MAX_PATH, 0, s_processToWaitFor, NULL },
303 { _T("ZoneId"), CT_LONG, 0, 0, 0, 0, &g_zoneId, NULL },
304 { _T(""), CT_END_OF_LIST, 0, 0, 0, 0, NULL, NULL }
305 };
306
307 /**
308 * Help text
309 */
310 static TCHAR m_szHelpText[] =
311 _T("Usage: nxagentd [options]\n")
312 _T("Where valid options are:\n")
313 _T(" -c <file> : Use configuration file <file> (default ") AGENT_DEFAULT_CONFIG _T(")\n")
314 _T(" -C : Load configuration file, dump resulting configuration, and exit\n")
315 _T(" -d : Run as daemon/service\n")
316 _T(" -D <level> : Set debug level (0..9)\n")
317 #ifdef _WIN32
318 _T(" -e <name> : Windows event source name\n")
319 #endif
320 _T(" -f : Run in foreground\n")
321 #if !defined(_WIN32)
322 _T(" -g <gid> : Chhange group ID to <gid> after start\n")
323 #endif
324 _T(" -h : Display help and exit\n")
325 #ifdef _WIN32
326 _T(" -H : Hide agent's window when in standalone mode\n")
327 _T(" -i : Installed Windows service must be interactive\n")
328 _T(" -I : Install Windows service\n")
329 #endif
330 _T(" -K : Shutdown all connected external sub-agents\n")
331 _T(" -M <addr> : Download config from management server <addr>\n")
332 #ifdef _WIN32
333 _T(" -n <name> : Service name\n")
334 _T(" -N <name> : Service display name\n")
335 #endif
336 #if !defined(_WIN32)
337 _T(" -p : Path to pid file (default: /var/run/nxagentd.pid)\n")
338 #endif
339 _T(" -P <text> : Set platform suffix to <text>\n")
340 _T(" -r <addr> : Register agent on management server <addr>\n")
341 #ifdef _WIN32
342 _T(" -R : Remove Windows service\n")
343 _T(" -s : Start Windows servive\n")
344 _T(" -S : Stop Windows service\n")
345 #endif
346 #if !defined(_WIN32)
347 _T(" -u <uid> : Chhange user ID to <uid> after start\n")
348 #endif
349 _T(" -v : Display version and exit\n")
350 _T("\n");
351
352 /**
353 * Server info: constructor
354 */
355 ServerInfo::ServerInfo(const TCHAR *name, bool control, bool master)
356 {
357 #ifdef UNICODE
358 m_name = MBStringFromWideString(name);
359 #else
360 m_name = strdup(name);
361 #endif
362
363 char *p = strchr(m_name, '/');
364 if (p != NULL)
365 {
366 *p = 0;
367 p++;
368 m_address = InetAddress::resolveHostName(m_name);
369 if (m_address.isValid())
370 {
371 int bits = strtol(p, NULL, 10);
372 if ((bits >= 0) && (bits <= ((m_address.getFamily() == AF_INET) ? 32 : 128)))
373 m_address.setMaskBits(bits);
374 }
375 m_redoResolve = false;
376 }
377 else
378 {
379 m_address = InetAddress::resolveHostName(m_name);
380 m_redoResolve = true;
381 }
382
383 m_control = control;
384 m_master = master;
385 m_lastResolveTime = time(NULL);
386 m_mutex = MutexCreate();
387 }
388
389 /**
390 * Server info: destructor
391 */
392 ServerInfo::~ServerInfo()
393 {
394 safe_free(m_name);
395 MutexDestroy(m_mutex);
396 }
397
398 /**
399 * Server info: resolve hostname if needed
400 */
401 void ServerInfo::resolve()
402 {
403 time_t now = time(NULL);
404 time_t age = now - m_lastResolveTime;
405 if ((age >= 3600) || ((age > 300) && !m_address.isValid()))
406 {
407 m_address = InetAddress::resolveHostName(m_name);
408 m_lastResolveTime = now;
409 }
410 }
411
412 /**
413 * Server info: match address
414 */
415 bool ServerInfo::match(const InetAddress &addr)
416 {
417 MutexLock(m_mutex);
418 if (m_redoResolve)
419 resolve();
420 bool result = m_address.isValid() ? m_address.contain(addr) : false;
421 MutexUnlock(m_mutex);
422 return result;
423 }
424
425 #ifdef _WIN32
426
427 /**
428 * Get our own console window handle (an alternative to Microsoft's GetConsoleWindow)
429 */
430 static HWND GetConsoleHWND()
431 {
432 HWND hWnd;
433 DWORD wpid, cpid;
434
435 cpid = GetCurrentProcessId();
436 while(1)
437 {
438 hWnd = FindWindowEx(NULL, NULL, _T("ConsoleWindowClass"), NULL);
439 if (hWnd == NULL)
440 break;
441
442 GetWindowThreadProcessId(hWnd, &wpid);
443 if (cpid == wpid)
444 break;
445 }
446
447 return hWnd;
448 }
449
450 /**
451 * Get proc address and write log file
452 */
453 static FARPROC GetProcAddressAndLog(HMODULE hModule, LPCSTR procName)
454 {
455 FARPROC ptr;
456
457 ptr = GetProcAddress(hModule, procName);
458 if ((ptr == NULL) && (g_dwFlags & AF_LOG_UNRESOLVED_SYMBOLS))
459 nxlog_write(MSG_NO_FUNCTION, EVENTLOG_WARNING_TYPE, "s", procName);
460 return ptr;
461 }
462
463 /**
464 * Shutdown thread (created by H_RestartAgent)
465 */
466 static THREAD_RESULT THREAD_CALL ShutdownThread(void *pArg)
467 {
468 DebugPrintf(INVALID_INDEX, 1, _T("Shutdown thread started"));
469 Shutdown();
470 ExitProcess(0);
471 return THREAD_OK; // Never reached
472 }
473
474 #endif /* _WIN32 */
475
476
477 /**
478 * Restart agent
479 */
480 static LONG H_RestartAgent(const TCHAR *action, StringList *args, const TCHAR *data, AbstractCommSession *session)
481 {
482 DebugPrintf(INVALID_INDEX, 1, _T("H_RestartAgent() called"));
483
484 TCHAR szCmdLine[4096], szPlatformSuffixOption[MAX_PSUFFIX_LENGTH + 16];
485
486 if (g_szPlatformSuffix[0] != 0)
487 {
488 _sntprintf(szPlatformSuffixOption, MAX_PSUFFIX_LENGTH + 16, _T("-P \"%s\" "), g_szPlatformSuffix);
489 }
490 else
491 {
492 szPlatformSuffixOption[0] = 0;
493 }
494
495 #ifdef _WIN32
496 _sntprintf(szCmdLine, 4096, _T("\"%s\" -c \"%s\" -n \"%s\" -e \"%s\" %s%s%s%s%s-D %d %s-X %u"), s_executableName,
497 g_szConfigFile, g_windowsServiceName, g_windowsEventSourceName,
498 (g_dwFlags & AF_DAEMON) ? _T("-d ") : _T(""),
499 (g_dwFlags & AF_HIDE_WINDOW) ? _T("-H ") : _T(""),
500 (g_dwFlags & AF_CENTRAL_CONFIG) ? _T("-M ") : _T(""),
501 (g_dwFlags & AF_CENTRAL_CONFIG) ? g_szConfigServer : _T(""),
502 (g_dwFlags & AF_CENTRAL_CONFIG) ? _T(" ") : _T(""),
503 s_debugLevel, szPlatformSuffixOption,
504 (g_dwFlags & AF_DAEMON) ? 0 : GetCurrentProcessId());
505 DebugPrintf(INVALID_INDEX, 1, _T("Restarting agent with command line '%s'"), szCmdLine);
506
507 DWORD dwResult;
508 STARTUPINFO si;
509 PROCESS_INFORMATION pi;
510
511 // Fill in process startup info structure
512 memset(&si, 0, sizeof(STARTUPINFO));
513 si.cb = sizeof(STARTUPINFO);
514
515 // Create new process
516 if (!CreateProcess(NULL, szCmdLine, NULL, NULL, FALSE,
517 (g_dwFlags & AF_DAEMON) ? (CREATE_NO_WINDOW | DETACHED_PROCESS) : (CREATE_NEW_CONSOLE),
518 NULL, NULL, &si, &pi))
519 {
520 nxlog_write(MSG_CREATE_PROCESS_FAILED, EVENTLOG_ERROR_TYPE, "se", szCmdLine, GetLastError());
521 dwResult = ERR_EXEC_FAILED;
522 }
523 else
524 {
525 // Close all handles
526 CloseHandle(pi.hThread);
527 CloseHandle(pi.hProcess);
528 dwResult = ERR_SUCCESS;
529 }
530 if ((dwResult == ERR_SUCCESS) && (!(g_dwFlags & AF_DAEMON)))
531 {
532 if (g_dwFlags & AF_HIDE_WINDOW)
533 {
534 ConditionSet(s_shutdownCondition);
535 }
536 else
537 {
538 ThreadCreate(ShutdownThread, 0, NULL);
539 }
540 }
541 return dwResult;
542 #else
543 _sntprintf(szCmdLine, 4096, _T("\"%s\" -c \"%s\" %s%s%s%s-D %d %s-X %lu"), s_executableName,
544 g_szConfigFile, (g_dwFlags & AF_DAEMON) ? _T("-d ") : _T(""),
545 (g_dwFlags & AF_CENTRAL_CONFIG) ? _T("-M ") : _T(""),
546 (g_dwFlags & AF_CENTRAL_CONFIG) ? g_szConfigServer : _T(""),
547 (g_dwFlags & AF_CENTRAL_CONFIG) ? _T(" ") : _T(""),
548 (int)s_debugLevel, szPlatformSuffixOption,
549 (unsigned long)s_pid);
550 DebugPrintf(INVALID_INDEX, 1, _T("Restarting agent with command line '%s'"), szCmdLine);
551 return ExecuteCommand(szCmdLine, NULL, NULL);
552 #endif
553 }
554
555 /**
556 * This function writes message from subagent to agent's log
557 */
558 static void WriteSubAgentMsg(int logLevel, int debugLevel, const TCHAR *pszMsg)
559 {
560 if (logLevel == EVENTLOG_DEBUG_TYPE)
561 {
562 if (debugLevel <= (int)s_debugLevel)
563 nxlog_write(MSG_DEBUG, EVENTLOG_DEBUG_TYPE, "s", pszMsg);
564 }
565 else
566 {
567 nxlog_write(MSG_SUBAGENT_MSG, logLevel, "s", pszMsg);
568 }
569 }
570
571 /**
572 * Signal handler for UNIX platforms
573 */
574 #if !defined(_WIN32)
575
576 static THREAD_RESULT THREAD_CALL SignalHandler(void *pArg)
577 {
578 sigset_t signals;
579 int nSignal;
580
581 sigemptyset(&signals);
582 sigaddset(&signals, SIGTERM);
583 sigaddset(&signals, SIGINT);
584 sigaddset(&signals, SIGSEGV);
585 sigaddset(&signals, SIGHUP);
586 sigaddset(&signals, SIGUSR1);
587 sigaddset(&signals, SIGUSR2);
588 #if !defined(__sun) && !defined(_AIX) && !defined(__hpux)
589 sigaddset(&signals, SIGPIPE);
590 #endif
591
592 sigprocmask(SIG_BLOCK, &signals, NULL);
593
594 while(1)
595 {
596 if (sigwait(&signals, &nSignal) == 0)
597 {
598 switch(nSignal)
599 {
600 case SIGTERM:
601 case SIGINT:
602 goto stop_handler;
603 case SIGSEGV:
604 abort();
605 break;
606 default:
607 break;
608 }
609 }
610 else
611 {
612 ThreadSleepMs(100);
613 }
614 }
615
616 stop_handler:
617 sigprocmask(SIG_UNBLOCK, &signals, NULL);
618 return THREAD_OK;
619 }
620
621 #endif
622
623 /**
624 * Load platform subagent
625 */
626 static void LoadPlatformSubagent()
627 {
628 #ifdef _WIN32
629 LoadSubAgent(_T("WINNT.NSM"));
630 #else
631 #if HAVE_SYS_UTSNAME_H && !defined(_STATIC_AGENT)
632 struct utsname un;
633 TCHAR szName[MAX_PATH];
634 int i;
635
636 if (uname(&un) != -1)
637 {
638 // Convert system name to lowercase
639 for(i = 0; un.sysname[i] != 0; i++)
640 un.sysname[i] = tolower(un.sysname[i]);
641 if (!strcmp(un.sysname, "hp-ux"))
642 strcpy(un.sysname, "hpux");
643 _sntprintf(szName, MAX_PATH, _T("%hs.nsm"), un.sysname);
644 LoadSubAgent(szName);
645 }
646 #endif
647 #endif
648 }
649
650 /**
651 * Send file to server (subagent API)
652 */
653 static bool SendFileToServer(void *session, UINT32 requestId, const TCHAR *file, long offset)
654 {
655 if (session == NULL)
656 return false;
657 return ((CommSession *)session)->sendFile(requestId, file, offset);
658 }
659
660 /**
661 * Parser server list
662 */
663 static void ParseServerList(TCHAR *serverList, bool isControl, bool isMaster)
664 {
665 TCHAR *pItem, *pEnd;
666
667 for(pItem = pEnd = serverList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
668 {
669 pEnd = _tcschr(pItem, _T(','));
670 if (pEnd != NULL)
671 *pEnd = 0;
672 StrStrip(pItem);
673
674 g_serverList.add(new ServerInfo(pItem, isControl, isMaster));
675 }
676 free(serverList);
677 }
678
679 /**
680 * Agent initialization
681 */
682 BOOL Initialize()
683 {
684 TCHAR *pItem, *pEnd;
685
686 if (s_debugLevel == (UINT32)NXCONFIG_UNINITIALIZED_VALUE)
687 s_debugLevel = 0;
688
689 if (!_tcscmp(g_szDataDirectory, _T("{default}")))
690 {
691 GetNetXMSDirectory(nxDirData, g_szDataDirectory);
692 }
693
694 //Initialize config policy folder
695 TCHAR tail = g_szDataDirectory[_tcslen(g_szDataDirectory) - 1];
696 _sntprintf(g_szConfigPolicyDir, MAX_PATH, _T("%s%s%s"), g_szDataDirectory,
697 ((tail != '\\') && (tail != '/')) ? FS_PATH_SEPARATOR : _T(""),
698 CONFIG_AP_FOLDER FS_PATH_SEPARATOR);
699 CreateFolder(g_szConfigPolicyDir);
700
701 // Load configuration
702 g_config->loadConfigDirectory(g_szConfigPolicyDir, _T("agent"));
703 g_config->parseTemplate(_T("agent"), m_cfgTemplate);
704
705 // Open log file
706 if (!nxlog_open((g_dwFlags & AF_USE_SYSLOG) ? NXAGENTD_SYSLOG_NAME : g_szLogFile,
707 ((g_dwFlags & AF_USE_SYSLOG) ? NXLOG_USE_SYSLOG : 0) |
708 ((g_dwFlags & AF_BACKGROUND_LOG_WRITER) ? NXLOG_BACKGROUND_WRITER : 0) |
709 ((g_dwFlags & AF_DAEMON) ? 0 : NXLOG_PRINT_TO_STDOUT),
710 _T("NXAGENTD.EXE"),
711 #ifdef _WIN32
712 0, NULL, MSG_DEBUG))
713 #else
714 g_dwNumMessages, g_szMessages, MSG_DEBUG))
715 #endif
716 {
717 //TODO: set flag that log have been opened with errors
718 s_debugLevel = 1;
719 g_failFlags |= FAIL_OPEN_LOG;
720 nxlog_open(NXAGENTD_SYSLOG_NAME, NXLOG_USE_SYSLOG |
721 ((g_dwFlags & AF_BACKGROUND_LOG_WRITER) ? NXLOG_BACKGROUND_WRITER : 0) |
722 ((g_dwFlags & AF_DAEMON) ? 0 : NXLOG_PRINT_TO_STDOUT),
723 _T("NXAGENTD.EXE"),
724 #ifdef _WIN32
725 0, NULL, MSG_DEBUG);
726 #else
727 g_dwNumMessages, g_szMessages, MSG_DEBUG);
728 #endif
729 _ftprintf(stderr, _T("ERROR: Cannot open log file, logs will be written to syslog with debug level 1\n"));
730
731 }
732 else
733 {
734 if (!(g_dwFlags & AF_USE_SYSLOG))
735 {
736 if (!nxlog_set_rotation_policy((int)s_logRotationMode, s_maxLogSize, (int)s_logHistorySize, s_dailyLogFileSuffix))
737 if (!(g_dwFlags & AF_DAEMON))
738 _tprintf(_T("WARNING: cannot set log rotation policy; using default values\n"));
739 }
740 }
741 nxlog_write(MSG_USE_CONFIG_D, NXLOG_INFO, "s", g_szConfigIncludeDir);
742 nxlog_write(MSG_DEBUG_LEVEL, NXLOG_INFO, "d", s_debugLevel);
743 nxlog_set_debug_level(s_debugLevel);
744
745 if (_tcscmp(g_masterAgent, _T("not_set")))
746 {
747 g_dwFlags |= AF_SUBAGENT_LOADER;
748 DebugPrintf(INVALID_INDEX, 1, _T("Switched to external subagent loader mode, master agent address is %s"), g_masterAgent);
749 }
750
751 DebugPrintf(INVALID_INDEX, 1, _T("Data directory: %s"), g_szDataDirectory);
752 CreateFolder(g_szDataDirectory);
753
754 #ifndef _WIN32
755 nxlog_debug(2, _T("Effective user ID %d"), (int)geteuid());
756 nxlog_debug(2, _T("Effective group ID %d"), (int)getegid());
757 #endif
758
759 //Initialize log parser policy folder
760 tail = g_szDataDirectory[_tcslen(g_szDataDirectory) - 1];
761 _sntprintf(g_szLogParserDirectory, MAX_PATH, _T("%s%s%s"), g_szDataDirectory,
762 ((tail != '\\') && (tail != '/')) ? FS_PATH_SEPARATOR : _T(""),
763 LOGPARSER_AP_FOLDER FS_PATH_SEPARATOR);
764 DebugPrintf(INVALID_INDEX, 6, _T("Log parser policy directory: %s"), g_szLogParserDirectory);
765 CreateFolder(g_szLogParserDirectory);
766 DebugPrintf(INVALID_INDEX, 6, _T("Configuration policy directory: %s"), g_szConfigPolicyDir);
767 CreateFolder(g_szFileStore);
768
769 #ifdef _WIN32
770 WSADATA wsaData;
771 int wrc = WSAStartup(MAKEWORD(2, 2), &wsaData);
772 if (wrc != 0)
773 {
774 nxlog_write(MSG_WSASTARTUP_FAILED, NXLOG_ERROR, "e", wrc);
775 return FALSE;
776 }
777 #endif
778
779 // Initialize API for subagents
780 s_subAgentsStopCondition = ConditionCreate(TRUE);
781 InitSubAgentAPI(WriteSubAgentMsg, SendTrap, SendTrap, EnumerateSessions, FindServerSession,
782 SendFileToServer, PushData, GetLocalDatabaseHandle, s_subAgentsStopCondition, g_szDataDirectory);
783 DebugPrintf(INVALID_INDEX, 1, _T("Subagent API initialized"));
784
785 // Initialize cryptografy
786 if (!InitCryptoLib(s_enabledCiphers))
787 {
788 nxlog_write(MSG_INIT_CRYPTO_FAILED, EVENTLOG_ERROR_TYPE, "e", WSAGetLastError());
789 return FALSE;
790 }
791
792 // Initialize libssl - it is not used by core agent
793 // but may be needed by some subagents. Allowing first load of libssl by
794 // subagent via dlopen() may lead to undesired side effects
795 #ifdef _WITH_ENCRYPTION
796 SSL_library_init();
797 SSL_load_error_strings();
798 #endif
799
800 DBInit(MSG_DB_LIBRARY, MSG_SQL_ERROR);
801
802 if (!OpenLocalDatabase())
803 {
804 nxlog_write(MSG_LOCAL_DB_OPEN_FAILED, NXLOG_ERROR, NULL);
805 }
806
807 if (!(g_dwFlags & AF_SUBAGENT_LOADER))
808 {
809 if (g_dwFlags & AF_ENABLE_SNMP_PROXY)
810 {
811 g_snmpProxyThreadPool = ThreadPoolCreate(2, 128, _T("SNMPPROXY"));
812 }
813 InitSessionList();
814
815 // Initialize built-in parameters
816 if (!InitParameterList())
817 return FALSE;
818
819 // Parse outgoing server connection (tunnel) list
820 if (s_serverConnectionList != NULL)
821 ParseTunnelList(s_serverConnectionList);
822
823 // Parse server lists
824 if (m_pszMasterServerList != NULL)
825 ParseServerList(m_pszMasterServerList, true, true);
826 if (m_pszControlServerList != NULL)
827 ParseServerList(m_pszControlServerList, true, false);
828 if (m_pszServerList != NULL)
829 ParseServerList(m_pszServerList, false, false);
830
831 // Add built-in actions
832 AddAction(_T("Agent.Restart"), AGENT_ACTION_SUBAGENT, NULL, H_RestartAgent, _T("CORE"), _T("Restart agent"));
833
834 // Load platform subagents
835 #if !defined(_WIN32)
836 InitStaticSubagents();
837 #endif
838 if (g_dwFlags & AF_ENABLE_AUTOLOAD)
839 {
840 LoadPlatformSubagent();
841 }
842 }
843
844 // Wait for external process if requested
845 if (s_processToWaitFor[0] != 0)
846 {
847 DebugPrintf(INVALID_INDEX, 1, _T("Waiting for process %s"), s_processToWaitFor);
848 if (!WaitForProcess(s_processToWaitFor))
849 nxlog_write(MSG_WAITFORPROCESS_FAILED, EVENTLOG_ERROR_TYPE, "s", s_processToWaitFor);
850 }
851
852 // Load other subagents
853 if (m_pszSubagentList != NULL)
854 {
855 for(pItem = pEnd = m_pszSubagentList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
856 {
857 pEnd = _tcschr(pItem, _T('\n'));
858 if (pEnd != NULL)
859 *pEnd = 0;
860 StrStrip(pItem);
861 LoadSubAgent(pItem);
862 }
863 free(m_pszSubagentList);
864 }
865
866 // Parse action list
867 if (m_pszActionList != NULL)
868 {
869 for(pItem = pEnd = m_pszActionList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
870 {
871 pEnd = _tcschr(pItem, _T('\n'));
872 if (pEnd != NULL)
873 *pEnd = 0;
874 StrStrip(pItem);
875 if (!AddActionFromConfig(pItem, FALSE))
876 nxlog_write(MSG_ADD_ACTION_FAILED, EVENTLOG_WARNING_TYPE, "s", pItem);
877 }
878 free(m_pszActionList);
879 }
880 if (m_pszShellActionList != NULL)
881 {
882 for(pItem = pEnd = m_pszShellActionList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
883 {
884 pEnd = _tcschr(pItem, _T('\n'));
885
886 if (pEnd != NULL)
887 *pEnd = 0;
888 StrStrip(pItem);
889 if (!AddActionFromConfig(pItem, TRUE))
890 nxlog_write(MSG_ADD_ACTION_FAILED, EVENTLOG_WARNING_TYPE, "s", pItem);
891 }
892 free(m_pszShellActionList);
893 }
894
895 // Parse external parameters list
896 if (m_pszExtParamList != NULL)
897 {
898 for(pItem = pEnd = m_pszExtParamList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
899 {
900 pEnd = _tcschr(pItem, _T('\n'));
901 if (pEnd != NULL)
902 *pEnd = 0;
903 StrStrip(pItem);
904 if (!AddExternalParameter(pItem, FALSE, FALSE))
905 nxlog_write(MSG_ADD_EXT_PARAM_FAILED, EVENTLOG_WARNING_TYPE, "s", pItem);
906 }
907 free(m_pszExtParamList);
908 }
909 if (m_pszShExtParamList != NULL)
910 {
911 for(pItem = pEnd = m_pszShExtParamList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
912 {
913 pEnd = _tcschr(pItem, _T('\n'));
914 if (pEnd != NULL)
915 *pEnd = 0;
916 StrStrip(pItem);
917 if (!AddExternalParameter(pItem, TRUE, FALSE))
918 nxlog_write(MSG_ADD_EXT_PARAM_FAILED, EVENTLOG_WARNING_TYPE, "s", pItem);
919 }
920 free(m_pszShExtParamList);
921 }
922
923 // Parse external lists
924 if (m_pszExtListsList != NULL)
925 {
926 for(pItem = pEnd = m_pszExtListsList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
927 {
928 pEnd = _tcschr(pItem, _T('\n'));
929 if (pEnd != NULL)
930 *pEnd = 0;
931 StrStrip(pItem);
932 if (!AddExternalParameter(pItem, FALSE, TRUE))
933 nxlog_write(MSG_ADD_EXT_PARAM_FAILED, EVENTLOG_WARNING_TYPE, "s", pItem);
934 }
935 free(m_pszExtListsList);
936 }
937
938 // Parse external parameters providers list
939 if (m_pszParamProviderList != NULL)
940 {
941 for(pItem = pEnd = m_pszParamProviderList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
942 {
943 pEnd = _tcschr(pItem, _T('\n'));
944 if (pEnd != NULL)
945 *pEnd = 0;
946 StrStrip(pItem);
947 if (!AddParametersProvider(pItem))
948 nxlog_write(MSG_ADD_PARAM_PROVIDER_FAILED, EVENTLOG_WARNING_TYPE, "s", pItem);
949 }
950 free(m_pszParamProviderList);
951 }
952
953 // Parse external subagents list
954 if (!(g_dwFlags & AF_SUBAGENT_LOADER) && (m_pszExtSubagentList != NULL))
955 {
956 for(pItem = pEnd = m_pszExtSubagentList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
957 {
958 pEnd = _tcschr(pItem, _T('\n'));
959 if (pEnd != NULL)
960 *pEnd = 0;
961 StrStrip(pItem);
962 if (!AddExternalSubagent(pItem))
963 nxlog_write(MSG_ADD_EXTERNAL_SUBAGENT_FAILED, EVENTLOG_WARNING_TYPE, "s", pItem);
964 }
965 free(m_pszExtSubagentList);
966 }
967
968 // Parse application agents list
969 if (!(g_dwFlags & AF_SUBAGENT_LOADER) && (m_pszAppAgentList != NULL))
970 {
971 for(pItem = pEnd = m_pszAppAgentList; pEnd != NULL && *pItem != 0; pItem = pEnd + 1)
972 {
973 pEnd = _tcschr(pItem, _T('\n'));
974 if (pEnd != NULL)
975 *pEnd = 0;
976 StrStrip(pItem);
977 RegisterApplicationAgent(pItem);
978 }
979 free(m_pszAppAgentList);
980 }
981
982 ThreadSleep(1);
983
984 // If StartupDelay is greater than zero, then wait
985 if (g_dwStartupDelay > 0)
986 {
987 if (g_dwFlags & AF_DAEMON)
988 {
989 ThreadSleep(g_dwStartupDelay);
990 }
991 else
992 {
993 UINT32 i;
994
995 _tprintf(_T("XXXXXX%*s]\rWAIT ["), g_dwStartupDelay, _T(" "));
996 fflush(stdout);
997 for(i = 0; i < g_dwStartupDelay; i++)
998 {
999 ThreadSleep(1);
1000 _puttc(_T('.'), stdout);
1001 fflush(stdout);
1002 }
1003 _tprintf(_T("\n"));
1004 }
1005 }
1006
1007 StartParamProvidersPoller();
1008
1009 // Agent start time
1010 g_tmAgentStartTime = time(NULL);
1011
1012 s_eventSenderThread = ThreadCreateEx(TrapSender, 0, NULL);
1013
1014 if (g_dwFlags & AF_ENABLE_SNMP_TRAP_PROXY)
1015 {
1016 s_snmpTrapSenderThread = ThreadCreateEx(SNMPTrapSender, 0, NULL);
1017 s_snmpTrapReceiverThread = ThreadCreateEx(SNMPTrapReceiver, 0, NULL);
1018 }
1019
1020 if (g_dwFlags & AF_ENABLE_SYSLOG_PROXY)
1021 {
1022 s_syslogSenderThread = ThreadCreateEx(SyslogSender, 0, NULL);
1023 s_syslogReceiverThread = ThreadCreateEx(SyslogReceiver, 0, NULL);
1024 }
1025
1026 if (g_dwFlags & AF_SUBAGENT_LOADER)
1027 {
1028 s_masterAgentListenerThread = ThreadCreateEx(MasterAgentListener, 0, NULL);
1029 }
1030 else
1031 {
1032 // Start network listener and session watchdog
1033 StartLocalDataCollector();
1034 s_listenerThread = ThreadCreateEx(ListenerThread, 0, NULL);
1035 s_sessionWatchdogThread = ThreadCreateEx(SessionWatchdog, 0, NULL);
1036 StartPushConnector();
1037 StartStorageDiscoveryConnector();
1038 StartSessionAgentConnector();
1039 if (g_dwFlags & AF_ENABLE_CONTROL_CONNECTOR)
1040 {
1041 StartControlConnector();
1042 }
1043
1044 if (g_dwFlags & AF_REGISTER)
1045 {
1046 RegisterOnServer(g_szRegistrar);
1047 }
1048
1049 s_tunnelManagerThread = ThreadCreateEx(TunnelManager, 0, NULL);
1050 }
1051
1052 #if defined(_WIN32)
1053 s_shutdownCondition = ConditionCreate(TRUE);
1054 #endif
1055 ThreadSleep(1);
1056
1057 // Start watchdog process
1058 if (!(g_dwFlags & AF_SUBAGENT_LOADER))
1059 {
1060 if (g_dwFlags & AF_ENABLE_WATCHDOG)
1061 StartWatchdog();
1062 }
1063
1064 // Delete file used for upgrade if exists
1065 TCHAR upgradeFileName[MAX_PATH];
1066 ReadRegistryAsString(_T("upgrade.file"), upgradeFileName, MAX_PATH, _T(""));
1067 if(upgradeFileName[0] != 0)
1068 {
1069 _tremove(upgradeFileName);
1070 DeleteRegistryEntry(_T("upgrade.file"));
1071 }
1072
1073 //Update policy inventory according to files that exist on file system
1074 UpdatePolicyInventory();
1075
1076 return TRUE;
1077 }
1078
1079 /**
1080 * Shutdown agent
1081 */
1082 void Shutdown()
1083 {
1084 DebugPrintf(INVALID_INDEX, 2, _T("Shutdown() called"));
1085 if (g_dwFlags & AF_ENABLE_WATCHDOG)
1086 StopWatchdog();
1087
1088 g_dwFlags |= AF_SHUTDOWN;
1089 ConditionSet(s_subAgentsStopCondition);
1090
1091 if (g_dwFlags & AF_SUBAGENT_LOADER)
1092 {
1093 // TODO: shall we inform master agent listener about shutdown?
1094 //ThreadJoin(s_masterAgentListenerThread);
1095 }
1096 else
1097 {
1098 ShutdownLocalDataCollector();
1099 ShutdownTrapSender();
1100 ThreadJoin(s_sessionWatchdogThread);
1101 ThreadJoin(s_listenerThread);
1102 ThreadJoin(s_tunnelManagerThread);
1103 }
1104 ThreadJoin(s_eventSenderThread);
1105 if (g_dwFlags & AF_ENABLE_SNMP_TRAP_PROXY)
1106 {
1107 ShutdownSNMPTrapSender();
1108 ThreadJoin(s_snmpTrapReceiverThread);
1109 ThreadJoin(s_snmpTrapSenderThread);
1110 }
1111 if (g_dwFlags & AF_ENABLE_SYSLOG_PROXY)
1112 {
1113 ShutdownSyslogSender();
1114 ThreadJoin(s_syslogReceiverThread);
1115 ThreadJoin(s_syslogSenderThread);
1116 }
1117
1118 DestroySessionList();
1119 MsgWaitQueue::shutdown();
1120
1121 if (g_dwFlags & AF_ENABLE_SNMP_PROXY)
1122 {
1123 ThreadPoolDestroy(g_snmpProxyThreadPool);
1124 }
1125
1126 UnloadAllSubAgents();
1127 CloseLocalDatabase();
1128 nxlog_write(MSG_AGENT_STOPPED, EVENTLOG_INFORMATION_TYPE, NULL);
1129 nxlog_close();
1130
1131 delete g_config;
1132
1133 // Notify main thread about shutdown
1134 #ifdef _WIN32
1135 ConditionSet(s_shutdownCondition);
1136 #endif
1137
1138 // Remove PID file
1139 #if !defined(_WIN32)
1140 _tremove(g_szPidFile);
1141 #endif
1142 }
1143
1144 /**
1145 * Common Main()
1146 */
1147 void Main()
1148 {
1149 nxlog_write(MSG_AGENT_STARTED, NXLOG_INFO, NULL);
1150
1151 if (g_dwFlags & AF_DAEMON)
1152 {
1153 #if defined(_WIN32)
1154 ConditionWait(s_shutdownCondition, INFINITE);
1155 #else
1156 StartMainLoop(SignalHandler, NULL);
1157 #endif
1158 }
1159 else
1160 {
1161 #if defined(_WIN32)
1162 if (g_dwFlags & AF_HIDE_WINDOW)
1163 {
1164 HWND hWnd;
1165
1166 hWnd = GetConsoleHWND();
1167 if (hWnd != NULL)
1168 ShowWindow(hWnd, SW_HIDE);
1169 ConditionWait(s_shutdownCondition, INFINITE);
1170 ThreadSleep(1);
1171 }
1172 else
1173 {
1174 _tprintf(_T("Agent running. Press ESC to shutdown.\n"));
1175 while(1)
1176 {
1177 if (_getch() == 27)
1178 break;
1179 }
1180 _tprintf(_T("Agent shutting down...\n"));
1181 Shutdown();
1182 }
1183 #else
1184 _tprintf(_T("Agent running. Press Ctrl+C to shutdown.\n"));
1185 StartMainLoop(SignalHandler, NULL);
1186 _tprintf(_T("\nStopping agent...\n"));
1187 #endif
1188 }
1189 }
1190
1191 /**
1192 * Do necessary actions on agent restart
1193 */
1194 static void DoRestartActions(UINT32 dwOldPID)
1195 {
1196 #if defined(_WIN32)
1197 if (dwOldPID == 0)
1198 {
1199 // Service
1200 StopAgentService();
1201 WaitForService(SERVICE_STOPPED);
1202 StartAgentService();
1203 ExitProcess(0);
1204 }
1205 else
1206 {
1207 HANDLE hProcess;
1208
1209 hProcess = OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE, FALSE, dwOldPID);
1210 if (hProcess != NULL)
1211 {
1212 if (WaitForSingleObject(hProcess, 60000) == WAIT_TIMEOUT)
1213 {
1214 TerminateProcess(hProcess, 0);
1215 }
1216 CloseHandle(hProcess);
1217 }
1218 }
1219 #else
1220 int i;
1221
1222 kill(dwOldPID, SIGTERM);
1223 for(i = 0; i < 30; i++)
1224 {
1225 sleep(2);
1226 if (kill(dwOldPID, SIGCONT) == -1)
1227 break;
1228 }
1229
1230 // Kill previous instance of agent if it's still running
1231 if (i == 30)
1232 kill(dwOldPID, SIGKILL);
1233 #endif
1234 }
1235
1236 /**
1237 * Create configuration file
1238 */
1239 static int CreateConfig(const char *pszServer, const char *pszLogFile, const char *pszFileStore,
1240 const char *configIncludeDir, int iNumSubAgents, char **ppszSubAgentList)
1241 {
1242 FILE *fp;
1243 time_t currTime;
1244 int i;
1245
1246 if (_taccess(g_szConfigFile, 0) == 0)
1247 return 0; // File already exist, we shouldn't overwrite it
1248
1249 fp = _tfopen(g_szConfigFile, _T("w"));
1250 if (fp != NULL)
1251 {
1252 currTime = time(NULL);
1253 _ftprintf(fp, _T("#\n# NetXMS agent configuration file\n# Created by agent installer at %s#\n\n"),
1254 _tctime(&currTime));
1255 _ftprintf(fp, _T("MasterServers = %hs\nConfigIncludeDir = %hs\nLogFile = %hs\nFileStore = %hs\n"),
1256 pszServer, configIncludeDir, pszLogFile, pszFileStore);
1257 for(i = 0; i < iNumSubAgents; i++)
1258 _ftprintf(fp, _T("SubAgent = %hs\n"), ppszSubAgentList[i]);
1259 fclose(fp);
1260 }
1261 return (fp != NULL) ? 0 : 2;
1262 }
1263
1264 /**
1265 * Init config
1266 */
1267 static void InitConfig()
1268 {
1269 g_config = new Config();
1270 g_config->setTopLevelTag(_T("config"));
1271
1272 // Set default data directory on Windows
1273 #ifdef _WIN32
1274 if (SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, g_szDataDirectory) == S_OK)
1275 {
1276 _tcscat(g_szDataDirectory, _T("\\nxagentd"));
1277 }
1278 #endif
1279 }
1280
1281 /**
1282 * Initiate shutdown of connected external subagents
1283 */
1284 static void InitiateExtSubagentShutdown()
1285 {
1286 NXCPMessage msg;
1287 msg.setCode(CMD_SHUTDOWN);
1288 if (SendControlMessage(&msg))
1289 _tprintf(_T("Control message sent successfully to master agent\n"));
1290 else
1291 _tprintf(_T("ERROR: Unable to send control message to master agent\n"));
1292 }
1293
1294 #ifndef _WIN32
1295
1296 /**
1297 * Get user ID
1298 */
1299 static int GetUserId(const char *name)
1300 {
1301 char *eptr;
1302 int id = (int)strtol(name, &eptr, 10);
1303 if (*eptr == 0)
1304 return id;
1305
1306 #if HAVE_GETPWNAM
1307 struct passwd *p = getpwnam(name);
1308 if (p == NULL)
1309 {
1310 _tprintf(_T("Invalid user ID \"%hs\"\n"), name);
1311 return 0;
1312 }
1313 return p->pw_uid;
1314 #else
1315 _tprintf(_T("Invalid user ID \"%hs\"\n"), name);
1316 return 0;
1317 #endif
1318 }
1319
1320 /**
1321 * Get group ID
1322 */
1323 static int GetGroupId(const char *name)
1324 {
1325 char *eptr;
1326 int id = (int)strtol(name, &eptr, 10);
1327 if (*eptr == 0)
1328 return id;
1329
1330 #if HAVE_GETGRNAM
1331 struct group *g = getgrnam(name);
1332 if (g == NULL)
1333 {
1334 _tprintf(_T("Invalid group ID \"%hs\"\n"), name);
1335 return 0;
1336 }
1337 return g->gr_gid;
1338 #else
1339 _tprintf(_T("Invalid group ID \"%hs\"\n"), name);
1340 return 0;
1341 #endif
1342 }
1343
1344 #endif
1345
1346 /**
1347 * Update agent environment from config
1348 */
1349 static void UpdateEnvironment()
1350 {
1351 ObjectArray<ConfigEntry> *entrySet = g_config->getSubEntries(_T("/ENV"), _T("*"));
1352 if (entrySet == NULL)
1353 return;
1354 for(int i = 0; i < entrySet->size(); i++)
1355 {
1356 ConfigEntry *e = entrySet->get(i);
1357 size_t len = _tcslen(e->getName()) + _tcslen(e->getValue()) + 2;
1358 char *env = (char *)malloc(len);
1359 if (env != NULL)
1360 {
1361 #ifdef UNICODE
1362 char *mbName = MBStringFromWideString(e->getName());
1363 char *mbValue = MBStringFromWideString(e->getValue());
1364 snprintf(env, len, "%s=%s", mbName, mbValue);
1365 free(mbName);
1366 free(mbValue);
1367 #else
1368 sprintf(env, "%s=%s", e->getName(), e->getValue());
1369 #endif
1370 putenv(env);
1371 }
1372 }
1373 delete entrySet;
1374 }
1375
1376 /**
1377 * Application entry point
1378 */
1379 int main(int argc, char *argv[])
1380 {
1381 int ch, iExitCode = 0, iAction = ACTION_RUN_AGENT;
1382 BOOL bRestart = FALSE;
1383 UINT32 dwOldPID, dwMainPID;
1384 char *eptr;
1385 #ifdef _WIN32
1386 TCHAR szModuleName[MAX_PATH];
1387 HKEY hKey;
1388 DWORD dwSize;
1389 #else
1390 TCHAR *pszEnv;
1391 int uid = 0, gid = 0;
1392 #endif
1393
1394 InitNetXMSProcess();
1395
1396 #if defined(__sun) || defined(_AIX) || defined(__hpux)
1397 signal(SIGPIPE, SIG_IGN);
1398 signal(SIGHUP, SIG_IGN);
1399 signal(SIGQUIT, SIG_IGN);
1400 signal(SIGUSR1, SIG_IGN);
1401 signal(SIGUSR2, SIG_IGN);
1402 #endif
1403
1404 // Check for alternate config file location
1405 #ifdef _WIN32
1406 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\NetXMS\\Agent"), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
1407 {
1408 dwSize = MAX_PATH * sizeof(TCHAR);
1409 RegQueryValueEx(hKey, _T("ConfigFile"), NULL, NULL, (BYTE *)g_szConfigFile, &dwSize);
1410 dwSize = MAX_PATH * sizeof(TCHAR);
1411 RegQueryValueEx(hKey, _T("ConfigIncludeDir"), NULL, NULL, (BYTE *)g_szConfigIncludeDir, &dwSize);
1412 RegCloseKey(hKey);
1413 }
1414 #else
1415 pszEnv = _tgetenv(_T("NXAGENTD_CONFIG"));
1416 if (pszEnv != NULL)
1417 nx_strncpy(g_szConfigFile, pszEnv, MAX_PATH);
1418
1419 pszEnv = _tgetenv(_T("NXAGENTD_CONFIG_D"));
1420 if (pszEnv != NULL)
1421 nx_strncpy(g_szConfigIncludeDir, pszEnv, MAX_PATH);
1422 #endif
1423
1424 // Parse command line
1425 if (argc == 1)
1426 iAction = ACTION_HELP;
1427 opterr = 1;
1428 while((ch = getopt(argc, argv, VALID_OPTIONS)) != -1)
1429 {
1430 switch(ch)
1431 {
1432 case 'c': // Configuration file
1433 #ifdef UNICODE
1434 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, optarg, -1, g_szConfigFile, MAX_PATH);
1435 g_szConfigFile[MAX_PATH - 1] = 0;
1436 #else
1437 nx_strncpy(g_szConfigFile, optarg, MAX_PATH);
1438 #endif
1439 break;
1440 case 'C': // Configuration check only
1441 iAction = ACTION_CHECK_CONFIG;
1442 break;
1443 case 'd': // Run as daemon
1444 g_dwFlags |= AF_DAEMON;
1445 break;
1446 case 'D': // Turn on debug output
1447 s_debugLevel = strtoul(optarg, &eptr, 0);
1448 if ((*eptr != 0) || (s_debugLevel > 9))
1449 {
1450 fprintf(stderr, "Invalid debug level: %s\n", optarg);
1451 iAction = -1;
1452 iExitCode = 1;
1453 }
1454 break;
1455 case 'f': // Run in foreground
1456 g_dwFlags &= ~AF_DAEMON;
1457 break;
1458 #ifndef _WIN32
1459 case 'g': // set group ID
1460 gid = GetGroupId(optarg);
1461 break;
1462 #endif
1463 case 'h': // Display help and exit
1464 iAction = ACTION_HELP;
1465 break;
1466 #ifdef _WIN32
1467 case 'H': // Hide window
1468 g_dwFlags |= AF_HIDE_WINDOW;
1469 break;
1470 #endif
1471 case 'K': // Shutdown external sub-agents
1472 iAction = ACTION_SHUTDOWN_EXT_AGENTS;
1473 break;
1474 #ifndef _WIN32
1475 case 'p': // PID file
1476 #ifdef UNICODE
1477 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, optarg, -1, g_szPidFile, MAX_PATH);
1478 g_szPidFile[MAX_PATH - 1] = 0;
1479 #else
1480 nx_strncpy(g_szPidFile, optarg, MAX_PATH);
1481 #endif
1482 break;
1483 #endif
1484 case 'M':
1485 g_dwFlags |= AF_CENTRAL_CONFIG;
1486 #ifdef UNICODE
1487 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, optarg, -1, g_szConfigServer, MAX_DB_STRING);
1488 g_szConfigServer[MAX_DB_STRING - 1] = 0;
1489 #else
1490 nx_strncpy(g_szConfigServer, optarg, MAX_DB_STRING);
1491 #endif
1492 break;
1493 case 'r':
1494 g_dwFlags |= AF_REGISTER;
1495 #ifdef UNICODE
1496 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, optarg, -1, g_szRegistrar, MAX_DB_STRING);
1497 g_szRegistrar[MAX_DB_STRING - 1] = 0;
1498 #else
1499 nx_strncpy(g_szRegistrar, optarg, MAX_DB_STRING);
1500 #endif
1501 break;
1502 case 'P': // Platform suffix
1503 #ifdef UNICODE
1504 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, optarg, -1, g_szPlatformSuffix, MAX_PSUFFIX_LENGTH);
1505 g_szPlatformSuffix[MAX_PSUFFIX_LENGTH - 1] = 0;
1506 #else
1507 nx_strncpy(g_szPlatformSuffix, optarg, MAX_PSUFFIX_LENGTH);
1508 #endif
1509 break;
1510 #ifndef _WIN32
1511 case 'u': // set user ID
1512 uid = GetUserId(optarg);
1513 break;
1514 #endif
1515 case 'v': // Print version and exit
1516 _tprintf(_T("NetXMS Core Agent Version ") AGENT_VERSION_STRING _T(" Build ") NETXMS_VERSION_BUILD_STRING _T(" (") NETXMS_BUILD_TAG _T(")") IS_UNICODE_BUILD_STRING _T("\n"));
1517 iAction = ACTION_NONE;
1518 break;
1519 case 'W': // Watchdog process
1520 iAction = ACTION_RUN_WATCHDOG;
1521 dwMainPID = strtoul(optarg, NULL, 10);
1522 break;
1523 case 'X': // Agent is being restarted
1524 bRestart = TRUE;
1525 dwOldPID = strtoul(optarg, NULL, 10);
1526 break;
1527 case 'Z': // Create configuration file
1528 iAction = ACTION_CREATE_CONFIG;
1529 #ifdef UNICODE
1530 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, optarg, -1, g_szConfigFile, MAX_PATH);
1531 g_szConfigFile[MAX_PATH - 1] = 0;
1532 #else
1533 nx_strncpy(g_szConfigFile, optarg, MAX_PATH);
1534 #endif
1535 break;
1536 #ifdef _WIN32
1537 case 'i':
1538 g_dwFlags |= AF_INTERACTIVE_SERVICE;
1539 break;
1540 case 'I': // Install Windows service
1541 iAction = ACTION_INSTALL_SERVICE;
1542 break;
1543 case 'R': // Remove Windows service
1544 iAction = ACTION_REMOVE_SERVICE;
1545 break;
1546 case 's': // Start Windows service
1547 iAction = ACTION_START_SERVICE;
1548 break;
1549 case 'S': // Stop Windows service
1550 iAction = ACTION_STOP_SERVICE;
1551 break;
1552 case 'E': // Install Windows event source
1553 iAction = ACTION_INSTALL_EVENT_SOURCE;
1554 break;
1555 case 'U': // Remove Windows event source
1556 iAction = ACTION_REMOVE_EVENT_SOURCE;
1557 break;
1558 case 'e': // Event source name
1559 #ifdef UNICODE
1560 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, optarg, -1, g_windowsEventSourceName, MAX_PATH);
1561 g_windowsEventSourceName[MAX_PATH - 1] = 0;
1562 #else
1563 nx_strncpy(g_windowsEventSourceName, optarg, MAX_PATH);
1564 #endif
1565 break;
1566 case 'n': // Service name
1567 #ifdef UNICODE
1568 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, optarg, -1, g_windowsServiceName, MAX_PATH);
1569 g_windowsServiceName[MAX_PATH - 1] = 0;
1570 #else
1571 nx_strncpy(g_windowsServiceName, optarg, MAX_PATH);
1572 #endif
1573 break;
1574 case 'N': // Service display name
1575 #ifdef UNICODE
1576 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, optarg, -1, g_windowsServiceDisplayName, MAX_PATH);
1577 g_windowsServiceDisplayName[MAX_PATH - 1] = 0;
1578 #else
1579 nx_strncpy(g_windowsServiceDisplayName, optarg, MAX_PATH);
1580 #endif
1581 break;
1582 #endif
1583 case '?':
1584 iAction = ACTION_HELP;
1585 iExitCode = 1;
1586 break;
1587 default:
1588 break;
1589 }
1590 }
1591
1592 #if !defined(_WIN32)
1593 if (!_tcscmp(g_szConfigFile, _T("{search}")))
1594 {
1595 TCHAR path[MAX_PATH] = _T("");
1596 const TCHAR *homeDir = _tgetenv(_T("NETXMS_HOME"));
1597 if (homeDir != NULL)
1598 {
1599 _sntprintf(path, MAX_PATH, _T("%s/etc/nxagentd.conf"), homeDir);
1600 }
1601 if ((path[0] != 0) && (_taccess(path, 4) == 0))
1602 {
1603 _tcscpy(g_szConfigFile, path);
1604 }
1605 else if (_taccess(PREFIX _T("/etc/nxagentd.conf"), 4) == 0)
1606 {
1607 _tcscpy(g_szConfigFile, PREFIX _T("/etc/nxagentd.conf"));
1608 }
1609 else if (_taccess(_T("/Database/etc/nxagentd.conf"), 4) == 0) // for ZeroShell
1610 {
1611 _tcscpy(g_szConfigFile, _T("/Database/etc/nxagentd.conf"));
1612 }
1613 else if (_taccess(_T("/usr/etc/nxagentd.conf"), 4) == 0)
1614 {
1615 _tcscpy(g_szConfigFile, _T("/usr/etc/nxagentd.conf"));
1616 }
1617 else
1618 {
1619 _tcscpy(g_szConfigFile, _T("/etc/nxagentd.conf"));
1620 }
1621 }
1622 if (!_tcscmp(g_szConfigIncludeDir, _T("{search}")))
1623 {
1624 TCHAR path[MAX_PATH] = _T("");
1625 const TCHAR *homeDir = _tgetenv(_T("NETXMS_HOME"));
1626 if (homeDir != NULL)
1627 {
1628 _sntprintf(path, MAX_PATH, _T("%s/etc/nxagentd.conf.d"), homeDir);
1629 }
1630 if ((path[0] != 0) && (_taccess(path, 4) == 0))
1631 {
1632 _tcscpy(g_szConfigIncludeDir, path);
1633 }
1634 else if (_taccess(PREFIX _T("/etc/nxagentd.conf.d"), 4) == 0)
1635 {
1636 _tcscpy(g_szConfigIncludeDir, PREFIX _T("/etc/nxagentd.conf.d"));
1637 }
1638 else if (_taccess(_T("/Database/etc/nxagentd.conf.d"), 4) == 0)
1639 {
1640 _tcscpy(g_szConfigIncludeDir, _T("/Database/etc/nxagentd.conf.d"));
1641 }
1642 else if (_taccess(_T("/usr/etc/nxagentd.conf.d"), 4) == 0)
1643 {
1644 _tcscpy(g_szConfigIncludeDir, _T("/usr/etc/nxagentd.conf.d"));
1645 }
1646 else
1647 {
1648 _tcscpy(g_szConfigIncludeDir, _T("/etc/nxagentd.conf.d"));
1649 }
1650 }
1651 #else
1652 if (!_tcscmp(g_szConfigFile, _T("{search}")))
1653 {
1654 TCHAR path[MAX_PATH];
1655 GetNetXMSDirectory(nxDirEtc, path);
1656 _tcscat(path, _T("\\nxagentd.conf"));
1657 if (_taccess(path, 4) == 0)
1658 {
1659 _tcscpy(g_szConfigFile, path);
1660 }
1661 else
1662 {
1663 _tcscpy(g_szConfigFile, _T("C:\\nxagentd.conf"));
1664 }
1665 }
1666 if (!_tcscmp(g_szConfigIncludeDir, _T("{search}")))
1667 {
1668 TCHAR path[MAX_PATH];
1669 GetNetXMSDirectory(nxDirEtc, path);
1670 _tcscat(path, _T("\\nxagentd.conf.d"));
1671 if (_taccess(path, 4) == 0)
1672 {
1673 _tcscpy(g_szConfigIncludeDir, path);
1674 }
1675 else
1676 {
1677 _tcscpy(g_szConfigIncludeDir, _T("C:\\nxagentd.conf.d"));
1678 }
1679 }
1680 #endif
1681
1682 if (bRestart)
1683 DoRestartActions(dwOldPID);
1684
1685 InitConfig();
1686
1687 // Do requested action
1688 switch(iAction)
1689 {
1690 case ACTION_RUN_AGENT:
1691 // Set default value for session idle timeout based on
1692 // connect() timeout, if possible
1693 #if HAVE_SYSCTLBYNAME && !defined(_IPSO)
1694 {
1695 LONG nVal;
1696 size_t nSize;
1697
1698 nSize = sizeof(nVal);
1699 if (sysctlbyname("net.inet.tcp.keepinit", &nVal, &nSize, NULL, 0) == 0)
1700 {
1701 g_dwIdleTimeout = nVal / 1000 + 15;
1702 }
1703 }
1704 #endif
1705
1706 if (g_dwFlags & AF_CENTRAL_CONFIG)
1707 {
1708 if (s_debugLevel > 0)
1709 _tprintf(_T("Downloading configuration from %s...\n"), g_szConfigServer);
1710 if (DownloadConfig(g_szConfigServer))
1711 {
1712 if (s_debugLevel > 0)
1713 _tprintf(_T("Configuration downloaded successfully\n"));
1714 }
1715 else
1716 {
1717 if (s_debugLevel > 0)
1718 _tprintf(_T("Configuration download failed\n"));
1719 }
1720 }
1721
1722 if (g_config->loadConfig(g_szConfigFile, _T("agent")))
1723 {
1724 const TCHAR *dir = g_config->getValue(_T("/agent/ConfigIncludeDir"));
1725 if (dir != NULL)
1726 nx_strncpy(g_szConfigIncludeDir, dir, MAX_PATH);
1727 g_config->loadConfigDirectory(g_szConfigIncludeDir, _T("agent"));
1728 if (g_config->parseTemplate(_T("agent"), m_cfgTemplate))
1729 {
1730 DecryptPassword(_T("netxms"), g_szSharedSecret, g_szSharedSecret, MAX_SECRET_LENGTH);
1731
1732 // try to guess executable path
1733 #ifdef _WIN32
1734 GetModuleFileName(GetModuleHandle(NULL), s_executableName, MAX_PATH);
1735 #else
1736 #ifdef UNICODE
1737 char __buffer[PATH_MAX];
1738 #else
1739 #define __buffer s_executableName
1740 #endif
1741 if (realpath(argv[0], __buffer) == NULL)
1742 {
1743 // fallback
1744 TCHAR *path = _tgetenv(_T("NETXMS_HOME"));
1745 if (path != NULL)
1746 {
1747 nx_strncpy(s_executableName, path, sizeof(s_executableName) / sizeof(s_executableName[0]));
1748 }
1749 else
1750 {
1751 nx_strncpy(s_executableName, PREFIX, sizeof(s_executableName) / sizeof(s_executableName[0]));
1752 }
1753 _tcsncat(s_executableName, _T("/bin/nxagentd"), sizeof(s_executableName) / sizeof(s_executableName[0]));
1754 }
1755 else
1756 {
1757 #ifdef UNICODE
1758 int len = strlen(__buffer);
1759 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, __buffer, len, s_executableName, len);
1760 #endif
1761 }
1762 #endif
1763
1764 // Set exception handler
1765 #ifdef _WIN32
1766 if (g_dwFlags & AF_CATCH_EXCEPTIONS)
1767 SetExceptionHandler(SEHServiceExceptionHandler, SEHServiceExceptionDataWriter, s_dumpDir,
1768 _T("nxagentd"), MSG_EXCEPTION, g_dwFlags & AF_WRITE_FULL_DUMP, !(g_dwFlags & AF_DAEMON));
1769 __try {
1770 #endif
1771 if ((!_tcsicmp(g_szLogFile, _T("{syslog}"))) ||
1772 (!_tcsicmp(g_szLogFile, _T("{eventlog}"))))
1773 g_dwFlags |= AF_USE_SYSLOG;
1774
1775 #ifdef _WIN32
1776 if (g_dwFlags & AF_DAEMON)
1777 {
1778 InitService();
1779 }
1780 else
1781 {
1782 if (Initialize())
1783 {
1784 Main();
1785 }
1786 else
1787 {
1788 ConsolePrintf(_T("Agent initialization failed\n"));
1789 nxlog_close();
1790 iExitCode = 3;
1791 }
1792 }
1793 #else /* _WIN32 */
1794 if (g_dwFlags & AF_DAEMON)
1795 {
1796 if (daemon(0, 0) == -1)
1797 {
1798 perror("Unable to setup itself as a daemon");
1799 iExitCode = 4;
1800 }
1801 }
1802 if (iExitCode == 0)
1803 {
1804 #ifndef _WIN32
1805 if (gid == 0)
1806 {
1807 const TCHAR *v = g_config->getValue(_T("/agent/GroupId"));
1808 if (v != NULL)
1809 {
1810 #ifdef UNICODE
1811 char vmb[64];
1812 WideCharToMultiByte(CP_ACP, WC_DEFAULTCHAR | WC_COMPOSITECHECK, v, -1, vmb, 64, NULL, NULL);
1813 vmb[63] = 0;
1814 gid = GetGroupId(vmb);
1815 #else
1816 gid = GetGroupId(v);
1817 #endif
1818 }
1819 }
1820 if (uid == 0)
1821 {
1822 const TCHAR *v = g_config->getValue(_T("/agent/UserId"));
1823 if (v != NULL)
1824 {
1825 #ifdef UNICODE
1826 char vmb[64];
1827 WideCharToMultiByte(CP_ACP, WC_DEFAULTCHAR | WC_COMPOSITECHECK, v, -1, vmb, 64, NULL, NULL);
1828 vmb[63] = 0;
1829 uid = GetUserId(vmb);
1830 #else
1831 uid = GetUserId(v);
1832 #endif
1833 }
1834 }
1835
1836 if (gid > 0)
1837 {
1838 if (setgid(gid) != 0)
1839 _tprintf(_T("setgid(%d) call failed (%s)\n"), gid, _tcserror(errno));
1840 }
1841 if (uid > 0)
1842 {
1843 if (setuid(uid) != 0)
1844 _tprintf(_T("setuid(%d) call failed (%s)\n"), uid, _tcserror(errno));
1845 }
1846 #endif
1847
1848 UpdateEnvironment();
1849
1850 s_pid = getpid();
1851 if (Initialize())
1852 {
1853 FILE *fp;
1854
1855 // Write PID file
1856 fp = _tfopen(g_szPidFile, _T("w"));
1857 if (fp != NULL)
1858 {
1859 _ftprintf(fp, _T("%d"), s_pid);
1860 fclose(fp);
1861 }
1862 Main();
1863 Shutdown();
1864 }
1865 else
1866 {
1867 ConsolePrintf(_T("Agent initialization failed\n"));
1868 nxlog_close();
1869 iExitCode = 3;
1870 }
1871 }
1872 #endif /* _WIN32 */
1873
1874 #if defined(_WIN32)
1875 if (s_shutdownCondition != INVALID_CONDITION_HANDLE)
1876 ConditionDestroy(s_shutdownCondition);
1877 #endif
1878 #ifdef _WIN32
1879 LIBNETXMS_EXCEPTION_HANDLER
1880 #endif
1881 }
1882 else
1883 {
1884 ConsolePrintf(_T("Error parsing configuration file\n"));
1885 iExitCode = 2;
1886 }
1887 }
1888 else
1889 {
1890 ConsolePrintf(_T("Error loading configuration file\n"));
1891 iExitCode = 2;
1892 }
1893 break;
1894 case ACTION_CHECK_CONFIG:
1895 {
1896 bool validConfig = g_config->loadConfig(g_szConfigFile, _T("agent"), false);
1897 if (validConfig)
1898 {
1899 const TCHAR *dir = g_config->getValue(_T("/agent/ConfigIncludeDir"));
1900 if (dir != NULL)
1901 {
1902 validConfig = g_config->loadConfigDirectory(dir, _T("agent"), false);
1903 if (!validConfig)
1904 {
1905 ConsolePrintf(_T("Error reading additional configuration files from \"%s\"\n"), dir);
1906 }
1907 }
1908 }
1909
1910 if (validConfig)
1911 {
1912 g_config->print(stdout);
1913 validConfig = g_config->parseTemplate(_T("agent"), m_cfgTemplate);
1914 }
1915
1916 if (!validConfig)
1917 {
1918 ConsolePrintf(_T("Configuration file check failed\n"));
1919 iExitCode = 2;
1920 }
1921 }
1922 break;
1923 case ACTION_RUN_WATCHDOG:
1924 iExitCode = WatchdogMain(dwMainPID);
1925 break;
1926 case ACTION_CREATE_CONFIG:
1927 iExitCode = CreateConfig(CHECK_NULL_A(argv[optind]), CHECK_NULL_A(argv[optind + 1]),
1928 CHECK_NULL_A(argv[optind + 2]), CHECK_NULL_A(argv[optind + 3]),
1929 argc - optind - 4, &argv[optind + 4]);
1930 break;
1931 case ACTION_SHUTDOWN_EXT_AGENTS:
1932 InitiateExtSubagentShutdown();
1933 iExitCode = 0;
1934 break;
1935 #ifdef _WIN32
1936 case ACTION_INSTALL_SERVICE:
1937 GetModuleFileName(GetModuleHandle(NULL), szModuleName, MAX_PATH);
1938 InstallService(szModuleName, g_szConfigFile, s_debugLevel);
1939 break;
1940 case ACTION_REMOVE_SERVICE:
1941 RemoveService();
1942 break;
1943 case ACTION_INSTALL_EVENT_SOURCE:
1944 GetModuleFileName(GetModuleHandle(NULL), szModuleName, MAX_PATH);
1945 InstallEventSource(szModuleName);
1946 break;
1947 case ACTION_REMOVE_EVENT_SOURCE:
1948 RemoveEventSource();
1949 break;
1950 case ACTION_START_SERVICE:
1951 StartAgentService();
1952 break;
1953 case ACTION_STOP_SERVICE:
1954 StopAgentService();
1955 break;
1956 #endif
1957 case ACTION_HELP:
1958 _fputts(m_szHelpText, stdout);
1959 break;
1960 default:
1961 break;
1962 }
1963
1964 return iExitCode;
1965 }