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