Windows installer adds PING and SSH subagents to agent configuration on server
[public/netxms.git] / src / agent / subagents / ssh / session.cpp
CommitLineData
12acf3d3
VK
1/*
2** NetXMS SSH subagent
3** Copyright (C) 2004-2016 Victor Kirhenshtein
4**
5** This program is free software; you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation; either version 2 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program; if not, write to the Free Software
17** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18**
19** File: session.cpp
12acf3d3
VK
20**/
21
22#include "ssh_subagent.h"
23
24/**
25 * SSH session constructor
26 */
547e3f2c 27SSHSession::SSHSession(const InetAddress& addr, UINT16 port, INT32 id)
12acf3d3 28{
547e3f2c 29 m_id = id;
12acf3d3
VK
30 m_addr = addr;
31 m_port = port;
32 m_session = NULL;
547e3f2c
VK
33 m_lastAccess = 0;
34 m_user[0] = 0;
35 m_busy = false;
36 _sntprintf(m_name, MAX_SSH_SESSION_NAME_LEN, _T("nobody@%s:%d/%d"), (const TCHAR *)m_addr.toString(), m_port, m_id);
12acf3d3
VK
37}
38
39/**
40 * SSH session destructor
41 */
42SSHSession::~SSHSession()
43{
44 disconnect();
45}
46
547e3f2c
VK
47/**
48 * Check if session match for given target
49 */
50bool SSHSession::match(const InetAddress& addr, UINT16 port, const TCHAR *user) const
51{
52 return addr.equals(m_addr) && ((unsigned int)port == m_port) && !_tcscmp(m_user, user);
53}
54
55/**
56 * Acquire session
57 */
58bool SSHSession::acquire()
59{
60 if (m_busy || !isConnected())
61 return false;
62 m_busy = true;
63 return true;
64}
65
66/**
67 * Release session
68 */
69void SSHSession::release()
70{
71 m_busy = false;
72}
73
12acf3d3
VK
74/**
75 * Connect to server
76 */
77bool SSHSession::connect(const TCHAR *user, const TCHAR *password)
78{
79 if (m_session != NULL)
80 return false; // already connected
81
82 m_session = ssh_new();
83 if (m_session == NULL)
84 return false; // cannot create session
85
86 bool success = false;
87
88 char hostname[64];
89 ssh_options_set(m_session, SSH_OPTIONS_HOST, m_addr.toStringA(hostname));
90 ssh_options_set(m_session, SSH_OPTIONS_PORT, &m_port);
0f50b524
VK
91 long timeout = (long)g_sshConnectTimeout * (long)1000; // convert milliseconds to microseconds
92 ssh_options_set(m_session, SSH_OPTIONS_TIMEOUT_USEC, &timeout);
12acf3d3
VK
93#ifdef UNICODE
94 char mbuser[256];
95 WideCharToMultiByte(CP_UTF8, 0, user, -1, mbuser, 256, NULL, NULL);
96 ssh_options_set(m_session, SSH_OPTIONS_USER, mbuser);
97#else
98 ssh_options_set(m_session, SSH_OPTIONS_USER, user);
99#endif
100
101 if (ssh_connect(m_session) == SSH_OK)
102 {
103#ifdef UNICODE
104 char mbpassword[256];
105 WideCharToMultiByte(CP_UTF8, 0, password, -1, mbpassword, 256, NULL, NULL);
106 if (ssh_userauth_password(m_session, NULL, mbpassword) == SSH_AUTH_SUCCESS)
107#else
108 if (ssh_userauth_password(m_session, NULL, password) == SSH_AUTH_SUCCESS)
109#endif
110 {
111 success = true;
112 }
113 else
114 {
115 nxlog_debug(6, _T("SSH: login as %s on %s:%d failed"), user, (const TCHAR *)m_addr.toString(), m_port);
116 }
117 }
118 else
119 {
120 nxlog_debug(6, _T("SSH: connect to %s:%d failed"), (const TCHAR *)m_addr.toString(), m_port);
121 }
122
547e3f2c
VK
123 if (success)
124 {
125 nx_strncpy(m_user, user, MAX_SSH_LOGIN_LEN);
126 _sntprintf(m_name, MAX_SSH_SESSION_NAME_LEN, _T("%s@%s:%d/%d"), m_user, (const TCHAR *)m_addr.toString(), m_port, m_id);
127 m_lastAccess = time(NULL);
128 }
129 else
12acf3d3
VK
130 {
131 if (ssh_is_connected(m_session))
132 ssh_disconnect(m_session);
133 ssh_free(m_session);
134 m_session = NULL;
135 }
136 return success;
137}
138
139/**
140 * Disconnect from server
141 */
142void SSHSession::disconnect()
143{
144 if (m_session == NULL)
145 return;
146
147 if (ssh_is_connected(m_session))
148 ssh_disconnect(m_session);
149 ssh_free(m_session);
150 m_session = NULL;
151}
152
153/**
154 * Execute command and capture output
155 */
156StringList *SSHSession::execute(const TCHAR *command)
157{
158 if ((m_session == NULL) || !ssh_is_connected(m_session))
159 return NULL;
160
161 ssh_channel channel = ssh_channel_new(m_session);
162 if (channel == NULL)
163 return NULL;
164
165 StringList *output = NULL;
166 if (ssh_channel_open_session(channel) == SSH_OK)
167 {
168#ifdef UNICODE
169 char *mbcmd = UTF8StringFromWideString(command);
170 if (ssh_channel_request_exec(channel, mbcmd) == SSH_OK)
171#else
172 if (ssh_channel_request_exec(channel, command) == SSH_OK)
173#endif
174 {
175 output = new StringList();
176 char buffer[8192];
177 int nbytes = ssh_channel_read(channel, buffer, sizeof(buffer) - 1, 0);
178 int offset = 0;
179 while(nbytes > 0)
180 {
181 buffer[nbytes + offset] = 0;
182 char *curr = buffer;
183 char *eol = strchr(curr, '\n');
184 while(eol != NULL)
185 {
186 *eol = 0;
241541f4
VK
187 char *cr = strchr(curr, '\r');
188 if (cr != NULL)
189 *cr = 0;
12acf3d3
VK
190 output->addMBString(curr);
191 curr = eol + 1;
192 eol = strchr(curr, '\n');
193 }
358febc2 194 offset = (int)strlen(curr);
12acf3d3
VK
195 if (offset > 0)
196 memmove(buffer, curr, offset);
197 nbytes = ssh_channel_read(channel, &buffer[offset], sizeof(buffer) - offset - 1, 0);
198 }
199 if (nbytes == 0)
200 {
201 if (offset > 0)
202 {
203 buffer[offset] = 0;
241541f4
VK
204 char *cr = strchr(buffer, '\r');
205 if (cr != NULL)
206 *cr = 0;
12acf3d3
VK
207 output->addMBString(buffer);
208 }
209 ssh_channel_send_eof(channel);
210 }
211 else
212 {
213 delete_and_null(output);
214 }
215 }
216 else
217 {
218 nxlog_debug(6, _T("SSH: command \"%s\" execution on %s:%d failed"), command, (const TCHAR *)m_addr.toString(), m_port);
219 }
220 ssh_channel_close(channel);
221 }
222 else
223 {
224 nxlog_debug(6, _T("SSH: cannot open channel on %s:%d"), (const TCHAR *)m_addr.toString(), m_port);
225 }
226 ssh_channel_free(channel);
547e3f2c 227 m_lastAccess = time(NULL);
12acf3d3
VK
228 return output;
229}