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