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