aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAris Adamantiadis <aris@0xbadc0de.be>2009-07-25 17:03:01 +0200
committerAris Adamantiadis <aris@0xbadc0de.be>2009-07-25 17:03:01 +0200
commita935ad1857b91b6aa179d14137f520d978647341 (patch)
treed86d4f8292843caca7f9155dba40261ea24146d8
parent7abb3941c8858204f3d3bc2d59e17fa7b04489bf (diff)
downloadlibssh-a935ad1857b91b6aa179d14137f520d978647341.tar.gz
libssh-a935ad1857b91b6aa179d14137f520d978647341.tar.xz
libssh-a935ad1857b91b6aa179d14137f520d978647341.zip
New example directory with the begining of a scp
-rw-r--r--CMakeLists.txt2
-rw-r--r--examples/CMakeLists.txt15
-rw-r--r--examples/authentication.c114
-rw-r--r--examples/examples_common.h21
-rw-r--r--examples/knownhosts.c97
-rw-r--r--examples/libssh_scp.c220
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;
+}