1 /*
2 * Sample showing how to use libssh2 to execute a command remotely.
3 *
4 * The sample code has fixed values for host name, user name, password
5 * and command to run.
6 *
7 * Run it like this:
8 *
9 * $ ./ssh2_exec 127.0.0.1 user password "uptime"
10 *
11 */
12
13 #include "libssh2_config.h"
14 #include <libssh2.h>
15
16 #ifdef HAVE_WINSOCK2_H
17 # include <winsock2.h>
18 #endif
19 #ifdef HAVE_SYS_SOCKET_H
20 # include <sys/socket.h>
21 #endif
22 #ifdef HAVE_NETINET_IN_H
23 # include <netinet/in.h>
24 #endif
25 #ifdef HAVE_SYS_SELECT_H
26 # include <sys/select.h>
27 #endif
28 # ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
31 #ifdef HAVE_ARPA_INET_H
32 # include <arpa/inet.h>
33 #endif
34 #ifdef HAVE_SYS_TIME_H
35 #include <sys/time.h>
36 #endif
37 #include <sys/types.h>
38 #ifdef HAVE_STDLIB_H
39 #include <stdlib.h>
40 #endif
41 #include <fcntl.h>
42 #include <errno.h>
43 #include <stdio.h>
44 #include <ctype.h>
45
waitsocket(int socket_fd,LIBSSH2_SESSION * session)46 static int waitsocket(int socket_fd, LIBSSH2_SESSION *session)
47 {
48 struct timeval timeout;
49 int rc;
50 fd_set fd;
51 fd_set *writefd = NULL;
52 fd_set *readfd = NULL;
53 int dir;
54
55 timeout.tv_sec = 10;
56 timeout.tv_usec = 0;
57
58 FD_ZERO(&fd);
59
60 FD_SET(socket_fd, &fd);
61
62 /* now make sure we wait in the correct direction */
63 dir = libssh2_session_block_directions(session);
64
65 if(dir & LIBSSH2_SESSION_BLOCK_INBOUND)
66 readfd = &fd;
67
68 if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
69 writefd = &fd;
70
71 rc = select(socket_fd + 1, readfd, writefd, NULL, &timeout);
72
73 return rc;
74 }
75
main(int argc,char * argv[])76 int main(int argc, char *argv[])
77 {
78 const char *hostname = "127.0.0.1";
79 const char *commandline = "uptime";
80 const char *username = "user";
81 const char *password = "password";
82 unsigned long hostaddr;
83 int sock;
84 struct sockaddr_in sin;
85 const char *fingerprint;
86 LIBSSH2_SESSION *session;
87 LIBSSH2_CHANNEL *channel;
88 int rc;
89 int exitcode;
90 char *exitsignal = (char *)"none";
91 int bytecount = 0;
92 size_t len;
93 LIBSSH2_KNOWNHOSTS *nh;
94 int type;
95
96 #ifdef WIN32
97 WSADATA wsadata;
98 int err;
99
100 err = WSAStartup(MAKEWORD(2, 0), &wsadata);
101 if(err != 0) {
102 fprintf(stderr, "WSAStartup failed with error: %d\n", err);
103 return 1;
104 }
105 #endif
106
107 if(argc > 1)
108 /* must be ip address only */
109 hostname = argv[1];
110
111 if(argc > 2) {
112 username = argv[2];
113 }
114 if(argc > 3) {
115 password = argv[3];
116 }
117 if(argc > 4) {
118 commandline = argv[4];
119 }
120
121 rc = libssh2_init(0);
122 if(rc != 0) {
123 fprintf(stderr, "libssh2 initialization failed (%d)\n", rc);
124 return 1;
125 }
126
127 hostaddr = inet_addr(hostname);
128
129 /* Ultra basic "connect to port 22 on localhost"
130 * Your code is responsible for creating the socket establishing the
131 * connection
132 */
133 sock = socket(AF_INET, SOCK_STREAM, 0);
134
135 sin.sin_family = AF_INET;
136 sin.sin_port = htons(22);
137 sin.sin_addr.s_addr = hostaddr;
138 if(connect(sock, (struct sockaddr*)(&sin),
139 sizeof(struct sockaddr_in)) != 0) {
140 fprintf(stderr, "failed to connect!\n");
141 return -1;
142 }
143
144 /* Create a session instance */
145 session = libssh2_session_init();
146 if(!session)
147 return -1;
148
149 /* tell libssh2 we want it all done non-blocking */
150 libssh2_session_set_blocking(session, 0);
151
152 /* ... start it up. This will trade welcome banners, exchange keys,
153 * and setup crypto, compression, and MAC layers
154 */
155 while((rc = libssh2_session_handshake(session, sock)) ==
156 LIBSSH2_ERROR_EAGAIN);
157 if(rc) {
158 fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
159 return -1;
160 }
161
162 nh = libssh2_knownhost_init(session);
163 if(!nh) {
164 /* eeek, do cleanup here */
165 return 2;
166 }
167
168 /* read all hosts from here */
169 libssh2_knownhost_readfile(nh, "known_hosts",
170 LIBSSH2_KNOWNHOST_FILE_OPENSSH);
171
172 /* store all known hosts to here */
173 libssh2_knownhost_writefile(nh, "dumpfile",
174 LIBSSH2_KNOWNHOST_FILE_OPENSSH);
175
176 fingerprint = libssh2_session_hostkey(session, &len, &type);
177 if(fingerprint) {
178 struct libssh2_knownhost *host;
179 #if LIBSSH2_VERSION_NUM >= 0x010206
180 /* introduced in 1.2.6 */
181 int check = libssh2_knownhost_checkp(nh, hostname, 22,
182 fingerprint, len,
183 LIBSSH2_KNOWNHOST_TYPE_PLAIN|
184 LIBSSH2_KNOWNHOST_KEYENC_RAW,
185 &host);
186 #else
187 /* 1.2.5 or older */
188 int check = libssh2_knownhost_check(nh, hostname,
189 fingerprint, len,
190 LIBSSH2_KNOWNHOST_TYPE_PLAIN|
191 LIBSSH2_KNOWNHOST_KEYENC_RAW,
192 &host);
193 #endif
194 fprintf(stderr, "Host check: %d, key: %s\n", check,
195 (check <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH)?
196 host->key:"<none>");
197
198 /*****
199 * At this point, we could verify that 'check' tells us the key is
200 * fine or bail out.
201 *****/
202 }
203 else {
204 /* eeek, do cleanup here */
205 return 3;
206 }
207 libssh2_knownhost_free(nh);
208
209 if(strlen(password) != 0) {
210 /* We could authenticate via password */
211 while((rc = libssh2_userauth_password(session, username, password)) ==
212 LIBSSH2_ERROR_EAGAIN);
213 if(rc) {
214 fprintf(stderr, "Authentication by password failed.\n");
215 goto shutdown;
216 }
217 }
218 else {
219 /* Or by public key */
220 while((rc = libssh2_userauth_publickey_fromfile(session, username,
221 "/home/user/"
222 ".ssh/id_rsa.pub",
223 "/home/user/"
224 ".ssh/id_rsa",
225 password)) ==
226 LIBSSH2_ERROR_EAGAIN);
227 if(rc) {
228 fprintf(stderr, "\tAuthentication by public key failed\n");
229 goto shutdown;
230 }
231 }
232
233 #if 0
234 libssh2_trace(session, ~0);
235 #endif
236
237 /* Exec non-blocking on the remove host */
238 while((channel = libssh2_channel_open_session(session)) == NULL &&
239 libssh2_session_last_error(session, NULL, NULL, 0) ==
240 LIBSSH2_ERROR_EAGAIN) {
241 waitsocket(sock, session);
242 }
243 if(channel == NULL) {
244 fprintf(stderr, "Error\n");
245 exit(1);
246 }
247 while((rc = libssh2_channel_exec(channel, commandline)) ==
248 LIBSSH2_ERROR_EAGAIN) {
249 waitsocket(sock, session);
250 }
251 if(rc != 0) {
252 fprintf(stderr, "Error\n");
253 exit(1);
254 }
255 for(;;) {
256 /* loop until we block */
257 int rc;
258 do {
259 char buffer[0x4000];
260 rc = libssh2_channel_read(channel, buffer, sizeof(buffer) );
261 if(rc > 0) {
262 int i;
263 bytecount += rc;
264 fprintf(stderr, "We read:\n");
265 for(i = 0; i < rc; ++i)
266 fputc(buffer[i], stderr);
267 fprintf(stderr, "\n");
268 }
269 else {
270 if(rc != LIBSSH2_ERROR_EAGAIN)
271 /* no need to output this for the EAGAIN case */
272 fprintf(stderr, "libssh2_channel_read returned %d\n", rc);
273 }
274 }
275 while(rc > 0);
276
277 /* this is due to blocking that would occur otherwise so we loop on
278 this condition */
279 if(rc == LIBSSH2_ERROR_EAGAIN) {
280 waitsocket(sock, session);
281 }
282 else
283 break;
284 }
285 exitcode = 127;
286 while((rc = libssh2_channel_close(channel)) == LIBSSH2_ERROR_EAGAIN)
287 waitsocket(sock, session);
288
289 if(rc == 0) {
290 exitcode = libssh2_channel_get_exit_status(channel);
291 libssh2_channel_get_exit_signal(channel, &exitsignal,
292 NULL, NULL, NULL, NULL, NULL);
293 }
294
295 if(exitsignal)
296 fprintf(stderr, "\nGot signal: %s\n", exitsignal);
297 else
298 fprintf(stderr, "\nEXIT: %d bytecount: %d\n", exitcode, bytecount);
299
300 libssh2_channel_free(channel);
301 channel = NULL;
302
303 shutdown:
304
305 libssh2_session_disconnect(session,
306 "Normal Shutdown, Thank you for playing");
307 libssh2_session_free(session);
308
309 #ifdef WIN32
310 closesocket(sock);
311 #else
312 close(sock);
313 #endif
314 fprintf(stderr, "all done\n");
315
316 libssh2_exit();
317
318 return 0;
319 }
320