| sample.c | sample.c | |||
|---|---|---|---|---|
| /* client.c */ | /* client.c */ | |||
| /* | /* | |||
| Copyright 2003 Aris Adamantiadis | Copyright 2003-2009 Aris Adamantiadis | |||
| This file is part of the SSH Library | This file is part of the SSH Library | |||
| You are free to copy this file, modify it in any way, consider it being pub lic | You are free to copy this file, modify it in any way, consider it being pub lic | |||
| domain. This does not apply to the rest of the library though, but it is | domain. This does not apply to the rest of the library though, but it is | |||
| allowed to cut-and-paste working code from this file to any license of | allowed to cut-and-paste working code from this file to any license of | |||
| program. | program. | |||
| The goal is to show the API in action. It's not a reference on how terminal | The goal is to show the API in action. It's not a reference on how terminal | |||
| clients must be made or how a client should react. | clients must be made or how a client should react. | |||
| */ | */ | |||
| skipping to change at line 30 | skipping to change at line 30 | |||
| #include <termios.h> | #include <termios.h> | |||
| #include <sys/select.h> | #include <sys/select.h> | |||
| #include <sys/time.h> | #include <sys/time.h> | |||
| #ifdef HAVE_PTY_H | #ifdef HAVE_PTY_H | |||
| #include <pty.h> | #include <pty.h> | |||
| #endif | #endif | |||
| #include <sys/ioctl.h> | #include <sys/ioctl.h> | |||
| #include <signal.h> | #include <signal.h> | |||
| #include <errno.h> | #include <errno.h> | |||
| #include <libssh/callbacks.h> | ||||
| #include <libssh/libssh.h> | #include <libssh/libssh.h> | |||
| #include <libssh/sftp.h> | #include <libssh/sftp.h> | |||
| #include <fcntl.h> | #include <fcntl.h> | |||
| #include "examples_common.h" | ||||
| #define MAXCMD 10 | #define MAXCMD 10 | |||
| char *host; | char *host; | |||
| char *user; | char *user; | |||
| int sftp; | ||||
| char *cmds[MAXCMD]; | char *cmds[MAXCMD]; | |||
| struct termios terminal; | struct termios terminal; | |||
| void do_sftp(SSH_SESSION *session); | ||||
| #ifdef WITH_PCAP | ||||
| /* this header file won't be necessary in the future */ | ||||
| #include <libssh/pcap.h> | ||||
| char *pcap_file=NULL; | ||||
| #endif | ||||
| static int auth_callback(const char *prompt, char *buf, size_t len, | ||||
| int echo, int verify, void *userdata) { | ||||
| char *answer = NULL; | ||||
| char *ptr; | ||||
| (void) verify; | ||||
| (void) userdata; | ||||
| if (echo) { | ||||
| while ((answer = fgets(buf, len, stdin)) == NULL); | ||||
| if ((ptr = strchr(buf, '\n'))) { | ||||
| ptr = '\0'; | ||||
| } | ||||
| } else { | ||||
| answer = getpass(prompt); | ||||
| } | ||||
| if (answer == NULL) { | ||||
| return -1; | ||||
| } | ||||
| strncpy(buf, answer, len); | ||||
| return 0; | ||||
| } | ||||
| struct ssh_callbacks_struct cb = { | ||||
| .auth_function=auth_callback, | ||||
| .userdata=NULL | ||||
| }; | ||||
| static void add_cmd(char *cmd){ | static void add_cmd(char *cmd){ | |||
| int n; | int n; | |||
| for(n=0;cmds[n] && (n<MAXCMD);n++); | for(n=0;cmds[n] && (n<MAXCMD);n++); | |||
| if(n==MAXCMD) | if(n==MAXCMD) | |||
| return; | return; | |||
| cmds[n]=strdup(cmd); | cmds[n]=strdup(cmd); | |||
| } | } | |||
| static void usage(){ | static void usage(){ | |||
| fprintf(stderr,"Usage : ssh [options] [login@]hostname\n" | fprintf(stderr,"Usage : ssh [options] [login@]hostname\n" | |||
| "sample client - libssh-%s\n" | "sample client - libssh-%s\n" | |||
| "Options :\n" | "Options :\n" | |||
| " -l user : log in as user\n" | " -l user : log in as user\n" | |||
| " -p port : connect to port\n" | " -p port : connect to port\n" | |||
| " -d : use DSS to verify host public key\n" | " -d : use DSS to verify host public key\n" | |||
| " -r : use RSA to verify host public key\n", | " -r : use RSA to verify host public key\n" | |||
| #ifdef WITH_PCAP | ||||
| " -P file : create a pcap debugging file\n" | ||||
| #endif | ||||
| , | ||||
| ssh_version(0)); | ssh_version(0)); | |||
| exit(0); | exit(0); | |||
| } | } | |||
| static int opts(int argc, char **argv){ | static int opts(int argc, char **argv){ | |||
| int i; | int i; | |||
| if(strstr(argv[0],"sftp")) | ||||
| sftp=1; | ||||
| // for(i=0;i<argc;i++) | // for(i=0;i<argc;i++) | |||
| // printf("%d : %s\n",i,argv[i]); | // printf("%d : %s\n",i,argv[i]); | |||
| /* insert your own arguments here */ | /* insert your own arguments here */ | |||
| while((i=getopt(argc,argv,""))!=-1){ | while((i=getopt(argc,argv,"P:"))!=-1){ | |||
| switch(i){ | switch(i){ | |||
| #ifdef WITH_PCAP | ||||
| case 'P': | ||||
| pcap_file=optarg; | ||||
| break; | ||||
| #endif | ||||
| default: | default: | |||
| fprintf(stderr,"unknown option %c\n",optopt); | fprintf(stderr,"unknown option %c\n",optopt); | |||
| usage(); | usage(); | |||
| } | } | |||
| } | } | |||
| if(optind < argc) | if(optind < argc) | |||
| host=argv[optind++]; | host=argv[optind++]; | |||
| while(optind < argc) | while(optind < argc) | |||
| add_cmd(argv[optind++]); | add_cmd(argv[optind++]); | |||
| if(host==NULL) | if(host==NULL) | |||
| skipping to change at line 111 | skipping to change at line 155 | |||
| } | } | |||
| static void do_exit(int i) { | static void do_exit(int i) { | |||
| /* unused variable */ | /* unused variable */ | |||
| (void) i; | (void) i; | |||
| do_cleanup(0); | do_cleanup(0); | |||
| exit(0); | exit(0); | |||
| } | } | |||
| CHANNEL *chan; | ssh_channel chan; | |||
| int signal_delayed=0; | int signal_delayed=0; | |||
| static void sigwindowchanged(int i){ | static void sigwindowchanged(int i){ | |||
| (void) i; | (void) i; | |||
| signal_delayed=1; | signal_delayed=1; | |||
| } | } | |||
| static void setsignal(void){ | static void setsignal(void){ | |||
| signal(SIGWINCH, sigwindowchanged); | signal(SIGWINCH, sigwindowchanged); | |||
| signal_delayed=0; | signal_delayed=0; | |||
| } | } | |||
| static void sizechanged(void){ | static void sizechanged(void){ | |||
| struct winsize win = { 0, 0, 0, 0 }; | struct winsize win = { 0, 0, 0, 0 }; | |||
| ioctl(1, TIOCGWINSZ, &win); | ioctl(1, TIOCGWINSZ, &win); | |||
| channel_change_pty_size(chan,win.ws_col, win.ws_row); | channel_change_pty_size(chan,win.ws_col, win.ws_row); | |||
| // printf("Changed pty size\n"); | // printf("Changed pty size\n"); | |||
| setsignal(); | setsignal(); | |||
| } | } | |||
| static void select_loop(SSH_SESSION *session,CHANNEL *channel){ | ||||
| /* There are two flavors of select loop: the one based on | ||||
| * ssh_select and the one based on channel_select. | ||||
| * The ssh_select one permits you to give your own file descriptors to | ||||
| * follow. It is thus a complete select loop. | ||||
| * The second one only selects on channels. It is simplier to use | ||||
| * but doesn't permit you to fill in your own file descriptor. It is | ||||
| * more adapted if you can't use ssh_select as a main loop (because | ||||
| * you already have another main loop system). | ||||
| */ | ||||
| #ifdef USE_CHANNEL_SELECT | ||||
| /* channel_select base main loop, with a standard select(2) | ||||
| */ | ||||
| static void select_loop(ssh_session session,ssh_channel channel){ | ||||
| fd_set fds; | fd_set fds; | |||
| struct timeval timeout; | struct timeval timeout; | |||
| char buffer[10]; | char buffer[4096]; | |||
| BUFFER *readbuf=buffer_new(); | ssh_buffer readbuf=buffer_new(); | |||
| CHANNEL *channels[2]; | ssh_channel channels[2]; | |||
| int lus; | int lus; | |||
| int eof=0; | int eof=0; | |||
| int maxfd; | int maxfd; | |||
| int ret; | int ret; | |||
| while(channel){ | while(channel){ | |||
| /* when a signal is caught, ssh_select will return | /* when a signal is caught, ssh_select will return | |||
| * with SSH_EINTR, which means it should be started | * with SSH_EINTR, which means it should be started | |||
| * again. It lets you handle the signal the faster you | * again. It lets you handle the signal the faster you | |||
| * can, like in this window changed example. Of course, if | * can, like in this window changed example. Of course, if | |||
| * your signal handler doesn't call libssh at all, you're | * your signal handler doesn't call libssh at all, you're | |||
| skipping to change at line 161 | skipping to change at line 220 | |||
| if(!eof) | if(!eof) | |||
| FD_SET(0,&fds); | FD_SET(0,&fds); | |||
| timeout.tv_sec=30; | timeout.tv_sec=30; | |||
| timeout.tv_usec=0; | timeout.tv_usec=0; | |||
| FD_SET(ssh_get_fd(session),&fds); | FD_SET(ssh_get_fd(session),&fds); | |||
| maxfd=ssh_get_fd(session)+1; | maxfd=ssh_get_fd(session)+1; | |||
| ret=select(maxfd,&fds,NULL,NULL,&timeout); | ret=select(maxfd,&fds,NULL,NULL,&timeout); | |||
| if(ret==EINTR) | if(ret==EINTR) | |||
| continue; | continue; | |||
| if(FD_ISSET(0,&fds)){ | if(FD_ISSET(0,&fds)){ | |||
| lus=read(0,buffer,10); | lus=read(0,buffer,sizeof(buffer)); | |||
| if(lus) | if(lus) | |||
| channel_write(channel,buffer,lus); | channel_write(channel,buffer,lus); | |||
| else { | else { | |||
| eof=1; | eof=1; | |||
| channel_send_eof(channel); | channel_send_eof(channel); | |||
| } | } | |||
| } | } | |||
| if(FD_ISSET(ssh_get_fd(session),&fds)){ | if(FD_ISSET(ssh_get_fd(session),&fds)){ | |||
| ssh_set_fd_toread(session); | ssh_set_fd_toread(session); | |||
| } | } | |||
| skipping to change at line 228 | skipping to change at line 287 | |||
| write(2,buffer_get(readbuf),lus); | write(2,buffer_get(readbuf),lus); | |||
| } | } | |||
| } | } | |||
| if(channel && channel_is_closed(channel)){ | if(channel && channel_is_closed(channel)){ | |||
| channel_free(channel); | channel_free(channel); | |||
| channel=NULL; | channel=NULL; | |||
| } | } | |||
| } | } | |||
| buffer_free(readbuf); | buffer_free(readbuf); | |||
| } | } | |||
| #else /* CHANNEL_SELECT */ | ||||
| static void select_loop(ssh_session session,ssh_channel channel){ | ||||
| fd_set fds; | ||||
| struct timeval timeout; | ||||
| char buffer[4096]; | ||||
| /* channels will be set to the channels to poll. | ||||
| * outchannels will contain the result of the poll | ||||
| */ | ||||
| ssh_channel channels[2], outchannels[2]; | ||||
| int lus; | ||||
| int eof=0; | ||||
| int maxfd; | ||||
| int ret; | ||||
| while(channel){ | ||||
| do{ | ||||
| FD_ZERO(&fds); | ||||
| if(!eof) | ||||
| FD_SET(0,&fds); | ||||
| timeout.tv_sec=30; | ||||
| timeout.tv_usec=0; | ||||
| FD_SET(ssh_get_fd(session),&fds); | ||||
| maxfd=ssh_get_fd(session)+1; | ||||
| channels[0]=channel; // set the first channel we wan | ||||
| t to read from | ||||
| channels[1]=NULL; | ||||
| ret=ssh_select(channels,outchannels,maxfd,&fds,&time | ||||
| out); | ||||
| if(signal_delayed) | ||||
| sizechanged(); | ||||
| if(ret==EINTR) | ||||
| continue; | ||||
| if(FD_ISSET(0,&fds)){ | ||||
| lus=read(0,buffer,sizeof(buffer)); | ||||
| if(lus) | ||||
| channel_write(channel,buffer,lus); | ||||
| else { | ||||
| eof=1; | ||||
| channel_send_eof(channel); | ||||
| } | ||||
| } | ||||
| if(channel && channel_is_closed(channel)){ | ||||
| ssh_log(session,SSH_LOG_RARE,"exit-status : | ||||
| %d\n",channel_get_exit_status(channel)); | ||||
| channel_free(channel); | ||||
| channel=NULL; | ||||
| channels[0]=NULL; | ||||
| } | ||||
| if(outchannels[0]){ | ||||
| while(channel && channel_is_open(channel) && | ||||
| channel_poll(channel,0)){ | ||||
| lus=channel_read(channel,buffer,size | ||||
| of(buffer),0); | ||||
| if(lus==-1){ | ||||
| fprintf(stderr, "Error readi | ||||
| ng channel: %s\n", | ||||
| ssh_get_erro | ||||
| r(session)); | ||||
| return; | ||||
| } | ||||
| if(lus==0){ | ||||
| ssh_log(session,SSH_LOG_RARE | ||||
| ,"EOF received\n"); | ||||
| ssh_log(session,SSH_LOG_RARE | ||||
| ,"exit-status : %d\n",channel_get_exit_status(channel)); | ||||
| channel_free(channel); | ||||
| channel=channels[0]=NULL; | ||||
| } else | ||||
| write(1,buffer,lus); | ||||
| } | ||||
| while(channel && channel_is_open(channel) && | ||||
| channel_poll(channel,1)){ /* stderr */ | ||||
| lus=channel_read(channel,buffer,size | ||||
| of(buffer),1); | ||||
| if(lus==-1){ | ||||
| fprintf(stderr, "Error readi | ||||
| ng channel: %s\n", | ||||
| ssh_get_erro | ||||
| r(session)); | ||||
| return; | ||||
| } | ||||
| if(lus==0){ | ||||
| ssh_log(session,SSH_LOG_RARE | ||||
| ,"EOF received\n"); | ||||
| ssh_log(session,SSH_LOG_RARE | ||||
| ,"exit-status : %d\n",channel_get_exit_status(channel)); | ||||
| channel_free(channel); | ||||
| channel=channels[0]=NULL; | ||||
| } else | ||||
| write(2,buffer,lus); | ||||
| } | ||||
| } | ||||
| if(channel && channel_is_closed(channel)){ | ||||
| channel_free(channel); | ||||
| channel=NULL; | ||||
| } | ||||
| } while (ret==EINTR || ret==SSH_EINTR); | ||||
| } | ||||
| } | ||||
| #endif | ||||
| static void shell(SSH_SESSION *session){ | static void shell(ssh_session session){ | |||
| CHANNEL *channel; | ssh_channel channel; | |||
| struct termios terminal_local; | struct termios terminal_local; | |||
| int interactive=isatty(0); | int interactive=isatty(0); | |||
| channel = channel_new(session); | channel = channel_new(session); | |||
| if(interactive){ | if(interactive){ | |||
| tcgetattr(0,&terminal_local); | tcgetattr(0,&terminal_local); | |||
| memcpy(&terminal,&terminal_local,sizeof(struct termios)); | memcpy(&terminal,&terminal_local,sizeof(struct termios)); | |||
| } | } | |||
| if(channel_open_session(channel)){ | if(channel_open_session(channel)){ | |||
| printf("error opening channel : %s\n",ssh_get_error(session)); | printf("error opening channel : %s\n",ssh_get_error(session)); | |||
| return; | return; | |||
| skipping to change at line 258 | skipping to change at line 406 | |||
| printf("Requesting shell : %s\n",ssh_get_error(session)); | printf("Requesting shell : %s\n",ssh_get_error(session)); | |||
| return; | return; | |||
| } | } | |||
| if(interactive){ | if(interactive){ | |||
| cfmakeraw(&terminal_local); | cfmakeraw(&terminal_local); | |||
| tcsetattr(0,TCSANOW,&terminal_local); | tcsetattr(0,TCSANOW,&terminal_local); | |||
| setsignal(); | setsignal(); | |||
| } | } | |||
| signal(SIGTERM,do_cleanup); | signal(SIGTERM,do_cleanup); | |||
| select_loop(session,channel); | select_loop(session,channel); | |||
| if(interactive) | ||||
| do_cleanup(0); | ||||
| } | } | |||
| static void batch_shell(SSH_SESSION *session){ | static void batch_shell(ssh_session session){ | |||
| CHANNEL *channel; | ssh_channel channel; | |||
| char buffer[1024]; | char buffer[1024]; | |||
| int i,s=0; | int i,s=0; | |||
| for(i=0;i<MAXCMD && cmds[i];++i) | for(i=0;i<MAXCMD && cmds[i];++i) | |||
| s+=snprintf(buffer+s,sizeof(buffer)-s,"%s ",cmds[i]); | s+=snprintf(buffer+s,sizeof(buffer)-s,"%s ",cmds[i]); | |||
| channel=channel_new(session); | channel=channel_new(session); | |||
| channel_open_session(channel); | channel_open_session(channel); | |||
| if(channel_request_exec(channel,buffer)){ | if(channel_request_exec(channel,buffer)){ | |||
| printf("error executing \"%s\" : %s\n",buffer,ssh_get_error(session )); | printf("error executing \"%s\" : %s\n",buffer,ssh_get_error(session )); | |||
| return; | return; | |||
| } | } | |||
| select_loop(session,channel); | select_loop(session,channel); | |||
| } | } | |||
| #ifdef WITH_SFTP | static int client(ssh_session session){ | |||
| /* it's just a proof of concept code for sftp, till i write a real document | int auth=0; | |||
| ation about it */ | char *banner; | |||
| void do_sftp(SSH_SESSION *session){ | int state; | |||
| SFTP_SESSION *sftp_session=sftp_new(session); | if (user) | |||
| SFTP_DIR *dir; | if (ssh_options_set(session, SSH_OPTIONS_USER, user) < 0) | |||
| SFTP_ATTRIBUTES *file; | return -1; | |||
| SFTP_FILE *fichier; | if (ssh_options_set(session, SSH_OPTIONS_HOST ,host) < 0) | |||
| SFTP_FILE *to; | return -1; | |||
| int len=1; | ||||
| int i; | ssh_options_parse_config(session, NULL); | |||
| char data[8000]; | ||||
| if(!sftp_session){ | if(ssh_connect(session)){ | |||
| fprintf(stderr, "sftp error initialising channel: %s\n", | fprintf(stderr,"Connection failed : %s\n",ssh_get_error(session)); | |||
| ssh_get_error(session)); | return -1; | |||
| return; | } | |||
| } | state=verify_knownhost(session); | |||
| if(sftp_init(sftp_session)){ | if (state != 0) | |||
| fprintf(stderr, "error initialising sftp: %s\n", | return -1; | |||
| ssh_get_error(session)); | ssh_userauth_none(session, NULL); | |||
| return; | banner=ssh_get_issue_banner(session); | |||
| } | if(banner){ | |||
| /* the connection is made */ | printf("%s\n",banner); | |||
| /* opening a directory */ | free(banner); | |||
| dir=sftp_opendir(sftp_session,"./"); | } | |||
| if(!dir) { | auth=authenticate_console(session); | |||
| fprintf(stderr, "Directory not opened(%s)\n", ssh_get_error(session | if(auth != SSH_AUTH_SUCCESS){ | |||
| )); | return -1; | |||
| return ; | } | |||
| } | ssh_log(session, SSH_LOG_FUNCTIONS, "Authentication success"); | |||
| /* reading the whole directory, file by file */ | if(!cmds[0]) | |||
| while((file=sftp_readdir(sftp_session,dir))){ | shell(session); | |||
| fprintf(stderr, "%30s(%.8o) : %.5d.%.5d : %.10llu bytes\n", | else | |||
| file->name, | batch_shell(session); | |||
| file->permissions, | return 0; | |||
| file->uid, | } | |||
| file->gid, | ||||
| (long long unsigned int) file->size); | #ifdef WITH_PCAP | |||
| sftp_attributes_free(file); | ssh_pcap_file pcap; | |||
| } | void set_pcap(ssh_session session); | |||
| /* when file=NULL, an error has occured OR the directory listing is end | void set_pcap(ssh_session session){ | |||
| of file */ | if(!pcap_file) | |||
| if(!sftp_dir_eof(dir)){ | return; | |||
| fprintf(stderr, "Error: %s\n", ssh_get_error(session)); | pcap=ssh_pcap_file_new(); | |||
| return; | if(ssh_pcap_file_open(pcap,pcap_file) == SSH_ERROR){ | |||
| } | printf("Error opening pcap file\n"); | |||
| if(sftp_closedir(dir)){ | ssh_pcap_file_free(pcap); | |||
| fprintf(stderr, "Error: %s\n", ssh_get_error(session)); | pcap=NULL; | |||
| return; | return; | |||
| } | } | |||
| /* this will open a file and copy it into your /home directory */ | ssh_set_pcap_file(session,pcap); | |||
| /* the small buffer size was intended to stress the library. of course, | } | |||
| you can use a buffer till 20kbytes without problem */ | ||||
| void cleanup_pcap(void); | ||||
| fichier=sftp_open(sftp_session,"/usr/bin/ssh",O_RDONLY, 0); | void cleanup_pcap(){ | |||
| if(!fichier){ | ssh_pcap_file_free(pcap); | |||
| fprintf(stderr, "Error opening /usr/bin/ssh: %s\n", | pcap=NULL; | |||
| ssh_get_error(session)); | ||||
| return; | ||||
| } | ||||
| /* open a file for writing... */ | ||||
| to=sftp_open(sftp_session,"ssh-copy",O_WRONLY | O_CREAT, 0); | ||||
| if(!to){ | ||||
| fprintf(stderr, "Error opening ssh-copy for writing: %s\n", | ||||
| ssh_get_error(session)); | ||||
| return; | ||||
| } | ||||
| while((len=sftp_read(fichier,data,4096)) > 0){ | ||||
| if(sftp_write(to,data,len)!=len){ | ||||
| fprintf(stderr, "Error writing %d bytes: %s\n", | ||||
| len, ssh_get_error(session)); | ||||
| return; | ||||
| } | ||||
| } | ||||
| printf("finished\n"); | ||||
| if(len<0) | ||||
| fprintf(stderr, "Error reading file: %s\n", ssh_get_error(session)) | ||||
| ; | ||||
| sftp_close(fichier); | ||||
| sftp_close(to); | ||||
| printf("fichiers ferm\n"); | ||||
| to=sftp_open(sftp_session,"/tmp/grosfichier",O_WRONLY|O_CREAT, 0644); | ||||
| for(i=0;i<1000;++i){ | ||||
| len=sftp_write(to,data,8000); | ||||
| printf("wrote %d bytes\n",len); | ||||
| if(len != 8000){ | ||||
| printf("chunk %d : %d (%s)\n",i,len,ssh_get_error(session)); | ||||
| } | ||||
| } | ||||
| sftp_close(to); | ||||
| /* close the sftp session */ | ||||
| sftp_free(sftp_session); | ||||
| printf("session sftp termin�\n"); | ||||
| } | } | |||
| #endif | #endif | |||
| static int auth_kbdint(SSH_SESSION *session){ | ||||
| int err=ssh_userauth_kbdint(session,NULL,NULL); | ||||
| const char *name, *instruction, *prompt; | ||||
| char *ptr; | ||||
| char buffer[128]; | ||||
| int i,n; | ||||
| char echo; | ||||
| while (err==SSH_AUTH_INFO){ | ||||
| name=ssh_userauth_kbdint_getname(session); | ||||
| instruction=ssh_userauth_kbdint_getinstruction(session); | ||||
| n=ssh_userauth_kbdint_getnprompts(session); | ||||
| if(strlen(name)>0) | ||||
| printf("%s\n",name); | ||||
| if(strlen(instruction)>0) | ||||
| printf("%s\n",instruction); | ||||
| for(i=0;i<n;++i){ | ||||
| prompt=ssh_userauth_kbdint_getprompt(session,i,&echo); | ||||
| if(echo){ | ||||
| printf("%s",prompt); | ||||
| fgets(buffer,sizeof(buffer),stdin); | ||||
| buffer[sizeof(buffer)-1]=0; | ||||
| if((ptr=strchr(buffer,'\n'))) | ||||
| *ptr=0; | ||||
| if (ssh_userauth_kbdint_setanswer(session,i,buffer) < 0) { | ||||
| return SSH_AUTH_ERROR; | ||||
| } | ||||
| memset(buffer,0,strlen(buffer)); | ||||
| } else { | ||||
| ptr=getpass(prompt); | ||||
| if (ssh_userauth_kbdint_setanswer(session,i,ptr) < 0) { | ||||
| return SSH_AUTH_ERROR; | ||||
| } | ||||
| } | ||||
| } | ||||
| err=ssh_userauth_kbdint(session,NULL,NULL); | ||||
| } | ||||
| return err; | ||||
| } | ||||
| int main(int argc, char **argv){ | int main(int argc, char **argv){ | |||
| SSH_SESSION *session; | ssh_session session; | |||
| SSH_OPTIONS *options; | ||||
| int auth=0; | ||||
| char *password; | ||||
| char *banner; | ||||
| char *hexa; | ||||
| int state; | ||||
| char buf[10]; | ||||
| unsigned char *hash = NULL; | ||||
| int hlen; | ||||
| options=ssh_options_new(); | ||||
| if(ssh_options_getopt(options,&argc, argv)){ | ||||
| fprintf(stderr,"error parsing command line :%s\n",ssh_get_error(opti | ||||
| ons)); | ||||
| usage(); | ||||
| } | ||||
| opts(argc,argv); | ||||
| signal(SIGTERM, do_exit); | ||||
| if (user) { | ||||
| if (ssh_options_set_username(options,user) < 0) { | ||||
| ssh_options_free(options); | ||||
| return 1; | ||||
| } | ||||
| } | ||||
| if (ssh_options_set_host(options,host) < 0) { | session = ssh_new(); | |||
| ssh_options_free(options); | ||||
| return 1; | ||||
| } | ||||
| session=ssh_new(); | ||||
| ssh_set_options(session,options); | ||||
| if(ssh_connect(session)){ | ||||
| fprintf(stderr,"Connection failed : %s\n",ssh_get_error(session)); | ||||
| ssh_disconnect(session); | ||||
| ssh_finalize(); | ||||
| return 1; | ||||
| } | ||||
| state=ssh_is_server_known(session); | ||||
| hlen = ssh_get_pubkey_hash(session, &hash); | ssh_callbacks_init(&cb); | |||
| if (hlen < 0) { | ssh_set_callbacks(session,&cb); | |||
| ssh_disconnect(session); | ||||
| ssh_finalize(); | ||||
| return 1; | ||||
| } | ||||
| switch(state){ | ||||
| case SSH_SERVER_KNOWN_OK: | ||||
| break; /* ok */ | ||||
| case SSH_SERVER_KNOWN_CHANGED: | ||||
| fprintf(stderr,"Host key for server changed : server's one is n | ||||
| ow :\n"); | ||||
| ssh_print_hexa("Public key hash",hash, hlen); | ||||
| free(hash); | ||||
| fprintf(stderr,"For security reason, connection will be stopped | ||||
| \n"); | ||||
| ssh_disconnect(session); | ||||
| ssh_finalize(); | ||||
| exit(-1); | ||||
| case SSH_SERVER_FOUND_OTHER: | ||||
| fprintf(stderr,"The host key for this server was not found but | ||||
| an other type of key exists.\n"); | ||||
| fprintf(stderr,"An attacker might change the default server key | ||||
| to confuse your client" | ||||
| "into thinking the key does not exist\n" | ||||
| "We advise you to rerun the client with -d or -r for more s | ||||
| afety.\n"); | ||||
| ssh_disconnect(session); | ||||
| ssh_finalize(); | ||||
| exit(-1); | ||||
| case SSH_SERVER_FILE_NOT_FOUND: | ||||
| fprintf(stderr,"Could not find known host file. If you accept t | ||||
| he host key here,\n"); | ||||
| fprintf(stderr,"the file will be automatically created.\n"); | ||||
| /* fallback to SSH_SERVER_NOT_KNOWN behaviour */ | ||||
| case SSH_SERVER_NOT_KNOWN: | ||||
| hexa = ssh_get_hexa(hash, hlen); | ||||
| fprintf(stderr,"The server is unknown. Do you trust the host ke | ||||
| y ?\n"); | ||||
| fprintf(stderr, "Public key hash: %s\n", hexa); | ||||
| free(hexa); | ||||
| fgets(buf,sizeof(buf),stdin); | ||||
| if(strncasecmp(buf,"yes",3)!=0){ | ||||
| ssh_disconnect(session); | ||||
| exit(-1); | ||||
| } | ||||
| fprintf(stderr,"This new key will be written on disk for furthe | ||||
| r usage. do you agree ?\n"); | ||||
| fgets(buf,sizeof(buf),stdin); | ||||
| if(strncasecmp(buf,"yes",3)==0){ | ||||
| if (ssh_write_knownhost(session) < 0) { | ||||
| free(hash); | ||||
| fprintf(stderr, "error %s\n", strerror(errno)); | ||||
| exit(-1); | ||||
| } | ||||
| } | ||||
| break; | if(ssh_options_getopt(session, &argc, argv)) { | |||
| case SSH_SERVER_ERROR: | fprintf(stderr, "error parsing command line :%s\n", | |||
| free(hash); | ssh_get_error(session)); | |||
| fprintf(stderr,"%s",ssh_get_error(session)); | usage(); | |||
| ssh_disconnect(session); | ||||
| ssh_finalize(); | ||||
| exit(-1); | ||||
| } | } | |||
| free(hash); | opts(argc,argv); | |||
| signal(SIGTERM, do_exit); | ||||
| ssh_userauth_none(session, NULL); | #ifdef WITH_PCAP | |||
| set_pcap(session); | ||||
| auth = ssh_auth_list(session); | ||||
| printf("auth: 0x%04x\n", auth); | ||||
| printf("supported auth methods: "); | ||||
| if (auth & SSH_AUTH_METHOD_PUBLICKEY) { | ||||
| printf("publickey"); | ||||
| } | ||||
| if (auth & SSH_AUTH_METHOD_INTERACTIVE) { | ||||
| printf(", keyboard-interactive"); | ||||
| } | ||||
| printf("\n"); | ||||
| /* no ? you should :) */ | ||||
| auth=ssh_userauth_autopubkey(session, NULL); | ||||
| if(auth==SSH_AUTH_ERROR){ | ||||
| fprintf(stderr,"Authenticating with pubkey: %s\n",ssh_get_error(ses | ||||
| sion)); | ||||
| ssh_finalize(); | ||||
| return -1; | ||||
| } | ||||
| banner=ssh_get_issue_banner(session); | ||||
| if(banner){ | ||||
| printf("%s\n",banner); | ||||
| free(banner); | ||||
| } | ||||
| if(auth!=SSH_AUTH_SUCCESS){ | ||||
| auth=auth_kbdint(session); | ||||
| if(auth==SSH_AUTH_ERROR){ | ||||
| fprintf(stderr,"authenticating with keyb-interactive: %s\n", | ||||
| ssh_get_error(session)); | ||||
| ssh_finalize(); | ||||
| return -1; | ||||
| } | ||||
| } | ||||
| if(auth!=SSH_AUTH_SUCCESS){ | ||||
| password=getpass("Password: "); | ||||
| if(ssh_userauth_password(session,NULL,password) != SSH_AUTH_SUCCESS | ||||
| ){ | ||||
| fprintf(stderr,"Authentication failed: %s\n",ssh_get_error(sess | ||||
| ion)); | ||||
| ssh_disconnect(session); | ||||
| ssh_finalize(); | ||||
| return -1; | ||||
| } | ||||
| memset(password,0,strlen(password)); | ||||
| } | ||||
| ssh_log(session, SSH_LOG_FUNCTIONS, "Authentication success"); | ||||
| if(strstr(argv[0],"sftp")){ | ||||
| sftp=1; | ||||
| ssh_log(session, SSH_LOG_FUNCTIONS, "Doing sftp instead"); | ||||
| } | ||||
| if(!sftp){ | ||||
| if(!cmds[0]) | ||||
| shell(session); | ||||
| else | ||||
| batch_shell(session); | ||||
| } | ||||
| #ifdef WITH_SFTP | ||||
| else | ||||
| do_sftp(session); | ||||
| #endif | #endif | |||
| if(!sftp && !cmds[0]) | client(session); | |||
| do_cleanup(0); | ||||
| ssh_disconnect(session); | ssh_disconnect(session); | |||
| ssh_free(session); | ||||
| #ifdef WITH_PCAP | ||||
| cleanup_pcap(); | ||||
| #endif | ||||
| ssh_finalize(); | ssh_finalize(); | |||
| return 0; | return 0; | |||
| } | } | |||
| End of changes. 26 change blocks. | ||||
| 316 lines changed or deleted | 258 lines changed or added | |||
This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/ | ||||