Sun code escaped.
[public/netxms.git] / src / agent / core / push.cpp
CommitLineData
f480bdd4
VK
1/* \r
2** NetXMS multiplatform core agent\r
f918b160 3** Copyright (C) 2003-2013 Victor Kirhenshtein\r
f480bdd4
VK
4**\r
5** This program is free software; you can redistribute it and/or modify\r
6** it under the terms of the GNU General Public License as published by\r
7** the Free Software Foundation; either version 2 of the License, or\r
8** (at your option) any later version.\r
9**\r
10** This program is distributed in the hope that it will be usefu,,\r
11** but ITHOUT ANY WARRANTY; without even the implied warranty of\r
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
13** GNU General Public License for more details.\r
14**\r
15** You should have received a copy of the GNU General Public License\r
16** along with this program; if not, write to the Free Software\r
17** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
18**\r
0bd64860 19** File: push.cpp\r
f480bdd4
VK
20**\r
21**/\r
22\r
23#include "nxagentd.h"\r
24\r
0bd64860
VK
25/**\r
26 * Push parameter's data\r
27 */\r
0137b9f7 28bool PushData(const TCHAR *parameter, const TCHAR *value)\r
f480bdd4
VK
29{\r
30 CSCPMessage msg;\r
0137b9f7 31 bool success = false;\r
f480bdd4 32\r
0bd64860
VK
33 AgentWriteDebugLog(6, _T("PushData: \"%s\" = \"%s\""), parameter, value);\r
34\r
f480bdd4
VK
35 msg.SetCode(CMD_PUSH_DCI_DATA);\r
36 msg.SetVariable(VID_NAME, parameter);\r
37 msg.SetVariable(VID_VALUE, value);\r
38\r
0137b9f7
VK
39 if (g_dwFlags & AF_SUBAGENT_LOADER)\r
40 {\r
41 success = SendMessageToMasterAgent(&msg);\r
42 }\r
43 else\r
44 {\r
45 MutexLock(g_hSessionListAccess);\r
46 for(DWORD i = 0; i < g_dwMaxSessions; i++)\r
47 if (g_pSessionList[i] != NULL)\r
48 if (g_pSessionList[i]->canAcceptTraps())\r
49 {\r
50 g_pSessionList[i]->sendMessage(&msg);\r
51 success = true;\r
52 }\r
53 MutexUnlock(g_hSessionListAccess);\r
54 }\r
f480bdd4
VK
55 return success;\r
56}\r
0bd64860
VK
57\r
58/**\r
59 * Process push request\r
60 */\r
84d1bd22 61static void ProcessPushRequest(HPIPE hPipe)\r
0bd64860
VK
62{\r
63 TCHAR buffer[256];\r
64\r
65 AgentWriteDebugLog(5, _T("ProcessPushRequest: connection established"));\r
66 while(true)\r
67 {\r
68 CSCPMessage *msg = ReadMessageFromPipe(hPipe, NULL);\r
69 if (msg == NULL)\r
70 break;\r
71 AgentWriteDebugLog(6, _T("ProcessPushRequest: received message %s"), NXCPMessageCodeName(msg->GetCode(), buffer));\r
72 if (msg->GetCode() == CMD_PUSH_DCI_DATA)\r
73 {\r
74 DWORD count = msg->GetVariableLong(VID_NUM_ITEMS);\r
75 DWORD varId = VID_PUSH_DCI_DATA_BASE;\r
76 for(DWORD i = 0; i < count; i++)\r
77 {\r
78 TCHAR name[MAX_PARAM_NAME], value[MAX_RESULT_LENGTH];\r
79 msg->GetVariableStr(varId++, name, MAX_PARAM_NAME);\r
80 msg->GetVariableStr(varId++, value, MAX_RESULT_LENGTH);\r
81 PushData(name, value);\r
82 }\r
83 }\r
84 else\r
85 {\r
86 }\r
87 delete msg;\r
88 }\r
89 AgentWriteDebugLog(5, _T("ProcessPushRequest: connection closed"));\r
90}\r
91\r
92/**\r
93 * Connector thread for external push command\r
94 */\r
95#ifdef _WIN32\r
96\r
97static THREAD_RESULT THREAD_CALL PushConnector(void *arg)\r
98{\r
99 SECURITY_ATTRIBUTES sa;\r
100 PSECURITY_DESCRIPTOR sd = NULL;\r
101 SID_IDENTIFIER_AUTHORITY sidAuthWorld = SECURITY_WORLD_SID_AUTHORITY;\r
102 EXPLICIT_ACCESS ea;\r
103 PSID sidEveryone = NULL;\r
104 ACL *acl = NULL;\r
105 TCHAR errorText[1024];\r
106\r
107 // Create a well-known SID for the Everyone group.\r
108 if(!AllocateAndInitializeSid(&sidAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &sidEveryone))\r
109 {\r
110 AgentWriteDebugLog(2, _T("PushConnector: AllocateAndInitializeSid failed (%s)"), GetSystemErrorText(GetLastError(), errorText, 1024));\r
111 goto cleanup;\r
112 }\r
113\r
114 // Initialize an EXPLICIT_ACCESS structure for an ACE.\r
115 // The ACE will allow either Everyone or given user to access pipe\r
116 ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));\r
117 ea.grfAccessPermissions = (FILE_GENERIC_READ | FILE_GENERIC_WRITE) & ~FILE_CREATE_PIPE_INSTANCE;\r
118 ea.grfAccessMode = SET_ACCESS;\r
119 ea.grfInheritance = NO_INHERITANCE;\r
120 const TCHAR *user = g_config->getValue(_T("/agent/PushUser"), _T("*"));\r
121 if ((user[0] == 0) || !_tcscmp(user, _T("*")))\r
122 {\r
123 ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;\r
124 ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;\r
125 ea.Trustee.ptstrName = (LPTSTR)sidEveryone;\r
126 }\r
127 else\r
128 {\r
129 ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME;\r
130 ea.Trustee.TrusteeType = TRUSTEE_IS_USER;\r
131 ea.Trustee.ptstrName = (LPTSTR)user;\r
132 AgentWriteDebugLog(2, _T("PushConnector: will allow connections only for user %s"), user);\r
133 }\r
134\r
135 // Create a new ACL that contains the new ACEs.\r
136 if (SetEntriesInAcl(1, &ea, NULL, &acl) != ERROR_SUCCESS)\r
137 {\r
138 AgentWriteDebugLog(2, _T("PushConnector: SetEntriesInAcl failed (%s)"), GetSystemErrorText(GetLastError(), errorText, 1024));\r
139 goto cleanup;\r
140 }\r
141\r
142 sd = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);\r
143 if (sd == NULL)\r
144 {\r
145 AgentWriteDebugLog(2, _T("PushConnector: LocalAlloc failed (%s)"), GetSystemErrorText(GetLastError(), errorText, 1024));\r
146 goto cleanup;\r
147 }\r
148\r
149 if (!InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION))\r
150 {\r
151 AgentWriteDebugLog(2, _T("PushConnector: InitializeSecurityDescriptor failed (%s)"), GetSystemErrorText(GetLastError(), errorText, 1024));\r
152 goto cleanup;\r
153 }\r
154\r
155 // Add the ACL to the security descriptor. \r
156 if (!SetSecurityDescriptorDacl(sd, TRUE, acl, FALSE))\r
157 {\r
158 AgentWriteDebugLog(2, _T("PushConnector: SetSecurityDescriptorDacl failed (%s)"), GetSystemErrorText(GetLastError(), errorText, 1024));\r
159 goto cleanup;\r
160 }\r
161\r
162 sa.nLength = sizeof(SECURITY_ATTRIBUTES);\r
163 sa.bInheritHandle = FALSE;\r
164 sa.lpSecurityDescriptor = sd;\r
165 HANDLE hPipe = CreateNamedPipe(_T("\\\\.\\pipe\\nxagentd.push"), PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 1, 8192, 8192, 0, &sa);\r
166 if (hPipe == INVALID_HANDLE_VALUE)\r
167 {\r
168 AgentWriteDebugLog(2, _T("PushConnector: CreateNamedPipe failed (%s)"), GetSystemErrorText(GetLastError(), errorText, 1024));\r
169 goto cleanup;\r
170 }\r
171\r
172 AgentWriteDebugLog(2, _T("PushConnector: named pipe created, waiting for connection"));\r
173 int connectErrors = 0;\r
174 while(!(g_dwFlags & AF_SHUTDOWN))\r
175 {\r
176 BOOL connected = ConnectNamedPipe(hPipe, NULL);\r
177 if (connected || (GetLastError() == ERROR_PIPE_CONNECTED))\r
178 {\r
179 ProcessPushRequest(hPipe);\r
180 DisconnectNamedPipe(hPipe);\r
181 connectErrors = 0;\r
182 }\r
183 else\r
184 {\r
185 AgentWriteDebugLog(2, _T("PushConnector: ConnectNamedPipe failed (%s)"), GetSystemErrorText(GetLastError(), errorText, 1024));\r
186 connectErrors++;\r
187 if (connectErrors > 10)\r
188 break; // Stop this connector if ConnectNamedPipe fails instantly\r
189 }\r
190 }\r
191\r
192cleanup:\r
193 if (hPipe != NULL)\r
194 CloseHandle(hPipe);\r
195\r
196 if (sd != NULL)\r
197 LocalFree(sd);\r
198\r
199 if (acl != NULL)\r
200 LocalFree(acl);\r
201\r
202 if (sidEveryone != NULL)\r
203 FreeSid(sidEveryone);\r
204\r
205 AgentWriteDebugLog(2, _T("PushConnector: listener thread stopped"));\r
206 return THREAD_OK;\r
207}\r
208\r
209#else\r
210\r
211static THREAD_RESULT THREAD_CALL PushConnector(void *arg)\r
212{\r
d9f50739
AK
213 mode_t prevMask = 0;\r
214\r
84d1bd22 215 SOCKET hPipe = socket(AF_UNIX, SOCK_STREAM, 0);\r
4c0c75c7 216 if (hPipe == INVALID_SOCKET)\r
77205aad
VK
217 {\r
218 AgentWriteDebugLog(2, _T("PushConnector: socket failed (%s)"), _tcserror(errno));\r
219 goto cleanup;\r
220 }\r
221 \r
222 struct sockaddr_un addrLocal;\r
223 addrLocal.sun_family = AF_UNIX;\r
d4656b7e 224 strcpy(addrLocal.sun_path, "/tmp/.nxagentd.push"); \r
77205aad 225 unlink(addrLocal.sun_path);\r
d9f50739 226 prevMask = umask(S_IWGRP | S_IWOTH);\r
b3e2fd0e 227 if (bind(hPipe, (struct sockaddr *)&addrLocal, SUN_LEN(&addrLocal)) == -1)\r
77205aad
VK
228 {\r
229 AgentWriteDebugLog(2, _T("PushConnector: bind failed (%s)"), _tcserror(errno));\r
d9f50739 230 umask(prevMask);\r
77205aad
VK
231 goto cleanup;\r
232 }\r
d9f50739 233 umask(prevMask);\r
77205aad
VK
234\r
235 if (listen(hPipe, 5) == -1)\r
236 {\r
237 AgentWriteDebugLog(2, _T("PushConnector: listen failed (%s)"), _tcserror(errno));\r
238 goto cleanup;\r
239 }\r
240 \r
241 while(!(g_dwFlags & AF_SHUTDOWN))\r
242 {\r
243 struct sockaddr_un addrRemote;\r
e797258d 244 socklen_t size = sizeof(struct sockaddr_un);\r
84d1bd22 245 SOCKET cs = accept(hPipe, (struct sockaddr *)&addrRemote, &size);\r
77205aad
VK
246 if (cs > 0)\r
247 {\r
84d1bd22 248 ProcessPushRequest(cs);\r
77205aad
VK
249 shutdown(cs, 2);\r
250 close(cs);\r
251 }\r
252 else\r
253 {\r
254 AgentWriteDebugLog(2, _T("PushConnector: accept failed (%s)"), _tcserror(errno));\r
255 }\r
256 }\r
257\r
258cleanup:\r
259 if (hPipe != -1)\r
260 close(hPipe);\r
261\r
0bd64860
VK
262 AgentWriteDebugLog(2, _T("PushConnector: listener thread stopped"));\r
263 return THREAD_OK;\r
264}\r
265\r
266#endif\r
267\r
268/**\r
269 * Start push connector\r
270 */\r
271\r
272void StartPushConnector()\r
273{\r
274 ThreadCreate(PushConnector, 0, NULL);\r
275}\r