902f794a2e7c827c05d78fd384af341889812eb8
[public/netxms.git] / src / agent / core / session.cpp
1 /*
2 ** NetXMS multiplatform core agent
3 ** Copyright (C) 2003-2009 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: session.cpp
20 **
21 **/
22
23 #include "nxagentd.h"
24
25 #ifdef _WIN32
26 #define write _write
27 #define close _close
28 #endif
29
30
31 //
32 // Externals
33 //
34
35 void UnregisterSession(DWORD dwIndex);
36 void ProxySNMPRequest(CSCPMessage *pRequest, CSCPMessage *pResponse);
37 DWORD DeployPolicy(DWORD session, CSCPMessage *request);
38 DWORD UninstallPolicy(DWORD session, CSCPMessage *request);
39
40
41 //
42 // Constants
43 //
44
45 #define RAW_MSG_SIZE 262144
46
47
48 //
49 // Client communication read thread
50 //
51
52 THREAD_RESULT THREAD_CALL CommSession::readThreadStarter(void *pArg)
53 {
54 ((CommSession *)pArg)->readThread();
55
56 // When CommSession::ReadThread exits, all other session
57 // threads are already stopped, so we can safely destroy
58 // session object
59 UnregisterSession(((CommSession *)pArg)->getIndex());
60 delete (CommSession *)pArg;
61 return THREAD_OK;
62 }
63
64
65 //
66 // Client communication write thread
67 //
68
69 THREAD_RESULT THREAD_CALL CommSession::writeThreadStarter(void *pArg)
70 {
71 ((CommSession *)pArg)->writeThread();
72 return THREAD_OK;
73 }
74
75
76 //
77 // Received message processing thread
78 //
79
80 THREAD_RESULT THREAD_CALL CommSession::processingThreadStarter(void *pArg)
81 {
82 ((CommSession *)pArg)->processingThread();
83 return THREAD_OK;
84 }
85
86
87 //
88 // Client communication write thread
89 //
90
91 THREAD_RESULT THREAD_CALL CommSession::proxyReadThreadStarter(void *pArg)
92 {
93 ((CommSession *)pArg)->proxyReadThread();
94 return THREAD_OK;
95 }
96
97
98 //
99 // Client session class constructor
100 //
101
102 CommSession::CommSession(SOCKET hSocket, DWORD dwHostAddr,
103 BOOL bMasterServer, BOOL bControlServer)
104 {
105 m_pSendQueue = new Queue;
106 m_pMessageQueue = new Queue;
107 m_hSocket = hSocket;
108 m_hProxySocket = -1;
109 m_dwIndex = INVALID_INDEX;
110 m_pMsgBuffer = (CSCP_BUFFER *)malloc(sizeof(CSCP_BUFFER));
111 m_hWriteThread = INVALID_THREAD_HANDLE;
112 m_hProcessingThread = INVALID_THREAD_HANDLE;
113 m_dwHostAddr = dwHostAddr;
114 m_bIsAuthenticated = (g_dwFlags & AF_REQUIRE_AUTH) ? FALSE : TRUE;
115 m_bMasterServer = bMasterServer;
116 m_bControlServer = bControlServer;
117 m_bProxyConnection = FALSE;
118 m_bAcceptTraps = FALSE;
119 m_hCurrFile = -1;
120 m_pCtx = NULL;
121 m_ts = time(NULL);
122 }
123
124
125 //
126 // Destructor
127 //
128
129 CommSession::~CommSession()
130 {
131 shutdown(m_hSocket, SHUT_RDWR);
132 closesocket(m_hSocket);
133 if (m_hProxySocket != -1)
134 closesocket(m_hProxySocket);
135 delete m_pSendQueue;
136 delete m_pMessageQueue;
137 safe_free(m_pMsgBuffer);
138 if (m_hCurrFile != -1)
139 close(m_hCurrFile);
140 DestroyEncryptionContext(m_pCtx);
141 }
142
143
144 //
145 // Start all threads
146 //
147
148 void CommSession::run()
149 {
150 m_hWriteThread = ThreadCreateEx(writeThreadStarter, 0, this);
151 m_hProcessingThread = ThreadCreateEx(processingThreadStarter, 0, this);
152 ThreadCreate(readThreadStarter, 0, this);
153 }
154
155
156 //
157 // Disconnect session
158 //
159
160 void CommSession::disconnect()
161 {
162 DebugPrintf(m_dwIndex, 5, "CommSession::disconnect()");
163 shutdown(m_hSocket, SHUT_RDWR);
164 if (m_hProxySocket != -1)
165 shutdown(m_hProxySocket, SHUT_RDWR);
166 }
167
168
169 //
170 // Reading thread
171 //
172
173 void CommSession::readThread()
174 {
175 CSCP_MESSAGE *pRawMsg;
176 CSCPMessage *pMsg;
177 BYTE *pDecryptionBuffer = NULL;
178 int iErr;
179 char szBuffer[256];
180 WORD wFlags;
181
182 // Initialize raw message receiving function
183 RecvNXCPMessage(0, NULL, m_pMsgBuffer, 0, NULL, NULL, 0);
184
185 pRawMsg = (CSCP_MESSAGE *)malloc(RAW_MSG_SIZE);
186 #ifdef _WITH_ENCRYPTION
187 pDecryptionBuffer = (BYTE *)malloc(RAW_MSG_SIZE);
188 #endif
189 while(1)
190 {
191 if ((iErr = RecvNXCPMessage(m_hSocket, pRawMsg, m_pMsgBuffer, RAW_MSG_SIZE,
192 &m_pCtx, pDecryptionBuffer, INFINITE)) <= 0)
193 {
194 break;
195 }
196
197 // Check if message is too large
198 if (iErr == 1)
199 continue;
200
201 // Check for decryption failure
202 if (iErr == 2)
203 {
204 nxlog_write(MSG_DECRYPTION_FAILURE, EVENTLOG_WARNING_TYPE, NULL);
205 continue;
206 }
207
208 // Check that actual received packet size is equal to encoded in packet
209 if ((int)ntohl(pRawMsg->dwSize) != iErr)
210 {
211 DebugPrintf(m_dwIndex, 5, "Actual message size doesn't match wSize value (%d,%d)", iErr, ntohl(pRawMsg->dwSize));
212 continue; // Bad packet, wait for next
213 }
214
215 // Update activity timestamp
216 m_ts = time(NULL);
217
218 if (m_bProxyConnection)
219 {
220 // Forward received message to remote peer
221 SendEx(m_hProxySocket, (char *)pRawMsg, iErr, 0);
222 }
223 else
224 {
225 wFlags = ntohs(pRawMsg->wFlags);
226 if (wFlags & MF_BINARY)
227 {
228 // Convert message header to host format
229 pRawMsg->dwId = ntohl(pRawMsg->dwId);
230 pRawMsg->wCode = ntohs(pRawMsg->wCode);
231 pRawMsg->dwNumVars = ntohl(pRawMsg->dwNumVars);
232 DebugPrintf(m_dwIndex, 6, "Received raw message %s", NXCPMessageCodeName(pRawMsg->wCode, szBuffer));
233
234 if (pRawMsg->wCode == CMD_FILE_DATA)
235 {
236 if ((m_hCurrFile != -1) && (m_dwFileRqId == pRawMsg->dwId))
237 {
238 if (write(m_hCurrFile, pRawMsg->df, pRawMsg->dwNumVars) == (int)pRawMsg->dwNumVars)
239 {
240 if (wFlags & MF_END_OF_FILE)
241 {
242 CSCPMessage msg;
243
244 close(m_hCurrFile);
245 m_hCurrFile = -1;
246
247 msg.SetCode(CMD_REQUEST_COMPLETED);
248 msg.SetId(pRawMsg->dwId);
249 msg.SetVariable(VID_RCC, ERR_SUCCESS);
250 sendMessage(&msg);
251 }
252 }
253 else
254 {
255 // I/O error
256 CSCPMessage msg;
257
258 close(m_hCurrFile);
259 m_hCurrFile = -1;
260
261 msg.SetCode(CMD_REQUEST_COMPLETED);
262 msg.SetId(pRawMsg->dwId);
263 msg.SetVariable(VID_RCC, ERR_IO_FAILURE);
264 sendMessage(&msg);
265 }
266 }
267 }
268 }
269 else if (wFlags & MF_CONTROL)
270 {
271 // Convert message header to host format
272 pRawMsg->dwId = ntohl(pRawMsg->dwId);
273 pRawMsg->wCode = ntohs(pRawMsg->wCode);
274 pRawMsg->dwNumVars = ntohl(pRawMsg->dwNumVars);
275 DebugPrintf(m_dwIndex, 6, "Received control message %s", NXCPMessageCodeName(pRawMsg->wCode, szBuffer));
276
277 if (pRawMsg->wCode == CMD_GET_NXCP_CAPS)
278 {
279 CSCP_MESSAGE *pMsg;
280
281 pMsg = (CSCP_MESSAGE *)malloc(CSCP_HEADER_SIZE);
282 pMsg->dwId = htonl(pRawMsg->dwId);
283 pMsg->wCode = htons((WORD)CMD_NXCP_CAPS);
284 pMsg->wFlags = htons(MF_CONTROL);
285 pMsg->dwNumVars = htonl(NXCP_VERSION << 24);
286 pMsg->dwSize = htonl(CSCP_HEADER_SIZE);
287 sendRawMessage(pMsg, m_pCtx);
288 }
289 }
290 else
291 {
292 // Create message object from raw message
293 pMsg = new CSCPMessage(pRawMsg);
294 if (pMsg->GetCode() == CMD_REQUEST_SESSION_KEY)
295 {
296 DebugPrintf(m_dwIndex, 6, "Received message %s", NXCPMessageCodeName(pMsg->GetCode(), szBuffer));
297 if (m_pCtx == NULL)
298 {
299 CSCPMessage *pResponse;
300
301 SetupEncryptionContext(pMsg, &m_pCtx, &pResponse, NULL, NXCP_VERSION);
302 sendMessage(pResponse);
303 delete pResponse;
304 }
305 delete pMsg;
306 }
307 else
308 {
309 m_pMessageQueue->Put(pMsg);
310 }
311 }
312 }
313 }
314 if (iErr < 0)
315 nxlog_write(MSG_SESSION_BROKEN, EVENTLOG_WARNING_TYPE, "e", WSAGetLastError());
316 free(pRawMsg);
317 #ifdef _WITH_ENCRYPTION
318 free(pDecryptionBuffer);
319 #endif
320
321 // Notify other threads to exit
322 m_pSendQueue->Put(INVALID_POINTER_VALUE);
323 m_pMessageQueue->Put(INVALID_POINTER_VALUE);
324 if (m_hProxySocket != -1)
325 shutdown(m_hProxySocket, SHUT_RDWR);
326
327 // Wait for other threads to finish
328 ThreadJoin(m_hWriteThread);
329 ThreadJoin(m_hProcessingThread);
330 if (m_bProxyConnection)
331 ThreadJoin(m_hProxyReadThread);
332
333 DebugPrintf(m_dwIndex, 5, "Session with %s closed", IpToStr(m_dwHostAddr, szBuffer));
334 }
335
336
337 //
338 // Send prepared raw message over the network and destroy it
339 //
340
341 BOOL CommSession::sendRawMessage(CSCP_MESSAGE *pMsg, CSCP_ENCRYPTION_CONTEXT *pCtx)
342 {
343 BOOL bResult = TRUE;
344 char szBuffer[128];
345
346 DebugPrintf(m_dwIndex, 6, "Sending message %s (size %d)", NXCPMessageCodeName(ntohs(pMsg->wCode), szBuffer), ntohl(pMsg->dwSize));
347 if ((pCtx != NULL) && (pCtx != PROXY_ENCRYPTION_CTX))
348 {
349 CSCP_ENCRYPTED_MESSAGE *pEnMsg;
350
351 pEnMsg = CSCPEncryptMessage(pCtx, pMsg);
352 free(pMsg);
353 if (pEnMsg != NULL)
354 {
355 if (SendEx(m_hSocket, (const char *)pEnMsg, ntohl(pEnMsg->dwSize), 0) <= 0)
356 {
357 bResult = FALSE;
358 }
359 free(pEnMsg);
360 }
361 }
362 else
363 {
364 if (SendEx(m_hSocket, (const char *)pMsg, ntohl(pMsg->dwSize), 0) <= 0)
365 {
366 bResult = FALSE;
367 }
368 free(pMsg);
369 }
370 if (!bResult)
371 DebugPrintf(m_dwIndex, 6, "CommSession::SendRawMessage() for %s (size %d) failed", NXCPMessageCodeName(ntohs(pMsg->wCode), szBuffer), ntohl(pMsg->dwSize));
372 return bResult;
373 }
374
375
376 //
377 // Writing thread
378 //
379
380 void CommSession::writeThread()
381 {
382 CSCP_MESSAGE *pMsg;
383
384 while(1)
385 {
386 pMsg = (CSCP_MESSAGE *)m_pSendQueue->GetOrBlock();
387 if (pMsg == INVALID_POINTER_VALUE) // Session termination indicator
388 break;
389
390 if (!sendRawMessage(pMsg, m_pCtx))
391 break;
392 }
393 m_pSendQueue->Clear();
394 }
395
396
397 //
398 // Message processing thread
399 //
400
401 void CommSession::processingThread()
402 {
403 CSCPMessage *pMsg;
404 char szBuffer[128];
405 CSCPMessage msg;
406 DWORD dwCommand, dwRet;
407
408 while(1)
409 {
410 pMsg = (CSCPMessage *)m_pMessageQueue->GetOrBlock();
411 if (pMsg == INVALID_POINTER_VALUE) // Session termination indicator
412 break;
413 dwCommand = pMsg->GetCode();
414 DebugPrintf(m_dwIndex, 6, "Received message %s", NXCPMessageCodeName((WORD)dwCommand, szBuffer));
415
416 // Prepare response message
417 msg.SetCode(CMD_REQUEST_COMPLETED);
418 msg.SetId(pMsg->GetId());
419
420 // Check if authentication required
421 if ((!m_bIsAuthenticated) && (dwCommand != CMD_AUTHENTICATE))
422 {
423 msg.SetVariable(VID_RCC, ERR_AUTH_REQUIRED);
424 }
425 else if ((g_dwFlags & AF_REQUIRE_ENCRYPTION) && (m_pCtx == NULL))
426 {
427 msg.SetVariable(VID_RCC, ERR_ENCRYPTION_REQUIRED);
428 }
429 else
430 {
431 switch(dwCommand)
432 {
433 case CMD_AUTHENTICATE:
434 authenticate(pMsg, &msg);
435 break;
436 case CMD_GET_PARAMETER:
437 getParameter(pMsg, &msg);
438 break;
439 case CMD_GET_LIST:
440 getList(pMsg, &msg);
441 break;
442 case CMD_KEEPALIVE:
443 msg.SetVariable(VID_RCC, ERR_SUCCESS);
444 break;
445 case CMD_ACTION:
446 action(pMsg, &msg);
447 break;
448 case CMD_TRANSFER_FILE:
449 recvFile(pMsg, &msg);
450 break;
451 case CMD_UPGRADE_AGENT:
452 msg.SetVariable(VID_RCC, upgrade(pMsg));
453 break;
454 case CMD_GET_PARAMETER_LIST:
455 msg.SetVariable(VID_RCC, ERR_SUCCESS);
456 GetParameterList(&msg);
457 break;
458 case CMD_GET_AGENT_CONFIG:
459 getConfig(&msg);
460 break;
461 case CMD_UPDATE_AGENT_CONFIG:
462 updateConfig(pMsg, &msg);
463 break;
464 case CMD_SETUP_PROXY_CONNECTION:
465 dwRet = setupProxyConnection(pMsg);
466 // Proxy session established, incoming messages will
467 // not be processed locally. Acknowledgement message sent
468 // by SetupProxyConnection() in case of success.
469 if (dwRet == ERR_SUCCESS)
470 goto stop_processing;
471 msg.SetVariable(VID_RCC, dwRet);
472 break;
473 case CMD_ENABLE_AGENT_TRAPS:
474 if (m_bMasterServer)
475 {
476 m_bAcceptTraps = TRUE;
477 msg.SetVariable(VID_RCC, ERR_SUCCESS);
478 }
479 else
480 {
481 msg.SetVariable(VID_RCC, ERR_ACCESS_DENIED);
482 }
483 break;
484 case CMD_SNMP_REQUEST:
485 if (m_bMasterServer && (g_dwFlags & AF_ENABLE_SNMP_PROXY))
486 {
487 ProxySNMPRequest(pMsg, &msg);
488 }
489 else
490 {
491 msg.SetVariable(VID_RCC, ERR_ACCESS_DENIED);
492 }
493 break;
494 case CMD_DEPLOY_AGENT_POLICY:
495 if (m_bMasterServer)
496 {
497 msg.SetVariable(VID_RCC, DeployPolicy(m_dwIndex, pMsg));
498 }
499 else
500 {
501 msg.SetVariable(VID_RCC, ERR_ACCESS_DENIED);
502 }
503 break;
504 case CMD_UNINSTALL_AGENT_POLICY:
505 if (m_bMasterServer)
506 {
507 msg.SetVariable(VID_RCC, UninstallPolicy(m_dwIndex, pMsg));
508 }
509 else
510 {
511 msg.SetVariable(VID_RCC, ERR_ACCESS_DENIED);
512 }
513 break;
514 default:
515 // Attempt to process unknown command by subagents
516 if (!ProcessCmdBySubAgent(dwCommand, pMsg, &msg, this))
517 msg.SetVariable(VID_RCC, ERR_UNKNOWN_COMMAND);
518 break;
519 }
520 }
521 delete pMsg;
522
523 // Send response
524 sendMessage(&msg);
525 msg.DeleteAllVariables();
526 }
527
528 stop_processing:
529 ;
530 }
531
532
533 //
534 // Authenticate peer
535 //
536
537 void CommSession::authenticate(CSCPMessage *pRequest, CSCPMessage *pMsg)
538 {
539 if (m_bIsAuthenticated)
540 {
541 // Already authenticated
542 pMsg->SetVariable(VID_RCC, (g_dwFlags & AF_REQUIRE_AUTH) ? ERR_ALREADY_AUTHENTICATED : ERR_AUTH_NOT_REQUIRED);
543 }
544 else
545 {
546 char szSecret[MAX_SECRET_LENGTH];
547 BYTE hash[32];
548 WORD wAuthMethod;
549
550 wAuthMethod = pRequest->GetVariableShort(VID_AUTH_METHOD);
551 switch(wAuthMethod)
552 {
553 case AUTH_PLAINTEXT:
554 pRequest->GetVariableStr(VID_SHARED_SECRET, szSecret, MAX_SECRET_LENGTH);
555 if (!strcmp(szSecret, g_szSharedSecret))
556 {
557 m_bIsAuthenticated = TRUE;
558 pMsg->SetVariable(VID_RCC, ERR_SUCCESS);
559 }
560 else
561 {
562 nxlog_write(MSG_AUTH_FAILED, EVENTLOG_WARNING_TYPE, "as", m_dwHostAddr, "PLAIN");
563 pMsg->SetVariable(VID_RCC, ERR_AUTH_FAILED);
564 }
565 break;
566 case AUTH_MD5_HASH:
567 pRequest->GetVariableBinary(VID_SHARED_SECRET, (BYTE *)szSecret, MD5_DIGEST_SIZE);
568 CalculateMD5Hash((BYTE *)g_szSharedSecret, strlen(g_szSharedSecret), hash);
569 if (!memcmp(szSecret, hash, MD5_DIGEST_SIZE))
570 {
571 m_bIsAuthenticated = TRUE;
572 pMsg->SetVariable(VID_RCC, ERR_SUCCESS);
573 }
574 else
575 {
576 nxlog_write(MSG_AUTH_FAILED, EVENTLOG_WARNING_TYPE, "as", m_dwHostAddr, "MD5");
577 pMsg->SetVariable(VID_RCC, ERR_AUTH_FAILED);
578 }
579 break;
580 case AUTH_SHA1_HASH:
581 pRequest->GetVariableBinary(VID_SHARED_SECRET, (BYTE *)szSecret, SHA1_DIGEST_SIZE);
582 CalculateSHA1Hash((BYTE *)g_szSharedSecret, strlen(g_szSharedSecret), hash);
583 if (!memcmp(szSecret, hash, SHA1_DIGEST_SIZE))
584 {
585 m_bIsAuthenticated = TRUE;
586 pMsg->SetVariable(VID_RCC, ERR_SUCCESS);
587 }
588 else
589 {
590 nxlog_write(MSG_AUTH_FAILED, EVENTLOG_WARNING_TYPE, "as", m_dwHostAddr, "SHA1");
591 pMsg->SetVariable(VID_RCC, ERR_AUTH_FAILED);
592 }
593 break;
594 default:
595 pMsg->SetVariable(VID_RCC, ERR_NOT_IMPLEMENTED);
596 break;
597 }
598 }
599 }
600
601
602 //
603 // Get parameter's value
604 //
605
606 void CommSession::getParameter(CSCPMessage *pRequest, CSCPMessage *pMsg)
607 {
608 char szParameter[MAX_PARAM_NAME], szValue[MAX_RESULT_LENGTH];
609 DWORD dwErrorCode;
610
611 pRequest->GetVariableStr(VID_PARAMETER, szParameter, MAX_PARAM_NAME);
612 dwErrorCode = GetParameterValue(m_dwIndex, szParameter, szValue);
613 pMsg->SetVariable(VID_RCC, dwErrorCode);
614 if (dwErrorCode == ERR_SUCCESS)
615 pMsg->SetVariable(VID_VALUE, szValue);
616 }
617
618
619 //
620 // Get list of values
621 //
622
623 void CommSession::getList(CSCPMessage *pRequest, CSCPMessage *pMsg)
624 {
625 char szParameter[MAX_PARAM_NAME];
626
627 pRequest->GetVariableStr(VID_PARAMETER, szParameter, MAX_PARAM_NAME);
628
629 StringList value;
630 DWORD dwErrorCode = GetEnumValue(m_dwIndex, szParameter, &value);
631 pMsg->SetVariable(VID_RCC, dwErrorCode);
632 if (dwErrorCode == ERR_SUCCESS)
633 {
634 pMsg->SetVariable(VID_NUM_STRINGS, (DWORD)value.getSize());
635 for(int i = 0; i < value.getSize(); i++)
636 pMsg->SetVariable(VID_ENUM_VALUE_BASE + i, value.getValue(i));
637 }
638 }
639
640
641 //
642 // Perform action on request
643 //
644
645 void CommSession::action(CSCPMessage *pRequest, CSCPMessage *pMsg)
646 {
647 char szAction[MAX_PARAM_NAME];
648 StringList args;
649 DWORD i, dwRetCode;
650
651 if ((g_dwFlags & AF_ENABLE_ACTIONS) && m_bControlServer)
652 {
653 // Get action name and arguments
654 pRequest->GetVariableStr(VID_ACTION_NAME, szAction, MAX_PARAM_NAME);
655 DWORD numArgs = pRequest->GetVariableLong(VID_NUM_ARGS);
656 for(i = 0; i < numArgs; i++)
657 args.addPreallocated(pRequest->GetVariableStr(VID_ACTION_ARG_BASE + i));
658
659 // Execute action
660 dwRetCode = ExecAction(szAction, &args);
661 pMsg->SetVariable(VID_RCC, dwRetCode);
662 }
663 else
664 {
665 pMsg->SetVariable(VID_RCC, ERR_ACCESS_DENIED);
666 }
667 }
668
669
670 //
671 // Prepare for receiving file
672 //
673
674 void CommSession::recvFile(CSCPMessage *pRequest, CSCPMessage *pMsg)
675 {
676 TCHAR szFileName[MAX_PATH], szFullPath[MAX_PATH];
677
678 if (m_bMasterServer)
679 {
680 szFileName[0] = 0;
681 pRequest->GetVariableStr(VID_FILE_NAME, szFileName, MAX_PATH);
682 DebugPrintf(m_dwIndex, 5, "CommSession::recvFile(): Preparing for receiving file \"%s\"", szFileName);
683 BuildFullPath(szFileName, szFullPath);
684
685 // Check if for some reason we have already opened file
686 if (m_hCurrFile != -1)
687 {
688 pMsg->SetVariable(VID_RCC, ERR_RESOURCE_BUSY);
689 }
690 else
691 {
692 DebugPrintf(m_dwIndex, 5, "CommSession::recvFile(): Writing to local file \"%s\"", szFullPath);
693 m_hCurrFile = _topen(szFullPath, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, 0600);
694 if (m_hCurrFile == -1)
695 {
696 DebugPrintf(m_dwIndex, 2, "CommSession::recvFile(): Error opening file \"%s\" for writing (%s)", szFullPath, strerror(errno));
697 pMsg->SetVariable(VID_RCC, ERR_IO_FAILURE);
698 }
699 else
700 {
701 m_dwFileRqId = pRequest->GetId();
702 pMsg->SetVariable(VID_RCC, ERR_SUCCESS);
703 }
704 }
705 }
706 else
707 {
708 pMsg->SetVariable(VID_RCC, ERR_ACCESS_DENIED);
709 }
710 }
711
712
713 //
714 // Send file to server
715 //
716
717 static void SendFileProgressCallback(INT64 bytesTransferred, void *cbArg)
718 {
719 ((CommSession *)cbArg)->updateTimeStamp();
720 }
721
722 bool CommSession::sendFile(DWORD requestId, const TCHAR *file, long offset)
723 {
724 return SendFileOverNXCP(m_hSocket, requestId, file, m_pCtx, offset, SendFileProgressCallback, this) ? true : false;
725 }
726
727
728 //
729 // Upgrade agent from package in the file store
730 //
731
732 DWORD CommSession::upgrade(CSCPMessage *pRequest)
733 {
734 if (m_bMasterServer)
735 {
736 TCHAR szPkgName[MAX_PATH], szFullPath[MAX_PATH];
737
738 szPkgName[0] = 0;
739 pRequest->GetVariableStr(VID_FILE_NAME, szPkgName, MAX_PATH);
740 BuildFullPath(szPkgName, szFullPath);
741 return UpgradeAgent(szFullPath);
742 }
743 else
744 {
745 return ERR_ACCESS_DENIED;
746 }
747 }
748
749
750 //
751 // Get agent's configuration file
752 //
753
754 void CommSession::getConfig(CSCPMessage *pMsg)
755 {
756 if (m_bMasterServer)
757 {
758 pMsg->SetVariable(VID_RCC,
759 pMsg->SetVariableFromFile(VID_CONFIG_FILE, g_szConfigFile) ? ERR_SUCCESS : ERR_IO_FAILURE);
760 }
761 else
762 {
763 pMsg->SetVariable(VID_RCC, ERR_ACCESS_DENIED);
764 }
765 }
766
767
768 //
769 // Update agent's configuration file
770 //
771
772 void CommSession::updateConfig(CSCPMessage *pRequest, CSCPMessage *pMsg)
773 {
774 if (m_bMasterServer)
775 {
776 BYTE *pConfig;
777 int hFile;
778 DWORD dwSize;
779
780 if (pRequest->IsVariableExist(VID_CONFIG_FILE))
781 {
782 dwSize = pRequest->GetVariableBinary(VID_CONFIG_FILE, NULL, 0);
783 pConfig = (BYTE *)malloc(dwSize);
784 pRequest->GetVariableBinary(VID_CONFIG_FILE, pConfig, dwSize);
785 hFile = _topen(g_szConfigFile, O_CREAT | O_TRUNC | O_WRONLY, 0644);
786 if (hFile != -1)
787 {
788 if (dwSize > 0)
789 {
790 for(DWORD i = 0; i < dwSize - 1; i++)
791 if (pConfig[i] == 0x0D)
792 {
793 dwSize--;
794 memmove(&pConfig[i], &pConfig[i + 1], dwSize - i);
795 i--;
796 }
797 }
798 write(hFile, pConfig, dwSize);
799 close(hFile);
800 pMsg->SetVariable(VID_RCC, ERR_SUCCESS);
801 }
802 else
803 {
804 DebugPrintf(m_dwIndex, 2, "CommSession::updateConfig(): Error opening file \"%s\" for writing (%s)",
805 g_szConfigFile, strerror(errno));
806 pMsg->SetVariable(VID_RCC, ERR_FILE_OPEN_ERROR);
807 }
808 free(pConfig);
809 }
810 else
811 {
812 pMsg->SetVariable(VID_RCC, ERR_MALFORMED_COMMAND);
813 }
814 }
815 else
816 {
817 pMsg->SetVariable(VID_RCC, ERR_ACCESS_DENIED);
818 }
819 }
820
821
822 //
823 // Setup proxy connection
824 //
825
826 DWORD CommSession::setupProxyConnection(CSCPMessage *pRequest)
827 {
828 DWORD dwResult, dwAddr;
829 WORD wPort;
830 struct sockaddr_in sa;
831 CSCP_ENCRYPTION_CONTEXT *pSavedCtx;
832 TCHAR szBuffer[32];
833
834 if (m_bMasterServer && (g_dwFlags & AF_ENABLE_PROXY))
835 {
836 dwAddr = pRequest->GetVariableLong(VID_IP_ADDRESS);
837 wPort = pRequest->GetVariableShort(VID_AGENT_PORT);
838 m_hProxySocket = socket(AF_INET, SOCK_STREAM, 0);
839 if (m_hProxySocket != -1)
840 {
841 // Fill in address structure
842 memset(&sa, 0, sizeof(sa));
843 sa.sin_addr.s_addr = htonl(dwAddr);
844 sa.sin_family = AF_INET;
845 sa.sin_port = htons(wPort);
846 if (connect(m_hProxySocket, (struct sockaddr *)&sa, sizeof(sa)) != -1)
847 {
848 CSCPMessage msg;
849 CSCP_MESSAGE *pRawMsg;
850
851 // Stop writing thread
852 m_pSendQueue->Put(INVALID_POINTER_VALUE);
853
854 // Wait while all queued messages will be sent
855 while(m_pSendQueue->Size() > 0)
856 ThreadSleepMs(100);
857
858 // Finish proxy connection setup
859 pSavedCtx = m_pCtx;
860 m_pCtx = PROXY_ENCRYPTION_CTX;
861 m_bProxyConnection = TRUE;
862 dwResult = ERR_SUCCESS;
863 m_hProxyReadThread = ThreadCreateEx(proxyReadThreadStarter, 0, this);
864
865 // Send confirmation message
866 // We cannot use sendMessage() and writing thread, because
867 // encryption context already overriden, and writing thread
868 // already stopped
869 msg.SetCode(CMD_REQUEST_COMPLETED);
870 msg.SetId(pRequest->GetId());
871 msg.SetVariable(VID_RCC, RCC_SUCCESS);
872 pRawMsg = msg.CreateMessage();
873 sendRawMessage(pRawMsg, pSavedCtx);
874 DestroyEncryptionContext(pSavedCtx);
875
876 DebugPrintf(m_dwIndex, 5, "Established proxy connection to %s:%d", IpToStr(dwAddr, szBuffer), wPort);
877 }
878 else
879 {
880 dwResult = ERR_CONNECT_FAILED;
881 }
882 }
883 else
884 {
885 dwResult = ERR_SOCKET_ERROR;
886 }
887 }
888 else
889 {
890 dwResult = ERR_ACCESS_DENIED;
891 }
892 return dwResult;
893 }
894
895
896 //
897 // Proxy reading thread
898 //
899
900 void CommSession::proxyReadThread(void)
901 {
902 fd_set rdfs;
903 struct timeval tv;
904 char pBuffer[8192];
905 int nRet;
906
907 while(1)
908 {
909 FD_ZERO(&rdfs);
910 FD_SET(m_hProxySocket, &rdfs);
911 tv.tv_sec = 0;
912 tv.tv_usec = 5000000; // Half-second timeout
913 nRet = select(SELECT_NFDS(m_hProxySocket + 1), &rdfs, NULL, NULL, &tv);
914 if (nRet < 0)
915 break;
916 if (nRet > 0)
917 {
918 nRet = recv(m_hProxySocket, pBuffer, 8192, 0);
919 if (nRet <= 0)
920 break;
921 SendEx(m_hSocket, pBuffer, nRet, 0);
922 }
923 }
924 disconnect();
925 }