1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 **/
19 
20 #include "checks_ssh.h"
21 
22 /* the size of temporary buffer used to read from data channel */
23 #define DATA_BUFFER_SIZE	4096
24 
25 #if defined(HAVE_SSH2)
26 #include <libssh2.h>
27 #elif defined (HAVE_SSH)
28 #include <libssh/libssh.h>
29 #endif
30 
31 #if defined(HAVE_SSH2) || defined(HAVE_SSH)
32 #include "comms.h"
33 #include "log.h"
34 
35 #define SSH_RUN_KEY	"ssh.run"
36 #endif
37 
38 #if defined(HAVE_SSH2)
39 static const char	*password;
40 
kbd_callback(const char * name,int name_len,const char * instruction,int instruction_len,int num_prompts,const LIBSSH2_USERAUTH_KBDINT_PROMPT * prompts,LIBSSH2_USERAUTH_KBDINT_RESPONSE * responses,void ** abstract)41 static void	kbd_callback(const char *name, int name_len, const char *instruction,
42 		int instruction_len, int num_prompts,
43 		const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts,
44 		LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses, void **abstract)
45 {
46 	(void)name;
47 	(void)name_len;
48 	(void)instruction;
49 	(void)instruction_len;
50 
51 	if (num_prompts == 1)
52 	{
53 		responses[0].text = zbx_strdup(NULL, password);
54 		responses[0].length = strlen(password);
55 	}
56 
57 	(void)prompts;
58 	(void)abstract;
59 }
60 
waitsocket(int socket_fd,LIBSSH2_SESSION * session)61 static int	waitsocket(int socket_fd, LIBSSH2_SESSION *session)
62 {
63 	struct timeval	tv;
64 	int		rc, dir;
65 	fd_set		fd, *writefd = NULL, *readfd = NULL;
66 
67 	tv.tv_sec = 10;
68 	tv.tv_usec = 0;
69 
70 	FD_ZERO(&fd);
71 	FD_SET(socket_fd, &fd);
72 
73 	/* now make sure we wait in the correct direction */
74 	dir = libssh2_session_block_directions(session);
75 
76 	if (0 != (dir & LIBSSH2_SESSION_BLOCK_INBOUND))
77 		readfd = &fd;
78 
79 	if (0 != (dir & LIBSSH2_SESSION_BLOCK_OUTBOUND))
80 		writefd = &fd;
81 
82 	rc = select(socket_fd + 1, readfd, writefd, NULL, &tv);
83 
84 	return rc;
85 }
86 
87 /* example ssh.run["ls /"] */
ssh_run(DC_ITEM * item,AGENT_RESULT * result,const char * encoding)88 static int	ssh_run(DC_ITEM *item, AGENT_RESULT *result, const char *encoding)
89 {
90 	zbx_socket_t	s;
91 	LIBSSH2_SESSION	*session;
92 	LIBSSH2_CHANNEL	*channel;
93 	int		auth_pw = 0, rc, ret = NOTSUPPORTED, exitcode;
94 	char		tmp_buf[DATA_BUFFER_SIZE], *userauthlist, *publickey = NULL, *privatekey = NULL, *ssherr,
95 			*output, *buffer = NULL;
96 	size_t		offset = 0, buf_size = DATA_BUFFER_SIZE;
97 
98 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
99 
100 	if (FAIL == zbx_tcp_connect(&s, CONFIG_SOURCE_IP, item->interface.addr, item->interface.port, 0,
101 			ZBX_TCP_SEC_UNENCRYPTED, NULL, NULL))
102 	{
103 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot connect to SSH server: %s", zbx_socket_strerror()));
104 		goto close;
105 	}
106 
107 	/* initializes an SSH session object */
108 	if (NULL == (session = libssh2_session_init()))
109 	{
110 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot initialize SSH session"));
111 		goto tcp_close;
112 	}
113 
114 	/* set blocking mode on session */
115 	libssh2_session_set_blocking(session, 1);
116 
117 	/* Create a session instance and start it up. This will trade welcome */
118 	/* banners, exchange keys, and setup crypto, compression, and MAC layers */
119 	if (0 != libssh2_session_startup(session, s.socket))
120 	{
121 		libssh2_session_last_error(session, &ssherr, NULL, 0);
122 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot establish SSH session: %s", ssherr));
123 		goto session_free;
124 	}
125 
126 	/* check what authentication methods are available */
127 	if (NULL != (userauthlist = libssh2_userauth_list(session, item->username, strlen(item->username))))
128 	{
129 		if (NULL != strstr(userauthlist, "password"))
130 			auth_pw |= 1;
131 		if (NULL != strstr(userauthlist, "keyboard-interactive"))
132 			auth_pw |= 2;
133 		if (NULL != strstr(userauthlist, "publickey"))
134 			auth_pw |= 4;
135 	}
136 	else
137 	{
138 		libssh2_session_last_error(session, &ssherr, NULL, 0);
139 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain authentication methods: %s", ssherr));
140 		goto session_close;
141 	}
142 
143 	zabbix_log(LOG_LEVEL_DEBUG, "%s() supported authentication methods:'%s'", __func__, userauthlist);
144 
145 	switch (item->authtype)
146 	{
147 		case ITEM_AUTHTYPE_PASSWORD:
148 			if (auth_pw & 1)
149 			{
150 				/* we could authenticate via password */
151 				if (0 != libssh2_userauth_password(session, item->username, item->password))
152 				{
153 					libssh2_session_last_error(session, &ssherr, NULL, 0);
154 					SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Password authentication failed: %s",
155 							ssherr));
156 					goto session_close;
157 				}
158 				else
159 					zabbix_log(LOG_LEVEL_DEBUG, "%s() password authentication succeeded", __func__);
160 			}
161 			else if (auth_pw & 2)
162 			{
163 				/* or via keyboard-interactive */
164 				password = item->password;
165 				if (0 != libssh2_userauth_keyboard_interactive(session, item->username, &kbd_callback))
166 				{
167 					libssh2_session_last_error(session, &ssherr, NULL, 0);
168 					SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Keyboard-interactive authentication"
169 							" failed: %s", ssherr));
170 					goto session_close;
171 				}
172 				else
173 					zabbix_log(LOG_LEVEL_DEBUG, "%s() keyboard-interactive authentication succeeded",
174 							__func__);
175 			}
176 			else
177 			{
178 				SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Unsupported authentication method."
179 						" Supported methods: %s", userauthlist));
180 				goto session_close;
181 			}
182 			break;
183 		case ITEM_AUTHTYPE_PUBLICKEY:
184 			if (auth_pw & 4)
185 			{
186 				if (NULL == CONFIG_SSH_KEY_LOCATION)
187 				{
188 					SET_MSG_RESULT(result, zbx_strdup(NULL, "Authentication by public key failed."
189 							" SSHKeyLocation option is not set"));
190 					goto session_close;
191 				}
192 
193 				/* or by public key */
194 				publickey = zbx_dsprintf(publickey, "%s/%s", CONFIG_SSH_KEY_LOCATION, item->publickey);
195 				privatekey = zbx_dsprintf(privatekey, "%s/%s", CONFIG_SSH_KEY_LOCATION,
196 						item->privatekey);
197 
198 				if (SUCCEED != zbx_is_regular_file(publickey))
199 				{
200 					SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot access public key file %s",
201 							publickey));
202 					goto session_close;
203 				}
204 
205 				if (SUCCEED != zbx_is_regular_file(privatekey))
206 				{
207 					SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot access private key file %s",
208 							privatekey));
209 					goto session_close;
210 				}
211 
212 				rc = libssh2_userauth_publickey_fromfile(session, item->username, publickey,
213 						privatekey, item->password);
214 
215 				if (0 != rc)
216 				{
217 					libssh2_session_last_error(session, &ssherr, NULL, 0);
218 					SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Public key authentication failed:"
219 							" %s", ssherr));
220 					goto session_close;
221 				}
222 				else
223 					zabbix_log(LOG_LEVEL_DEBUG, "%s() authentication by public key succeeded",
224 							__func__);
225 			}
226 			else
227 			{
228 				SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Unsupported authentication method."
229 						" Supported methods: %s", userauthlist));
230 				goto session_close;
231 			}
232 			break;
233 	}
234 
235 	/* exec non-blocking on the remove host */
236 	while (NULL == (channel = libssh2_channel_open_session(session)))
237 	{
238 		switch (libssh2_session_last_error(session, NULL, NULL, 0))
239 		{
240 			/* marked for non-blocking I/O but the call would block. */
241 			case LIBSSH2_ERROR_EAGAIN:
242 				waitsocket(s.socket, session);
243 				continue;
244 			default:
245 				SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot establish generic session channel"));
246 				goto session_close;
247 		}
248 	}
249 
250 	dos2unix(item->params);	/* CR+LF (Windows) => LF (Unix) */
251 	/* request a shell on a channel and execute command */
252 	while (0 != (rc = libssh2_channel_exec(channel, item->params)))
253 	{
254 		switch (rc)
255 		{
256 			case LIBSSH2_ERROR_EAGAIN:
257 				waitsocket(s.socket, session);
258 				continue;
259 			default:
260 				SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot request a shell"));
261 				goto channel_close;
262 		}
263 	}
264 
265 	buffer = (char *)zbx_malloc(buffer, buf_size);
266 
267 	while (0 != (rc = libssh2_channel_read(channel, tmp_buf, sizeof(tmp_buf))))
268 	{
269 		if (rc < 0)
270 		{
271 			if (LIBSSH2_ERROR_EAGAIN == rc)
272 				waitsocket(s.socket, session);
273 
274 			SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot read data from SSH server"));
275 			goto channel_close;
276 		}
277 
278 		if (MAX_EXECUTE_OUTPUT_LEN <= offset + rc)
279 		{
280 			SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Command output exceeded limit of %d KB",
281 					MAX_EXECUTE_OUTPUT_LEN / ZBX_KIBIBYTE));
282 			goto channel_close;
283 		}
284 
285 		zbx_str_memcpy_alloc(&buffer, &buf_size, &offset, tmp_buf, rc);
286 	}
287 
288 	output = convert_to_utf8(buffer, offset, encoding);
289 	zbx_rtrim(output, ZBX_WHITESPACE);
290 	zbx_replace_invalid_utf8(output);
291 
292 	SET_TEXT_RESULT(result, output);
293 	output = NULL;
294 
295 	ret = SYSINFO_RET_OK;
296 channel_close:
297 	/* close an active data channel */
298 	exitcode = 127;
299 	while (LIBSSH2_ERROR_EAGAIN == (rc = libssh2_channel_close(channel)))
300 		waitsocket(s.socket, session);
301 
302 	zbx_free(buffer);
303 
304 	if (0 != rc)
305 	{
306 		libssh2_session_last_error(session, &ssherr, NULL, 0);
307 		zabbix_log(LOG_LEVEL_WARNING, "%s() cannot close generic session channel: %s", __func__, ssherr);
308 	}
309 	else
310 		exitcode = libssh2_channel_get_exit_status(channel);
311 
312 	zabbix_log(LOG_LEVEL_DEBUG, "%s() exitcode:%d bytecount:" ZBX_FS_SIZE_T, __func__, exitcode, offset);
313 
314 	libssh2_channel_free(channel);
315 	channel = NULL;
316 
317 session_close:
318 	libssh2_session_disconnect(session, "Normal Shutdown");
319 
320 session_free:
321 	libssh2_session_free(session);
322 
323 tcp_close:
324 	zbx_tcp_close(&s);
325 
326 close:
327 	zbx_free(publickey);
328 	zbx_free(privatekey);
329 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
330 
331 	return ret;
332 }
333 #elif defined(HAVE_SSH)
334 
335 /* example ssh.run["ls /"] */
ssh_run(DC_ITEM * item,AGENT_RESULT * result,const char * encoding)336 static int	ssh_run(DC_ITEM *item, AGENT_RESULT *result, const char *encoding)
337 {
338 	ssh_session	session;
339 	ssh_channel	channel;
340 	ssh_key 	privkey = NULL, pubkey = NULL;
341 	int		rc, userauth, ret = NOTSUPPORTED;
342 	char		*output, *publickey = NULL, *privatekey = NULL, *buffer = NULL;
343 	char		tmp_buf[DATA_BUFFER_SIZE], userauthlist[64];
344 	size_t		offset = 0, buf_size = DATA_BUFFER_SIZE;
345 
346 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
347 
348 	/* initializes an SSH session object */
349 	if (NULL == (session = ssh_new()))
350 	{
351 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot initialize SSH session"));
352 		zabbix_log(LOG_LEVEL_DEBUG, "Cannot initialize SSH session");
353 
354 		goto close;
355 	}
356 
357 	/* set blocking mode on session */
358 	ssh_set_blocking(session, 1);
359 
360 	/* create a session instance and start it up */
361 	if (0 != ssh_options_set(session, SSH_OPTIONS_HOST, item->interface.addr) ||
362 			0 != ssh_options_set(session, SSH_OPTIONS_PORT, &item->interface.port) ||
363 			0 != ssh_options_set(session, SSH_OPTIONS_USER, item->username))
364 	{
365 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot set SSH session options: %s",
366 				ssh_get_error(session)));
367 		goto session_free;
368 	}
369 
370 	if (SSH_OK != ssh_connect(session))
371 	{
372 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot establish SSH session: %s", ssh_get_error(session)));
373 		goto session_free;
374 	}
375 
376 	/* check which authentication methods are available */
377 	if (SSH_AUTH_ERROR == ssh_userauth_none(session, NULL))
378 	{
379 		SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Error during authentication: %s", ssh_get_error(session)));
380 		goto session_close;
381 	}
382 
383 	userauthlist[0] = '\0';
384 
385 	if (0 != (userauth = ssh_userauth_list(session, NULL)))
386 	{
387 		if (0 != (userauth & SSH_AUTH_METHOD_NONE))
388 			offset += zbx_snprintf(userauthlist + offset, sizeof(userauthlist) - offset, "none, ");
389 		if (0 != (userauth & SSH_AUTH_METHOD_PASSWORD))
390 			offset += zbx_snprintf(userauthlist + offset, sizeof(userauthlist) - offset, "password, ");
391 		if (0 != (userauth & SSH_AUTH_METHOD_INTERACTIVE))
392 			offset += zbx_snprintf(userauthlist + offset, sizeof(userauthlist) - offset,
393 					"keyboard-interactive, ");
394 		if (0 != (userauth & SSH_AUTH_METHOD_PUBLICKEY))
395 			offset += zbx_snprintf(userauthlist + offset, sizeof(userauthlist) - offset, "publickey, ");
396 		if (0 != (userauth & SSH_AUTH_METHOD_HOSTBASED))
397 			offset += zbx_snprintf(userauthlist + offset, sizeof(userauthlist) - offset, "hostbased, ");
398 		if (2 <= offset)
399 			userauthlist[offset-2] = '\0';
400 	}
401 
402 	zabbix_log(LOG_LEVEL_DEBUG, "%s() supported authentication methods: %s", __func__, userauthlist);
403 
404 	switch (item->authtype)
405 	{
406 		case ITEM_AUTHTYPE_PASSWORD:
407 			if (0 != (userauth & SSH_AUTH_METHOD_PASSWORD))
408 			{
409 				/* we could authenticate via password */
410 				if (SSH_AUTH_SUCCESS != ssh_userauth_password(session, NULL, item->password))
411 				{
412 					SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Password authentication failed: %s",
413 							ssh_get_error(session)));
414 					goto session_close;
415 				}
416 				else
417 					zabbix_log(LOG_LEVEL_DEBUG, "%s() password authentication succeeded", __func__);
418 			}
419 			else if (0 != (userauth & SSH_AUTH_METHOD_INTERACTIVE))
420 			{
421 				/* or via keyboard-interactive */
422 				while (SSH_AUTH_INFO == (rc = ssh_userauth_kbdint(session, item->username, NULL)))
423 				{
424 					if (1 == ssh_userauth_kbdint_getnprompts(session) &&
425 							0 != ssh_userauth_kbdint_setanswer(session, 0, item->password))
426 					{
427 						zabbix_log(LOG_LEVEL_DEBUG,"Cannot set answer: %s",
428 								ssh_get_error(session));
429 					}
430 				}
431 
432 				if (SSH_AUTH_SUCCESS != rc)
433 				{
434 					SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Keyboard-interactive authentication"
435 							" failed: %s", ssh_get_error(session)));
436 					goto session_close;
437 				}
438 				else
439 				{
440 					zabbix_log(LOG_LEVEL_DEBUG, "%s() keyboard-interactive authentication"
441 							" succeeded", __func__);
442 				}
443 			}
444 			else
445 			{
446 				SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Unsupported authentication method."
447 						" Supported methods: %s", userauthlist));
448 				goto session_close;
449 			}
450 			break;
451 		case ITEM_AUTHTYPE_PUBLICKEY:
452 			if (0 != (userauth & SSH_AUTH_METHOD_PUBLICKEY))
453 			{
454 				if (NULL == CONFIG_SSH_KEY_LOCATION)
455 				{
456 					SET_MSG_RESULT(result, zbx_strdup(NULL, "Authentication by public key failed."
457 							" SSHKeyLocation option is not set"));
458 					goto session_close;
459 				}
460 
461 				/* or by public key */
462 				publickey = zbx_dsprintf(publickey, "%s/%s", CONFIG_SSH_KEY_LOCATION, item->publickey);
463 				privatekey = zbx_dsprintf(privatekey, "%s/%s", CONFIG_SSH_KEY_LOCATION,
464 						item->privatekey);
465 
466 				if (SUCCEED != zbx_is_regular_file(publickey))
467 				{
468 					SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot access public key file %s",
469 							publickey));
470 					goto session_close;
471 				}
472 
473 				if (SUCCEED != zbx_is_regular_file(privatekey))
474 				{
475 					SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot access private key file %s",
476 							privatekey));
477 					goto session_close;
478 				}
479 
480 				if (SSH_OK != ssh_pki_import_pubkey_file(publickey, &pubkey))
481 				{
482 					SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Failed to import public key: %s",
483 							ssh_get_error(session)));
484 					goto session_close;
485 				}
486 
487 				if (SSH_AUTH_SUCCESS != ssh_userauth_try_publickey(session, NULL, pubkey))
488 				{
489 					SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Public key try failed: %s",
490 							ssh_get_error(session)));
491 					goto session_close;
492 				}
493 
494 				if (SSH_OK != (rc = ssh_pki_import_privkey_file(privatekey, item->password, NULL, NULL,
495 						&privkey)))
496 				{
497 					if (SSH_EOF == rc)
498 					{
499 						SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot import private key"
500 								" file \"%s\" because it does not exist or permission"
501 								" denied", privatekey));
502 						goto session_close;
503 					}
504 
505 					SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot import private key \"%s\"",
506 							privatekey));
507 
508 					zabbix_log(LOG_LEVEL_DEBUG, "%s() failed to import private key \"%s\", rc:%d",
509 							__func__, privatekey, rc);
510 
511 					goto session_close;
512 				}
513 
514 				if (SSH_AUTH_SUCCESS != ssh_userauth_publickey(session, NULL, privkey))
515 				{
516 					SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Public key authentication failed:"
517 							" %s", ssh_get_error(session)));
518 					goto session_close;
519 				}
520 				else
521 					zabbix_log(LOG_LEVEL_DEBUG, "%s() authentication by public key succeeded",
522 							__func__);
523 			}
524 			else
525 			{
526 				SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Unsupported authentication method."
527 						" Supported methods: %s", userauthlist));
528 				goto session_close;
529 			}
530 			break;
531 	}
532 
533 	if (NULL == (channel = ssh_channel_new(session)))
534 	{
535 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot create generic session channel"));
536 		goto session_close;
537 	}
538 
539 	while (SSH_OK != (rc = ssh_channel_open_session(channel)))
540 	{
541 		if (SSH_AGAIN != rc)
542 		{
543 			SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot establish generic session channel"));
544 			goto channel_free;
545 		}
546 	}
547 
548 	/* request a shell on a channel and execute command */
549 	dos2unix(item->params);	/* CR+LF (Windows) => LF (Unix) */
550 
551 	while (SSH_OK != (rc = ssh_channel_request_exec(channel, item->params)))
552 	{
553 		if (SSH_AGAIN != rc)
554 		{
555 			SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot request a shell"));
556 			goto channel_free;
557 		}
558 	}
559 
560 	buffer = (char *)zbx_malloc(buffer, buf_size);
561 	offset = 0;
562 
563 	while (0 != (rc = ssh_channel_read(channel, tmp_buf, sizeof(tmp_buf), 0)))
564 	{
565 		if (rc < 0)
566 		{
567 			if (SSH_AGAIN == rc)
568 				continue;
569 
570 			SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot read data from SSH server"));
571 			goto channel_close;
572 		}
573 
574 		if (MAX_EXECUTE_OUTPUT_LEN <= offset + rc)
575 		{
576 			SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Command output exceeded limit of %d KB",
577 					MAX_EXECUTE_OUTPUT_LEN / ZBX_KIBIBYTE));
578 			goto channel_close;
579 		}
580 
581 		zbx_str_memcpy_alloc(&buffer, &buf_size, &offset, tmp_buf, rc);
582 	}
583 
584 	output = convert_to_utf8(buffer, offset, encoding);
585 	zbx_rtrim(output, ZBX_WHITESPACE);
586 	zbx_replace_invalid_utf8(output);
587 
588 	SET_TEXT_RESULT(result, output);
589 	output = NULL;
590 
591 	ret = SYSINFO_RET_OK;
592 channel_close:
593 	ssh_channel_close(channel);
594 	zbx_free(buffer);
595 channel_free:
596 	ssh_channel_free(channel);
597 session_close:
598 	if (NULL != privkey)
599 		ssh_key_free(privkey);
600 	if (NULL != pubkey)
601 		ssh_key_free(pubkey);
602 	ssh_disconnect(session);
603 session_free:
604 	ssh_free(session);
605 close:
606 	zbx_free(publickey);
607 	zbx_free(privatekey);
608 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
609 
610 	return ret;
611 }
612 #endif
613 
614 #if defined(HAVE_SSH2) || defined(HAVE_SSH)
get_value_ssh(DC_ITEM * item,AGENT_RESULT * result)615 int	get_value_ssh(DC_ITEM *item, AGENT_RESULT *result)
616 {
617 	AGENT_REQUEST	request;
618 	int		ret = NOTSUPPORTED;
619 	const char	*port, *encoding, *dns;
620 
621 	init_request(&request);
622 
623 	if (SUCCEED != parse_item_key(item->key, &request))
624 	{
625 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid item key format."));
626 		goto out;
627 	}
628 
629 	if (0 != strcmp(SSH_RUN_KEY, get_rkey(&request)))
630 	{
631 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Unsupported item key for this item type."));
632 		goto out;
633 	}
634 
635 	if (4 < get_rparams_num(&request))
636 	{
637 		SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
638 		goto out;
639 	}
640 
641 	if (NULL != (dns = get_rparam(&request, 1)) && '\0' != *dns)
642 	{
643 		strscpy(item->interface.dns_orig, dns);
644 		item->interface.addr = item->interface.dns_orig;
645 	}
646 
647 	if (NULL != (port = get_rparam(&request, 2)) && '\0' != *port)
648 	{
649 		if (FAIL == is_ushort(port, &item->interface.port))
650 		{
651 			SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid third parameter."));
652 			goto out;
653 		}
654 	}
655 	else
656 		item->interface.port = ZBX_DEFAULT_SSH_PORT;
657 
658 	encoding = get_rparam(&request, 3);
659 
660 	ret = ssh_run(item, result, ZBX_NULL2EMPTY_STR(encoding));
661 out:
662 	free_request(&request);
663 
664 	return ret;
665 }
666 #endif	/* defined(HAVE_SSH2) || defined(HAVE_SSH) */
667