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