diff options
Diffstat (limited to 'kftpgrabber/src/misc/libs/ssh/client.c')
-rw-r--r-- | kftpgrabber/src/misc/libs/ssh/client.c | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/kftpgrabber/src/misc/libs/ssh/client.c b/kftpgrabber/src/misc/libs/ssh/client.c new file mode 100644 index 0000000..a7a7569 --- /dev/null +++ b/kftpgrabber/src/misc/libs/ssh/client.c @@ -0,0 +1,261 @@ +/* client.c file */ +/* +Copyright 2003 Aris Adamantiadis + +This file is part of the SSH Library + +The SSH Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +The SSH Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with the SSH Library; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, +MA 02110-1301, USA. */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <netdb.h> +#include "priv.h" +#include "ssh2.h" +static void ssh_cleanup(SSH_SESSION *session); +#define set_status(opt,status) do {\ + if (opt->connect_status_function) \ + opt->connect_status_function(opt->connect_status_arg, status); \ + } while (0) +/* simply gets a banner from a socket */ +char *ssh_get_banner(SSH_SESSION *session){ + char buffer[128]; + int i = 0; + while (i < 127) { + if(read(session->fd, &buffer[i], 1)<=0){ + ssh_set_error(session,SSH_CONNECTION_LOST,"Remote host closed connection"); + return NULL; + } + if (buffer[i] == '\r') + buffer[i] = 0; + if (buffer[i] == '\n') { + buffer[i] = 0; + return strdup(buffer); + } + i++; + } + ssh_set_error(NULL,SSH_FATAL,"Too large banner"); + return NULL; +} + +/* ssh_send_banner sends a SSH banner to the server */ +/* TODO select a banner compatible with server version */ +/* switch SSH1/1.5/2 */ +/* and quit when the server is SSH1 only */ + +void ssh_send_banner(SSH_SESSION *session){ + char *banner=CLIENTBANNER ; + char buffer[128]; + if(session->options->clientbanner) + banner=session->options->clientbanner; + session->clientbanner=strdup(banner); + snprintf(buffer,128,"%s\r\n",session->clientbanner); + write(session->fd,buffer,strlen(buffer)); +} + + +int dh_handshake(SSH_SESSION *session){ + STRING *e,*f,*pubkey,*signature; + packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH2_MSG_KEXDH_INIT); + dh_generate_x(session); + dh_generate_e(session); + e=dh_get_e(session); + buffer_add_ssh_string(session->out_buffer,e); + packet_send(session); + free(e); + if(packet_wait(session,SSH2_MSG_KEXDH_REPLY,1)) + return -1; + pubkey=buffer_get_ssh_string(session->in_buffer); + if(!pubkey){ + ssh_set_error(NULL,SSH_FATAL,"No public key in packet"); + return -1; + } + dh_import_pubkey(session,pubkey); + f=buffer_get_ssh_string(session->in_buffer); + if(!f){ + ssh_set_error(NULL,SSH_FATAL,"No F number in packet"); + return -1; + } + dh_import_f(session,f); + free(f); + if(!(signature=buffer_get_ssh_string(session->in_buffer))){ + ssh_set_error(NULL,SSH_FATAL,"No signature in packet"); + return -1; + } + + dh_build_k(session); + packet_wait(session,SSH2_MSG_NEWKEYS,1); + ssh_say(2,"Got SSH_MSG_NEWKEYS\n"); + packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH2_MSG_NEWKEYS); + packet_send(session); + ssh_say(2,"SSH_MSG_NEWKEYS sent\n"); + make_sessionid(session); + /* set the cryptographic functions for the next crypto (it is needed for generate_session_keys for key lenghts) */ + if(crypt_set_algorithms(session)) + return -1; + generate_session_keys(session); + /* verify the host's signature. XXX do it sooner */ + if(signature_verify(session,signature)){ + free(signature); + return -1; + } + free(signature); /* forget it for now ... */ + /* once we got SSH2_MSG_NEWKEYS we can switch next_crypto and current_crypto */ + if(session->current_crypto) + crypto_free(session->current_crypto); + /* XXX later, include a function to change keys */ + session->current_crypto=session->next_crypto; + session->next_crypto=crypto_new(); + return 0; +} + +int ssh_service_request(SSH_SESSION *session,char *service){ + STRING *service_s; + packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH2_MSG_SERVICE_REQUEST); + service_s=string_from_char(service); + buffer_add_ssh_string(session->out_buffer,service_s); + free(service_s); + packet_send(session); + ssh_say(3,"Sent SSH_MSG_SERVICE_REQUEST (service %s)\n",service); + if(packet_wait(session,SSH2_MSG_SERVICE_ACCEPT,1)){ + ssh_set_error(session,SSH_INVALID_DATA,"did not receive SERVICE_ACCEPT"); + return -1; + } + ssh_say(3,"Received SSH_MSG_SERVICE_ACCEPT (service %s)\n",service); + return 0; +} + +SSH_SESSION *ssh_connect(SSH_OPTIONS *options){ + SSH_SESSION *session; + int fd; + if(!options){ + ssh_set_error(NULL,SSH_FATAL,"Null argument given to ssh_connect !"); + return NULL; + } + ssh_crypto_init(); + if(options->fd==-1 && !options->host){ + ssh_set_error(NULL,SSH_FATAL,"Hostname required"); + return NULL; + } + if(options->fd != -1) + fd=options->fd; + else + fd=ssh_connect_host(options->host,options->bindaddr,options->port, + options->timeout,options->timeout_usec); + if(fd<0) + return NULL; + set_status(options,0.2); + session=ssh_session_new(); + session->fd=fd; + session->alive=1; + session->options=options; + if(!(session->serverbanner=ssh_get_banner(session))){ + ssh_cleanup(session); + return NULL; + } + set_status(options,0.4); + ssh_say(2,"banner : %s\n",session->serverbanner); + ssh_send_banner(session); + set_status(options,0.5); + if(ssh_get_kex(session,0)){ + ssh_disconnect(session); + return NULL; + } + set_status(options,0.6); + list_kex(&session->server_kex); + if(set_kex(session)){ + ssh_disconnect(session); + return NULL; + } + send_kex(session,0); + set_status(options,0.8); + if(dh_handshake(session)){ + ssh_disconnect(session); + return NULL; + } + set_status(options,1.0); + session->connected=1; + return session; +} + +static void ssh_cleanup(SSH_SESSION *session){ + int i; + if(session->serverbanner) + free(session->serverbanner); + if(session->clientbanner) + free(session->clientbanner); + if(session->in_buffer) + buffer_free(session->in_buffer); + if(session->out_buffer) + buffer_free(session->out_buffer); + if(session->banner) + free(session->banner); + if(session->options) + options_free(session->options); + if(session->current_crypto) + crypto_free(session->current_crypto); + if(session->next_crypto) + crypto_free(session->next_crypto); + + /* delete all channels */ + while(session->channels) + channel_free(session->channels); + if(session->client_kex.methods) + for(i=0;i<10;i++) + if(session->client_kex.methods[i]) + free(session->client_kex.methods[i]); + if(session->server_kex.methods) + for(i=0;i<10;++i) + if(session->server_kex.methods[i]) + free(session->server_kex.methods[i]); + free(session->client_kex.methods); + free(session->server_kex.methods); + memset(session,'X',sizeof(SSH_SESSION)); /* burn connection, it could hangs sensitive datas */ + free(session); +} + +char *ssh_get_issue_banner(SSH_SESSION *session){ + if(!session->banner) + return NULL; + return string_to_char(session->banner); +} + +void ssh_disconnect(SSH_SESSION *session){ + STRING *str; + if(session->fd!= -1) { + packet_clear_out(session); + buffer_add_u8(session->out_buffer,SSH2_MSG_DISCONNECT); + buffer_add_u32(session->out_buffer,htonl(SSH2_DISCONNECT_BY_APPLICATION)); + str=string_from_char("Bye Bye"); + buffer_add_ssh_string(session->out_buffer,str); + free(str); + packet_send(session); + close(session->fd); + session->fd=-1; + } + session->alive=0; + ssh_cleanup(session); +} + +const char *ssh_copyright(){ + return LIBSSH_VERSION " (c) 2003-2004 Aris Adamantiadis (aris@0xbadc0de.be)" + " Distributed under the LGPL, please refer to COPYING file for informations" + " about your rights" ; +} |