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