1 /*
2  * Sample showing how to do SSH2 connect using ssh-agent.
3  *
4  * The sample code has default values for host name, user name:
5  *
6  * "ssh2_agent host user"
7  */
8 
9 #include "libssh2_config.h"
10 #include <libssh2.h>
11 #include <libssh2_sftp.h>
12 
13 #ifdef HAVE_WINDOWS_H
14 # include <windows.h>
15 #endif
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_UNISTD_H
26 #include <unistd.h>
27 #endif
28 # ifdef HAVE_ARPA_INET_H
29 #include <arpa/inet.h>
30 #endif
31 
32 #include <sys/types.h>
33 #include <fcntl.h>
34 #include <errno.h>
35 #include <stdio.h>
36 #include <ctype.h>
37 #include <stdlib.h>
38 
39 const char *username = "username";
40 
main(int argc,char * argv[])41 int main(int argc, char *argv[])
42 {
43     unsigned long hostaddr;
44     int sock = -1, i, rc;
45     struct sockaddr_in sin;
46     const char *fingerprint;
47     char *userauthlist;
48     LIBSSH2_SESSION *session = NULL;
49     LIBSSH2_CHANNEL *channel;
50     LIBSSH2_AGENT *agent = NULL;
51     struct libssh2_agent_publickey *identity, *prev_identity = NULL;
52 
53 #ifdef WIN32
54     WSADATA wsadata;
55     int err;
56 
57     err = WSAStartup(MAKEWORD(2, 0), &wsadata);
58     if(err != 0) {
59         fprintf(stderr, "WSAStartup failed with error: %d\n", err);
60         return 1;
61     }
62 #endif
63 
64     if(argc > 1) {
65         hostaddr = inet_addr(argv[1]);
66     }
67     else {
68         hostaddr = htonl(0x7F000001);
69     }
70 
71     if(argc > 2) {
72         username = argv[2];
73     }
74 
75     rc = libssh2_init(0);
76     if(rc != 0) {
77         fprintf(stderr, "libssh2 initialization failed (%d)\n", rc);
78         return 1;
79     }
80 
81     /* Ultra basic "connect to port 22 on localhost".  Your code is
82      * responsible for creating the socket establishing the connection
83      */
84     sock = socket(AF_INET, SOCK_STREAM, 0);
85     if(sock == -1) {
86         fprintf(stderr, "failed to create socket!\n");
87         rc = 1;
88         goto shutdown;
89     }
90 
91     sin.sin_family = AF_INET;
92     sin.sin_port = htons(22);
93     sin.sin_addr.s_addr = hostaddr;
94     if(connect(sock, (struct sockaddr*)(&sin),
95                 sizeof(struct sockaddr_in)) != 0) {
96         fprintf(stderr, "failed to connect!\n");
97         goto shutdown;
98     }
99 
100     /* Create a session instance and start it up. This will trade welcome
101      * banners, exchange keys, and setup crypto, compression, and MAC layers
102      */
103     session = libssh2_session_init();
104     if(libssh2_session_handshake(session, sock)) {
105         fprintf(stderr, "Failure establishing SSH session\n");
106         return 1;
107     }
108 
109     /* At this point we havn't authenticated. The first thing to do is check
110      * the hostkey's fingerprint against our known hosts Your app may have it
111      * hard coded, may go to a file, may present it to the user, that's your
112      * call
113      */
114     fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
115     fprintf(stderr, "Fingerprint: ");
116     for(i = 0; i < 20; i++) {
117         fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
118     }
119     fprintf(stderr, "\n");
120 
121     /* check what authentication methods are available */
122     userauthlist = libssh2_userauth_list(session, username, strlen(username));
123     fprintf(stderr, "Authentication methods: %s\n", userauthlist);
124     if(strstr(userauthlist, "publickey") == NULL) {
125         fprintf(stderr, "\"publickey\" authentication is not supported\n");
126         goto shutdown;
127     }
128 
129     /* Connect to the ssh-agent */
130     agent = libssh2_agent_init(session);
131     if(!agent) {
132         fprintf(stderr, "Failure initializing ssh-agent support\n");
133         rc = 1;
134         goto shutdown;
135     }
136     if(libssh2_agent_connect(agent)) {
137         fprintf(stderr, "Failure connecting to ssh-agent\n");
138         rc = 1;
139         goto shutdown;
140     }
141     if(libssh2_agent_list_identities(agent)) {
142         fprintf(stderr, "Failure requesting identities to ssh-agent\n");
143         rc = 1;
144         goto shutdown;
145     }
146     while(1) {
147         rc = libssh2_agent_get_identity(agent, &identity, prev_identity);
148         if(rc == 1)
149             break;
150         if(rc < 0) {
151             fprintf(stderr,
152                     "Failure obtaining identity from ssh-agent support\n");
153             rc = 1;
154             goto shutdown;
155         }
156         if(libssh2_agent_userauth(agent, username, identity)) {
157             fprintf(stderr, "\tAuthentication with username %s and "
158                    "public key %s failed!\n",
159                    username, identity->comment);
160         }
161         else {
162             fprintf(stderr, "\tAuthentication with username %s and "
163                    "public key %s succeeded!\n",
164                    username, identity->comment);
165             break;
166         }
167         prev_identity = identity;
168     }
169     if(rc) {
170         fprintf(stderr, "Couldn't continue authentication\n");
171         goto shutdown;
172     }
173 
174     /* We're authenticated now. */
175 
176     /* Request a shell */
177     channel = libssh2_channel_open_session(session);
178     if(!channel) {
179         fprintf(stderr, "Unable to open a session\n");
180         goto shutdown;
181     }
182 
183     /* Some environment variables may be set,
184      * It's up to the server which ones it'll allow though
185      */
186     libssh2_channel_setenv(channel, "FOO", "bar");
187 
188     /* Request a terminal with 'vanilla' terminal emulation
189      * See /etc/termcap for more options
190      */
191     if(libssh2_channel_request_pty(channel, "vanilla")) {
192         fprintf(stderr, "Failed requesting pty\n");
193         goto skip_shell;
194     }
195 
196     /* Open a SHELL on that pty */
197     if(libssh2_channel_shell(channel)) {
198         fprintf(stderr, "Unable to request shell on allocated pty\n");
199         goto shutdown;
200     }
201 
202     /* At this point the shell can be interacted with using
203      * libssh2_channel_read()
204      * libssh2_channel_read_stderr()
205      * libssh2_channel_write()
206      * libssh2_channel_write_stderr()
207      *
208      * Blocking mode may be (en|dis)abled with: libssh2_channel_set_blocking()
209      * If the server send EOF, libssh2_channel_eof() will return non-0
210      * To send EOF to the server use: libssh2_channel_send_eof()
211      * A channel can be closed with: libssh2_channel_close()
212      * A channel can be freed with: libssh2_channel_free()
213      */
214 
215   skip_shell:
216     if(channel) {
217         libssh2_channel_free(channel);
218         channel = NULL;
219     }
220 
221     /* Other channel types are supported via:
222      * libssh2_scp_send()
223      * libssh2_scp_recv2()
224      * libssh2_channel_direct_tcpip()
225      */
226 
227   shutdown:
228 
229     if(agent) {
230         libssh2_agent_disconnect(agent);
231         libssh2_agent_free(agent);
232     }
233 
234     if(session) {
235         libssh2_session_disconnect(session,
236                                    "Normal Shutdown, Thank you for playing");
237         libssh2_session_free(session);
238     }
239 
240     if(sock != -1) {
241 #ifdef WIN32
242         closesocket(sock);
243 #else
244         close(sock);
245 #endif
246     }
247 
248     fprintf(stderr, "all done!\n");
249 
250     libssh2_exit();
251 
252     return rc;
253 }
254