5113456 [rkeene@sledge /home/rkeene/projects/libssh-win32/v0.11]$ cat -n sample.c
  1 /* client.c */
  2 /*
  3 Copyright 2003 Aris Adamantiadis
  4 
  5 This file is part of the SSH Library
  6 
  7 You are free to copy this file, modify it in any way, consider it being public
  8 domain. This does not apply to the rest of the library though, but it is 
  9 allowed to cut-and-paste working code from this file to any license of
 10 program.
 11 The goal is to show the API in action. It's not a reference on how terminal
 12 clients must be made or how a client should react.
 13 */
 14 
 15 #include "libssh/priv.h"
 16 
 17 #include <stdio.h>
 18 #include <unistd.h>
 19 #include <stdlib.h>
 20 #include <string.h>
 21 #ifdef HAVE_TERMIOS_H
 22 #include <termios.h>
 23 #endif
 24 
 25 #ifdef HAVE_SYS_SELECT_H
 26 #include <sys/select.h>
 27 #endif
 28 #include <sys/time.h>
 29 #ifdef HAVE_PTY_H
 30 #include <pty.h>
 31 #endif
 32 #ifdef HAVE_SIGNAL_H
 33 #include <signal.h>
 34 #endif
 35 #include <errno.h>
 36 #include <libssh/libssh.h>
 37 #include <libssh/sftp.h>
 38 
 39 #include <fcntl.h>
 40 
 41 #define MAXCMD 10
 42 char *host;
 43 char *user;
 44 int sftp;
 45 char *cmds[MAXCMD];
 46 #ifdef HAVE_TERMIOS_H
 47 struct termios terminal;
 48 #endif
 49 void do_sftp(SSH_SESSION *session);
 50 
 51 void add_cmd(char *cmd){
 52     int n;
 53     for(n=0;cmds[n] && (n<MAXCMD);n++);
 54     if(n==MAXCMD)
 55         return;
 56     cmds[n]=strdup(cmd);
 57 }
 58 
 59 void usage(){
 60     fprintf(stderr,"Usage : ssh [options] [login@]hostname\n"
 61     "Options :\n"
 62     "  -l user : log in as user\n"
 63     "  -p port : connect to port\n"
 64     "  -d : use DSS to verify host public key\n"
 65     "  -r : use RSA to verify host public key\n");
 66     exit(0);
 67 }
 68 
 69 int opts(int argc, char **argv){
 70     int i;
 71     if(strstr(argv[0],"sftp"))
 72         sftp=1;
 73 //    for(i=0;i<argc;i++)
 74 //        printf("%d : %s\n",i,argv[i]);
 75     /* insert your own arguments here */
 76     while((i=getopt(argc,argv,""))!=-1){
 77         switch(i){
 78             default:
 79                 fprintf(stderr,"unknown option %c\n",optopt);
 80                 usage();
 81         }
 82     }
 83     if(optind < argc)
 84         host=argv[optind++];
 85     while(optind < argc)
 86         add_cmd(argv[optind++]);
 87     if(host==NULL)
 88         usage();
 89     return 0;
 90 }
 91 
 92 void do_cleanup(){
 93 #ifdef HAVE_TCSETATTR
 94     tcsetattr(0,TCSANOW,&terminal);
 95 #endif
 96 }
 97 void do_exit(){
 98     do_cleanup();
 99     exit(0);
100 }
101 CHANNEL *chan;
102 int signal_delayed=0;
103 void setsignal();
104 void sigwindowchanged(){
105     signal_delayed=1;
106 }
107 void sizechanged(){
108 #ifdef HAVE_PTY_H
109     struct winsize win = { 0, 0, 0, 0 };
110     ioctl(1, TIOCGWINSZ, &win);
111     channel_change_pty_size(chan,win.ws_col, win.ws_row);
112 //    printf("Changed pty size\n");
113     setsignal();
114 #endif
115 }
116 void setsignal(){
117 #ifdef HAVE_SIGNAL
118     signal(SIGWINCH,sigwindowchanged);
119     signal_delayed=0;
120 #endif
121 }
122 
123 void select_loop(SSH_SESSION *session, CHANNEL *channel){
124     fd_set fds;
125     struct timeval timeout;
126     char buffer[10];
127     BUFFER *readbuf = buffer_new();
128     CHANNEL *channels[2] = {channel, NULL};
129     CHANNEL *outchannel[2] = {NULL, NULL};
130     int lus;
131     int eof = 0;
132     int ret;
133     while (channel) {
134        /* when a signal is caught, ssh_select will return
135          * with SSH_EINTR, which means it should be started 
136          * again. It lets you handle the signal the faster you
137          * can, like in this window changed example. Of course, if
138          * your signal handler doesn't call libssh at all, you're
139          * free to handle signals directly in sighandler.
140          */
141         do {
142             FD_ZERO(&fds);
143             if(!eof) {
144                 FD_SET(fileno(stdin), &fds);
145             }
146             timeout.tv_sec = 30;
147             timeout.tv_usec = 0;
148             ret = ssh_select(channels,outchannel,fileno(stdin)+1,&fds,&timeout);
149             if (signal_delayed) {
150                 sizechanged();        
151             }
152         } while (ret==SSH_EINTR);
153         if(FD_ISSET(fileno(stdin),&fds)){
154             lus=fread(buffer,1,10,stdin);
155             if(lus){
156                 channel_write(channel,buffer,lus);
157             }
158             else{
159                 eof=1;
160                 channel_send_eof(channel);
161             }
162         }
163         if(outchannel[0]){
164             while(channel_poll(outchannel[0],0)){
165                 lus=channel_read(outchannel[0],readbuf,0,0);
166                 if(lus==-1){
167                     ssh_say(0,"error reading channel : %s\n",ssh_get_error(session));
168                     return;
169                 }
170                 if(lus==0){
171                     ssh_say(1,"EOF received\n");
172                 } else
173                     write(1,buffer_get(readbuf),lus);
174             }
175             while(channel_poll(outchannel[0],1)){ /* stderr */
176                 lus=channel_read(outchannel[0],readbuf,0,1);
177                 if(lus==-1){
178                     ssh_say(0,"error reading channel : %s\n",ssh_get_error(session));
179                     return;
180                 }
181                 if(lus==0){
182                     ssh_say(1,"EOF received\n");
183                 } else
184                     write(2,buffer_get(readbuf),lus);
185             }
186         }
187         if(!channel_is_open(channel)){
188             channel_free(channel);
189             channel=NULL;
190         }
191     }
192     buffer_free(readbuf);
193 }
194 
195 void shell(SSH_SESSION *session){
196     CHANNEL *channel;
197 #ifdef HAVE_TERMIOS_H
198     struct termios terminal_local;
199 #endif
200     int interactive=isatty(0);
201     if(interactive){
202 #ifdef HAVE_TCGETATTR
203         tcgetattr(0,&terminal_local);
204         memcpy(&terminal,&terminal_local,sizeof(struct termios));
205         cfmakeraw(&terminal_local);
206         tcsetattr(0,TCSANOW,&terminal_local);
207 #endif
208         setsignal();
209     }
210 #ifdef HAVE_SIGNAL
211     signal(SIGTERM,do_cleanup);
212 #endif
213     channel = channel_open_session(session);
214     chan=channel;
215     if(interactive){
216         channel_request_pty(channel);
217         sizechanged();
218     }
219     channel_request_shell(channel);
220     select_loop(session,channel);
221 }
222 void batch_shell(SSH_SESSION *session){
223     CHANNEL *channel;
224     char buffer[1024];
225     int i,s=0;
226     for(i=0;i<MAXCMD && cmds[i];++i)
227         s+=snprintf(buffer+s,sizeof(buffer)-s,"%s ",cmds[i]);
228     channel=channel_open_session(session);
229     if(channel_request_exec(channel,buffer)){
230         printf("error executing \"%s\" : %s\n",buffer,ssh_get_error(session));
231         return;
232     }
233     select_loop(session,channel);
234 }
235         
236 /* it's just a proof of concept code for sftp, till i write a real documentation about it */
237 void do_sftp(SSH_SESSION *session){
238     SFTP_SESSION *sftp=sftp_new(session);
239     SFTP_DIR *dir;
240     SFTP_ATTRIBUTES *file;
241     SFTP_FILE *fichier;
242     SFTP_FILE *to;
243     int len=1;
244     int i;
245     char data[8000];
246     if(!sftp){
247         ssh_say(0,"sftp error initialising channel : %s\n",ssh_get_error(session));
248         return;
249     }
250     if(sftp_init(sftp)){
251         ssh_say(0,"error initialising sftp : %s\n",ssh_get_error(session));
252         return;
253     }
254     /* the connection is made */
255     /* opening a directory */
256     dir=sftp_opendir(sftp,"./");
257     if(!dir) {
258         ssh_say(0,"Directory not opened(%s)\n",ssh_get_error(session));
259         return ;
260     }
261     /* reading the whole directory, file by file */
262     while((file=sftp_readdir(sftp,dir))){
263         ssh_say(0,"%30s(%.8lo) : %.5d.%.5d : %.10lld
	bytes\n",file->name,file->permissions,file->uid,file->gid,file->size);
264         sftp_attributes_free(file);
265     }
266     /* when file=NULL, an error has occured OR the directory listing is end of file */
267     if(!sftp_dir_eof(dir)){
268         ssh_say(0,"error : %s\n",ssh_get_error(session));
269         return;
270     }
271     if(sftp_dir_close(dir)){
272         ssh_say(0,"Error : %s\n",ssh_get_error(session));
273         return;
274     }
275     /* this will open a file and copy it into your /home directory */
276     /* the small buffer size was intended to stress the library. of course, you can use a buffer till 20kbytes without
	problem */
277 
278     fichier=sftp_open(sftp,"/usr/bin/ssh",O_RDONLY,NULL);
279     if(!fichier){
280         ssh_say(0,"Error opening /usr/bin/ssh : %s\n",ssh_get_error(session));
281         return;
282     }
283     /* open a file for writing... */
284     to=sftp_open(sftp,"ssh-copy",O_WRONLY | O_CREAT,NULL);
285     if(!to){
286         ssh_say(0,"Error opening ssh-copy for writing : %s\n",ssh_get_error(session));
287         return;
288     }
289     while((len=sftp_read(fichier,data,4096)) > 0){
290         if(sftp_write(to,data,len)!=len){
291             ssh_say(0,"error writing %d bytes : %s\n",len,ssh_get_error(session));
292             return;
293         }
294     }
295     printf("finished\n");
296     if(len<0)
297         ssh_say(0,"Error reading file : %s\n",ssh_get_error(session));     
298     sftp_file_close(fichier);
299     sftp_file_close(to);
300     printf("fichiers fermés\n");
301     to=sftp_open(sftp,"/tmp/grosfichier",O_WRONLY|O_CREAT,NULL);
302     for(i=0;i<1000;++i){
303         len=sftp_write(to,data,8000);
304         printf("wrote %d bytes\n",len);
305         if(len != 8000){
306             printf("chunk %d : %d (%s)\n",i,len,ssh_get_error(session));
307         }
308     }
309     sftp_file_close(to);
310     /* close the sftp session */
311     sftp_free(sftp);
312     printf("session sftp terminée\n");
313 }
314 int auth_kbdint(SSH_SESSION *session){
315     int err=ssh_userauth_kbdint(session,NULL,NULL);
316     char *name,*instruction,*prompt,*ptr;
317     char buffer[128];
318     int i,n;
319     char echo;
320     while (err==SSH_AUTH_INFO){
321         name=ssh_userauth_kbdint_getname(session);
322         instruction=ssh_userauth_kbdint_getinstruction(session);
323         n=ssh_userauth_kbdint_getnprompts(session);
324         if(strlen(name)>0)
325             printf("%s\n",name);
326         if(strlen(instruction)>0)
327             printf("%s\n",instruction);
328         for(i=0;i<n;++i){
329             prompt=ssh_userauth_kbdint_getprompt(session,i,&echo);
330             if(echo){
331                 printf("%s",prompt);
332                 fgets(buffer,sizeof(buffer),stdin);
333                 buffer[sizeof(buffer)-1]=0;
334                 if((ptr=strchr(buffer,'\n')))
335                     *ptr=0;
336                 ssh_userauth_kbdint_setanswer(session,i,buffer);
337                 memset(buffer,0,strlen(buffer));
338             } else {
339 #ifdef HAVE_GETPASS
340                 ptr=getpass(prompt);
341 #else
342         fprintf(stderr, "%s", prompt);
343         ptr = malloc(1024);
344         fgets(ptr, 1024, stdin);
345         if (strlen(ptr) > 0) {
346             if (ptr[strlen(ptr) - 1] == '\n') {
347                 ptr[strlen(ptr) - 1] = '\0';
348             }
349         }
350 #endif
351                 ssh_userauth_kbdint_setanswer(session,i,ptr);
352             }
353         }
354         err=ssh_userauth_kbdint(session,NULL,NULL);
355     }
356     return err;
357 }
358 
359 int main(int argc, char **argv){
360     SSH_SESSION *session;
361     SSH_OPTIONS *options;
362     int auth=0;
363     char *password;
364     char *banner;
365     int state;
366     char buf[10];
367     char hash[MD5_DIGEST_LEN];
368 
369     options=ssh_getopt(&argc, argv);
370     if(!options){
371         fprintf(stderr,"Error : %s\n",ssh_get_error(NULL));
372         usage();
373         return -1;
374     }    
375     opts(argc,argv);
376 #ifdef HAVE_SIGNAL
377     signal(SIGTERM,do_exit);
378 #endif
379     if(user)
380         options_set_username(options,user);
381     options_set_host(options,host);
382     session=ssh_connect(options);
383     if(!session){
384         fprintf(stderr,"[4891] Connection failed : %s\n",ssh_get_error(NULL));
385         return -1;
386     }
387 
388     state=ssh_is_server_known(session);
389     switch(state){
390         case SSH_SERVER_KNOWN_OK:
391             break; /* ok */
392         case SSH_SERVER_KNOWN_CHANGED:
393             fprintf(stderr,"Host key for server changed : server's one is now :\n");
394             ssh_get_pubkey_hash(session,hash);
395             ssh_print_hexa("Public key hash",hash,MD5_DIGEST_LEN);
396             fprintf(stderr,"For security reason, connection will be stopped\n");
397             ssh_disconnect(session);
398             exit(-1);
399         case SSH_SERVER_FOUND_OTHER:
400             fprintf(stderr,"The host key for this server was not found but an other type of key exists.\n");
401             fprintf(stderr,"An attacker might change the default server key to confuse your client"
402                 "into thinking the key does not exist\n"
403                 "We advise you to rerun the client with -d or -r for more safety.\n");
404                 ssh_disconnect(session);
405                 exit(-1);
406         case SSH_SERVER_NOT_KNOWN:
407             fprintf(stderr,"The server is unknown. Do you trust the host key ?\n");
408             ssh_get_pubkey_hash(session,hash);
409             ssh_print_hexa("Public key hash",hash,MD5_DIGEST_LEN);
410             fgets(buf,sizeof(buf),stdin);
411             if(strncasecmp(buf,"yes",3)!=0){
412                 ssh_disconnect(session);
413                 exit(-1);
414             }
415             fprintf(stderr,"This new key will be written on disk for further usage. do you agree ?\n");
416             fgets(buf,sizeof(buf),stdin);
417             if(strncasecmp(buf,"yes",3)==0){
418                 if(ssh_write_knownhost(session))
419                     fprintf(stderr,"error %s\n",ssh_get_error(session));
420             }
421             
422             break;
423         case SSH_SERVER_ERROR:
424             fprintf(stderr,"%s",ssh_get_error(session));
425             ssh_disconnect(session);
426             exit(-1);
427     }
428 
429     /* no ? you should :) */
430     auth=ssh_userauth_autopubkey(session);
431     if(auth==SSH_AUTH_ERROR){
432         fprintf(stderr,"Authenticating with pubkey: %s\n",ssh_get_error(session));
433         return -1;
434     }
435     banner=ssh_get_issue_banner(session);
436     if(banner){
437         printf("%s\n",banner);
438         free(banner);
439     }
440     if(auth!=SSH_AUTH_SUCCESS){
441         auth=auth_kbdint(session);
442         if(auth==SSH_AUTH_ERROR){
443             fprintf(stderr,"authenticating with keyb-interactive: %s\n",
444                     ssh_get_error(session));
445             return -1;
446         }
447     }
448     if(auth!=SSH_AUTH_SUCCESS){
449 #ifdef HAVE_GETPASS
450         password=getpass("Password : ");
451 #else
452     fprintf(stderr, "Password : ");
453     password = malloc(1024);
454     fgets(password, 1024, stdin);
455     if (strlen(password) > 0) {
456         if (password[strlen(password) - 1] == '\n') {
457             password[strlen(password) - 1] = '\0';
458         }
459     }
460 #endif
461         if(ssh_userauth_password(session,NULL,password) != SSH_AUTH_SUCCESS){
462             fprintf(stderr,"Authentication failed: %s\n",ssh_get_error(session));
463             ssh_disconnect(session);
464             return -1;
465         }
466         memset(password,0,strlen(password));
467     }
468     ssh_say(1,"Authentication success\n");
469     if(!sftp){
470         if(!cmds[0])
471             shell(session);
472         else
473             batch_shell(session);
474     }
475     else
476         do_sftp(session);    
477     if(!sftp && !cmds[0])
478         do_cleanup();
479     ssh_disconnect(session);
480     return 0;
481 }

sample.c is a sample program using libssh (v0.11 for Win32)
5113457 [rkeene@sledge /home/rkeene/projects/libssh-win32/v0.11]$

Click here to go back to the directory listing.
Click here to download this file.
last modified: 2007-02-17 11:46:50