diff options
author | Aris Adamantiadis <aris@0xbadc0de.be> | 2009-07-25 17:03:01 +0200 |
---|---|---|
committer | Aris Adamantiadis <aris@0xbadc0de.be> | 2009-07-25 17:03:01 +0200 |
commit | a935ad1857b91b6aa179d14137f520d978647341 (patch) | |
tree | d86d4f8292843caca7f9155dba40261ea24146d8 | |
parent | 7abb3941c8858204f3d3bc2d59e17fa7b04489bf (diff) | |
download | libssh-a935ad1857b91b6aa179d14137f520d978647341.tar.gz libssh-a935ad1857b91b6aa179d14137f520d978647341.tar.xz libssh-a935ad1857b91b6aa179d14137f520d978647341.zip |
New example directory with the begining of a scp
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | examples/CMakeLists.txt | 15 | ||||
-rw-r--r-- | examples/authentication.c | 114 | ||||
-rw-r--r-- | examples/examples_common.h | 21 | ||||
-rw-r--r-- | examples/knownhosts.c | 97 | ||||
-rw-r--r-- | examples/libssh_scp.c | 220 |
6 files changed, 469 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ed88ae0..821bed4c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,6 +55,8 @@ configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) add_subdirectory(doc) add_subdirectory(include) add_subdirectory(libssh) +add_subdirectory(examples) +add_subdirectory(tests) # build samples include_directories(${CMAKE_SOURCE_DIR}/include) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 00000000..3f6dd063 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,15 @@ +project(libssh-library C) + +set(examples_SRCS + libssh_scp.c + authentication.c + knownhosts.c +) + +include_directories( + ${LIBSSH_PUBLIC_INCLUDE_DIRS} +) + +add_executable(libssh_scp ${examples_SRCS}) + +target_link_libraries(libssh_scp ${LIBSSH_SHARED_LIBRARY} ) diff --git a/examples/authentication.c b/examples/authentication.c new file mode 100644 index 00000000..06a0b713 --- /dev/null +++ b/examples/authentication.c @@ -0,0 +1,114 @@ +/* + * authentication.c + * This file contains an example of how to do an authentication to a + * SSH server using libssh + */ + +/* +Copyright 2003-2009 Aris Adamantiadis + +This file is part of the SSH Library + +You are free to copy this file, modify it in any way, consider it being public +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 +program. +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. + */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> + +#include <libssh/libssh.h> +#include "examples_common.h" + +int authenticate_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 authenticate_console(ssh_session session){ + int auth; + int methods; + char *password; + char *banner; + + ssh_userauth_none(session, NULL); + methods = ssh_auth_list(session); + printf("supported auth methods: "); + if (methods & SSH_AUTH_METHOD_PUBLICKEY) { + printf("publickey"); + } + if (methods & SSH_AUTH_METHOD_INTERACTIVE) { + printf(", keyboard-interactive"); + } + if (methods & SSH_AUTH_METHOD_PASSWORD) { + printf(", password"); + } + printf("\n"); + + auth=ssh_userauth_autopubkey(session, NULL); + if(auth==SSH_AUTH_ERROR){ + return auth; + } + banner=ssh_get_issue_banner(session); + if(banner){ + printf("%s\n",banner); + free(banner); + } + if(auth!=SSH_AUTH_SUCCESS && (methods & SSH_AUTH_METHOD_INTERACTIVE)){ + auth=authenticate_kbdint(session); + if(auth==SSH_AUTH_ERROR){ + return auth; + } + } + if(auth!=SSH_AUTH_SUCCESS && (methods & SSH_AUTH_METHOD_PASSWORD)){ + password=getpass("Password: "); + if(ssh_userauth_password(session,NULL,password) != SSH_AUTH_SUCCESS){ + return auth; + } + memset(password,0,strlen(password)); + } + if(auth==SSH_AUTH_SUCCESS) + ssh_log(session, SSH_LOG_FUNCTIONS, "Authentication success"); + if(auth==SSH_AUTH_PARTIAL) + return SSH_AUTH_DENIED; + return auth; +} diff --git a/examples/examples_common.h b/examples/examples_common.h new file mode 100644 index 00000000..55f5db7d --- /dev/null +++ b/examples/examples_common.h @@ -0,0 +1,21 @@ +/* +Copyright 2009 Aris Adamantiadis + +This file is part of the SSH Library + +You are free to copy this file, modify it in any way, consider it being public +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 +program. +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. +*/ +#ifndef EXAMPLES_COMMON_H_ +#define EXAMPLES_COMMON_H_ + +int authenticate_console(ssh_session session); +int authenticate_kbdint(ssh_session session); +int verify_knownhost(ssh_session session); + + +#endif /* EXAMPLES_COMMON_H_ */ diff --git a/examples/knownhosts.c b/examples/knownhosts.c new file mode 100644 index 00000000..bee9c91b --- /dev/null +++ b/examples/knownhosts.c @@ -0,0 +1,97 @@ +/* + * knownhosts.c + * This file contains an example of how verify the identity of a + * SSH server using libssh + */ + +/* +Copyright 2003-2009 Aris Adamantiadis + +This file is part of the SSH Library + +You are free to copy this file, modify it in any way, consider it being public +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 +program. +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. + */ + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <libssh/libssh.h> +#include "examples_common.h" + +int verify_knownhost(ssh_session session){ + char *hexa; + int state; + char buf[10]; + unsigned char *hash = NULL; + int hlen; + + state=ssh_is_server_known(session); + + hlen = ssh_get_pubkey_hash(session, &hash); + if (hlen < 0) { + 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 now :\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 safety.\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 the host key here,\n"); + fprintf(stderr,"the file will be automatically created.\n"); + /* fallback to SSH_SERVER_NOT_KNOWN behavior */ + case SSH_SERVER_NOT_KNOWN: + hexa = ssh_get_hexa(hash, hlen); + fprintf(stderr,"The server is unknown. Do you trust the host key ?\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 further 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; + case SSH_SERVER_ERROR: + free(hash); + fprintf(stderr,"%s",ssh_get_error(session)); + ssh_disconnect(session); + ssh_finalize(); + exit(-1); + } + free(hash); + return 0; +} diff --git a/examples/libssh_scp.c b/examples/libssh_scp.c new file mode 100644 index 00000000..b31c6c65 --- /dev/null +++ b/examples/libssh_scp.c @@ -0,0 +1,220 @@ +/* libssh_scp.c + * Sample implementation of a SCP client + */ + +/* +Copyright 2009 Aris Adamantiadis + +This file is part of the SSH Library + +You are free to copy this file, modify it in any way, consider it being public +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 +program. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include <libssh/libssh.h> +#include "examples_common.h" + +char *host; +char *user; +int sftp; + +static void usage(const char *argv0){ + fprintf(stderr,"Usage : %s [options] [login@]hostname\n" + "sample scp client - libssh-%s\n" + "Options :\n" + " -l user : log in as user\n" + " -p port : connect to port\n" + " -d : use DSS to verify host public key\n" + " -r : use RSA to verify host public key\n", + argv0, + ssh_version(0)); + exit(0); +} + +static int opts(int argc, char **argv){ + int i; + if(strstr(argv[0],"sftp")) + sftp=1; + // for(i=0;i<argc;i++) + // printf("%d : %s\n",i,argv[i]); + /* insert your own arguments here */ + while((i=getopt(argc,argv,""))!=-1){ + switch(i){ + default: + fprintf(stderr,"unknown option %c\n",optopt); + usage(argv[0]); + } + } + if(optind < argc) + host=argv[optind++]; + if(host==NULL) + usage(argv[0]); + return 0; +} + +ssh_channel chan; + +static void select_loop(SSH_SESSION *session,ssh_channel channel){ + fd_set fds; + struct timeval timeout; + char buffer[10]; + ssh_buffer readbuf=buffer_new(); + ssh_channel channels[2]; + int lus; + int eof=0; + int maxfd; + int ret; + while(channel){ + /* when a signal is caught, ssh_select will return + * with SSH_EINTR, which means it should be started + * again. It lets you handle the signal the faster you + * can, like in this window changed example. Of course, if + * your signal handler doesn't call libssh at all, you're + * free to handle signals directly in sighandler. + */ + 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; + ret=select(maxfd,&fds,NULL,NULL,&timeout); + if(ret==EINTR) + continue; + if(FD_ISSET(0,&fds)){ + lus=read(0,buffer,10); + if(lus) + channel_write(channel,buffer,lus); + else { + eof=1; + channel_send_eof(channel); + } + } + if(FD_ISSET(ssh_get_fd(session),&fds)){ + ssh_set_fd_toread(session); + } + channels[0]=channel; // set the first channel we want to read from + channels[1]=NULL; + ret=channel_select(channels,NULL,NULL,NULL); // no specific timeout - just poll + } while (ret==EINTR || ret==SSH_EINTR); + + // we already looked for input from stdin. Now, we are looking for input from the 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(channels[0]){ + while(channel && channel_is_open(channel) && channel_poll(channel,0)){ + lus=channel_read_buffer(channel,readbuf,0,0); + if(lus==-1){ + fprintf(stderr, "Error reading channel: %s\n", + ssh_get_error(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_get(readbuf),lus); + } + while(channel && channel_is_open(channel) && channel_poll(channel,1)){ /* stderr */ + lus=channel_read_buffer(channel,readbuf,0,1); + if(lus==-1){ + fprintf(stderr, "Error reading channel: %s\n", + ssh_get_error(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_get(readbuf),lus); + } + } + if(channel && channel_is_closed(channel)){ + channel_free(channel); + channel=NULL; + } + } + buffer_free(readbuf); +} + +static void batch_shell(ssh_session session){ + ssh_channel channel; + char buffer[1024]; + channel=channel_new(session); + channel_open_session(channel); + if(channel_request_exec(channel,buffer)){ + printf("error executing \"%s\" : %s\n",buffer,ssh_get_error(session)); + return; + } + select_loop(session,channel); +} + +int main(int argc, char **argv){ + SSH_SESSION *session; + SSH_OPTIONS *options; + int auth=0; + + + options=ssh_options_new(); + if(ssh_options_getopt(options,&argc, argv)){ + fprintf(stderr,"error parsing command line :%s\n",ssh_get_error(options)); + usage(argv[0]); + } + opts(argc,argv); + if (user) { + if (ssh_options_set_username(options,user) < 0) { + ssh_options_free(options); + return 1; + } + } + + if (ssh_options_set_host(options,host) < 0) { + 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; + } + if(verify_knownhost(session)<0){ + ssh_disconnect(session); + ssh_finalize(); + return 1; + } + auth=authenticate_console(session); + if(auth==SSH_AUTH_SUCCESS){ + batch_shell(session); + } else if(auth==SSH_AUTH_DENIED){ + fprintf(stderr,"Authentication failed\n"); + } else { + fprintf(stderr,"Error while authenticating : %s\n",ssh_get_error(session)); + } + ssh_disconnect(session); + ssh_finalize(); + + return 0; +} |