extcap: add ciscodump.
[metze/wireshark/wip.git] / extcap / ssh-base.c
1 /* ssh-base.c
2  * ssh-base has base utility functions to connect to hosts via ssh
3  *
4  * Copyright 2016, Dario Lombardo
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24
25 #include "ssh-base.h"
26
27 #include <extcap/extcap-base.h>
28 #include <log.h>
29 #include <string.h>
30
31 #define verbose_print(...) { if (verbose) printf(__VA_ARGS__); }
32
33 ssh_session create_ssh_connection(const char* hostname, const unsigned int port, const char* username,
34         const char* password, const char* sshkey_path, const char* sshkey_passphrase, char** err_info)
35 {
36         ssh_session sshs;
37
38         /* Open session and set options */
39         sshs = ssh_new();
40         if (sshs == NULL) {
41                 *err_info = g_strdup_printf("Can't create ssh session");
42                 return NULL;
43         }
44
45         if (!hostname) {
46                 *err_info = g_strdup_printf("Hostname needed");
47                 goto failure;
48         }
49
50         if (ssh_options_set(sshs, SSH_OPTIONS_HOST, hostname)) {
51                 *err_info = g_strdup_printf("Can't set the hostname: %s", hostname);
52                 goto failure;
53         }
54
55         if (port != 0) {
56                 if (ssh_options_set(sshs, SSH_OPTIONS_PORT, &port)) {
57                         *err_info = g_strdup_printf("Can't set the port: %d", port);
58                         goto failure;
59                 }
60         }
61
62         if (!username)
63                 username = g_get_user_name();
64
65         if (ssh_options_set(sshs, SSH_OPTIONS_USER, username)) {
66                 *err_info = g_strdup_printf("Can't set the username: %s", username);
67                 goto failure;
68         }
69
70         g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Opening ssh connection to %s@%s:%u", username, hostname, port);
71
72         /* Connect to server */
73         if (ssh_connect(sshs) != SSH_OK) {
74                 *err_info = g_strdup_printf("Error connecting to %s@%s:%u (%s)", username, hostname, port,
75                         ssh_get_error(sshs));
76                 goto failure;
77         }
78
79 #ifdef HAVE_LIBSSH_USERAUTH_AGENT
80         g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, ("Connecting using ssh-agent...");
81         /* Try to authenticate using ssh agent */
82         if (ssh_userauth_agent(sshs, NULL) == SSH_AUTH_SUCCESS) {
83                 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "done");
84                 return sshs;
85         }
86         g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, ("failed");
87 #endif
88
89         /* If a public key path has been provided, try to authenticate using it */
90         if (sshkey_path) {
91                 ssh_key pkey = ssh_key_new();
92                 int ret;
93
94                 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Connecting using public key in %s...", sshkey_path);
95                 ret = ssh_pki_import_privkey_file(sshkey_path, sshkey_passphrase, NULL, NULL, &pkey);
96
97                 if (ret == SSH_OK) {
98                         if (ssh_userauth_publickey(sshs, NULL, pkey) == SSH_AUTH_SUCCESS) {
99                                 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "done");
100                                 ssh_key_free(pkey);
101                                 return sshs;
102                         }
103                 }
104                 ssh_key_free(pkey);
105                 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "failed (%s)", ssh_get_error(sshs));
106         }
107
108         /* Try to authenticate using standard public key */
109         g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Connecting using standard public key...");
110         if (ssh_userauth_publickey_auto(sshs, NULL, NULL) == SSH_AUTH_SUCCESS) {
111                 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "done");
112                 return sshs;
113         }
114         g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "failed");
115
116         /* If a password has been provided and all previous attempts failed, try to use it */
117         if (password) {
118                 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Connecting using password...");
119                 if (ssh_userauth_password(sshs, username, password) == SSH_AUTH_SUCCESS) {
120                         g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "done");
121                         return sshs;
122                 }
123                 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "failed");
124         }
125
126         *err_info = g_strdup_printf("Can't find a valid authentication. Disconnecting.");
127
128         /* All authentication failed. Disconnect and return */
129         ssh_disconnect(sshs);
130
131 failure:
132         ssh_free(sshs);
133         return NULL;
134 }
135
136 int ssh_channel_printf(ssh_channel channel, const char* fmt, ...)
137 {
138         gchar* buf;
139         va_list arg;
140         int ret = EXIT_SUCCESS;
141
142         va_start(arg, fmt);
143         buf = g_strdup_vprintf(fmt, arg);
144         if (ssh_channel_write(channel, buf, (guint32)strlen(buf)) == SSH_ERROR)
145                 ret = EXIT_FAILURE;
146         va_end(arg);
147         g_free(buf);
148
149         return ret;
150 }
151
152 void ssh_cleanup(ssh_session* sshs, ssh_channel* channel)
153 {
154         if (*channel) {
155                 ssh_channel_send_eof(*channel);
156                 ssh_channel_close(*channel);
157                 ssh_channel_free(*channel);
158                 *channel = NULL;
159         }
160
161         if (*sshs) {
162                 ssh_disconnect(*sshs);
163                 ssh_free(*sshs);
164                 *sshs = NULL;
165         }
166 }
167
168 /*
169  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
170  *
171  * Local variables:
172  * c-basic-offset: 8
173  * tab-width: 8
174  * indent-tabs-mode: t
175  * End:
176  *
177  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
178  * :indentSize=8:tabSize=8:noTabs=false:
179  */