1 /*
2 * Sample showing how to do SFTP transfers.
3 *
4 * The sample code has default values for host name, user name, password
5 * and path to copy, but you can specify them on the command line like:
6 *
7 * "sftp 192.168.0.1 user password /tmp/secrets -p|-i|-k"
8 */
9
10 #include "libssh2_config.h"
11 #include <libssh2.h>
12 #include <libssh2_sftp.h>
13
14 #ifdef HAVE_WINSOCK2_H
15 # include <winsock2.h>
16 #endif
17 #ifdef HAVE_SYS_SOCKET_H
18 # include <sys/socket.h>
19 #endif
20 #ifdef HAVE_NETINET_IN_H
21 # include <netinet/in.h>
22 #endif
23 # ifdef HAVE_UNISTD_H
24 #include <unistd.h>
25 #endif
26 #ifdef HAVE_ARPA_INET_H
27 # include <arpa/inet.h>
28 #endif
29 #ifdef HAVE_SYS_TIME_H
30 # include <sys/time.h>
31 #endif
32
33 #include <sys/types.h>
34 #include <fcntl.h>
35 #include <errno.h>
36 #include <stdio.h>
37 #include <ctype.h>
38
39
40 const char *keyfile1 = "~/.ssh/id_rsa.pub";
41 const char *keyfile2 = "~/.ssh/id_rsa";
42 const char *username = "username";
43 const char *password = "password";
44 const char *sftppath = "/tmp/TEST";
45
46
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)47 static void kbd_callback(const char *name, int name_len,
48 const char *instruction, int instruction_len,
49 int num_prompts,
50 const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts,
51 LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses,
52 void **abstract)
53 {
54 int i;
55 size_t n;
56 char buf[1024];
57 (void)abstract;
58
59 fprintf(stderr, "Performing keyboard-interactive authentication.\n");
60
61 fprintf(stderr, "Authentication name: '");
62 fwrite(name, 1, name_len, stderr);
63 fprintf(stderr, "'\n");
64
65 fprintf(stderr, "Authentication instruction: '");
66 fwrite(instruction, 1, instruction_len, stderr);
67 fprintf(stderr, "'\n");
68
69 fprintf(stderr, "Number of prompts: %d\n\n", num_prompts);
70
71 for(i = 0; i < num_prompts; i++) {
72 fprintf(stderr, "Prompt %d from server: '", i);
73 fwrite(prompts[i].text, 1, prompts[i].length, stderr);
74 fprintf(stderr, "'\n");
75
76 fprintf(stderr, "Please type response: ");
77 fgets(buf, sizeof(buf), stdin);
78 n = strlen(buf);
79 while(n > 0 && strchr("\r\n", buf[n - 1]))
80 n--;
81 buf[n] = 0;
82
83 responses[i].text = strdup(buf);
84 responses[i].length = n;
85
86 fprintf(stderr, "Response %d from user is '", i);
87 fwrite(responses[i].text, 1, responses[i].length, stderr);
88 fprintf(stderr, "'\n\n");
89 }
90
91 fprintf(stderr,
92 "Done. Sending keyboard-interactive responses to server now.\n");
93 }
94
95
main(int argc,char * argv[])96 int main(int argc, char *argv[])
97 {
98 unsigned long hostaddr;
99 int sock, i, auth_pw = 0;
100 struct sockaddr_in sin;
101 const char *fingerprint;
102 char *userauthlist;
103 LIBSSH2_SESSION *session;
104 int rc;
105 LIBSSH2_SFTP *sftp_session;
106 LIBSSH2_SFTP_HANDLE *sftp_handle;
107
108 #ifdef WIN32
109 WSADATA wsadata;
110 int err;
111
112 err = WSAStartup(MAKEWORD(2, 0), &wsadata);
113 if(err != 0) {
114 fprintf(stderr, "WSAStartup failed with error: %d\n", err);
115 return 1;
116 }
117 #endif
118
119 if(argc > 1) {
120 hostaddr = inet_addr(argv[1]);
121 }
122 else {
123 hostaddr = htonl(0x7F000001);
124 }
125
126 if(argc > 2) {
127 username = argv[2];
128 }
129 if(argc > 3) {
130 password = argv[3];
131 }
132 if(argc > 4) {
133 sftppath = argv[4];
134 }
135
136 rc = libssh2_init(0);
137 if(rc != 0) {
138 fprintf(stderr, "libssh2 initialization failed (%d)\n", rc);
139 return 1;
140 }
141
142 /*
143 * The application code is responsible for creating the socket
144 * and establishing the connection
145 */
146 sock = socket(AF_INET, SOCK_STREAM, 0);
147
148 sin.sin_family = AF_INET;
149 sin.sin_port = htons(22);
150 sin.sin_addr.s_addr = hostaddr;
151 if(connect(sock, (struct sockaddr*)(&sin),
152 sizeof(struct sockaddr_in)) != 0) {
153 fprintf(stderr, "failed to connect!\n");
154 return -1;
155 }
156
157 /* Create a session instance
158 */
159 session = libssh2_session_init();
160 if(!session)
161 return -1;
162
163 /* Since we have set non-blocking, tell libssh2 we are blocking */
164 libssh2_session_set_blocking(session, 1);
165
166 /* ... start it up. This will trade welcome banners, exchange keys,
167 * and setup crypto, compression, and MAC layers
168 */
169 rc = libssh2_session_handshake(session, sock);
170 if(rc) {
171 fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
172 return -1;
173 }
174
175 /* At this point we havn't yet authenticated. The first thing to do
176 * is check the hostkey's fingerprint against our known hosts Your app
177 * may have it hard coded, may go to a file, may present it to the
178 * user, that's your call
179 */
180 fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
181 fprintf(stderr, "Fingerprint: ");
182 for(i = 0; i < 20; i++) {
183 fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]);
184 }
185 fprintf(stderr, "\n");
186
187 /* check what authentication methods are available */
188 userauthlist = libssh2_userauth_list(session, username, strlen(username));
189 fprintf(stderr, "Authentication methods: %s\n", userauthlist);
190 if(strstr(userauthlist, "password") != NULL) {
191 auth_pw |= 1;
192 }
193 if(strstr(userauthlist, "keyboard-interactive") != NULL) {
194 auth_pw |= 2;
195 }
196 if(strstr(userauthlist, "publickey") != NULL) {
197 auth_pw |= 4;
198 }
199
200 /* if we got an 4. argument we set this option if supported */
201 if(argc > 5) {
202 if((auth_pw & 1) && !strcasecmp(argv[5], "-p")) {
203 auth_pw = 1;
204 }
205 if((auth_pw & 2) && !strcasecmp(argv[5], "-i")) {
206 auth_pw = 2;
207 }
208 if((auth_pw & 4) && !strcasecmp(argv[5], "-k")) {
209 auth_pw = 4;
210 }
211 }
212
213 if(auth_pw & 1) {
214 /* We could authenticate via password */
215 if(libssh2_userauth_password(session, username, password)) {
216 fprintf(stderr, "Authentication by password failed.\n");
217 goto shutdown;
218 }
219 }
220 else if(auth_pw & 2) {
221 /* Or via keyboard-interactive */
222 if(libssh2_userauth_keyboard_interactive(session, username,
223 &kbd_callback) ) {
224 fprintf(stderr,
225 "\tAuthentication by keyboard-interactive failed!\n");
226 goto shutdown;
227 }
228 else {
229 fprintf(stderr,
230 "\tAuthentication by keyboard-interactive succeeded.\n");
231 }
232 }
233 else if(auth_pw & 4) {
234 /* Or by public key */
235 if(libssh2_userauth_publickey_fromfile(session, username, keyfile1,
236 keyfile2, password)) {
237 fprintf(stderr, "\tAuthentication by public key failed!\n");
238 goto shutdown;
239 }
240 else {
241 fprintf(stderr, "\tAuthentication by public key succeeded.\n");
242 }
243 }
244 else {
245 fprintf(stderr, "No supported authentication methods found!\n");
246 goto shutdown;
247 }
248
249 fprintf(stderr, "libssh2_sftp_init()!\n");
250 sftp_session = libssh2_sftp_init(session);
251
252 if(!sftp_session) {
253 fprintf(stderr, "Unable to init SFTP session\n");
254 goto shutdown;
255 }
256
257 fprintf(stderr, "libssh2_sftp_open()!\n");
258 /* Request a file via SFTP */
259 sftp_handle =
260 libssh2_sftp_open(sftp_session, sftppath, LIBSSH2_FXF_READ, 0);
261
262 if(!sftp_handle) {
263 fprintf(stderr, "Unable to open file with SFTP: %ld\n",
264 libssh2_sftp_last_error(sftp_session));
265 goto shutdown;
266 }
267 fprintf(stderr, "libssh2_sftp_open() is done, now receive data!\n");
268 do {
269 char mem[1024];
270
271 /* loop until we fail */
272 fprintf(stderr, "libssh2_sftp_read()!\n");
273 rc = libssh2_sftp_read(sftp_handle, mem, sizeof(mem));
274 if(rc > 0) {
275 write(1, mem, rc);
276 }
277 else {
278 break;
279 }
280 } while(1);
281
282 libssh2_sftp_close(sftp_handle);
283 libssh2_sftp_shutdown(sftp_session);
284
285 shutdown:
286
287 libssh2_session_disconnect(session, "Normal Shutdown");
288 libssh2_session_free(session);
289
290 #ifdef WIN32
291 closesocket(sock);
292 #else
293 close(sock);
294 #endif
295 fprintf(stderr, "all done\n");
296
297 libssh2_exit();
298
299 return 0;
300 }
301