bcf3139235f0920f8435bf470764149afc677bed
[public/netxms.git] / src / server / core / audit.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2013 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: audit.cpp
20 **
21 **/
22
23 #include "nxcore.h"
24
25 /**
26 * Static data
27 */
28 static VolatileCounter m_recordId = 1;
29 static UINT32 m_auditServerAddr = 0;
30 static WORD m_auditServerPort;
31 static int m_auditFacility;
32 static int m_auditSeverity;
33 static char m_auditTag[MAX_SYSLOG_TAG_LEN];
34 static char m_localHostName[256];
35
36 /**
37 * Send syslog record to audit server
38 */
39 static void SendSyslogRecord(const TCHAR *text)
40 {
41 static char month[12][5] = { "Jan ", "Feb ", "Mar ", "Apr ",
42 "May ", "Jun ", "Jul ", "Aug ",
43 "Sep ", "Oct ", "Nov ", "Dec " };
44 char message[1025];
45
46 if (m_auditServerAddr == 0)
47 return;
48
49 time_t ts = time(NULL);
50 struct tm *now = localtime(&ts);
51
52 #ifdef UNICODE
53 char *mbText = MBStringFromWideString(text);
54 snprintf(message, 1025, "<%d>%s %2d %02d:%02d:%02d %s %s %s", (m_auditFacility << 3) + m_auditSeverity, month[now->tm_mon],
55 now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec, m_localHostName, m_auditTag, mbText);
56 free(mbText);
57 #else
58 snprintf(message, 1025, "<%d>%s %2d %02d:%02d:%02d %s %s %s", (m_auditFacility << 3) + m_auditSeverity, month[now->tm_mon],
59 now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec, m_localHostName, m_auditTag, text);
60 #endif
61 message[1024] = 0;
62
63 SOCKET hSocket = socket(AF_INET, SOCK_DGRAM, 0);
64 if (hSocket != INVALID_SOCKET)
65 {
66 struct sockaddr_in addr;
67
68 memset(&addr, 0, sizeof(struct sockaddr_in));
69 addr.sin_family = AF_INET;
70 addr.sin_addr.s_addr = m_auditServerAddr;
71 addr.sin_port = m_auditServerPort;
72
73 sendto(hSocket, message, (int)strlen(message), 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
74 shutdown(hSocket, SHUT_RDWR);
75 closesocket(hSocket);
76 }
77 }
78
79 /**
80 * Initalize audit log
81 */
82 void InitAuditLog()
83 {
84 DB_RESULT hResult;
85
86 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
87 hResult = DBSelect(hdb, _T("SELECT max(record_id) FROM audit_log"));
88 if (hResult != NULL)
89 {
90 if (DBGetNumRows(hResult) > 0)
91 m_recordId = DBGetFieldULong(hResult, 0, 0) + 1;
92 DBFreeResult(hResult);
93 }
94
95 // External audit server
96 TCHAR temp[256];
97 ConfigReadStr(_T("ExternalAuditServer"), temp, 256, _T("none"));
98 if (_tcscmp(temp, _T("none")))
99 {
100 m_auditServerAddr = ResolveHostName(temp);
101 m_auditServerPort = htons((WORD)ConfigReadInt(_T("ExternalAuditPort"), 514));
102 m_auditFacility = ConfigReadInt(_T("ExternalAuditFacility"), 13); // default is log audit facility
103 m_auditSeverity = ConfigReadInt(_T("ExternalAuditSeverity"), SYSLOG_SEVERITY_NOTICE);
104 ConfigReadStrA(_T("ExternalAuditTag"), m_auditTag, MAX_SYSLOG_TAG_LEN, "netxmsd-audit");
105
106 // Get local host name
107 #ifdef _WIN32
108 DWORD size = 256;
109 GetComputerNameA(m_localHostName, &size);
110 #else
111 gethostname(m_localHostName, 256);
112 m_localHostName[255] = 0;
113 char *ptr = strchr(m_localHostName, '.');
114 if (ptr != NULL)
115 *ptr = 0;
116 #endif
117
118 SendSyslogRecord(_T("NetXMS server audit subsystem started"));
119 }
120 DBConnectionPoolReleaseConnection(hdb);
121 }
122
123 /**
124 * Handler for EnumerateSessions()
125 */
126 static void SendNewRecord(ClientSession *pSession, void *pArg)
127 {
128 UPDATE_INFO *pUpdate;
129
130 if (pSession->isAuthenticated() && pSession->isSubscribed(NXC_CHANNEL_AUDIT_LOG))
131 {
132 pUpdate = (UPDATE_INFO *)malloc(sizeof(UPDATE_INFO));
133 pUpdate->dwCategory = INFO_CAT_AUDIT_RECORD;
134 pUpdate->pData = new NXCPMessage((NXCPMessage *)pArg);
135 pSession->queueUpdate(pUpdate);
136 }
137 }
138
139 /**
140 * Write audit record
141 */
142 void NXCORE_EXPORTABLE WriteAuditLog(const TCHAR *subsys, BOOL isSuccess, UINT32 userId,
143 const TCHAR *workstation, int sessionId, UINT32 objectId,
144 const TCHAR *format, ...)
145 {
146 String text, query;
147 va_list args;
148 NXCPMessage msg;
149
150 va_start(args, format);
151 text.appendFormattedStringV(format, args);
152 va_end(args);
153
154 query.appendFormattedString(_T("INSERT INTO audit_log (record_id,timestamp,subsystem,success,user_id,workstation,session_id,object_id,message) VALUES(%d,") TIME_T_FMT _T(",%s,%d,%d,%s,%d,%d,%s)"),
155 InterlockedIncrement(&m_recordId), time(NULL), (const TCHAR *)DBPrepareString(g_dbDriver, subsys), isSuccess ? 1 : 0,
156 userId, (const TCHAR *)DBPrepareString(g_dbDriver, workstation), sessionId, objectId, (const TCHAR *)DBPrepareString(g_dbDriver, text));
157 QueueSQLRequest(query);
158
159 msg.setCode(CMD_AUDIT_RECORD);
160 msg.setField(VID_SUBSYSTEM, subsys);
161 msg.setField(VID_SUCCESS_AUDIT, (WORD)isSuccess);
162 msg.setField(VID_USER_ID, userId);
163 msg.setField(VID_WORKSTATION, workstation);
164 msg.setField(VID_SESSION_ID, sessionId);
165 msg.setField(VID_OBJECT_ID, objectId);
166 msg.setField(VID_MESSAGE, (const TCHAR *)text);
167 EnumerateClientSessions(SendNewRecord, &msg);
168
169 if (m_auditServerAddr != 0)
170 {
171 String extText;
172 TCHAR buffer[256];
173
174 extText = _T("[");
175 if (ResolveUserId(userId, buffer, 256))
176 {
177 extText += buffer;
178 }
179 else
180 {
181 extText.appendFormattedString(_T("{%d}"), userId);
182 }
183
184 extText.appendFormattedString(_T("@%s] "), workstation);
185
186 extText += (const TCHAR *)text;
187 SendSyslogRecord((const TCHAR *)extText);
188 }
189 }