summaryrefslogtreecommitdiffstats
path: root/kftpgrabber/src/misc/libs/ssh
diff options
context:
space:
mode:
Diffstat (limited to 'kftpgrabber/src/misc/libs/ssh')
-rw-r--r--kftpgrabber/src/misc/libs/ssh/Makefile.am8
-rw-r--r--kftpgrabber/src/misc/libs/ssh/auth.c597
-rw-r--r--kftpgrabber/src/misc/libs/ssh/base64.c210
-rw-r--r--kftpgrabber/src/misc/libs/ssh/buffer.c161
-rw-r--r--kftpgrabber/src/misc/libs/ssh/channels.c691
-rw-r--r--kftpgrabber/src/misc/libs/ssh/client.c261
-rw-r--r--kftpgrabber/src/misc/libs/ssh/connect.c295
-rw-r--r--kftpgrabber/src/misc/libs/ssh/crypt.c100
-rw-r--r--kftpgrabber/src/misc/libs/ssh/crypto.h47
-rw-r--r--kftpgrabber/src/misc/libs/ssh/dh.c411
-rw-r--r--kftpgrabber/src/misc/libs/ssh/error.c67
-rw-r--r--kftpgrabber/src/misc/libs/ssh/gzip.c140
-rw-r--r--kftpgrabber/src/misc/libs/ssh/kex.c264
-rw-r--r--kftpgrabber/src/misc/libs/ssh/keyfiles.c341
-rw-r--r--kftpgrabber/src/misc/libs/ssh/keys.c353
-rw-r--r--kftpgrabber/src/misc/libs/ssh/libssh.h218
-rw-r--r--kftpgrabber/src/misc/libs/ssh/misc.c98
-rw-r--r--kftpgrabber/src/misc/libs/ssh/options.c341
-rw-r--r--kftpgrabber/src/misc/libs/ssh/packet.c303
-rw-r--r--kftpgrabber/src/misc/libs/ssh/priv.h384
-rw-r--r--kftpgrabber/src/misc/libs/ssh/sftp.c1289
-rw-r--r--kftpgrabber/src/misc/libs/ssh/sftp.h225
-rw-r--r--kftpgrabber/src/misc/libs/ssh/ssh2.h69
-rw-r--r--kftpgrabber/src/misc/libs/ssh/string.c65
-rw-r--r--kftpgrabber/src/misc/libs/ssh/wrapper.c241
25 files changed, 7179 insertions, 0 deletions
diff --git a/kftpgrabber/src/misc/libs/ssh/Makefile.am b/kftpgrabber/src/misc/libs/ssh/Makefile.am
new file mode 100644
index 0000000..91a0031
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/Makefile.am
@@ -0,0 +1,8 @@
+INCLUDES = $(all_includes)
+METASOURCES = AUTO
+noinst_LIBRARIES = libssh.a
+libssh_a_SOURCES = auth.c base64.c buffer.c channels.c client.c connect.c\
+ crypt.c dh.c error.c gzip.c kex.c keyfiles.c keys.c misc.c options.c\
+ packet.c sftp.c string.c wrapper.c
+noinst_HEADERS = crypto.h libssh.h sftp.h ssh2.h
+AM_CFLAGS = -w
diff --git a/kftpgrabber/src/misc/libs/ssh/auth.c b/kftpgrabber/src/misc/libs/ssh/auth.c
new file mode 100644
index 0000000..88ac7ec
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/auth.c
@@ -0,0 +1,597 @@
+/* auth.c deals with authentication methods */
+/*
+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 "priv.h"
+#include "ssh2.h"
+#include <string.h>
+#include <netdb.h>
+
+static int ask_userauth(SSH_SESSION *session){
+ if(session->auth_service_asked)
+ return 0;
+ else {
+ if(ssh_service_request(session,"ssh-userauth"))
+ return -1;
+ else
+ session->auth_service_asked++;
+ }
+ return 0;
+
+}
+
+static void burn(char *ptr){
+ if(ptr)
+ memset(ptr,'X',strlen(ptr));
+}
+
+static void string_burn(STRING *s){
+ memset(s->string,'X',string_len(s));
+}
+
+static int wait_auth_status(SSH_SESSION *session,int kbdint){
+ int err=SSH_AUTH_ERROR;
+ int cont=1;
+ STRING *can_continue;
+ u8 partial=0;
+ char *c_cont;
+ while(cont){
+ if(packet_read(session))
+ break;
+ if(packet_translate(session))
+ break;
+ switch(session->in_packet.type){
+ case SSH2_MSG_USERAUTH_FAILURE:
+ can_continue=buffer_get_ssh_string(session->in_buffer);
+ if(!can_continue || buffer_get_u8(session->in_buffer,&partial)!=1 ){
+ ssh_set_error(session,SSH_INVALID_DATA,"invalid SSH_MSG_USERAUTH_FAILURE message");
+ return SSH_AUTH_ERROR;
+ }
+ c_cont=string_to_char(can_continue);
+ if(partial){
+ err=SSH_AUTH_PARTIAL;
+ ssh_set_error(session,SSH_NO_ERROR,"partial success, authentications that can continue : %s",c_cont);
+ }
+ else {
+ err=SSH_AUTH_DENIED;
+ ssh_set_error(session,SSH_REQUEST_DENIED,"Access denied. authentications that can continue : %s",c_cont);
+ }
+ free(can_continue);
+ free(c_cont);
+ cont=0;
+ break;
+ case SSH2_MSG_USERAUTH_PK_OK:
+ /* SSH monkeys have defined the same number for both */
+ /* SSH_MSG_USERAUTH_PK_OK and SSH_MSG_USERAUTH_INFO_REQUEST */
+ /* which is not really smart; */
+ /*case SSH2_MSG_USERAUTH_INFO_REQUEST: */
+ if(kbdint){
+ err=SSH_AUTH_INFO;
+ cont=0;
+ break;
+ }
+ /* continue through success */
+ case SSH2_MSG_USERAUTH_SUCCESS:
+ err=SSH_AUTH_SUCCESS;
+ cont=0;
+ break;
+ case SSH2_MSG_USERAUTH_BANNER:
+ {
+ STRING *banner=buffer_get_ssh_string(session->in_buffer);
+ if(!banner){
+ ssh_say(1,"The banner message was invalid. continuing though\n");
+ break;
+ }
+ ssh_say(2,"Received a message banner\n");
+ if(session->banner)
+ free(session->banner); /* erase the older one */
+ session->banner=banner;
+ break;
+ }
+ default:
+ packet_parse(session);
+ break;
+ }
+ }
+ return err;
+}
+
+/* use the "none" authentication question */
+
+int ssh_userauth_none(SSH_SESSION *session,char *username){
+ STRING *user;
+ STRING *service;
+ STRING *method;
+ if(!username)
+ if(!(username=session->options->username)){
+ if(options_default_username(session->options))
+ return SSH_AUTH_ERROR;
+ else
+ username=session->options->username;
+ }
+ if(ask_userauth(session))
+ return SSH_AUTH_ERROR;
+ user=string_from_char(username);
+ method=string_from_char("none");
+ service=string_from_char("ssh-connection");
+ packet_clear_out(session);
+ buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST);
+ buffer_add_ssh_string(session->out_buffer,user);
+ buffer_add_ssh_string(session->out_buffer,service);
+ buffer_add_ssh_string(session->out_buffer,method);
+ free(service);
+ free(method);
+ free(user);
+ packet_send(session);
+ return wait_auth_status(session,0);
+}
+
+int ssh_userauth_offer_pubkey(SSH_SESSION *session, char *username,int type, STRING *publickey){
+ STRING *user;
+ STRING *service;
+ STRING *method;
+ STRING *algo;
+ int err=SSH_AUTH_ERROR;
+ if(!username)
+ if(!(username=session->options->username)){
+ if(options_default_username(session->options))
+ return SSH_AUTH_ERROR;
+ else
+ username=session->options->username;
+ }
+ if(ask_userauth(session))
+ return SSH_AUTH_ERROR;
+ user=string_from_char(username);
+ service=string_from_char("ssh-connection");
+ method=string_from_char("publickey");
+ algo=string_from_char(ssh_type_to_char(type));
+
+ packet_clear_out(session);
+ buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST);
+ buffer_add_ssh_string(session->out_buffer,user);
+ buffer_add_ssh_string(session->out_buffer,service);
+ buffer_add_ssh_string(session->out_buffer,method);
+ buffer_add_u8(session->out_buffer,0);
+ buffer_add_ssh_string(session->out_buffer,algo);
+ buffer_add_ssh_string(session->out_buffer,publickey);
+ packet_send(session);
+ err=wait_auth_status(session,0);
+ free(user);
+ free(method);
+ free(service);
+ free(algo);
+ return err;
+}
+
+int ssh_userauth_pubkey(SSH_SESSION *session, char *username, STRING *publickey, PRIVATE_KEY *privatekey){
+ STRING *user;
+ STRING *service;
+ STRING *method;
+ STRING *algo;
+ STRING *sign;
+ int err=SSH_AUTH_ERROR;
+ if(!username)
+ if(!(username=session->options->username)){
+ if(options_default_username(session->options))
+ return err;
+ else
+ username=session->options->username;
+ }
+ if(ask_userauth(session))
+ return err;
+ user=string_from_char(username);
+ service=string_from_char("ssh-connection");
+ method=string_from_char("publickey");
+ algo=string_from_char(ssh_type_to_char(privatekey->type));
+
+
+ /* we said previously the public key was accepted */
+ packet_clear_out(session);
+ buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST);
+ buffer_add_ssh_string(session->out_buffer,user);
+ buffer_add_ssh_string(session->out_buffer,service);
+ buffer_add_ssh_string(session->out_buffer,method);
+ buffer_add_u8(session->out_buffer,1);
+ buffer_add_ssh_string(session->out_buffer,algo);
+ buffer_add_ssh_string(session->out_buffer,publickey);
+ sign=ssh_do_sign(session,session->out_buffer,privatekey);
+ if(sign){
+ buffer_add_ssh_string(session->out_buffer,sign);
+ free(sign);
+ packet_send(session);
+ err=wait_auth_status(session,0);
+ }
+ free(user);
+ free(service);
+ free(method);
+ free(algo);
+ return err;
+}
+
+int ssh_userauth_password(SSH_SESSION *session,char *username,char *password){
+ STRING *user;
+ STRING *service;
+ STRING *method;
+ STRING *password_s;
+ int err;
+ if(!username)
+ if(!(username=session->options->username)){
+ if(options_default_username(session->options))
+ return SSH_AUTH_ERROR;
+ else
+ username=session->options->username;
+ }
+ if(ask_userauth(session))
+ return SSH_AUTH_ERROR;
+ user=string_from_char(username);
+ service=string_from_char("ssh-connection");
+ method=string_from_char("password");
+ password_s=string_from_char(password);
+
+ packet_clear_out(session);
+ buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST);
+ buffer_add_ssh_string(session->out_buffer,user);
+ buffer_add_ssh_string(session->out_buffer,service);
+ buffer_add_ssh_string(session->out_buffer,method);
+ buffer_add_u8(session->out_buffer,0);
+ buffer_add_ssh_string(session->out_buffer,password_s);
+ free(user);
+ free(service);
+ free(method);
+ memset(password_s,0,strlen(password)+4);
+ free(password_s);
+ packet_send(session);
+ err=wait_auth_status(session,0);
+ return err;
+}
+
+static char *keys_path[]={NULL,"%s/.ssh/identity","%s/.ssh/id_dsa","%s/.ssh/id_rsa",NULL};
+static char *pub_keys_path[]={NULL,"%s/.ssh/identity.pub","%s/.ssh/id_dsa.pub","%s/.ssh/id_rsa.pub",NULL};
+
+/* this function initialy was in the client */
+/* but the fools are the ones who never change mind */
+int ssh_userauth_autopubkey(SSH_SESSION *session, const char *passphrase){
+ int count=1; /* bypass identity */
+ int type=0;
+ int err;
+ STRING *pubkey;
+ char *privkeyfile=NULL;
+ PRIVATE_KEY *privkey;
+ char *id=NULL;
+ /* always testing none */
+ err=ssh_userauth_none(session,NULL);
+ if(err==SSH_AUTH_ERROR || err==SSH_AUTH_SUCCESS){
+ return err;
+ }
+ if(session->options->identity){
+ ssh_say(2,"Trying identity file %s\n",session->options->identity);
+ keys_path[0]=session->options->identity;
+ /* let's hope alloca exists */
+ id=malloc(strlen(session->options->identity)+1 + 4);
+ sprintf(id,"%s.pub",session->options->identity);
+ pub_keys_path[0]=id;
+ count =0;
+ }
+ while((pubkey=publickey_from_next_file(session,pub_keys_path,keys_path, &privkeyfile,&type,&count))){
+ err=ssh_userauth_offer_pubkey(session,NULL,type,pubkey);
+ if(err==SSH_AUTH_ERROR){
+ if(id){
+ pub_keys_path[0]=NULL;
+ keys_path[0]=NULL;
+ free(id);
+ }
+ free(pubkey);
+ return err;
+ } else
+ if(err != SSH_AUTH_SUCCESS){
+ ssh_say(2,"Public key refused by server\n");
+ free(pubkey);
+ continue;
+ }
+ /* pubkey accepted by server ! */
+ privkey=privatekey_from_file(session,privkeyfile,type,passphrase);
+ if (!privkey) {
+ free(pubkey);
+
+ if (passphrase == NULL) {
+ return -666;
+ }
+
+ ssh_say(0, "Private key decryption failed with the provided password (%s).\n", ssh_get_error(session));
+ continue;
+ }
+ err=ssh_userauth_pubkey(session,NULL,pubkey,privkey);
+ if(err==SSH_AUTH_ERROR){
+ if(id){
+ pub_keys_path[0]=NULL;
+ keys_path[0]=NULL;
+ free(id);
+ }
+ free(pubkey);
+ private_key_free(privkey);
+ return err;
+ } else
+ if(err != SSH_AUTH_SUCCESS){
+ ssh_say(0,"Weird : server accepted our public key but refused the signature\nit might be a bug of libssh\n");
+ free(pubkey);
+ private_key_free(privkey);
+ continue;
+ }
+ /* auth success */
+ ssh_say(1,"Authentication using %s success\n",privkeyfile);
+ free(pubkey);
+ private_key_free(privkey);
+ free(privkeyfile);
+ if(id){
+ pub_keys_path[0]=NULL;
+ keys_path[0]=NULL;
+ free(id);
+ }
+ return SSH_AUTH_SUCCESS;
+ }
+ ssh_say(1,"Tried every public key, none matched\n");
+ ssh_set_error(session,SSH_NO_ERROR,"no public key matched");
+ if(id){
+ pub_keys_path[0]=NULL;
+ keys_path[0]=NULL;
+ free(id);
+ }
+
+ return SSH_AUTH_DENIED;
+}
+
+static struct ssh_kbdint *kbdint_new(){
+ struct ssh_kbdint *kbd=malloc(sizeof (struct ssh_kbdint));
+ memset(kbd,0,sizeof(*kbd));
+ return kbd;
+}
+
+
+static void kbdint_free(struct ssh_kbdint *kbd){
+ int i,n=kbd->nprompts;
+ if(kbd->name)
+ free(kbd->name);
+ if(kbd->instruction)
+ free(kbd->instruction);
+ if(kbd->prompts){
+ for(i=0;i<n;++i){
+ burn(kbd->prompts[i]);
+ free(kbd->prompts[i]);
+ }
+ free(kbd->prompts);
+ }
+ if(kbd->answers){
+ for(i=0;i<n;++i){
+ burn(kbd->answers[i]);
+ free(kbd->answers[i]);
+ }
+ free(kbd->answers);
+ }
+ if(kbd->echo){
+ free(kbd->echo);
+ }
+ free(kbd);
+}
+
+static void kbdint_clean(struct ssh_kbdint *kbd){
+ int i,n=kbd->nprompts;
+ if(kbd->name){
+ free(kbd->name);
+ kbd->name=NULL;
+ }
+ if(kbd->instruction){
+ free(kbd->instruction);
+ kbd->instruction=NULL;
+ }
+ if(kbd->prompts){
+ for(i=0;i<n;++i){
+ burn(kbd->prompts[i]);
+ free(kbd->prompts[i]);
+ }
+ free(kbd->prompts);
+ kbd->prompts=NULL;
+ }
+ if(kbd->answers){
+ for(i=0;i<n;++i){
+ burn(kbd->answers[i]);
+ free(kbd->answers[i]);
+ }
+ free(kbd->answers);
+ kbd->answers=NULL;
+ }
+ if(kbd->echo){
+ free(kbd->echo);
+ kbd->echo=NULL;
+ }
+ kbd->nprompts=0;
+}
+
+/* this function sends the first packet as explained in section 3.1
+ * of the draft */
+static int kbdauth_init(SSH_SESSION *session,
+ char *user, char *submethods){
+ STRING *user_s=string_from_char(user);
+ STRING *submethods_s=(submethods ? string_from_char(submethods): string_from_char(""));
+ STRING *service=string_from_char("ssh-connection");
+ STRING *method=string_from_char("keyboard-interactive");
+ packet_clear_out(session);
+ buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST);
+ buffer_add_ssh_string(session->out_buffer,user_s);
+ buffer_add_ssh_string(session->out_buffer,service);
+ buffer_add_ssh_string(session->out_buffer,method);
+ buffer_add_u32(session->out_buffer,0); /* language tag */
+ buffer_add_ssh_string(session->out_buffer,submethods_s);
+ free(user_s);
+ free(service);
+ free(method);
+ free(submethods_s);
+ if(packet_send(session))
+ return SSH_AUTH_ERROR;
+ return wait_auth_status(session,1);
+}
+
+static int kbdauth_info_get(SSH_SESSION *session){
+ STRING *name; /* name of the "asking" window showed to client */
+ STRING *instruction;
+ STRING *tmp;
+ u32 nprompts;
+ int i;
+ name=buffer_get_ssh_string(session->in_buffer);
+ instruction=buffer_get_ssh_string(session->in_buffer);
+ tmp=buffer_get_ssh_string(session->in_buffer);
+ buffer_get_u32(session->in_buffer,&nprompts);
+ if(!name || !instruction || !tmp){
+ if(name)
+ free(name);
+ if(instruction)
+ free(instruction);
+ /* tmp must be empty if we got here */
+ ssh_set_error(session,SSH_FATAL,"Invalid USERAUTH_INFO_REQUEST msg");
+ return SSH_AUTH_ERROR;
+ }
+ if(tmp)
+ free(tmp); /* no use */
+ if(!session->kbdint)
+ session->kbdint=kbdint_new();
+ else
+ kbdint_clean(session->kbdint);
+ session->kbdint->name=string_to_char(name);
+ free(name);
+ session->kbdint->instruction=string_to_char(instruction);
+ free(instruction);
+ nprompts=ntohl(nprompts);
+ if(nprompts>KBDINT_MAX_PROMPT){
+ ssh_set_error(session,SSH_FATAL,"Too much prompt asked from server: %lu(0x%.8lx)",nprompts,nprompts);
+ return SSH_AUTH_ERROR;
+ }
+ session->kbdint->nprompts=nprompts;
+ session->kbdint->prompts=malloc(nprompts*sizeof(char *));
+ memset(session->kbdint->prompts,0,nprompts*sizeof(char *));
+ session->kbdint->echo=malloc(nprompts);
+ memset(session->kbdint->echo,0,nprompts);
+ for(i=0;i<nprompts;++i){
+ tmp=buffer_get_ssh_string(session->in_buffer);
+ buffer_get_u8(session->in_buffer,&session->kbdint->echo[i]);
+ if(!tmp){
+ ssh_set_error(session,SSH_FATAL,"Short INFO_REQUEST packet");
+ return SSH_AUTH_ERROR;
+ }
+ session->kbdint->prompts[i]=string_to_char(tmp);
+ free(tmp);
+ }
+ return SSH_AUTH_INFO; /* we are not auth. but we parsed the packet */
+}
+
+/* sends challenge back to the server */
+static int kbdauth_send(SSH_SESSION *session) {
+ STRING *answer;
+ int i;
+ packet_clear_out(session);
+ buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_INFO_RESPONSE);
+ buffer_add_u32(session->out_buffer,htonl(session->kbdint->nprompts));
+ for(i=0;i<session->kbdint->nprompts;++i){
+ if(session->kbdint->answers[i])
+ answer=string_from_char(session->kbdint->answers[i]);
+ else
+ answer=string_from_char("");
+ buffer_add_ssh_string(session->out_buffer,answer);
+ string_burn(answer);
+ free(answer);
+ }
+ if(packet_send(session))
+ return SSH_AUTH_ERROR;
+ return wait_auth_status(session,1);
+}
+
+/* the heart of the whole keyboard interactive login */
+int ssh_userauth_kbdint(SSH_SESSION *session,char *user,char *submethods){
+ int err;
+ if( !session->kbdint){
+ /* first time we call. we must ask for a challenge */
+ if(!user)
+ if(!(user=session->options->username)){
+ if(options_default_username(session->options))
+ return SSH_AUTH_ERROR;
+ else
+ user=session->options->username;
+ }
+ if(ask_userauth(session))
+ return SSH_AUTH_ERROR;
+ err=kbdauth_init(session,user,submethods);
+ if(err!=SSH_AUTH_INFO)
+ return err; /* error or first try success */
+ err=kbdauth_info_get(session);
+ if(err==SSH_AUTH_ERROR){
+ kbdint_free(session->kbdint);
+ session->kbdint=NULL;
+ }
+ return err;
+ }
+ /* if we are at this point, it's because session->kbdint exists */
+ /* it means the user has set some informations there we need to send *
+ * the server. and then we need to ack the status (new questions or ok *
+ * pass in */
+ err=kbdauth_send(session);
+ kbdint_free(session->kbdint);
+ session->kbdint=NULL;
+ if(err!=SSH_AUTH_INFO)
+ return err;
+ err=kbdauth_info_get(session);
+ if(err==SSH_AUTH_ERROR){
+ kbdint_free(session->kbdint);
+ session->kbdint=NULL;
+ }
+ return err;
+}
+
+int ssh_userauth_kbdint_getnprompts(SSH_SESSION *session){
+ return session->kbdint->nprompts;
+}
+
+char *ssh_userauth_kbdint_getname(SSH_SESSION *session){
+ return session->kbdint->name;
+}
+
+char *ssh_userauth_kbdint_getinstruction(SSH_SESSION *session){
+ return session->kbdint->instruction;
+}
+
+char *ssh_userauth_kbdint_getprompt(SSH_SESSION *session, int i,
+ char *echo){
+ if(i > session->kbdint->nprompts)
+ return NULL;
+ if(echo)
+ *echo=session->kbdint->echo[i];
+ return session->kbdint->prompts[i];
+}
+
+void ssh_userauth_kbdint_setanswer(SSH_SESSION *session, unsigned int i, char *answer){
+ if (i>session->kbdint->nprompts)
+ return;
+ if(!session->kbdint->answers){
+ session->kbdint->answers=malloc(sizeof(char*)*session->kbdint->nprompts);
+ memset(session->kbdint->answers,0,sizeof(char *) * session->kbdint->nprompts);
+ }
+ if(session->kbdint->answers[i]){
+ burn(session->kbdint->answers[i]);
+ free(session->kbdint->answers[i]);
+ }
+ session->kbdint->answers[i]=strdup(answer);
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/base64.c b/kftpgrabber/src/misc/libs/ssh/base64.c
new file mode 100644
index 0000000..19db420
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/base64.c
@@ -0,0 +1,210 @@
+/* base64 contains the needed support for base64 alphabet system, */
+/* as described in RFC1521 */
+/*
+Copyright 2003,04 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. */
+
+/* just the dirtiest part of code i ever made */
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "priv.h"
+static char alphabet[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+/" ;
+
+/* transformations */
+#define SET_A(n,i) do { n |= (i&63) <<18; } while (0)
+#define SET_B(n,i) do { n |= (i&63) <<12; } while (0)
+#define SET_C(n,i) do { n |= (i&63) << 6; } while (0)
+#define SET_D(n,i) do { n |= (i&63); } while (0)
+
+#define GET_A(n) ((n & 0xff0000) >> 16)
+#define GET_B(n) ((n & 0xff00) >> 8)
+#define GET_C(n) (n & 0xff)
+
+static int _base64_to_bin(unsigned char dest[3], char *source,int num);
+static int get_equals(char *string);
+
+/* first part : base 64 to binary */
+
+/* base64_to_bin translates a base64 string into a binary one. important, if something went wrong (ie incorrect char)*/
+/* it returns NULL */
+BUFFER *base64_to_bin(char *source){
+ int len;
+ int equals;
+ BUFFER *buffer=buffer_new();
+ unsigned char block[3];
+
+ /* get the number of equals signs, which mirrors the padding */
+ equals=get_equals(source);
+ if(equals>2){
+ buffer_free(buffer);
+ return NULL;
+ }
+
+ len=strlen(source);
+ while(len>4){
+ if(_base64_to_bin(block,source,3)){
+ buffer_free(buffer);
+ return NULL;
+ }
+ buffer_add_data(buffer,block,3);
+ len-=4;
+ source+=4;
+ }
+ /* depending of the number of bytes resting, there are 3 possibilities (from the rfc) */
+ switch(len){
+/* (1) the final quantum of encoding input is an integral
+ multiple of 24 bits; here, the final unit of encoded output will be
+ an integral multiple of 4 characters with no "=" padding */
+ case 4:
+ if(equals!=0){
+ buffer_free(buffer);
+ return NULL;
+ }
+ if(_base64_to_bin(block,source,3)){
+ buffer_free(buffer);
+ return NULL;
+ }
+ buffer_add_data(buffer,block,3);
+ return buffer;
+/*(2) the final quantum of encoding input is exactly 8 bits; here, the final
+ unit of encoded output will be two characters followed by two "="
+ padding characters */
+ case 2:
+ if(equals!=2){
+ buffer_free(buffer);
+ return NULL;
+ }
+ if(_base64_to_bin(block,source,1)){
+ buffer_free(buffer);
+ return NULL;
+ }
+ buffer_add_data(buffer,block,1);
+ return buffer;
+/* the final quantum of encoding input is
+ exactly 16 bits; here, the final unit of encoded output will be three
+ characters followed by one "=" padding character */
+ case 3:
+ if(equals!=1){
+ buffer_free(buffer);
+ return NULL;
+ }
+ if(_base64_to_bin(block,source,2)){
+ buffer_free(buffer);
+ return NULL;
+ }
+ buffer_add_data(buffer,block,2);
+ return buffer;
+ default:
+ /* 4,3,2 are the only padding size allowed */
+ buffer_free(buffer);
+ return NULL;
+ }
+ return NULL;
+}
+
+#define BLOCK(letter,n) do { ptr=strchr(alphabet,source[n]);\
+ if(!ptr) return -1;\
+ i=ptr-alphabet;\
+ SET_##letter(*block,i);\
+ } while(0)
+/* returns 0 if ok, -1 if not (ie invalid char into the stuff) */
+static int to_block4(unsigned long *block, char *source,int num){
+ char *ptr;
+ unsigned int i;
+ *block=0;
+ if(num<1)
+ return 0;
+ BLOCK(A,0); /* 6 bits */
+ BLOCK(B,1); /* 12 */
+ if(num<2)
+ return 0;
+ BLOCK(C,2); /* 18 */
+ if(num < 3)
+ return 0;
+ BLOCK(D,3); /* 24 */
+ return 0;
+}
+
+/* num = numbers of final bytes to be decoded */
+static int _base64_to_bin(unsigned char dest[3], char *source,int num){
+ unsigned long block;
+ if(to_block4(&block,source,num))
+ return -1;
+ dest[0]=GET_A(block);
+ dest[1]=GET_B(block);
+ dest[2]=GET_C(block);
+ return 0;
+}
+
+/* counts the number of "=" signs, and replace them by zeroes */
+static int get_equals(char *string){
+ char *ptr=string;
+ int num=0;
+ while((ptr=strchr(ptr,'='))){
+ num++;
+ *ptr=0;
+ ptr++;
+ }
+
+ return num;
+}
+
+/* thanks sysk for debugging my mess :) */
+#define BITS(n) ((1<<n)-1)
+static void _bin_to_base64(unsigned char *dest, unsigned char source[3], int len){
+ switch (len){
+ case 1:
+ dest[0]=alphabet[(source[0]>>2)];
+ dest[1]=alphabet[((source[0] & BITS(2)) << 4)];
+ dest[2]='=';
+ dest[3]='=';
+ break;
+ case 2:
+ dest[0]=alphabet[source[0]>>2];
+ dest[1]=alphabet[(source[1]>>4) | ((source[0] & BITS(2)) << 4)];
+ dest[2]=alphabet[(source[1]&BITS(4)) << 2];
+ dest[3]='=';
+ break;
+ case 3:
+ dest[0]=alphabet[(source[0]>>2)];
+ dest[1]=alphabet[(source[1]>>4) | ((source[0] & BITS(2)) << 4)];
+ dest[2]=alphabet[ (source[2] >> 6) | (source[1]&BITS(4)) << 2];
+ dest[3]=alphabet[source[2]&BITS(6)];
+ break;
+ }
+}
+
+char *bin_to_base64(unsigned char *source, int len){
+ int flen=len + (3 - (len %3)); /* round to upper 3 multiple */
+ char *buffer;
+ char *ptr;
+ flen=(4 * flen)/3 + 1 ;
+ ptr=buffer=malloc(flen);
+ while(len>0){
+ _bin_to_base64(ptr,source,len>3?3:len);
+ ptr+=4;
+ source +=3;
+ len -=3;
+ }
+ ptr[0]=0;
+ return buffer;
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/buffer.c b/kftpgrabber/src/misc/libs/ssh/buffer.c
new file mode 100644
index 0000000..8d54e3c
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/buffer.c
@@ -0,0 +1,161 @@
+/* buffer.c */
+/* Well, buffers */
+/*
+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 <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include "priv.h"
+BUFFER *buffer_new(){
+ BUFFER *buffer=malloc(sizeof(BUFFER));
+ memset(buffer,0,sizeof(BUFFER));
+ return buffer;
+ }
+
+void buffer_free(BUFFER *buffer){
+ if(buffer->data){
+ memset(buffer->data,0,buffer->allocated); /* burn the data */
+ free(buffer->data);
+ }
+ free(buffer);
+ }
+
+void buffer_reinit(BUFFER *buffer){
+ memset(buffer->data,0,buffer->used);
+ buffer->used=0;
+ buffer->pos=0;
+}
+
+static void realloc_buffer(BUFFER *buffer,int needed){
+ needed=(needed+0x7f) & ~0x7f;
+ buffer->data=realloc(buffer->data,needed);
+ buffer->allocated=needed;
+}
+
+void buffer_add_data(BUFFER *buffer,void *data,int len){
+ if(buffer->allocated < buffer->used+len)
+ realloc_buffer(buffer,buffer->used+len);
+ memcpy(buffer->data+buffer->used,data,len);
+ buffer->used+=len;
+ }
+
+void buffer_add_ssh_string(BUFFER *buffer,STRING *string){
+ u32 len=ntohl(string->size);
+ buffer_add_data(buffer,string,len+sizeof(u32));
+ }
+
+void buffer_add_u32(BUFFER *buffer,u32 data){
+ buffer_add_data(buffer,&data,sizeof(data));
+}
+
+void buffer_add_u64(BUFFER *buffer,u64 data){
+ buffer_add_data(buffer,&data,sizeof(data));
+}
+
+void buffer_add_u8(BUFFER *buffer,u8 data){
+ buffer_add_data(buffer,&data,sizeof(u8));
+}
+
+void buffer_add_data_begin(BUFFER *buffer, void *data, int len){
+ if(buffer->allocated < buffer->used + len)
+ realloc_buffer(buffer,buffer->used+len);
+ memmove(buffer->data+len,buffer->data,buffer->used);
+ memcpy(buffer->data,data,len);
+ buffer->used+=len;
+}
+
+void buffer_add_buffer(BUFFER *buffer, BUFFER *source){
+ buffer_add_data(buffer,buffer_get(source),buffer_get_len(source));
+}
+
+void *buffer_get(BUFFER *buffer){
+ return buffer->data;
+}
+
+void *buffer_get_rest(BUFFER *buffer){
+ return buffer->data+buffer->pos;
+}
+
+int buffer_get_len(BUFFER *buffer){
+ return buffer->used;
+}
+
+int buffer_get_rest_len(BUFFER *buffer){
+ return buffer->used - buffer->pos;
+}
+
+int buffer_pass_bytes(BUFFER *buffer,int len){
+ if(buffer->used < buffer->pos+len)
+ return 0;
+ buffer->pos+=len;
+ /* if the buffer is empty after having passed the whole bytes into it, we can clean it */
+ if(buffer->pos==buffer->used){
+ buffer->pos=0;
+ buffer->used=0;
+ }
+ return len;
+}
+
+int buffer_pass_bytes_end(BUFFER *buffer,int len){
+ if(buffer->used < buffer->pos + len)
+ return 0;
+ buffer->used-=len;
+ return len;
+}
+
+int buffer_get_data(BUFFER *buffer, void *data, int len){
+ if(buffer->pos+len>buffer->used)
+ return 0; /*no enough data in buffer */
+ memcpy(data,buffer->data+buffer->pos,len);
+ buffer->pos+=len;
+ return len; /* no yet support for partial reads (is it really needed ?? ) */
+}
+
+int buffer_get_u8(BUFFER *buffer, u8 *data){
+ return buffer_get_data(buffer,data,sizeof(u8));
+}
+
+int buffer_get_u32(BUFFER *buffer, u32 *data){
+ return buffer_get_data(buffer,data,sizeof(u32));
+}
+
+int buffer_get_u64(BUFFER *buffer, u64 *data){
+ return buffer_get_data(buffer,data,sizeof(u64));
+}
+
+STRING *buffer_get_ssh_string(BUFFER *buffer){
+ u32 stringlen;
+ u32 hostlen;
+ STRING *str;
+ if(buffer_get_u32(buffer,&stringlen)==0)
+ return NULL;
+ hostlen=ntohl(stringlen);
+ /* verify if there is enough space in buffer to get it */
+ if(buffer->pos+hostlen>buffer->used)
+ return 0; /* it is indeed */
+ str=string_new(hostlen);
+ if(buffer_get_data(buffer,str->string,hostlen)!=hostlen){
+ ssh_say(0,"buffer_get_ssh_string: oddish : second test failed when first was successful. len=%d",hostlen);
+ free(str);
+ return NULL;
+ }
+ return str;
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/channels.c b/kftpgrabber/src/misc/libs/ssh/channels.c
new file mode 100644
index 0000000..9dd94d4
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/channels.c
@@ -0,0 +1,691 @@
+/* channels.c */
+/* It has support for ... ssh channels */
+/*
+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 <string.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include "priv.h"
+#include "ssh2.h"
+#define WINDOWLIMIT 1024
+#define WINDOWBASE 32000
+static void channel_default_bufferize(CHANNEL *channel, void *data, int len, int is_stderr);
+static CHANNEL *new_channel(SSH_SESSION *session){
+ CHANNEL *channel=malloc(sizeof(CHANNEL));
+ memset(channel,0,sizeof(CHANNEL));
+ channel->session=session;
+ if(!session->channels){
+ session->channels=channel;
+ channel->next=channel->prev=channel;
+ return channel;
+ }
+ channel->next=session->channels;
+ channel->prev=session->channels->prev;
+ channel->next->prev=channel;
+ channel->prev->next=channel;
+ return channel;
+}
+
+static u32 channel_new_id(SSH_SESSION *session){
+ u32 ret=session->maxchannel;
+ session->maxchannel++;
+ return ret;
+}
+
+static CHANNEL *channel_open(SSH_SESSION *session,char *type_c,int window,
+int maxpacket,BUFFER *payload){
+ CHANNEL *channel=new_channel(session);
+ STRING *type=string_from_char(type_c);
+ u32 foo;
+ int err;
+ packet_clear_out(session);
+ buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_OPEN);
+ channel->local_channel=channel_new_id(session);
+ channel->local_maxpacket=maxpacket;
+ channel->local_window=window;
+ ssh_say(2,"creating a channel %d with %d window and %d max packet\n",channel->local_channel,
+ window,maxpacket);
+ buffer_add_ssh_string(session->out_buffer,type);
+ buffer_add_u32(session->out_buffer,htonl(channel->local_channel));
+ buffer_add_u32(session->out_buffer,htonl(channel->local_window));
+ buffer_add_u32(session->out_buffer,htonl(channel->local_maxpacket));
+ free(type);
+ if(payload)
+ buffer_add_buffer(session->out_buffer,payload);
+ packet_send(session);
+ ssh_say(2,"Sent a SSH_MSG_CHANNEL_OPEN type %s for channel %d\n",type_c,channel->local_channel);
+ err=packet_wait(session,SSH2_MSG_CHANNEL_OPEN_CONFIRMATION,1);
+ switch(session->in_packet.type){
+ case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:
+ buffer_get_u32(session->in_buffer,&foo);
+ if(channel->local_channel!=ntohl(foo)){
+ ssh_set_error(session,SSH_INVALID_DATA,"server answered with sender chan num %d instead of given %d",
+ ntohl(foo),channel->local_channel);
+ channel_free(channel);
+ return NULL;
+ }
+ buffer_get_u32(session->in_buffer,&foo);
+ channel->remote_channel=ntohl(foo);
+ buffer_get_u32(session->in_buffer,&foo);
+ channel->remote_window=ntohl(foo);
+ buffer_get_u32(session->in_buffer,&foo);
+ channel->remote_maxpacket=ntohl(foo);
+ ssh_say(3,"Received a CHANNEL_OPEN_CONFIRMATION for channel %d:%d\n",
+ channel->local_channel,channel->remote_channel);
+ ssh_say(3,"Remote window : %ld, maxpacket : %ld\n",
+ channel->remote_window, channel->remote_maxpacket);
+ channel->open=1;
+ return channel;
+ case SSH2_MSG_CHANNEL_OPEN_FAILURE:
+ {
+ u32 code;
+ STRING *error_s;
+ char *error;
+ buffer_get_u32(session->in_buffer,&foo);
+ buffer_get_u32(session->in_buffer,&code);
+ error_s=buffer_get_ssh_string(session->in_buffer);
+ error=string_to_char(error_s);
+ ssh_set_error(session,SSH_REQUEST_DENIED,"Channel opening failure : channel %d error (%d) %s",
+ channel->local_channel,ntohl(code),error);
+ free(error);
+ free(error_s);
+ channel_free(channel);
+ return NULL;
+ }
+ default:
+ ssh_say(0,"Received unknown packet %d\n",session->in_packet.type);
+ channel_free(channel);
+ return NULL;
+ }
+ return NULL;
+}
+
+static CHANNEL *find_local_channel(SSH_SESSION *session,u32 num){
+ /* we assume we are always the local */
+ CHANNEL *initchan,*channel;
+ initchan=session->channels;
+ if(!initchan)
+ return NULL;
+ for(channel=initchan;channel->local_channel!=num;channel=channel->next){
+ if(channel->next==initchan)
+ return NULL;
+ }
+ return channel;
+}
+
+static void grow_window(SSH_SESSION *session, CHANNEL *channel){
+ u32 new_window=WINDOWBASE;
+ packet_clear_out(session);
+ buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_WINDOW_ADJUST);
+ buffer_add_u32(session->out_buffer,htonl(channel->remote_channel));
+ buffer_add_u32(session->out_buffer,htonl(new_window));
+ packet_send(session);
+ ssh_say(3,"growing window (channel %d:%d) to %d bytes\n",
+ channel->local_channel,channel->remote_channel,
+ channel->local_window + new_window);
+ channel->local_window+=new_window;
+}
+
+static CHANNEL *channel_from_msg(SSH_SESSION *session){
+ u32 chan;
+ CHANNEL *channel;
+ if (buffer_get_u32(session->in_buffer,&chan)!=sizeof(u32)){
+ ssh_set_error(session,SSH_FATAL,"Getting channel from message : short read");
+ return NULL;
+ }
+ channel=find_local_channel(session,ntohl(chan));
+ if(!channel)
+ ssh_set_error(session,SSH_FATAL,"Server specified invalid channel %d",ntohl(chan));
+ return channel;
+}
+
+static void channel_rcv_change_window(SSH_SESSION *session){
+ u32 bytes;
+ CHANNEL *channel;
+ int err;
+ channel=channel_from_msg(session);
+ if(!channel)
+ ssh_say(0,"%s\n",ssh_get_error(session));
+ err = buffer_get_u32(session->in_buffer,&bytes);
+ if(!channel || err!= sizeof(u32)){
+ ssh_say(1,"Error getting a window adjust message : invalid packet\n");
+ return;
+ }
+ bytes=ntohl(bytes);
+ ssh_say(3,"Adding %d bytes to channel (%d:%d) (from %d bytes)\n",bytes,
+ channel->local_channel,channel->remote_channel,channel->remote_window);
+ channel->remote_window+=bytes;
+}
+
+/* is_stderr is set to 1 if the data are extended, ie stderr */
+static void channel_rcv_data(SSH_SESSION *session,int is_stderr){
+ STRING *str;
+ CHANNEL *channel;
+ channel=channel_from_msg(session);
+ if(!channel){
+ ssh_say(0,"%s",ssh_get_error(session));
+ return;
+ }
+ if(is_stderr){
+ u32 ignore;
+ /* uint32 data type code. we can ignore it */
+ buffer_get_u32(session->in_buffer,&ignore);
+ }
+ str=buffer_get_ssh_string(session->in_buffer);
+
+ if(!str){
+ ssh_say(0,"Invalid data packet !\n");
+ return;
+ }
+ ssh_say(3,"adding %d bytes data in %d\n",string_len(str),is_stderr);
+ /* what shall we do in this case ? let's accept it anyway */
+ if(string_len(str)>channel->local_window)
+ ssh_say(0,"Data packet too big for our window(%d vs %d)",string_len(str),channel->local_window);
+ if(!is_stderr){
+ /* stdout */
+ if(channel->write_fct){
+ channel->write_fct(channel,str->string,string_len(str),channel->userarg);
+ } else {
+ channel_default_bufferize(channel,str->string,string_len(str),is_stderr);
+ }
+ } else {
+ /* stderr */
+ if(channel->write_err_fct){
+ channel->write_err_fct(channel,str->string,string_len(str),channel->userarg);
+ } else {
+ channel_default_bufferize(channel,str->string,string_len(str),is_stderr);
+ }
+ }
+ if(string_len(str)>=channel->local_window)
+ channel->local_window-=string_len(str);
+ else
+ channel->local_window=0; /* buggy remote */
+ if(channel->local_window < WINDOWLIMIT)
+ grow_window(session,channel); /* i wonder if this is the correct place to do that */
+ free(str);
+}
+
+static void channel_rcv_eof(SSH_SESSION *session){
+ CHANNEL *channel;
+ channel=channel_from_msg(session);
+ if(!channel){
+ ssh_say(0,"%s\n",ssh_get_error(session));
+ return;
+ }
+ ssh_say(2,"Received eof on channel (%d:%d)\n",channel->local_channel,
+ channel->remote_channel);
+/* channel->remote_window=0; */
+ channel->remote_eof=1;
+}
+
+static void channel_rcv_close(SSH_SESSION *session){
+ CHANNEL *channel;
+ channel=channel_from_msg(session);
+ if(!channel){
+ ssh_say(0,"%s\n",ssh_get_error(session));
+ return;
+ }
+ ssh_say(2,"Received close on channel (%d:%d)\n",channel->local_channel,
+ channel->remote_channel);
+ channel->open=0;
+ if(!channel->remote_eof)
+ ssh_say(2,"Remote host not polite enough to send an eof before close\n");
+ channel->remote_eof=1;
+}
+
+static void channel_rcv_request(SSH_SESSION *session){
+ STRING *request_s;
+ char *request;
+ u32 status;
+ CHANNEL *channel=channel_from_msg(session);
+ if(!channel){
+ ssh_say(1,"%s\n",ssh_get_error(session));
+ return;
+ }
+ request_s=buffer_get_ssh_string(session->in_buffer);
+ if(!request_s){
+ ssh_say(0,"Invalid MSG_CHANNEL_REQUEST\n");
+ return;
+ }
+ buffer_get_u8(session->in_buffer,(u8 *)&status);
+ request=string_to_char(request_s);
+ if(!strcmp(request,"exit-status")){
+ buffer_get_u32(session->in_buffer,&status);
+ status=ntohl(status);
+/* XXX do something with status, we might need it */
+ free(request_s);
+ free(request);
+ return ;
+ }
+ if(!strcmp(request,"exit-signal")){
+ STRING *signal_s;
+ char *signal;
+ char *core="(core dumped)";
+ u8 i;
+ signal_s=buffer_get_ssh_string(session->in_buffer);
+ if(!signal_s){
+ ssh_say(0,"Invalid MSG_CHANNEL_REQUEST\n");
+ free(request_s);
+ free(request);
+ return;
+ }
+ signal=string_to_char(signal_s);
+ buffer_get_u8(session->in_buffer,&i);
+ if(!i)
+ core="";
+ ssh_say(0,"Remote connection closed by signal SIG%s %s\n",signal,core);
+ free(signal_s);
+ free(signal);
+ free(request_s);
+ free(request);
+ return;
+ }
+ ssh_say(0,"Unknown request %s\n",request);
+ free(request_s);
+ free(request);
+}
+
+/* channel_handle is called by wait_packet, ie, when there is channel informations to handle . */
+void channel_handle(SSH_SESSION *session, int type){
+ ssh_say(3,"Channel_handle(%d)\n",type);
+ switch(type){
+ case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
+ channel_rcv_change_window(session);
+ break;
+ case SSH2_MSG_CHANNEL_DATA:
+ channel_rcv_data(session,0);
+ break;
+ case SSH2_MSG_CHANNEL_EXTENDED_DATA:
+ channel_rcv_data(session,1);
+ break;
+ case SSH2_MSG_CHANNEL_EOF:
+ channel_rcv_eof(session);
+ break;
+ case SSH2_MSG_CHANNEL_CLOSE:
+ channel_rcv_close(session);
+ break;
+ case SSH2_MSG_CHANNEL_REQUEST:
+ channel_rcv_request(session);
+ break;
+ default:
+ ssh_say(0,"Unexpected message %d\n",type);
+ }
+}
+
+/* when data has been received from the ssh server, it can be applied to the known
+ user function, with help of the callback, or inserted here */
+/* XXX is the window changed ? */
+static void channel_default_bufferize(CHANNEL *channel, void *data, int len, int is_stderr){
+ ssh_say(3,"placing %d bytes into channel buffer (stderr=%d)\n",len,is_stderr);
+ if(!is_stderr){
+ /* stdout */
+ if(!channel->stdout_buffer)
+ channel->stdout_buffer=buffer_new();
+ buffer_add_data(channel->stdout_buffer,data,len);
+ } else {
+ /* stderr */
+ if(!channel->stderr_buffer)
+ channel->stderr_buffer=buffer_new();
+ buffer_add_data(channel->stderr_buffer,data,len);
+ }
+}
+
+
+/* --8<-- PUBLIC INTERFACE BEGINS HERE -8<-----8< --- */
+
+/* deprecated */
+CHANNEL *open_session_channel(SSH_SESSION *session,int window,int maxpacket){
+ CHANNEL *chan=channel_open(session,"session",window,maxpacket,NULL);
+ return chan;
+}
+
+CHANNEL *channel_open_session(SSH_SESSION *session){
+ return open_session_channel(session,64000,32000);
+}
+
+/* tcpip forwarding */
+CHANNEL *channel_open_forward(SSH_SESSION *session,char *remotehost, int remoteport, char *sourcehost, int localport){
+ CHANNEL *chan;
+ BUFFER *payload=buffer_new();
+ STRING *str=string_from_char(remotehost);
+ buffer_add_ssh_string(payload,str);
+ free(str);
+ str=string_from_char(sourcehost);
+ buffer_add_u32(payload,htonl(remoteport));
+ buffer_add_ssh_string(payload,str);
+ free(str);
+ buffer_add_u32(payload,htonl(localport));
+ chan=channel_open(session,"direct-tcpip",64000,32000,payload);
+ buffer_free(payload);
+ return chan;
+}
+
+
+void channel_free(CHANNEL *channel){
+ SSH_SESSION *session=channel->session;
+ if(session->alive && channel->open)
+ channel_close(channel);
+ /* handle the "my channel is first on session list" case */
+ if(session->channels==channel)
+ session->channels=channel->next;
+ /* handle the "my channel is the only on session list" case */
+ if(channel->next == channel){
+ session->channels=NULL;
+ } else {
+ channel->prev->next=channel->next;
+ channel->next->prev=channel->prev;
+ }
+ if(channel->stdout_buffer)
+ buffer_free(channel->stdout_buffer);
+ if(channel->stderr_buffer)
+ buffer_free(channel->stderr_buffer);
+ /* debug trick to catch use after frees */
+ memset(channel,'X',sizeof(CHANNEL));
+ free(channel);
+}
+
+int channel_send_eof(CHANNEL *channel){
+ SSH_SESSION *session=channel->session;
+ int ret;
+ packet_clear_out(session);
+ buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_EOF);
+ buffer_add_u32(session->out_buffer,htonl(channel->remote_channel));
+ ret=packet_send(session);
+ ssh_say(1,"Sent a EOF on client channel (%d:%d)\n",channel->local_channel,
+ channel->remote_channel);
+ channel->local_eof=1;
+ return ret;
+}
+
+int channel_close(CHANNEL *channel){
+ SSH_SESSION *session=channel->session;
+ int ret=0;
+ if(!channel->local_eof)
+ ret=channel_send_eof(channel);
+ if(ret)
+ return ret;
+ packet_clear_out(session);
+ buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_CLOSE);
+ buffer_add_u32(session->out_buffer,htonl(channel->remote_channel));
+ ret=packet_send(session);
+ ssh_say(1,"Sent a close on client channel (%d:%d)\n",channel->local_channel,
+ channel->remote_channel);
+ if(!ret)
+ channel->open =0;
+ return ret;
+}
+
+/* Blocking write */
+/* The exact len is written */
+int channel_write(CHANNEL *channel ,void *data,int len){
+ SSH_SESSION *session=channel->session;
+ int effectivelen;
+ int origlen=len;
+ if(channel->local_eof){
+ ssh_set_error(session,SSH_REQUEST_DENIED,"Can't write to channel %d:%d"
+ " after EOF was sent",channel->local_channel,channel->remote_channel);
+ return -1;
+ }
+ while(len >0){
+ if(channel->remote_window<len){
+ ssh_say(2,"Remote window is %d bytes. going to write %d bytes\n",
+ channel->remote_window,len);
+ ssh_say(2,"Waiting for a growing window message...\n");
+ /* wonder what happens when the channel window is zero */
+ while(channel->remote_window==0){
+ /* parse every incoming packet */
+ packet_wait(channel->session,0,0);
+ }
+ effectivelen=len>channel->remote_window?channel->remote_window:len;
+ } else
+ effectivelen=len;
+ packet_clear_out(session);
+ buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_DATA);
+ buffer_add_u32(session->out_buffer,htonl(channel->remote_channel));
+ buffer_add_u32(session->out_buffer,htonl(effectivelen));
+ buffer_add_data(session->out_buffer,data,effectivelen);
+ packet_send(session);
+ ssh_say(2,"channel_write wrote %d bytes\n",effectivelen);
+ channel->remote_window-=effectivelen;
+ len -= effectivelen;
+ data+=effectivelen;
+ }
+ return origlen;
+}
+
+int channel_is_open(CHANNEL *channel){
+ return (channel->open!=0);
+}
+
+
+static int channel_request(CHANNEL *channel,char *request, BUFFER *buffer,int reply){
+ STRING *request_s=string_from_char(request);
+ SSH_SESSION *session=channel->session;
+ int err;
+ packet_clear_out(session);
+ buffer_add_u8(session->out_buffer,SSH2_MSG_CHANNEL_REQUEST);
+ buffer_add_u32(session->out_buffer,htonl(channel->remote_channel));
+ buffer_add_ssh_string(session->out_buffer,request_s);
+ buffer_add_u8(session->out_buffer,reply?1:0);
+ if(buffer)
+ buffer_add_data(session->out_buffer,buffer_get(buffer),buffer_get_len(buffer));
+ packet_send(session);
+ ssh_say(3,"Sent a SSH_MSG_CHANNEL_REQUEST %s\n",request);
+ free(request_s);
+ if(!reply)
+ return 0;
+ err=packet_wait(session,SSH2_MSG_CHANNEL_SUCCESS,1);
+ if(err)
+ if(session->in_packet.type==SSH2_MSG_CHANNEL_FAILURE){
+ ssh_say(2,"%s channel request failed\n",request);
+ ssh_set_error(session,SSH_REQUEST_DENIED,"Channel request %s failed",request);
+ }
+ else
+ ssh_say(3,"Received an unexpected %d message\n",session->in_packet.type);
+ else
+ ssh_say(3,"Received a SUCCESS\n");
+ return err;
+}
+
+int channel_request_pty_size(CHANNEL *channel, char *terminal, int col, int row){
+ STRING *term=string_from_char(terminal);
+ BUFFER *buffer=buffer_new();
+ int err;
+ buffer_add_ssh_string(buffer,term);
+ buffer_add_u32(buffer,htonl(col));
+ buffer_add_u32(buffer,htonl(row));
+ buffer_add_u32(buffer,0);
+ buffer_add_u32(buffer,0);
+/* a 0byte string */
+ buffer_add_u32(buffer,htonl(1));
+ buffer_add_u8(buffer,0);
+ free(term);
+ err=channel_request(channel,"pty-req",buffer,1);
+ buffer_free(buffer);
+ return err;
+}
+
+int channel_request_pty(CHANNEL *channel){
+ return channel_request_pty_size(channel,"xterm",80,24);
+}
+
+int channel_change_pty_size(CHANNEL *channel,int cols,int rows){
+ BUFFER *buffer=buffer_new();
+ int err;
+ /*buffer_add_u8(buffer,0);*/
+ buffer_add_u32(buffer,htonl(cols));
+ buffer_add_u32(buffer,htonl(rows));
+ buffer_add_u32(buffer,0);
+ buffer_add_u32(buffer,0);
+ err=channel_request(channel,"window-change",buffer,0);
+ buffer_free(buffer);
+ return err;
+}
+
+int channel_request_shell(CHANNEL *channel){
+ int err=channel_request(channel,"shell",NULL,1);
+ return err;
+}
+
+int channel_request_subsystem(CHANNEL *channel, char *system){
+ BUFFER* buffer=buffer_new();
+ int ret;
+ STRING *subsystem=string_from_char(system);
+ buffer_add_ssh_string(buffer,subsystem);
+ free(subsystem);
+ ret=channel_request(channel,"subsystem",buffer,1);
+ buffer_free(buffer);
+ return ret;
+}
+
+int channel_request_sftp( CHANNEL *channel){
+ return channel_request_subsystem(channel, "sftp");
+}
+
+
+int channel_request_env(CHANNEL *channel,char *name, char *value){
+ BUFFER *buffer=buffer_new();
+ int ret;
+ STRING *string=string_from_char(name);
+ buffer_add_ssh_string(buffer,string);
+ free(string);
+ string=string_from_char(value);
+ buffer_add_ssh_string(buffer,string);
+ free(string);
+ ret=channel_request(channel,"env",buffer,1);
+ buffer_free(buffer);
+ return ret;
+}
+
+int channel_request_exec(CHANNEL *channel, char *cmd){
+ BUFFER *buffer=buffer_new();
+ int ret;
+ STRING *command=string_from_char(cmd);
+ buffer_add_ssh_string(buffer,command);
+ free(command);
+ ret=channel_request(channel,"exec",buffer,1);
+ buffer_free(buffer);
+ return ret;
+}
+
+int channel_set_write_handler(CHANNEL *chan,
+ void (*write_fct)(CHANNEL *channel, void *data, int len, void *userdefined),void *user){
+ chan->write_fct=write_fct;
+ chan->userarg=user;
+ return 0;
+}
+
+int channel_set_stderr_write_handler(CHANNEL *chan,
+ void (*write_err_fct)(CHANNEL *channel, void *data, int len, void *userdefined),void *user){
+ chan->write_err_fct=write_err_fct;
+ chan->userarg=user;
+ return 0;
+}
+
+
+/* reads into a channel and put result into buffer */
+/* returns number of bytes read, 0 if eof or such and -1 in case of error */
+/* if bytes != 0, the exact number of bytes are going to be read */
+int channel_read(CHANNEL *channel, BUFFER *buffer,int bytes,int is_stderr){
+ BUFFER *stdbuf=NULL;
+ int len;
+ buffer_reinit(buffer);
+ /* maybe i should always set a buffer to avoid races between channel_default_bufferize and channel_read */
+ if(channel->write_fct){
+ ssh_set_error(channel->session,SSH_INVALID_REQUEST,"Specified channel hasn't got a default buffering system\n");
+ return -1;
+ }
+ if(is_stderr){
+ if(!channel->stderr_buffer)
+ channel->stderr_buffer=buffer_new();
+ stdbuf=channel->stderr_buffer;
+ } else {
+ if(!channel->stdout_buffer)
+ channel->stdout_buffer=buffer_new();
+ stdbuf=channel->stdout_buffer;
+ }
+ /* block reading if asked bytes=0 */
+ while((buffer_get_rest_len(stdbuf)==0) || (buffer_get_rest_len(stdbuf) < bytes)){
+ if(channel->remote_eof && buffer_get_rest_len(stdbuf)==0)
+ return 0;
+ if(channel->remote_eof)
+ break; /* return the resting bytes in buffer */
+ if(packet_read(channel->session)||packet_translate(channel->session))
+ return -1;
+ packet_parse(channel->session);
+ }
+
+ if(bytes==0){
+ /* write the ful buffer informations */
+ buffer_add_data(buffer,buffer_get_rest(stdbuf),buffer_get_rest_len(stdbuf));
+ buffer_reinit(stdbuf);
+ } else {
+ len=buffer_get_rest_len(stdbuf);
+ len= (len>bytes?bytes:len); /* read bytes bytes if len is greater, everything otherwise */
+ buffer_add_data(buffer,buffer_get_rest(stdbuf),len);
+ buffer_pass_bytes(stdbuf,len);
+ }
+ return buffer_get_len(buffer);
+}
+
+/* returns the number of bytes available, 0 if nothing is currently available, -1 if error */
+int channel_poll(CHANNEL *channel, int is_stderr){
+ BUFFER *buffer;
+ if(is_stderr){
+ buffer=channel->stderr_buffer;
+ if(!buffer)
+ buffer=channel->stderr_buffer=buffer_new();
+ } else {
+ buffer=channel->stdout_buffer;
+ if(!buffer)
+ buffer=channel->stdout_buffer=buffer_new();
+ }
+ while(buffer_get_len(buffer)==0){
+ if(ssh_fd_poll(channel->session)){
+ if(packet_read(channel->session)||packet_translate(channel->session))
+ return -1;
+ packet_parse(channel->session);
+ } else
+ return 0; /* nothing is available has said fd_poll */
+ }
+ return buffer_get_len(buffer);
+}
+
+/* nonblocking read on the specified channel. it will return <=len bytes of data read
+ atomicly. */
+int channel_read_nonblocking(CHANNEL *channel, char *dest, int len, int is_stderr){
+ int to_read=channel_poll(channel,is_stderr);
+ int lu;
+ BUFFER *buffer=buffer_new();
+ if(to_read<=0){
+ buffer_free(buffer);
+ return to_read; /* may be an error code */
+ }
+ if(to_read>len)
+ to_read=len;
+ lu=channel_read(channel,buffer,to_read,is_stderr);
+ memcpy(dest,buffer_get(buffer),lu>=0?lu:0);
+ buffer_free(buffer);
+ return lu;
+}
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" ;
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/connect.c b/kftpgrabber/src/misc/libs/ssh/connect.c
new file mode 100644
index 0000000..ba117f2
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/connect.c
@@ -0,0 +1,295 @@
+/* connect.c */
+/* it handles connections to ssh servers */
+/*
+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 <netdb.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <fcntl.h>
+#include "priv.h"
+#ifdef HAVE_SYS_POLL_H
+#include <sys/poll.h>
+#endif
+
+#ifndef HAVE_GETHOSTBYNAME
+#ifndef HAVE_GETHOSTBYADDR
+#error "your system doesn't have gethostbyname nor gethostbyaddr"
+#endif
+#endif
+#define FIRST_CHANNEL 42
+static void sock_set_nonblocking(int sock) {
+ fcntl(sock,F_SETFL,O_NONBLOCK);
+}
+static void sock_set_blocking(int sock){
+ fcntl(sock,F_SETFL,0);
+}
+
+/* connect_host connects to an IPv4 (or IPv6) host */
+/* specified by its IP address or hostname. */
+/* output is the file descriptor, <0 if failed. */
+
+int ssh_connect_host(const char *host, const char *bind_addr, int port,long timeout, long usec){
+ struct sockaddr_in sa;
+ struct sockaddr_in bindsa;
+ struct hostent *hp=NULL;
+ static int count=0; /* for reentrencity */
+ int s;
+ while(++count>1)
+ --count;
+#ifdef HAVE_GETHOSTBYADDR
+ hp=gethostbyaddr(host,4,AF_INET);
+#endif
+#ifdef HAVE_GETHOSTBYNAME
+ if(!hp)
+ hp=gethostbyname(host);
+#endif
+ if(!hp){
+ --count;
+ ssh_set_error(NULL,SSH_FATAL,"Failed to resolve hostname %s (%s)",host,hstrerror(h_errno));
+ return -1;
+ }
+ memset(&sa,0,sizeof(sa));
+ memcpy(&sa.sin_addr,hp->h_addr,hp->h_length);
+ sa.sin_family=hp->h_addrtype;
+ sa.sin_port=htons((unsigned short)port);
+ --count;
+
+ if(bind_addr){
+ ssh_say(2,"resolving %s\n",bind_addr);
+ hp=NULL;
+ while(++count>1)
+ --count;
+#ifdef HAVE_GETHOSTBYADDR
+ hp=gethostbyaddr(bind_addr,4,AF_INET);
+#endif
+#ifdef HAVE_GETHOSTBYNAME
+ if(!hp)
+ hp=gethostbyname(bind_addr);
+#endif
+ if(!hp){
+ --count;
+ ssh_set_error(NULL,SSH_FATAL,"Failed to resolve bind address %s (%s)",bind_addr,hstrerror(h_errno));
+ return -1;
+ }
+ }
+ memset(&bindsa,0,sizeof(bindsa));
+ /* create socket */
+ s=socket(sa.sin_family,SOCK_STREAM,0);
+ if(s<0){
+ if(bind_addr)
+ --count;
+ ssh_set_error(NULL,SSH_FATAL,"socket : %s",strerror(errno));
+ return s;
+ }
+
+ if(bind_addr){
+ memcpy(&bindsa.sin_addr,hp->h_addr,hp->h_length);
+ bindsa.sin_family=hp->h_addrtype;
+ --count;
+ if(bind(s,(struct sockaddr *)&bindsa,sizeof(bindsa))<0){
+ ssh_set_error(NULL,SSH_FATAL,"Binding local address : %s",strerror(errno));
+ close(s);
+ return -1;
+ }
+ }
+ if(timeout){
+ struct timeval to;
+ fd_set set;
+ int ret=0;
+ int len=sizeof(ret);
+ to.tv_sec=timeout;
+ to.tv_usec=usec;
+ sock_set_nonblocking(s);
+ connect(s,(struct sockaddr* )&sa,sizeof(sa));
+ FD_ZERO(&set);
+ FD_SET(s,&set);
+ ret=select(s+1,NULL,&set,NULL,&to);
+ if(ret==0){
+ /* timeout */
+ ssh_set_error(NULL,SSH_FATAL,"Timeout while connecting to %s:%d",host,port);
+ close(s);
+ return -1;
+ }
+ if(ret<0){
+ ssh_set_error(NULL,SSH_FATAL,"Select error : %s",strerror(errno));
+ close(s);
+ return -1;
+ }
+ /* get connect(2) return code. zero means no error */
+ getsockopt(s,SOL_SOCKET,SO_ERROR,&ret,&len);
+ if (ret!=0){
+ ssh_set_error(NULL,SSH_FATAL,"Connecting : %s",strerror(ret));
+ close(s);
+ return -1;
+ }
+ /* s is connected ? */
+ ssh_say(3,"socket connected with timeout\n");
+ sock_set_blocking(s);
+ return s;
+ }
+ if(connect(s,(struct sockaddr *)&sa,sizeof(sa))< 0){
+ close(s);
+ ssh_set_error(NULL,SSH_FATAL,"connect: %s",strerror(errno));
+ return -1;
+ }
+ return s;
+}
+
+/* connection_new() returns a newly allocated SSH_SESSION structure pointer */
+SSH_SESSION *ssh_session_new() {
+ SSH_SESSION *conn=malloc(sizeof (SSH_SESSION));
+ memset(conn,0,sizeof(SSH_SESSION));
+ conn->next_crypto=crypto_new();
+ conn->maxchannel=FIRST_CHANNEL;
+ return conn;
+}
+
+
+/* returns 1 if bytes are available on the stream, 0 instead */
+int ssh_fd_poll(SSH_SESSION *session){
+#ifdef HAVE_POLL
+ struct pollfd fdset;
+#else
+ struct timeval sometime;
+ fd_set descriptor;
+#endif
+ if(session->datatoread)
+ return(session->datatoread);
+#ifdef HAVE_POLL
+ fdset.fd=session->fd;
+ fdset.events=POLLHUP|POLLIN|POLLPRI;
+ fdset.revents=0;
+ if(poll(&fdset,1,0)==0)
+ return 0;
+ if(fdset.revents & (POLLHUP|POLLIN|POLLPRI))
+ return (session->datatoread=1);
+ return 0;
+#elif HAVE_SELECT
+
+ /* Set to return immediately (no blocking) */
+ sometime.tv_sec = 0;
+ sometime.tv_usec = 0;
+
+ /* Set up descriptor */
+ FD_ZERO(&descriptor);
+ FD_SET(session->fd, &descriptor);
+
+ /* Make the call, and listen for errors */
+ if (select(session->fd + 1, &descriptor, NULL, NULL, &sometime) < 0) {
+ ssh_set_error(NULL,SSH_FATAL, "select: %s", strerror(errno));
+ return -1;
+ }
+ session->datatoread=FD_ISSET(session->fd,&descriptor);
+ return session->datatoread;
+#else
+#error This system does not have poll() or select(), so ssh_fd_poll() will not work correctly
+ return 0;
+#endif
+}
+
+/* this function is a complete wrapper for the select syscall. it does more than wrapping ... */
+int ssh_select(CHANNEL **channels,CHANNEL **outchannels, int maxfd, fd_set *readfds, struct timeval *timeout){
+ struct timeval zerotime;
+ fd_set localset,localset2;
+ int rep;
+ int i,j;
+ int set;
+
+ zerotime.tv_sec=0;
+ zerotime.tv_usec=0;
+ /* first, poll the maxfd file descriptors from the user with a zero-second timeout. they have the bigger priority */
+ if(maxfd>0){
+ memcpy(&localset,readfds, sizeof(fd_set));
+ rep=select(maxfd,&localset,NULL,NULL,&zerotime);
+ /* catch the eventual errors */
+ if(rep==-1)
+ return -1;
+ }
+ j=0;
+ /* polls every channel. */
+ for(i=0;channels[i];i++){
+ if(channel_poll(channels[i],0)>0){
+ outchannels[j]=channels[i];
+ j++;
+ } else
+ if(channel_poll(channels[i],1)>0){
+ outchannels[j]=channels[i];
+ j++;
+ }
+ }
+ outchannels[j]=NULL;
+ /* look into the localset for active fd */
+ set=0;
+ for(i=0;(i<maxfd) && !set;i++)
+ if(FD_ISSET(i,&localset))
+ set=1;
+ /* j!=0 means a channel has data */
+ if( (j!=0) || (set!=0)){
+ if(maxfd>0)
+ memcpy(readfds,&localset,sizeof(fd_set));
+ return 0;
+ }
+ /* at this point, not any channel had any data ready for reading, nor any fd had data for reading */
+ memcpy(&localset,readfds,sizeof(fd_set));
+ for(i=0;channels[i];i++){
+ if(channels[i]->session->alive){
+ FD_SET(channels[i]->session->fd,&localset);
+ if(channels[i]->session->fd>maxfd-1)
+ maxfd=channels[i]->session->fd+1;
+ }
+ }
+ do {
+ rep=select(maxfd,&localset,NULL,NULL,timeout);
+ } while (rep==-1 && errno==EINTR);
+ if(rep==-1){
+ /* was the error due to a libssh's Channel or from a closed descriptor from the user ? user closed descriptors have been
+ caught in the first select and not closed since that moment. that case shouldn't occur at all */
+ return -1;
+ }
+ /* set the data_to_read flag on each session */
+ for(i=0;channels[i];i++)
+ if(FD_ISSET(channels[i]->session->fd,&localset))
+ channels[i]->session->datatoread=1;
+
+ /* now, test each channel */
+ j=0;
+ for(i=0;channels[i];i++){
+ if(FD_ISSET(channels[i]->session->fd,&localset))
+ if((channel_poll(channels[i],0)>0) || (channel_poll(channels[i],1)>0)){
+ outchannels[j]=channels[i];
+ j++;
+ }
+ }
+ outchannels[j]=NULL;
+ FD_ZERO(&localset2);
+ for(i=0;i<maxfd;i++)
+ if(FD_ISSET(i,readfds) && FD_ISSET(i,&localset))
+ FD_SET(i,&localset2);
+ memcpy(readfds,&localset2,sizeof(fd_set));
+ return 0;
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/crypt.c b/kftpgrabber/src/misc/libs/ssh/crypt.c
new file mode 100644
index 0000000..312c411
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/crypt.c
@@ -0,0 +1,100 @@
+/* crypt.c */
+/* it just contains the shit necessary to make blowfish-cbc work ... */
+/*
+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 <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/blowfish.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+
+#include <netdb.h>
+#include "priv.h"
+#include "crypto.h"
+
+u32 packet_decrypt_len(SSH_SESSION *session, char *crypted){
+ u32 *decrypted;
+ if(session->current_crypto)
+ packet_decrypt(session,crypted,session->current_crypto->in_cipher->blocksize);
+ decrypted=(u32 *)crypted;
+ ssh_say(3,"size decrypted : %lx\n",ntohl(*decrypted));
+ return ntohl(*decrypted);
+}
+
+int packet_decrypt(SSH_SESSION *session, void *data,u32 len){
+ struct crypto_struct *crypto=session->current_crypto->in_cipher;
+ char *out=malloc(len);
+ ssh_say(3,"Decrypting %d bytes data\n",len);
+ crypto->set_decrypt_key(crypto,session->current_crypto->decryptkey);
+ crypto->cbc_decrypt(crypto,data,out,len,session->current_crypto->decryptIV);
+ memcpy(data,out,len);
+ memset(out,0,len);
+ free(out);
+ return 0;
+}
+
+char * packet_encrypt(SSH_SESSION *session,void *data,u32 len){
+ struct crypto_struct *crypto;
+ HMAC_CTX *ctx;
+ char *out;
+ int finallen;
+ u32 seq=ntohl(session->send_seq);
+ if(!session->current_crypto)
+ return NULL; /* nothing to do here */
+ crypto= session->current_crypto->out_cipher;
+ ssh_say(3,"seq num = %d, len = %d\n",session->send_seq,len);
+ crypto->set_encrypt_key(crypto,session->current_crypto->encryptkey);
+ out=malloc(len);
+ ctx=hmac_init(session->current_crypto->encryptMAC,20,HMAC_SHA1);
+ hmac_update(ctx,(unsigned char *)&seq,sizeof(u32));
+ hmac_update(ctx,data,len);
+ hmac_final(ctx,session->current_crypto->hmacbuf,&finallen);
+#ifdef DEBUG_CRYPTO
+ ssh_print_hexa("mac :",data,len);
+ if(finallen!=20)
+ printf("Final len is %d\n",finallen);
+ ssh_print_hexa("packet hmac",session->current_crypto->hmacbuf,20);
+#endif
+ crypto->cbc_encrypt(crypto,data,out,len,session->current_crypto->encryptIV);
+ memcpy(data,out,len);
+ memset(out,0,len);
+ free(out);
+ return session->current_crypto->hmacbuf;
+}
+
+int packet_hmac_verify(SSH_SESSION *session,BUFFER *buffer,char *mac){
+ HMAC_CTX *ctx;
+ unsigned char hmacbuf[EVP_MAX_MD_SIZE];
+ int len;
+ u32 seq=htonl(session->recv_seq);
+ ctx=hmac_init(session->current_crypto->decryptMAC,20,HMAC_SHA1);
+ hmac_update(ctx,(unsigned char *)&seq,sizeof(u32));
+ hmac_update(ctx,buffer_get(buffer),buffer_get_len(buffer));
+ hmac_final(ctx,hmacbuf,&len);
+#ifdef DEBUG_CRYPTO
+ ssh_print_hexa("received mac",mac,len);
+ ssh_print_hexa("Computed mac",hmacbuf,len);
+ ssh_print_hexa("seq",(unsigned char *)&seq,sizeof(u32));
+#endif
+ return memcmp(mac,hmacbuf,len);
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/crypto.h b/kftpgrabber/src/misc/libs/ssh/crypto.h
new file mode 100644
index 0000000..83061e4
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/crypto.h
@@ -0,0 +1,47 @@
+/*
+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. */
+
+/* Crypto.h is an include file for internal structures of libssh */
+/* It hasn't to be into the final development set of files (and btw the filename would cause problems on most systems) */
+/* Openssl has (really) stupid defines */
+#ifdef set_key
+#undef set_key
+#endif
+#ifdef cbc_encrypt
+#undef cbc_encrypt
+#endif
+#ifdef cbc_decrypt
+#undef cbc_decrypt
+#endif
+#ifdef des_set_key
+#undef des_set_key
+#endif
+struct crypto_struct {
+ char *name; /* ssh name of the algorithm */
+ unsigned int blocksize; /* blocksize of the algo */
+ unsigned int keylen; /* length of the key structure */
+ void *key; /* a key buffer allocated for the algo */
+ unsigned int keysize; /* bytes of key used. != keylen */
+ void (*set_encrypt_key)(struct crypto_struct *cipher, void *key); /* sets the new key for immediate use */
+ void (*set_decrypt_key)(struct crypto_struct *cipher, void *key);
+ void (*cbc_encrypt)(struct crypto_struct *cipher, void *in, void *out,unsigned long len,void *IV);
+ void (*cbc_decrypt)(struct crypto_struct *cipher, void *in, void *out,unsigned long len,void *IV);
+};
+
diff --git a/kftpgrabber/src/misc/libs/ssh/dh.c b/kftpgrabber/src/misc/libs/ssh/dh.c
new file mode 100644
index 0000000..0a1b557
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/dh.c
@@ -0,0 +1,411 @@
+/* dh.c */
+/* this file contains usefull stuff for Diffie helman algorithm against SSH 2 */
+/*
+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. */
+
+/* Let us resume the dh protocol. */
+/* Each side computes a private prime number, x at client side, y at server side. */
+/* g and n are two numbers common to every ssh software. */
+/* client's public key (e) is calculated by doing */
+/* e = g^x mod p */
+/* client sents e to the server . */
+/* the server computes his own public key, f */
+/* f = g^y mod p */
+/* it sents it to the client */
+/* the common key K is calculated by the client by doing */
+/* k = f^x mod p */
+/* the server does the same with the client public key e */
+/* k' = e^y mod p */
+/* if everything went correctly, k and k' are equal */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include "priv.h"
+
+#include <openssl/rand.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <string.h>
+#include "crypto.h"
+static unsigned char p_value[] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
+ 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+ 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
+ 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+ 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
+ 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+ 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
+ 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
+ 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
+ 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+#define P_LEN 128 /* Size in bytes of the p number */
+
+static unsigned long g_int = 2 ; /* G is defined as 2 by the ssh2 standards */
+static bignum g;
+static bignum p;
+
+/* maybe it might be enhanced .... */
+/* XXX Do it. */
+void ssh_get_random(void *where, int len){
+ static int rndfd=0;
+ if(!rndfd){
+ rndfd=open("/dev/urandom",O_RDONLY);
+ if(rndfd<0){
+ fprintf(stderr,"Can't open /dev/urandom\n");
+ exit(-1);
+ }
+ }
+ read(rndfd,where,len);
+}
+
+/* it inits the values g and p which are used for DH key agreement */
+void ssh_crypto_init(){
+ static int init=0;
+ if(!init){
+ g=bignum_new();
+ bignum_set_word(g,g_int);
+ p=bignum_new();
+ bignum_bin2bn(p_value,P_LEN,p);
+ init++;
+ }
+}
+
+/* prints the bignum on stderr */
+void ssh_print_bignum(char *which,bignum num){
+ char *hex;
+ fprintf(stderr,"%s value: ",which);
+ hex=bignum_bn2hex(num);
+ fprintf(stderr,"%s\n",hex);
+ free(hex);
+}
+
+void ssh_print_hexa(char *descr,unsigned char *what, int len){
+ int i;
+ printf("%s : ",descr);
+ for(i=0;i<len-1;i++)
+ printf("%.2hhx:",what[i]);
+ printf("%.2hhx\n",what[i]);
+}
+
+void dh_generate_x(SSH_SESSION *session){
+ session->next_crypto->x=bignum_new();
+ bignum_rand(session->next_crypto->x,128,0,-1);
+ /* not harder than this */
+#ifdef DEBUG_CRYPTO
+ ssh_print_bignum("x",session->next_crypto->x);
+#endif
+}
+
+void dh_generate_e(SSH_SESSION *session){
+ bignum_CTX ctx=bignum_ctx_new();
+ session->next_crypto->e=bignum_new();
+ bignum_mod_exp(session->next_crypto->e,g,session->next_crypto->x,p,ctx);
+#ifdef DEBUG_CRYPTO
+ ssh_print_bignum("e",session->next_crypto->e);
+#endif
+ bignum_ctx_free(ctx);
+}
+
+
+STRING *make_bignum_string(bignum num){
+ STRING *ptr;
+ int pad=0;
+ int len=bignum_num_bytes(num);
+ int bits=bignum_num_bits(num);
+ int finallen;
+ /* remember if the fist bit is set, it is considered as a negative number. so 0's must be appended */
+ if(!(bits%8) && bignum_is_bit_set(num,bits-1))
+ pad++;
+ ssh_say(3,"%d bits, %d bytes, %d padding\n",bits,len,pad);
+ ptr=malloc(4 + len + pad);
+ ptr->size=htonl(len+pad);
+ if(pad)
+ ptr->string[0]=0;
+ finallen=bignum_bn2bin(num,ptr->string+pad);
+ return ptr;
+}
+
+bignum make_string_bn(STRING *string){
+ int len=ntohl(string->size);
+ ssh_say(3,"Importing a %d bits,%d bytes object ...\n",len*8,len);
+ return bignum_bin2bn(string->string,len,NULL);
+}
+
+STRING *dh_get_e(SSH_SESSION *session){
+ return make_bignum_string(session->next_crypto->e);
+}
+
+void dh_import_pubkey(SSH_SESSION *session,STRING *pubkey_string){
+ session->next_crypto->server_pubkey=pubkey_string;
+}
+
+void dh_import_f(SSH_SESSION *session,STRING *f_string){
+ session->next_crypto->f=make_string_bn(f_string);
+#ifdef DEBUG_CRYPTO
+ ssh_print_bignum("f",session->next_crypto->f);
+#endif
+}
+
+void dh_build_k(SSH_SESSION *session){
+ bignum_CTX ctx=bignum_ctx_new();
+ session->next_crypto->k=bignum_new();
+ bignum_mod_exp(session->next_crypto->k,session->next_crypto->f,session->next_crypto->x,p,ctx);
+#ifdef DEBUG_CRYPTO
+ ssh_print_bignum("shared secret key",session->next_crypto->k);
+#endif
+ bignum_ctx_free(ctx);
+}
+
+static void sha_add(STRING *str,SHACTX *ctx){
+ sha1_update(ctx,str,string_len(str)+4);
+}
+
+void make_sessionid(SSH_SESSION *session){
+ SHACTX *ctx;
+ STRING *num,*str;
+ int len;
+ ctx=sha1_init();
+
+ str=string_from_char(session->clientbanner);
+ sha_add(str,ctx);
+ free(str);
+
+ str=string_from_char(session->serverbanner);
+ sha_add(str,ctx);
+ free(str);
+
+ buffer_add_u32(session->in_hashbuf,0);
+ buffer_add_u8(session->in_hashbuf,0);
+ buffer_add_u32(session->out_hashbuf,0);
+ buffer_add_u8(session->out_hashbuf,0);
+
+ len=ntohl(buffer_get_len(session->out_hashbuf));
+ sha1_update(ctx,&len,4);
+
+ sha1_update(ctx,buffer_get(session->out_hashbuf),buffer_get_len(session->out_hashbuf));
+ buffer_free(session->out_hashbuf);
+ session->out_hashbuf=NULL;
+
+ len=ntohl(buffer_get_len(session->in_hashbuf));
+ sha1_update(ctx,&len,4);
+
+ sha1_update(ctx,buffer_get(session->in_hashbuf),buffer_get_len(session->in_hashbuf));
+ buffer_free(session->in_hashbuf);
+ session->in_hashbuf=NULL;
+ sha1_update(ctx,session->next_crypto->server_pubkey,len=(string_len(session->next_crypto->server_pubkey)+4));
+ num=make_bignum_string(session->next_crypto->e);
+ sha1_update(ctx,num,len=(string_len(num)+4));
+ free(num);
+ num=make_bignum_string(session->next_crypto->f);
+ sha1_update(ctx,num,len=(string_len(num)+4));
+ free(num);
+ num=make_bignum_string(session->next_crypto->k);
+ sha1_update(ctx,num,len=(string_len(num)+4));
+ free(num);
+ sha1_final(session->next_crypto->session_id,ctx);
+
+#ifdef DEBUG_CRYPTO
+ printf("Session hash : ");
+ ssh_print_hexa("session id",session->next_crypto->session_id,SHA_DIGEST_LENGTH);
+#endif
+}
+
+void hashbufout_add_cookie(SSH_SESSION *session){
+ session->out_hashbuf=buffer_new();
+ buffer_add_u8(session->out_hashbuf,20);
+ buffer_add_data(session->out_hashbuf,session->client_kex.cookie,16);
+}
+
+
+void hashbufin_add_cookie(SSH_SESSION *session,unsigned char *cookie){
+ session->in_hashbuf=buffer_new();
+ buffer_add_u8(session->in_hashbuf,20);
+ buffer_add_data(session->in_hashbuf,cookie,16);
+}
+
+static void generate_one_key(STRING *k,char session_id[SHA_DIGEST_LENGTH],char output[SHA_DIGEST_LENGTH],char letter){
+ SHACTX *ctx=sha1_init();
+ sha1_update(ctx,k,string_len(k)+4);
+ sha1_update(ctx,session_id,SHA_DIGEST_LENGTH);
+ sha1_update(ctx,&letter,1);
+ sha1_update(ctx,session_id,SHA_DIGEST_LENGTH);
+ sha1_final(output,ctx);
+}
+
+void generate_session_keys(SSH_SESSION *session){
+ STRING *k_string;
+ SHACTX *ctx;
+ k_string=make_bignum_string(session->next_crypto->k);
+
+ /* IV */
+ generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->encryptIV,'A');
+ generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->decryptIV,'B');
+
+ generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->encryptkey,'C');
+
+ /* some ciphers need more than 20 bytes of input key */
+ if(session->next_crypto->out_cipher->keylen > SHA_DIGEST_LENGTH*8){
+ ctx=sha1_init();
+ sha1_update(ctx,k_string,string_len(k_string)+4);
+ sha1_update(ctx,session->next_crypto->session_id,SHA_DIGEST_LENGTH);
+ sha1_update(ctx,session->next_crypto->encryptkey,SHA_DIGEST_LENGTH);
+ sha1_final(session->next_crypto->encryptkey+SHA_DIGEST_LEN,ctx);
+ }
+
+ generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->decryptkey,'D');
+
+ if(session->next_crypto->in_cipher->keylen > SHA_DIGEST_LENGTH*8){
+ ctx=sha1_init();
+ sha1_update(ctx,k_string,string_len(k_string)+4);
+ sha1_update(ctx,session->next_crypto->session_id,SHA_DIGEST_LENGTH);
+ sha1_update(ctx,session->next_crypto->decryptkey,SHA_DIGEST_LENGTH);
+ sha1_final(session->next_crypto->decryptkey+SHA_DIGEST_LEN,ctx);
+ }
+
+ generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->encryptMAC,'E');
+ generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->decryptMAC,'F');
+
+#ifdef DEBUG_CRYPTO
+ ssh_print_hexa("client->server IV",session->next_crypto->encryptIV,SHA_DIGEST_LENGTH);
+ ssh_print_hexa("server->client IV",session->next_crypto->decryptIV,SHA_DIGEST_LENGTH);
+ ssh_print_hexa("encryption key",session->next_crypto->encryptkey,16);
+ ssh_print_hexa("decryption key",session->next_crypto->decryptkey,16);
+ ssh_print_hexa("Encryption MAC",session->next_crypto->encryptMAC,SHA_DIGEST_LENGTH);
+ ssh_print_hexa("Decryption MAC",session->next_crypto->decryptMAC,20);
+#endif
+ free(k_string);
+}
+
+int ssh_get_pubkey_hash(SSH_SESSION *session,char hash[MD5_DIGEST_LEN]){
+ STRING *pubkey=session->current_crypto->server_pubkey;
+ MD5CTX *ctx;
+ int len=string_len(pubkey);
+
+ ctx=md5_init();
+ md5_update(ctx,pubkey->string,len);
+ md5_final(hash,ctx);
+ return MD5_DIGEST_LEN;
+}
+
+int pubkey_get_hash(SSH_SESSION *session, char hash[MD5_DIGEST_LEN]){
+ return ssh_get_pubkey_hash(session,hash);
+}
+
+STRING *ssh_get_pubkey(SSH_SESSION *session){
+ return string_copy(session->current_crypto->server_pubkey);
+}
+
+/* XXX i doubt it is still needed, or may need some fix */
+static int match(char *group,char *object){
+ char *ptr,*saved;
+ char *end;
+ ptr=strdup(group);
+ saved=ptr;
+ while(1){
+ end=strchr(ptr,',');
+ if(end)
+ *end=0;
+ if(!strcmp(ptr,object)){
+ free(saved);
+ return 0;
+ }
+ if(end)
+ ptr=end+1;
+ else{
+ free(saved);
+ return -1;
+ }
+ }
+ /* not reached */
+ return 1;
+}
+
+int sig_verify(PUBLIC_KEY *pubkey, SIGNATURE *signature, char *digest){
+ int valid=0;
+ char hash[SHA_DIGEST_LENGTH];
+ sha1(digest,SHA_DIGEST_LENGTH,hash);
+ switch(pubkey->type){
+ case TYPE_DSS:
+ valid=DSA_do_verify(hash,SHA_DIGEST_LENGTH,signature->dsa_sign,
+ pubkey->dsa_pub);
+ if(valid==1)
+ return 0;
+ if(valid==-1){
+ ssh_set_error(NULL,SSH_INVALID_DATA,"DSA error : %s",ERR_error_string(ERR_get_error(),NULL));
+ return -1;
+ }
+ ssh_set_error(NULL,SSH_NO_ERROR,"Invalid DSA signature");
+ return -1;
+ case TYPE_RSA:
+ case TYPE_RSA1:
+ valid=RSA_verify(NID_sha1,hash,SHA_DIGEST_LENGTH,
+ signature->rsa_sign->string,string_len(signature->rsa_sign),pubkey->rsa_pub);
+ if(valid==1)
+ return 0;
+ if(valid==-1){
+ ssh_set_error(NULL,SSH_INVALID_DATA,"RSA error : %s",ERR_error_string(ERR_get_error(),NULL));
+ return -1;
+ }
+ ssh_set_error(NULL,SSH_NO_ERROR,"Invalid RSA signature");
+ return -1;
+ default:
+ ssh_set_error(NULL,SSH_INVALID_DATA,"Unknown public key type");
+ return -1;
+ }
+return -1;
+}
+
+
+int signature_verify(SSH_SESSION *session,STRING *signature){
+ PUBLIC_KEY *pubkey;
+ SIGNATURE *sign;
+ int err;
+ if(session->options->dont_verify_hostkey){
+ ssh_say(1,"Host key wasn't verified\n");
+ return 0;
+ }
+ pubkey=publickey_from_string(session->next_crypto->server_pubkey);
+ if(!pubkey)
+ return -1;
+ if(session->options->wanted_methods[KEX_HOSTKEY]){
+ if(match(session->options->wanted_methods[KEX_HOSTKEY],pubkey->type_c)){
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"Public key from server (%s) doesn't match user preference (%s)",
+ pubkey->type,session->options->wanted_methods[KEX_HOSTKEY]);
+ publickey_free(pubkey);
+ return -1;
+ }
+ }
+ sign=signature_from_string(signature,pubkey,pubkey->type);
+ if(!sign){
+ ssh_set_error((session->connected?session:NULL),SSH_INVALID_DATA,"Invalid signature blob");
+ publickey_free(pubkey);
+ return -1;
+ }
+ ssh_say(1,"Going to verify a %s type signature\n",pubkey->type_c);
+ err=sig_verify(pubkey,sign,session->next_crypto->session_id);
+ signature_free(sign);
+ session->next_crypto->server_pubkey_type=pubkey->type_c;
+ publickey_free(pubkey);
+ return err;
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/error.c b/kftpgrabber/src/misc/libs/ssh/error.c
new file mode 100644
index 0000000..bbff5b2
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/error.c
@@ -0,0 +1,67 @@
+/* error.c */
+/* it does contain error processing functions */
+/*
+Copyright 2003,04 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 <stdarg.h>
+#include "priv.h"
+
+static char error_buffer[ERROR_BUFFERLEN];
+static int error_code;
+static int verbosity;
+
+/* ssh_set_error registers an error with a description. the error code is the class of error, and description is obvious.*/
+void ssh_set_error(SSH_SESSION *session,enum ssh_error code,char *descr,...){
+ va_list va;
+ va_start(va,descr);
+ vsnprintf(session?session->error_buffer : error_buffer,ERROR_BUFFERLEN,descr,va);
+ va_end(va);
+ if(session)
+ session->error_code=code;
+ else
+ error_code=code;
+}
+
+char *ssh_get_error(SSH_SESSION *session){
+ if(session)
+ return session->error_buffer;
+ else
+ return error_buffer;
+}
+
+enum ssh_error ssh_error_code(SSH_SESSION *session){
+ if(session)
+ return session->error_code;
+ else
+ return error_code;
+}
+
+void ssh_say(int priority, char *format,...){
+ va_list va;
+ va_start(va,format);
+ if(priority <= verbosity)
+ vfprintf(stderr,format,va);
+ va_end(va);
+}
+
+void ssh_set_verbosity(int num){
+ verbosity=num;
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/gzip.c b/kftpgrabber/src/misc/libs/ssh/gzip.c
new file mode 100644
index 0000000..1003b50
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/gzip.c
@@ -0,0 +1,140 @@
+/* gzip.c */
+/* include hooks for compression of packets */
+/*
+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 "priv.h"
+#ifdef HAVE_LIBZ
+#undef NO_GZIP
+#else
+#define NO_GZIP
+#endif
+
+#ifndef NO_GZIP
+#include <zlib.h>
+#include <string.h>
+#define BLOCKSIZE 4092
+
+static z_stream *initcompress(SSH_SESSION *session,int level){
+ z_stream *stream=malloc(sizeof(z_stream));
+ int status;
+ memset(stream,0,sizeof(z_stream));
+ status=deflateInit(stream,level);
+ if (status!=0)
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"status %d inititalising zlib deflate",status);
+ return stream;
+}
+
+BUFFER *gzip_compress(SSH_SESSION *session,BUFFER *source,int level){
+ BUFFER *dest;
+ static unsigned char out_buf[BLOCKSIZE];
+ void *in_ptr=buffer_get(source);
+ unsigned long in_size=buffer_get_len(source);
+ unsigned long len;
+ int status;
+ z_stream *zout=session->current_crypto->compress_out_ctx;
+ if(!zout)
+ zout=session->current_crypto->compress_out_ctx=initcompress(session,level);
+ dest=buffer_new();
+ zout->next_out=out_buf;
+ zout->next_in=in_ptr;
+ zout->avail_in=in_size;
+ do {
+ zout->avail_out=BLOCKSIZE;
+ status=deflate(zout,Z_PARTIAL_FLUSH);
+ if(status !=0){
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"status %d deflating zlib packet",status);
+ return NULL;
+ }
+ len=BLOCKSIZE-zout->avail_out;
+ buffer_add_data(dest,out_buf,len);
+ zout->next_out=out_buf;
+ } while (zout->avail_out == 0);
+
+ return dest;
+}
+
+int compress_buffer(SSH_SESSION *session,BUFFER *buf){
+ BUFFER *dest=gzip_compress(session,buf,9);
+ if(!dest)
+ return -1;
+ buffer_reinit(buf);
+ buffer_add_data(buf,buffer_get(dest),buffer_get_len(dest));
+ buffer_free(dest);
+ return 0;
+}
+
+/* decompression */
+
+static z_stream *initdecompress(SSH_SESSION *session){
+ z_stream *stream=malloc(sizeof(z_stream));
+ int status;
+ memset(stream,0,sizeof(z_stream));
+ status=inflateInit(stream);
+ if (status!=0){
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"Status = %d initiating inflate context !",status);
+ free(stream);
+ stream=NULL;
+ }
+ return stream;
+}
+
+BUFFER *gzip_decompress(SSH_SESSION *session,BUFFER *source){
+ BUFFER *dest;
+ static unsigned char out_buf[BLOCKSIZE];
+ void *in_ptr=buffer_get_rest(source);
+ unsigned long in_size=buffer_get_rest_len(source);
+ unsigned long len;
+ int status;
+ z_stream *zin=session->current_crypto->compress_in_ctx;
+ if(!zin)
+ zin=session->current_crypto->compress_in_ctx=initdecompress(session);
+ dest=buffer_new();
+ zin->next_out=out_buf;
+ zin->next_in=in_ptr;
+ zin->avail_in=in_size;
+ do {
+ zin->avail_out=BLOCKSIZE;
+ status=inflate(zin,Z_PARTIAL_FLUSH);
+ if(status !=Z_OK){
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"status %d inflating zlib packet",status);
+ buffer_free(dest);
+ return NULL;
+ }
+ len=BLOCKSIZE-zin->avail_out;
+ buffer_add_data(dest,out_buf,len);
+ zin->next_out=out_buf;
+ } while (zin->avail_out == 0);
+
+ return dest;
+}
+
+int decompress_buffer(SSH_SESSION *session,BUFFER *buf){
+ BUFFER *dest=gzip_decompress(session,buf);
+ buffer_reinit(buf);
+ if(!dest){
+ return -1; /* failed */
+ }
+ buffer_reinit(buf);
+ buffer_add_data(buf,buffer_get(dest),buffer_get_len(dest));
+ buffer_free(dest);
+ return 0;
+}
+
+#endif /* NO_GZIP */
diff --git a/kftpgrabber/src/misc/libs/ssh/kex.c b/kftpgrabber/src/misc/libs/ssh/kex.c
new file mode 100644
index 0000000..ae2c871
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/kex.c
@@ -0,0 +1,264 @@
+/* kex.c is used well, in key exchange :-) */
+/*
+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 <string.h>
+#include <stdlib.h>
+#include "priv.h"
+#include "ssh2.h"
+#ifdef HAVE_OPENSSL_BLOWFISH_H
+#define BLOWFISH "blowfish-cbc"
+#else
+#define BLOWFISH ""
+#endif
+#ifdef HAVE_OPENSSL_AES_H
+#define AES "aes256-cbc,aes192-cbc,aes128-cbc,"
+#else
+#define AES ""
+#endif
+#ifdef HAVE_LIBZ
+#define ZLIB "none,zlib"
+#else
+#define ZLIB "none"
+#endif
+char *default_methods[]={
+ "diffie-hellman-group1-sha1","ssh-dss,ssh-rsa",AES BLOWFISH, AES BLOWFISH,
+ "hmac-sha1","hmac-sha1","none","none","","",NULL };
+char *supported_methods[]={
+ "diffie-hellman-group1-sha1","ssh-dss,ssh-rsa",AES BLOWFISH,AES BLOWFISH,
+ "hmac-sha1","hmac-sha1",ZLIB,ZLIB,"","",NULL };
+/* descriptions of the key exchange packet */
+char *ssh_kex_nums[]={
+ "kex algos","server host key algo","encryption client->server","encryption server->client",
+ "mac algo client->server","mac algo server->client","compression algo client->server",
+ "compression algo server->client","languages client->server","languages server->client",NULL};
+
+/* tokenize will return a token of strings delimited by ",". the first element has to be freed */
+static char **tokenize(char *chain){
+ char **tokens;
+ int n=1;
+ int i=0;
+ char *ptr=chain=strdup(chain);
+ while(*ptr){
+ if(*ptr==','){
+ n++;
+ *ptr=0;
+ }
+ ptr++;
+ }
+ /* now n contains the number of tokens, the first possibly empty if the list was empty too e.g. "" */
+ tokens=malloc(sizeof(char *) * (n+1) ); /* +1 for the null */
+ ptr=chain;
+ for(i=0;i<n;i++){
+ tokens[i]=ptr;
+ while(*ptr)
+ ptr++; /* find a zero */
+ ptr++; /* then go one step further */
+ }
+ tokens[i]=NULL;
+ return tokens;
+}
+
+/* same as tokenize(), but with spaces instead of ',' */
+char **space_tokenize(char *chain){
+ char **tokens;
+ int n=1;
+ int i=0;
+ char *ptr=chain=strdup(chain);
+ while(*ptr==' ')
+ ++ptr; /* skip initial spaces */
+ while(*ptr){
+ if(*ptr==' '){
+ n++; /* count one token per word */
+ *ptr=0;
+ while(*(ptr+1)==' '){ /* don't count if the tokens have more than 2 spaces */
+ *(ptr++)=0;
+ }
+ }
+ ptr++;
+ }
+ /* now n contains the number of tokens, the first possibly empty if the list was empty too e.g. "" */
+ tokens=malloc(sizeof(char *) * (n+1) ); /* +1 for the null */
+ ptr=chain; /* we don't pass the initial spaces because the "chain" pointer is needed by the caller */
+ /* function to free the tokens. */
+ for(i=0;i<n;i++){
+ tokens[i]=ptr;
+ if(i!=n-1){
+ while(*ptr)
+ ptr++; /* find a zero */
+ while(!*(ptr+1))
+ ++ptr; /* if the zero is followed by other zeros, go through them */
+ ptr++; /* then go one step further */
+ }
+ }
+ tokens[i]=NULL;
+ return tokens;
+}
+
+/* find_matching gets 2 parameters : a list of available objects (in_d), separated by colons,*/
+/* and a list of prefered objects (what_d) */
+/* it will return a strduped pointer on the first prefered object found in the available objects list */
+
+static char *find_matching(char *in_d, char *what_d){
+ char ** tok_in, **tok_what;
+ int i_in, i_what;
+ char *ret;
+
+ if( ! (in_d && what_d))
+ return NULL; /* don't deal with null args */
+ ssh_say(3,"find_matching(\"%s\",\"%s\") = ",in_d,what_d);
+ tok_in=tokenize(in_d);
+ tok_what=tokenize(what_d);
+ for(i_in=0; tok_in[i_in]; ++i_in){
+ for(i_what=0; tok_what[i_what] ; ++i_what){
+ if(!strcmp(tok_in[i_in],tok_what[i_what])){
+ /* match */
+ ssh_say(3,"\"%s\"\n",tok_in[i_in]);
+ ret=strdup(tok_in[i_in]);
+ /* free the tokens */
+ free(tok_in[0]);
+ free(tok_what[0]);
+ free(tok_in);
+ free(tok_what);
+ return ret;
+ }
+ }
+ }
+ ssh_say(3,"NULL\n");
+ free(tok_in[0]);
+ free(tok_what[0]);
+ free(tok_in);
+ free(tok_what);
+ return NULL;
+}
+
+int ssh_get_kex(SSH_SESSION *session,int server_kex ){
+ STRING *str;
+ char *strings[10];
+ int i;
+ if(packet_wait(session,SSH2_MSG_KEXINIT,1))
+ return -1;
+ if(buffer_get_data(session->in_buffer,session->server_kex.cookie,16)!=16){
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"get_kex(): no cookie in packet");
+ return -1;
+ }
+ hashbufin_add_cookie(session,session->server_kex.cookie);
+ memset(strings,0,sizeof(char *)*10);
+ for(i=0;i<10;++i){
+ str=buffer_get_ssh_string(session->in_buffer);
+ if(!str)
+ break;
+ if(str){
+ buffer_add_ssh_string(session->in_hashbuf,str);
+ strings[i]=string_to_char(str);
+ free(str);
+ } else
+ strings[i]=NULL;
+ }
+ /* copy the server kex info into an array of strings */
+ if(server_kex){
+ session->client_kex.methods=malloc( 10 * sizeof(char **));
+ for(i=0;i<10;++i)
+ session->client_kex.methods[i]=strings[i];
+ } else { /* client */
+ session->server_kex.methods=malloc( 10 * sizeof(char **));
+ for(i=0;i<10;++i)
+ session->server_kex.methods[i]=strings[i];
+ }
+ return 0;
+}
+
+void list_kex(KEX *kex){
+ int i=0;
+#ifdef DEBUG_CRYPTO
+ ssh_print_hexa("session cookie",kex->cookie,16);
+#endif
+ for(i=0;i<10;i++){
+ ssh_say(2,"%s : %s\n",ssh_kex_nums[i],kex->methods[i]);
+ }
+}
+
+/* set_kex basicaly look at the option structure of the session and set the output kex message */
+/* it must be aware of the server kex message */
+/* it can fail if option is null, not any user specified kex method matches the server one, if not any default kex matches */
+
+int set_kex(SSH_SESSION *session){
+ KEX *server = &session->server_kex;
+ KEX *client=&session->client_kex;
+ SSH_OPTIONS *options=session->options;
+ int i;
+ char *wanted;
+ /* the client might ask for a specific cookie to be sent. useful for server debugging */
+ if(options->wanted_cookie)
+ memcpy(client->cookie,options->wanted_cookie,16);
+ else
+ ssh_get_random(client->cookie,16);
+ client->methods=malloc(10 * sizeof(char **));
+ memset(client->methods,0,10*sizeof(char **));
+ for (i=0;i<10;i++){
+ if(!(wanted=options->wanted_methods[i]))
+ wanted=default_methods[i];
+ client->methods[i]=find_matching(server->methods[i],wanted);
+ if(!client->methods[i] && i < KEX_LANG_C_S){
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"kex error : did not find one of algos %s in list %s for %s",
+ wanted,server->methods[i],ssh_kex_nums[i]);
+ return -1;
+ } else {
+ if(i>=KEX_LANG_C_S && !client->methods[i])
+ client->methods[i]=strdup(""); /* we can safely do that for languages */
+ }
+ }
+ return 0;
+}
+
+/* this function only sends the predefined set of kex methods */
+void send_kex(SSH_SESSION *session, int server_kex){
+ STRING *str;
+ int i=0;
+ KEX *kex=(server_kex ? &session->server_kex : &session->client_kex);
+ packet_clear_out(session);
+ buffer_add_u8(session->out_buffer,SSH2_MSG_KEXINIT);
+ buffer_add_data(session->out_buffer,kex->cookie,16);
+ hashbufout_add_cookie(session);
+ list_kex(kex);
+ for(i=0;i<10;i++){
+ str=string_from_char(kex->methods[i]);
+ buffer_add_ssh_string(session->out_hashbuf,str);
+ buffer_add_ssh_string(session->out_buffer,str);
+ free(str);
+ }
+ i=0;
+ buffer_add_u8(session->out_buffer,0);
+ buffer_add_u32(session->out_buffer,0);
+ packet_send(session);
+}
+
+/* returns 1 if at least one of the name algos is in the default algorithms table */
+int verify_existing_algo(int algo, char *name){
+ char *ptr;
+ if(algo>9 || algo <0)
+ return -1;
+ ptr=find_matching(supported_methods[algo],name);
+ if(ptr){
+ free(ptr);
+ return 1;
+ }
+ return 0;
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/keyfiles.c b/kftpgrabber/src/misc/libs/ssh/keyfiles.c
new file mode 100644
index 0000000..660155e
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/keyfiles.c
@@ -0,0 +1,341 @@
+/* keyfiles.c */
+/* This part of the library handles private and public key files needed for publickey authentication,*/
+/* as well as servers public hashes verifications and certifications. Lot of code here handles openssh */
+/* implementations (key files aren't standardized yet). */
+
+/*
+Copyright 2003,04 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 <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <openssl/pem.h>
+#include <openssl/dsa.h>
+#include <openssl/err.h>
+#include <openssl/rsa.h>
+#include "priv.h"
+#define MAXLINESIZE 80
+
+static int default_get_password(char *buf, int size,int rwflag, char *descr){
+ char *pass;
+ char buffer[256];
+ int len;
+ snprintf(buffer,256,"Please enter passphrase for %s",descr);
+ pass=getpass(buffer);
+ snprintf(buf,size,"%s",buffer);
+ len=strlen(buf);
+ memset(pass,0,strlen(pass));
+ return len;
+}
+
+/* in case the passphrase has been given in parameter */
+static int get_password_specified(char *buf,int size, int rwflag, char *password){
+ snprintf(buf,size,"%s",password);
+ return strlen(buf);
+}
+
+/* TODO : implement it to read both DSA and RSA at once */
+PRIVATE_KEY *privatekey_from_file(SSH_SESSION *session,char *filename,int type,char *passphrase){
+ FILE *file=fopen(filename,"r");
+ PRIVATE_KEY *privkey;
+ DSA *dsa=NULL;
+ RSA *rsa=NULL;
+
+ if (!file) {
+ ssh_set_error(session,SSH_REQUEST_DENIED,"Error opening %s : %s",filename,strerror(errno));
+ return NULL;
+ }
+
+ if (!passphrase) {
+ return NULL;
+ }
+
+ /* Add all encryption algorythms to OpenSSL or this will fail */
+ OpenSSL_add_all_algorithms();
+
+ if (type == TYPE_DSS) {
+ dsa = PEM_read_DSAPrivateKey(file,NULL,(void *)get_password_specified,passphrase);
+
+ fclose(file);
+ if(!dsa) {
+ ssh_set_error(session,SSH_FATAL,"parsing private key %s : %s",filename,ERR_error_string(ERR_get_error(),NULL));
+ return NULL;
+ }
+ } else if (type == TYPE_RSA) {
+ rsa=PEM_read_RSAPrivateKey(file,NULL,(void *)get_password_specified,passphrase);
+
+ fclose(file);
+ if(!rsa){
+ ssh_set_error(session,SSH_FATAL,"parsing private key %s : %s",filename,ERR_error_string(ERR_get_error(),NULL));
+ return NULL;
+ }
+ } else {
+ ssh_set_error(session,SSH_FATAL,"Invalid private key type %d",type);
+ return NULL;
+ }
+
+ privkey = malloc(sizeof(PRIVATE_KEY));
+ privkey->type = type;
+ privkey->dsa_priv = dsa;
+ privkey->rsa_priv = rsa;
+
+ return privkey;
+}
+
+void private_key_free(PRIVATE_KEY *prv){
+ if(prv->dsa_priv)
+ DSA_free(prv->dsa_priv);
+ if(prv->rsa_priv)
+ RSA_free(prv->rsa_priv);
+ memset(prv,0,sizeof(PRIVATE_KEY));
+ free(prv);
+}
+
+STRING *publickey_from_file(char *filename,int *_type){
+ BUFFER *buffer;
+ int type;
+ STRING *str;
+ char buf[4096]; /* noone will have bigger keys that that */
+ /* where have i head that again ? */
+ int fd=open(filename,O_RDONLY);
+ int r;
+ char *ptr;
+ if(fd<0){
+ ssh_set_error(NULL,SSH_INVALID_REQUEST,"nonexistent public key file");
+ return NULL;
+ }
+ if(read(fd,buf,8)!=8){
+ close(fd);
+ ssh_set_error(NULL,SSH_INVALID_REQUEST,"Invalid public key file");
+ return NULL;
+ }
+ buf[7]=0;
+ if(!strcmp(buf,"ssh-dss"))
+ type=TYPE_DSS;
+ else if (!strcmp(buf,"ssh-rsa"))
+ type=TYPE_RSA;
+ else {
+ close(fd);
+ ssh_set_error(NULL,SSH_INVALID_REQUEST,"Invalid public key file");
+ return NULL;
+ }
+ r=read(fd,buf,sizeof(buf)-1);
+ close(fd);
+ if(r<=0){
+ ssh_set_error(NULL,SSH_INVALID_REQUEST,"Invalid public key file");
+ return NULL;
+ }
+ buf[r]=0;
+ ptr=strchr(buf,' ');
+ if(ptr)
+ *ptr=0; /* eliminates the garbage at end of file */
+ buffer=base64_to_bin(buf);
+ if(buffer){
+ str=string_new(buffer_get_len(buffer));
+ string_fill(str,buffer_get(buffer),buffer_get_len(buffer));
+ buffer_free(buffer);
+ if(_type)
+ *_type=type;
+ return str;
+ } else {
+ ssh_set_error(NULL,SSH_INVALID_REQUEST,"Invalid public key file");
+ return NULL; /* invalid file */
+ }
+}
+
+
+/* why recursing ? i'll explain. on top, publickey_from_next_file will be executed until NULL returned */
+/* we can't return null if one of the possible keys is wrong. we must test them before getting over */
+STRING *publickey_from_next_file(SSH_SESSION *session,char **pub_keys_path,char **keys_path,
+ char **privkeyfile,int *type,int *count){
+ static char *home=NULL;
+ char public[256];
+ char private[256];
+ char *priv;
+ char *pub;
+ STRING *pubkey;
+ if(!home)
+ home=ssh_get_user_home_dir();
+ if(home==NULL) {
+ ssh_set_error(session,SSH_FATAL,"User home dir impossible to guess");
+ return NULL;
+ }
+ ssh_set_error(session,SSH_NO_ERROR,"no public key matched");
+ if((pub=pub_keys_path[*count])==NULL)
+ return NULL;
+ if((priv=keys_path[*count])==NULL)
+ return NULL;
+ ++*count;
+ /* are them readable ? */
+ snprintf(public,256,pub,home);
+ ssh_say(2,"Trying to open %s\n",public);
+ if(!ssh_file_readaccess_ok(public)){
+ ssh_say(2,"Failed\n");
+ return publickey_from_next_file(session,pub_keys_path,keys_path,privkeyfile,type,count);
+ }
+ snprintf(private,256,priv,home);
+ ssh_say(2,"Trying to open %s\n",private);
+ if(!ssh_file_readaccess_ok(private)){
+ ssh_say(2,"Failed\n");
+ return publickey_from_next_file(session,pub_keys_path,keys_path,privkeyfile,type,count);
+ }
+ ssh_say(2,"Okay both files ok\n");
+ /* ok, we are sure both the priv8 and public key files are readable : we return the public one as a string,
+ and the private filename in arguments */
+ pubkey=publickey_from_file(public,type);
+ if(!pubkey){
+ ssh_say(2,"Wasn't able to open public key file %s : %s\n",public,ssh_get_error(session));
+ return publickey_from_next_file(session,pub_keys_path,keys_path,privkeyfile,type,count);
+ }
+ *privkeyfile=realloc(*privkeyfile,strlen(private)+1);
+ strcpy(*privkeyfile,private);
+ return pubkey;
+}
+
+#define FOUND_OTHER ( (void *)-1)
+#define FILE_NOT_FOUND ((void *)-2)
+/* will return a token array containing [host,]ip keytype key */
+/* NULL if no match was found, FOUND_OTHER if the match is on an other */
+/* type of key (ie dsa if type was rsa) */
+static char **ssh_parse_knownhost(char *filename, char *hostname, char *type){
+ FILE *file=fopen(filename,"r");
+ char buffer[4096];
+ char *ptr;
+ char **tokens;
+ char **ret=NULL;
+ if(!file)
+ return FILE_NOT_FOUND;
+ while(fgets(buffer,sizeof(buffer),file)){
+ ptr=strchr(buffer,'\n');
+ if(ptr) *ptr=0;
+ if((ptr=strchr(buffer,'\r'))) *ptr=0;
+ if(!buffer[0])
+ continue; /* skip empty lines */
+ tokens=space_tokenize(buffer);
+ if(!tokens[0] || !tokens[1] || !tokens[2]){
+ /* it should have exactly 3 tokens */
+ free(tokens[0]);
+ free(tokens);
+ continue;
+ }
+ if(tokens[3]){
+ /* 3 tokens only, not four */
+ free(tokens[0]);
+ free(tokens);
+ continue;
+ }
+ ptr=tokens[0];
+ while(*ptr==' ')
+ ptr++; /* skip the initial spaces */
+ /* we allow spaces or ',' to follow the hostname. It's generaly an IP */
+ /* we don't care about ip, if the host key match there is no problem with ip */
+ if(strncasecmp(ptr,hostname,strlen(hostname))==0){
+ if(ptr[strlen(hostname)]==' ' || ptr[strlen(hostname)]=='\0'
+ || ptr[strlen(hostname)]==','){
+ if(strcasecmp(tokens[1],type)==0){
+ fclose(file);
+ return tokens;
+ } else {
+ ret=FOUND_OTHER;
+ }
+ }
+ }
+ /* not the good one */
+ free(tokens[0]);
+ free(tokens);
+ }
+ fclose(file);
+ /* we did not find */
+ return ret;
+}
+
+/* public function to test if the server is known or not */
+int ssh_is_server_known(SSH_SESSION *session){
+ char *pubkey_64;
+ BUFFER *pubkey_buffer;
+ STRING *pubkey=session->current_crypto->server_pubkey;
+ char **tokens;
+ options_default_known_hosts_file(session->options);
+ if(!session->options->host){
+ ssh_set_error(session,SSH_FATAL,"Can't verify host in known hosts if the hostname isn't known");
+ return SSH_SERVER_ERROR;
+ }
+ tokens=ssh_parse_knownhost(session->options->known_hosts_file,
+ session->options->host,session->current_crypto->server_pubkey_type);
+ if(tokens==NULL)
+ return SSH_SERVER_NOT_KNOWN;
+ if(tokens==FOUND_OTHER)
+ return SSH_SERVER_FOUND_OTHER;
+ if(tokens==FILE_NOT_FOUND){
+ ssh_set_error(session,SSH_FATAL,"verifying that server is a known host : file %s not found",session->options->known_hosts_file);
+ return SSH_SERVER_ERROR;
+ }
+ /* ok we found some public key in known hosts file. now un-base64it */
+ /* Some time, we may verify the IP address did not change. I honestly think */
+ /* it's not an important matter as IP address are known not to be secure */
+ /* and the crypto stuff is enough to prove the server's identity */
+ pubkey_64=tokens[2];
+ pubkey_buffer=base64_to_bin(pubkey_64);
+ /* at this point, we may free the tokens */
+ free(tokens[0]);
+ free(tokens);
+ if(!pubkey_buffer){
+ ssh_set_error(session,SSH_FATAL,"verifying that server is a known host : base 64 error");
+ return SSH_SERVER_ERROR;
+ }
+ if(buffer_get_len(pubkey_buffer)!=string_len(pubkey)){
+ buffer_free(pubkey_buffer);
+ return SSH_SERVER_KNOWN_CHANGED;
+ }
+ /* now test that they are identical */
+ if(memcmp(buffer_get(pubkey_buffer),pubkey->string,buffer_get_len(pubkey_buffer))!=0){
+ buffer_free(pubkey_buffer);
+ return SSH_SERVER_KNOWN_CHANGED;
+ }
+ buffer_free(pubkey_buffer);
+ return SSH_SERVER_KNOWN_OK;
+}
+
+int ssh_write_knownhost(SSH_SESSION *session){
+ char *pubkey_64;
+ STRING *pubkey=session->current_crypto->server_pubkey;
+ char buffer[4096];
+ FILE *file;
+ options_default_known_hosts_file(session->options);
+ if(!session->options->host){
+ ssh_set_error(session,SSH_FATAL,"Cannot write host in known hosts if the hostname is unknown");
+ return -1;
+ }
+ /* a = append only */
+ file=fopen(session->options->known_hosts_file,"a");
+ if(!file){
+ ssh_set_error(session,SSH_FATAL,"Opening known host file %s for appending : %s",
+ session->options->known_hosts_file,strerror(errno));
+ return -1;
+ }
+ pubkey_64=bin_to_base64(pubkey->string,string_len(pubkey));
+ snprintf(buffer,sizeof(buffer),"%s %s %s\n",session->options->host,session->current_crypto->server_pubkey_type,pubkey_64);
+ free(pubkey_64);
+ fwrite(buffer,strlen(buffer),1,file);
+ fclose(file);
+ return 0;
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/keys.c b/kftpgrabber/src/misc/libs/ssh/keys.c
new file mode 100644
index 0000000..f404f4b
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/keys.c
@@ -0,0 +1,353 @@
+/* keys handle the public key related functions */
+/* decoding a public key (both rsa and dsa), decoding a signature (rsa and dsa), veryfying them */
+
+/*
+Copyright 2003,04 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 <string.h>
+#include <openssl/dsa.h>
+#include <openssl/rsa.h>
+#include "priv.h"
+
+
+/* Public key decoding functions */
+
+char *ssh_type_to_char(int type){
+ switch(type){
+ case TYPE_DSS:
+ return "ssh-dss";
+ case TYPE_RSA:
+ case TYPE_RSA1:
+ return "ssh-rsa";
+ default:
+ return NULL;
+ }
+}
+
+PUBLIC_KEY *publickey_make_dss(BUFFER *buffer){
+ STRING *p,*q,*g,*pubkey;
+ PUBLIC_KEY *key=malloc(sizeof(PUBLIC_KEY));
+ key->type=TYPE_DSS;
+ key->type_c="ssh-dss";
+ p=buffer_get_ssh_string(buffer);
+ q=buffer_get_ssh_string(buffer);
+ g=buffer_get_ssh_string(buffer);
+ pubkey=buffer_get_ssh_string(buffer);
+ buffer_free(buffer); /* we don't need it anymore */
+ if(!p || !q || !g || !pubkey){
+ ssh_set_error(NULL,SSH_FATAL,"Invalid DSA public key");
+ if(p)
+ free(p);
+ if(q)
+ free(q);
+ if(g)
+ free(g);
+ if(pubkey)
+ free(pubkey);
+ free(key);
+ return NULL;
+ }
+ key->dsa_pub=DSA_new();
+ key->dsa_pub->p=make_string_bn(p);
+ key->dsa_pub->q=make_string_bn(q);
+ key->dsa_pub->g=make_string_bn(g);
+ key->dsa_pub->pub_key=make_string_bn(pubkey);
+ free(p);
+ free(q);
+ free(g);
+ free(pubkey);
+ return key;
+}
+
+PUBLIC_KEY *publickey_make_rsa(BUFFER *buffer){
+ STRING *e,*n;
+ PUBLIC_KEY *key=malloc(sizeof(PUBLIC_KEY));
+ key->type=TYPE_RSA;
+ key->type_c="ssh-rsa";
+ e=buffer_get_ssh_string(buffer);
+ n=buffer_get_ssh_string(buffer);
+ buffer_free(buffer); /* we don't need it anymore */
+ if(!e || !n){
+ ssh_set_error(NULL,SSH_FATAL,"Invalid RSA public key");
+ if(e)
+ free(e);
+ if(n)
+ free(n);
+ free(key);
+ return NULL;
+ }
+ key->rsa_pub=RSA_new();
+ key->rsa_pub->e=make_string_bn(e);
+ key->rsa_pub->n=make_string_bn(n);
+#ifdef DEBUG_CRYPTO
+ ssh_print_bignum("e",key->rsa_pub->e);
+ ssh_print_bignum("n",key->rsa_pub->n);
+#endif
+ free(e);
+ free(n);
+ return key;
+}
+
+void publickey_free(PUBLIC_KEY *key){
+ if(!key)
+ return;
+ switch(key->type){
+ case TYPE_DSS:
+ DSA_free(key->dsa_pub);
+ break;
+ case TYPE_RSA:
+ case TYPE_RSA1:
+ RSA_free(key->rsa_pub);
+ break;
+ default:
+ break;
+ }
+ free(key);
+}
+
+PUBLIC_KEY *publickey_from_string(STRING *pubkey_s){
+ BUFFER *tmpbuf=buffer_new();
+ STRING *type_s;
+ char *type;
+
+ buffer_add_data(tmpbuf,pubkey_s->string,string_len(pubkey_s));
+ type_s=buffer_get_ssh_string(tmpbuf);
+ if(!type_s){
+ buffer_free(tmpbuf);
+ ssh_set_error(NULL,SSH_FATAL,"Invalid public key format");
+ return NULL;
+ }
+ type=string_to_char(type_s);
+ free(type_s);
+ if(!strcmp(type,"ssh-dss")){
+ free(type);
+ return publickey_make_dss(tmpbuf);
+ }
+ if(!strcmp(type,"ssh-rsa")){
+ free(type);
+ return publickey_make_rsa(tmpbuf);
+ }
+ ssh_set_error(NULL,SSH_FATAL,"unknown public key protocol %s",type);
+ buffer_free(tmpbuf);
+ free(type);
+ return NULL;
+}
+
+/* Signature decoding functions */
+
+STRING *signature_to_string(SIGNATURE *sign){
+ STRING *str;
+ STRING *rs,*r,*s;
+ unsigned char buffer[40];
+ BUFFER *tmpbuf=buffer_new();
+ STRING *tmp;
+ tmp=string_from_char(ssh_type_to_char(sign->type));
+ buffer_add_ssh_string(tmpbuf,tmp);
+ free(tmp);
+ switch(sign->type){
+ case TYPE_DSS:
+ r=make_bignum_string(sign->dsa_sign->r);
+ s=make_bignum_string(sign->dsa_sign->s);
+ rs=string_new(40);
+ memset(buffer,0,40);
+ memcpy(buffer,r->string+string_len(r)-20,20);
+ memcpy(buffer+ 20, s->string + string_len(s) - 20, 20);
+ string_fill(rs,buffer,40);
+ free(r);
+ free(s);
+ buffer_add_ssh_string(tmpbuf,rs);
+ free(rs);
+ break;
+ case TYPE_RSA:
+ case TYPE_RSA1:
+ buffer_add_ssh_string(tmpbuf,sign->rsa_sign);
+ break;
+ }
+ str=string_new(buffer_get_len(tmpbuf));
+ string_fill(str,buffer_get(tmpbuf),buffer_get_len(tmpbuf));
+ buffer_free(tmpbuf);
+ return str;
+}
+
+/* TODO : split this function in two so it becomes smaller */
+SIGNATURE *signature_from_string(STRING *signature,PUBLIC_KEY *pubkey,int needed_type){
+ DSA_SIG *sig;
+ SIGNATURE *sign=malloc(sizeof(SIGNATURE));
+ BUFFER *tmpbuf=buffer_new();
+ STRING *rs;
+ STRING *r,*s,*type_s,*e;
+ int len,rsalen;
+ char *type;
+ buffer_add_data(tmpbuf,signature->string,string_len(signature));
+ type_s=buffer_get_ssh_string(tmpbuf);
+ if(!type_s){
+ ssh_set_error(NULL,SSH_FATAL,"Invalid signature packet");
+ buffer_free(tmpbuf);
+ return NULL;
+ }
+ type=string_to_char(type_s);
+ free(type_s);
+ switch(needed_type){
+ case TYPE_DSS:
+ if(strcmp(type,"ssh-dss")){
+ ssh_set_error(NULL,SSH_FATAL,"Invalid signature type : %s",type);
+ buffer_free(tmpbuf);
+ free(type);
+ return NULL;
+ }
+ break;
+ case TYPE_RSA:
+ if(strcmp(type,"ssh-rsa")){
+ ssh_set_error(NULL,SSH_FATAL,"Invalid signature type : %s",type);
+ buffer_free(tmpbuf);
+ free(type);
+ return NULL;
+ }
+ break;
+ default:
+ ssh_set_error(NULL,SSH_FATAL,"Invalid signature type : %s",type);
+ free(type);
+ buffer_free(tmpbuf);
+ return NULL;
+ }
+ free(type);
+ switch(needed_type){
+ case TYPE_DSS:
+ rs=buffer_get_ssh_string(tmpbuf);
+ buffer_free(tmpbuf);
+ if(!rs || string_len(rs)!=40){ /* 40 is the dual signature blob len. */
+ if(rs)
+ free(rs);
+ return NULL;
+ }
+ /* we make use of strings because we have all-made functions to convert them to bignums */
+ r=string_new(20);
+ s=string_new(20);
+ string_fill(r,rs->string,20);
+ string_fill(s,rs->string+20,20);
+ free(rs);
+ sig=DSA_SIG_new();
+ sig->r=make_string_bn(r); /* is that really portable ? Openssh's hack isn't better */
+ sig->s=make_string_bn(s);
+#ifdef DEBUG_CRYPTO
+ ssh_print_bignum("r",sig->r);
+ ssh_print_bignum("s",sig->s);
+#endif
+ free(r);
+ free(s);
+ sign->type=TYPE_DSS;
+ sign->dsa_sign=sig;
+ return sign;
+ case TYPE_RSA:
+ e=buffer_get_ssh_string(tmpbuf);
+ buffer_free(tmpbuf);
+ if(!e){
+ free(e);
+ return NULL;
+ }
+ len=string_len(e);
+ rsalen=RSA_size(pubkey->rsa_pub);
+ if(len>rsalen){
+ free(e);
+ free(sign);
+ ssh_set_error(NULL,SSH_FATAL,"signature too big ! %d instead of %d",len,rsalen);
+ return NULL;
+ }
+ if(len<rsalen)
+ ssh_say(0,"Len %d < %d\n",len,rsalen);
+ sign->type=TYPE_RSA;
+ sign->rsa_sign=e;
+#ifdef DEBUG_CRYPTO
+ ssh_say(0,"Len : %d\n",len);
+ ssh_print_hexa("rsa signature",e->string,len);
+#endif
+ return sign;
+ default:
+ return NULL;
+ }
+}
+
+void signature_free(SIGNATURE *sign){
+ if(!sign)
+ return;
+ switch(sign->type){
+ case TYPE_DSS:
+ DSA_SIG_free(sign->dsa_sign);
+ break;
+ case TYPE_RSA:
+ case TYPE_RSA1:
+ free(sign->rsa_sign);
+ break;
+ default:
+ ssh_say(1,"freeing a signature with no type !\n");
+ }
+ free(sign);
+}
+
+/* maybe the missing function from libcrypto */
+/* i think now, maybe it's a bad idea to name it has it should have be named in libcrypto */
+static STRING *RSA_do_sign(void *payload,int len,RSA *privkey){
+ STRING *sign;
+ void *buffer=malloc(RSA_size(privkey));
+ unsigned int size;
+ int err;
+ err=RSA_sign(NID_sha1,payload,len,buffer,&size,privkey);
+ if(!err){
+ free(buffer);
+ return NULL;
+ }
+ sign=string_new(size);
+ string_fill(sign,buffer,size);
+ free(buffer);
+ return sign;
+}
+
+STRING *ssh_do_sign(SSH_SESSION *session,BUFFER *sigbuf, PRIVATE_KEY *privatekey){
+ SHACTX *ctx;
+ STRING *session_str=string_new(SHA_DIGEST_LEN);
+ char hash[SHA_DIGEST_LEN];
+ SIGNATURE *sign;
+ STRING *signature;
+ string_fill(session_str,session->current_crypto->session_id,SHA_DIGEST_LENGTH);
+ ctx=sha1_init();
+ sha1_update(ctx,session_str,string_len(session_str)+4);
+ sha1_update(ctx,buffer_get(sigbuf),buffer_get_len(sigbuf));
+ sha1_final(hash,ctx);
+ free(session_str);
+ sign=malloc(sizeof(SIGNATURE));
+ switch(privatekey->type){
+ case TYPE_DSS:
+ sign->dsa_sign=DSA_do_sign(hash,SHA_DIGEST_LENGTH,privatekey->dsa_priv);
+ sign->rsa_sign=NULL;
+ break;
+ case TYPE_RSA:
+ sign->rsa_sign=RSA_do_sign(hash,SHA_DIGEST_LENGTH,privatekey->rsa_priv);
+ sign->dsa_sign=NULL;
+ break;
+ }
+ sign->type=privatekey->type;
+ if(!sign->dsa_sign && !sign->rsa_sign){
+ ssh_set_error(session,SSH_FATAL,"Signing : openssl error");
+ signature_free(sign);
+ return NULL;
+ }
+ signature=signature_to_string(sign);
+ signature_free(sign);
+ return signature;
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/libssh.h b/kftpgrabber/src/misc/libs/ssh/libssh.h
new file mode 100644
index 0000000..7fdc939
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/libssh.h
@@ -0,0 +1,218 @@
+/*
+Copyright 2003,04 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. */
+
+#ifndef _LIBSSH_H
+#define _LIBSSH_H
+#include "config.h"
+#include <unistd.h>
+#include <sys/select.h> /* for fd_set * */
+#include <sys/types.h>
+#define LIBSSH_VERSION "libssh-0.11-dev"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct string_struct STRING;
+typedef struct buffer_struct BUFFER;
+typedef struct public_key_struct PUBLIC_KEY;
+typedef struct private_key_struct PRIVATE_KEY;
+typedef struct ssh_options_struct SSH_OPTIONS;
+typedef struct channel_struct CHANNEL;
+typedef struct ssh_session SSH_SESSION;
+typedef struct ssh_kbdint SSH_KBDINT;
+
+/* integer values */
+typedef u_int32_t u32;
+typedef u_int16_t u16;
+typedef u_int64_t u64;
+typedef u_int8_t u8;
+
+/* the offsets of methods */
+#define KEX_ALGO 0
+#define KEX_HOSTKEY 1
+#define KEX_CRYPT_C_S 2
+#define KEX_CRYPT_S_C 3
+#define KEX_MAC_C_S 4
+#define KEX_MAC_S_C 5
+#define KEX_COMP_C_S 6
+#define KEX_COMP_S_C 7
+#define KEX_LANG_C_S 8
+#define KEX_LANG_S_C 9
+
+#define SSH_AUTH_SUCCESS 0
+#define SSH_AUTH_DENIED 1
+#define SSH_AUTH_PARTIAL 2
+#define SSH_AUTH_INFO 3
+#define SSH_AUTH_ERROR -1
+
+#define SSH_SERVER_ERROR -1
+#define SSH_SERVER_NOT_KNOWN 0
+#define SSH_SERVER_KNOWN_OK 1
+#define SSH_SERVER_KNOWN_CHANGED 2
+#define SSH_SERVER_FOUND_OTHER 3
+
+#ifndef MD5_DIGEST_LEN
+ #define MD5_DIGEST_LEN 16
+#endif
+/* errors */
+
+enum ssh_error {SSH_NO_ERROR, SSH_REQUEST_DENIED, SSH_INVALID_REQUEST, SSH_CONNECTION_LOST,SSH_FATAL,SSH_INVALID_DATA};
+char *ssh_get_error(SSH_SESSION *session); /* returns a static char array */
+enum ssh_error ssh_error_code(SSH_SESSION *session);
+void ssh_say(int priority,char *format,...);
+void ssh_set_verbosity(int num);
+
+ /* There is a verbosity level */
+ /* 3 : packet level */
+ /* 2 : protocol level */
+ /* 1 : functions level */
+ /* 0 : important messages only */
+ /* -1 : no messages */
+
+/* in client.c */
+
+SSH_SESSION *ssh_connect(SSH_OPTIONS *options);
+void ssh_disconnect(SSH_SESSION *session);
+int ssh_service_request(SSH_SESSION *session,char *service);
+char *ssh_get_issue_banner(SSH_SESSION *session);
+/* get copyright informations */
+const char *ssh_copyright();
+/* string.h */
+
+/* You can use these functions, they won't change */
+/* makestring returns a newly allocated string from a char * ptr */
+STRING *string_from_char(char *what);
+/* it returns the string len in host byte orders. str->size is big endian warning ! */
+int string_len(STRING *str);
+STRING *string_new(u32 size);
+/* string_fill copies the data in the string. it does NOT check for boundary so allocate enough place with new_string */
+/* right before */
+void string_fill(STRING *str,void *data,int len);
+/* returns a newly allocated char array with the str string and a final nul caracter */
+char *string_to_char(STRING *str);
+STRING *string_copy(STRING *str);
+
+/* deprecated */
+void ssh_crypto_init();
+
+/* useful for debug */
+void ssh_print_hexa(char *descr,unsigned char *what, int len);
+void ssh_get_random(void *,int);
+
+/* this one can be called by the client to see the hash of the public key before accepting it */
+int ssh_get_pubkey_hash(SSH_SESSION *session,char hash[MD5_DIGEST_LEN]);
+STRING *ssh_get_pubkey(SSH_SESSION *session);
+
+/* deprecated */
+int pubkey_get_hash(SSH_SESSION *session,char hash[MD5_DIGEST_LEN]);
+
+/* in connect.c */
+int ssh_fd_poll(SSH_SESSION *session);
+int ssh_select(CHANNEL **channels,CHANNEL **outchannels, int maxfd, fd_set *readfds, struct timeval *timeout);
+
+void publickey_free(PUBLIC_KEY *key);
+
+/* in keyfiles.c */
+
+PRIVATE_KEY *privatekey_from_file(SSH_SESSION *session,char *filename,int type,char *passphrase);
+void private_key_free(PRIVATE_KEY *prv);
+STRING *publickey_from_file(char *filename,int *_type);
+STRING *publickey_from_next_file(SSH_SESSION *session,char **pub_keys_path,char **keys_path,
+ char **privkeyfile,int *type,int *count);
+int ssh_is_server_known(SSH_SESSION *session);
+int ssh_write_knownhost(SSH_SESSION *session);
+
+/* in channels.c */
+
+/* this one is deprecated */
+CHANNEL *open_session_channel(SSH_SESSION *session,int window,int maxpacket);
+CHANNEL *channel_open_forward(SSH_SESSION *session,char *remotehost, int remoteport, char *sourcehost, int localport);
+CHANNEL *channel_open_session(SSH_SESSION *session);
+void channel_free(CHANNEL *channel);
+int channel_request_pty(CHANNEL *channel);
+int channel_request_pty_size(CHANNEL *channel, char *term,int cols, int rows);
+int channel_change_pty_size(CHANNEL *channel,int cols,int rows);
+int channel_request_shell(CHANNEL *channel);
+int channel_request_subsystem(CHANNEL *channel, char *system);
+int channel_request_env(CHANNEL *channel,char *name, char *value);
+int channel_request_exec(CHANNEL *channel, char *cmd);
+int channel_request_sftp(CHANNEL *channel);
+int channel_write(CHANNEL *channel,void *data,int len);
+int channel_set_write_handler(CHANNEL *channel,
+ void (*write_fct)(CHANNEL *channel, void *data, int len, void *userdefined),
+ void *user);
+int channel_set_stderr_write_handler(CHANNEL *channel,
+ void (*write_err_fct)(CHANNEL *channel, void *data, int len, void *userdefined),
+ void *user);
+int channel_send_eof(CHANNEL *channel);
+int channel_read(CHANNEL *channel, BUFFER *buffer,int bytes,int is_stderr);
+int channel_poll(CHANNEL *channel, int is_stderr);
+int channel_close(CHANNEL *channel);
+int channel_read_nonblocking(CHANNEL *channel, char *dest, int len, int is_stderr);
+int channel_is_open(CHANNEL *channel);
+/* in options.c */
+
+SSH_OPTIONS *options_new();
+SSH_OPTIONS *options_copy(SSH_OPTIONS *opt);
+int options_set_wanted_method(SSH_OPTIONS *opt,int method, char *list);
+void options_set_username(SSH_OPTIONS *opt,char *username);
+void options_set_port(SSH_OPTIONS *opt, unsigned int port);
+SSH_OPTIONS *ssh_getopt(int *argcptr, char **argv);
+void options_set_host(SSH_OPTIONS *opt, const char *host);
+/* don't connect to host, use fd instead */
+void options_set_fd(SSH_OPTIONS *opt, int fd);
+void options_set_bindaddr(SSH_OPTIONS *opt, char *bindaddr);
+void options_set_identity(SSH_OPTIONS *opt, char *identity);
+void options_set_status_callback(SSH_OPTIONS *opt, void (*callback)(void *arg, float status), void *arg);
+void options_set_timeout(SSH_OPTIONS *opt, long seconds, long usec);
+void options_set_ssh_dir(SSH_OPTIONS *opt, char *dir);
+void options_set_known_hosts_file(SSH_OPTIONS *opt, char *dir);
+/* buffer.c */
+
+BUFFER *buffer_new();
+void buffer_free(BUFFER *buffer);
+/* buffer_get returns a pointer to the begining of the buffer. no position is taken into account */
+void *buffer_get(BUFFER *buffer);
+/* same here */
+int buffer_get_len(BUFFER *buffer);
+
+
+/* in auth.c */
+/* these functions returns AUTH_ERROR is some serious error has happened,
+ AUTH_SUCCESS if success,
+ AUTH_PARTIAL if partial success,
+ AUTH_DENIED if refused */
+int ssh_userauth_none(SSH_SESSION *session,char *username);
+int ssh_userauth_password(SSH_SESSION *session,char *username,char *password);
+int ssh_userauth_offer_pubkey(SSH_SESSION *session, char *username,int type, STRING *publickey);
+int ssh_userauth_pubkey(SSH_SESSION *session, char *username, STRING *publickey, PRIVATE_KEY *privatekey);
+int ssh_userauth_autopubkey(SSH_SESSION *session, const char *passphrase);
+int ssh_userauth_kbdint(SSH_SESSION *session, char *user, char *submethods);
+int ssh_userauth_kbdint_getnprompts(SSH_SESSION *session);
+char *ssh_userauth_kbdint_getname(SSH_SESSION *session);
+char *ssh_userauth_kbdint_getinstruction(SSH_SESSION *session);
+char *ssh_userauth_kbdint_getprompt(SSH_SESSION *session, int i, char *echo);
+void ssh_userauth_kbdint_setanswer(SSH_SESSION *session, unsigned int i, char *answer);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _LIBSSH_H */
diff --git a/kftpgrabber/src/misc/libs/ssh/misc.c b/kftpgrabber/src/misc/libs/ssh/misc.c
new file mode 100644
index 0000000..fc3cb79
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/misc.c
@@ -0,0 +1,98 @@
+/* misc.c */
+/* some misc routines than aren't really part of the ssh protocols but can be useful to the client */
+
+/*
+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 <string.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <netdb.h>
+#include "libssh.h"
+
+/* if the program was executed suid root, don't trust the user ! */
+static int is_trusted(){
+ if(geteuid()!=getuid())
+ return 0;
+ return 1;
+}
+
+static char *get_homedir_from_uid(int uid){
+ struct passwd *pwd;
+ char *home;
+ while((pwd=getpwent())){
+ if(pwd->pw_uid == uid){
+ home=strdup(pwd->pw_dir);
+ endpwent();
+ return home;
+ }
+ }
+ endpwent();
+ return NULL;
+}
+
+static char *get_homedir_from_login(char *user){
+ struct passwd *pwd;
+ char *home;
+ while((pwd=getpwent())){
+ if(!strcmp(pwd->pw_name,user)){
+ home=strdup(pwd->pw_dir);
+ endpwent();
+ return home;
+ }
+ }
+ endpwent();
+ return NULL;
+}
+
+char *ssh_get_user_home_dir(){
+ char *home;
+ char *user;
+ int trusted=is_trusted();
+ if(trusted){
+ if((home=getenv("HOME")))
+ return strdup(home);
+ if((user=getenv("USER")))
+ return get_homedir_from_login(user);
+ }
+ return get_homedir_from_uid(getuid());
+}
+
+/* we have read access on file */
+int ssh_file_readaccess_ok(char *file){
+ if(!access(file,R_OK))
+ return 1;
+ return 0;
+}
+
+
+u64 ntohll(u64 a){
+#ifdef WORDS_BIGENDIAN
+ return a;
+#else
+ u32 low=a & 0xffffffff;
+ u32 high = a >> 32 ;
+ low=ntohl(low);
+ high=ntohl(high);
+ return (( ((u64)low) << 32) | ( high));
+#endif
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/options.c b/kftpgrabber/src/misc/libs/ssh/options.c
new file mode 100644
index 0000000..74ab189
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/options.c
@@ -0,0 +1,341 @@
+/* options.c */
+/* handle pre-connection options */
+/*
+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 <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include "priv.h"
+
+SSH_OPTIONS *options_new(){
+ SSH_OPTIONS *option=malloc(sizeof(SSH_OPTIONS));
+ memset(option,0,sizeof(SSH_OPTIONS));
+ option->port=22; /* set the default port */
+ option->fd=-1;
+ return option;
+}
+
+void options_set_port(SSH_OPTIONS *opt, unsigned int port){
+ opt->port=port&0xffff;
+}
+SSH_OPTIONS *options_copy(SSH_OPTIONS *opt){
+ SSH_OPTIONS *ret=options_new();
+ int i;
+ ret->fd=opt->fd;
+ ret->port=opt->port;
+ if(opt->username)
+ ret->username=strdup(opt->username);
+ if(opt->host)
+ ret->host=strdup(opt->host);
+ if(opt->bindaddr)
+ ret->host=strdup(opt->bindaddr);
+ if(opt->identity)
+ ret->identity=strdup(opt->identity);
+ if(opt->ssh_dir)
+ ret->ssh_dir=strdup(opt->ssh_dir);
+ if(opt->known_hosts_file)
+ ret->known_hosts_file=strdup(opt->known_hosts_file);
+ for(i=0;i<10;++i)
+ if(opt->wanted_methods[i])
+ ret->wanted_methods[i]=strdup(opt->wanted_methods[i]);
+ ret->passphrase_function=opt->passphrase_function;
+ ret->connect_status_function=opt->connect_status_function;
+ ret->connect_status_arg=opt->connect_status_arg;
+ ret->timeout=opt->timeout;
+ ret->timeout_usec=opt->timeout_usec;
+ return ret;
+}
+
+void options_free(SSH_OPTIONS *opt){
+ int i;
+ if(opt->username)
+ free(opt->username);
+ if(opt->identity)
+ free(opt->identity);
+ /* we don't touch the banner. if the implementation did use it, they have to free it */
+ if(opt->host)
+ free(opt->host);
+ if(opt->bindaddr)
+ free(opt->bindaddr);
+ if(opt->ssh_dir)
+ free(opt->ssh_dir);
+ for(i=0;i<10;i++)
+ if(opt->wanted_methods[i])
+ free(opt->wanted_methods[i]);
+ memset(opt,0,sizeof(SSH_OPTIONS));
+ free(opt);
+}
+
+
+void options_set_host(SSH_OPTIONS *opt, const char *hostname){
+ char *ptr=strdup(hostname);
+ char *ptr2=strchr(ptr,'@');
+ if(opt->host) /* don't leak memory */
+ free(opt->host);
+ if(ptr2){
+ *ptr2=0;
+ opt->host=strdup(ptr2+1);
+ if(opt->username)
+ free(opt->username);
+ opt->username=strdup(ptr);
+ free(ptr);
+ } else
+ opt->host=ptr;
+}
+
+void options_set_fd(SSH_OPTIONS *opt, int fd){
+ opt->fd=fd;
+}
+
+void options_set_bindaddr(SSH_OPTIONS *opt, char *bindaddr){
+ opt->bindaddr=strdup(bindaddr);
+}
+
+void options_set_username(SSH_OPTIONS *opt,char *username){
+ opt->username=strdup(username);
+}
+
+void options_set_ssh_dir(SSH_OPTIONS *opt, char *dir){
+ char buffer[1024];
+ snprintf(buffer,1024,dir,ssh_get_user_home_dir());
+ opt->ssh_dir=strdup(buffer);
+}
+void options_set_known_hosts_file(SSH_OPTIONS *opt, char *dir){
+ char buffer[1024];
+ snprintf(buffer,1024,dir,ssh_get_user_home_dir());
+ opt->known_hosts_file=strdup(buffer);
+}
+
+void options_set_identity(SSH_OPTIONS *opt, char *identity){
+ char buffer[1024];
+ snprintf(buffer,1024,identity,ssh_get_user_home_dir());
+ opt->identity=strdup(buffer);
+}
+
+/* what's the deal here ? some options MUST be set before authentication or key exchange,
+ * otherwise default values are going to be used. what must be configurable :
+ * Public key certification method *
+ * key exchange method (dh-sha1 for instance)*
+ * c->s, s->c ciphers *
+ * c->s s->c macs *
+ * c->s s->c compression */
+
+/* they all return 0 if all went well, 1 or !=0 if not. the most common error is unmatched algo (unimplemented) */
+/* don't forget other errors can happen if no matching algo is found in sshd answer */
+
+int options_set_wanted_method(SSH_OPTIONS *opt,int method, char *list){
+ if(method > 9 || method < 0){
+ ssh_set_error(NULL,SSH_FATAL,"method %d out of range",method);
+ return -1;
+ }
+ if( (!opt->use_nonexisting_algo) && !verify_existing_algo(method,list)){
+ ssh_set_error(NULL,SSH_FATAL,"Setting method : no algorithm for method \"%s\" (%s)\n",ssh_kex_nums[method],list);
+ return -1;
+ }
+ if(opt->wanted_methods[method])
+ free(opt->wanted_methods[method]);
+ opt->wanted_methods[method]=strdup(list);
+ return 0;
+}
+
+static char *get_username_from_uid(int uid){
+ struct passwd *pwd;
+ char *user;
+ while((pwd=getpwent())){
+ if(pwd->pw_uid == uid){
+ user=strdup(pwd->pw_name);
+ endpwent();
+ return user;
+ }
+ }
+ endpwent();
+ ssh_set_error(NULL,SSH_FATAL,"uid %d doesn't exist !",uid);
+ return NULL;
+}
+
+/* this function must be called when no specific username has been asked. it has to guess it */
+int options_default_username(SSH_OPTIONS *opt){
+ char *user;
+ if(opt->username)
+ return 0;
+ user=getenv("USER");
+ if(user){
+ opt->username=strdup(user);
+ return 0;
+ }
+ user=get_username_from_uid(getuid());
+ if(user){
+ opt->username=user;
+ return 0;
+ }
+ return -1;
+}
+
+int options_default_ssh_dir(SSH_OPTIONS *opt){
+ char buffer[256];
+ if(opt->ssh_dir)
+ return 0;
+ snprintf(buffer,256,"%s/.ssh/",ssh_get_user_home_dir());
+ opt->ssh_dir=strdup(buffer);
+ return 0;
+}
+
+int options_default_known_hosts_file(SSH_OPTIONS *opt){
+ char buffer[1024];
+ if(opt->known_hosts_file)
+ return 0;
+ options_default_ssh_dir(opt);
+ snprintf(buffer,1024,"%s/known_hosts",opt->ssh_dir);
+ opt->known_hosts_file=strdup(buffer);
+ return 0;
+}
+
+void options_set_status_callback(SSH_OPTIONS *opt, void (*callback)(void *arg, float status), void *arg ){
+ opt->connect_status_function=callback;
+ opt->connect_status_arg=arg;
+}
+
+void options_set_timeout(SSH_OPTIONS *opt, long seconds,long usec){
+ opt->timeout=seconds;
+ opt->timeout_usec=usec;
+}
+
+SSH_OPTIONS *ssh_getopt(int *argcptr, char **argv){
+ int i;
+ int argc=*argcptr;
+ char *user=NULL;
+ int port=22;
+ int debuglevel=0;
+ int usersa=0;
+ int usedss=0;
+ int compress=0;
+ int cont=1;
+ char *cipher=NULL;
+ char *localaddr=NULL;
+ char *identity=NULL;
+ char **save=malloc(argc * sizeof(char *));
+ int current=0;
+
+ int saveoptind=optind; /* need to save 'em */
+ int saveopterr=opterr;
+ SSH_OPTIONS *options;
+ opterr=0; /* shut up getopt */
+ while(cont && ((i=getopt(argc,argv,"c:i:Cl:p:vb:rd12"))!=-1)){
+
+ switch(i){
+ case 'l':
+ user=optarg;
+ break;
+ case 'p':
+ port=atoi(optarg)&0xffff;
+ break;
+ case 'v':
+ debuglevel++;
+ break;
+ case 'r':
+ usersa++;
+ break;
+ case 'd':
+ usedss++;
+ break;
+ case 'c':
+ cipher=optarg;
+ break;
+ case 'i':
+ identity=optarg;
+ break;
+ case 'b':
+ localaddr=optarg;
+ break;
+ case 'C':
+ compress++;
+ break;
+ case '2':
+ break; /* only ssh2 support till now */
+ case '1':
+ ssh_set_error(NULL,SSH_FATAL,"libssh does not support SSH1 protocol");
+ cont =0;
+ break;
+ default:
+ {
+ char opt[3]="- ";
+ opt[1]=optopt;
+ save[current++]=strdup(opt);
+ if(optarg)
+ save[current++]=argv[optind+1];
+ }
+ }
+ }
+ opterr=saveopterr;
+ while(optind < argc)
+ save[current++]=argv[optind++];
+
+ if(usersa && usedss){
+ ssh_set_error(NULL,SSH_FATAL,"either RSA or DSS must be chosen");
+ cont=0;
+ }
+ ssh_set_verbosity(debuglevel);
+ optind=saveoptind;
+ if(!cont){
+ free(save);
+ return NULL;
+ }
+ /* first recopy the save vector into original's */
+ for(i=0;i<current;i++)
+ argv[i+1]=save[i]; /* don't erase argv[0] */
+ argv[current+1]=NULL;
+ *argcptr=current+1;
+ free(save);
+ /* set a new option struct */
+ options=options_new();
+ if(compress){
+ if(options_set_wanted_method(options,KEX_COMP_C_S,"zlib"))
+ cont=0;
+ if(options_set_wanted_method(options,KEX_COMP_S_C,"zlib"))
+ cont=0;
+ }
+ if(cont &&cipher){
+ if(options_set_wanted_method(options,KEX_CRYPT_C_S,cipher))
+ cont=0;
+ if(cont && options_set_wanted_method(options,KEX_CRYPT_S_C,cipher))
+ cont=0;
+ }
+ if(cont && usersa)
+ if(options_set_wanted_method(options,KEX_HOSTKEY,"ssh-rsa"))
+ cont=0;
+ if(cont && usedss)
+ if(options_set_wanted_method(options,KEX_HOSTKEY,"ssh-dss"))
+ cont=0;
+ if(cont && user)
+ options_set_username(options,user);
+ if(cont && identity)
+ options_set_identity(options,identity);
+ if(cont && localaddr)
+ options_set_bindaddr(options,localaddr);
+ options_set_port(options,port);
+ if(!cont){
+ options_free(options);
+ return NULL;
+ } else
+ return options;
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/packet.c b/kftpgrabber/src/misc/libs/ssh/packet.c
new file mode 100644
index 0000000..c41e3a5
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/packet.c
@@ -0,0 +1,303 @@
+/* packet.c */
+/* packet building functions */
+/*
+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 <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include "priv.h"
+#include "ssh2.h"
+#include <netdb.h>
+#include <errno.h>
+#include "crypto.h"
+
+/* XXX include selected mac size */
+static int macsize=SHA_DIGEST_LENGTH;
+
+/* completeread will read blocking until len bytes have been read */
+static int completeread(int fd, void *buffer, int len){
+ int r;
+ int total=0;
+ int toread=len;
+ while((r=read(fd,buffer+total,toread))){
+ if(r==-1)
+ return -1;
+ total += r;
+ toread-=r;
+ if(total==len)
+ return len;
+ if(r==0)
+ return 0;
+ }
+ return total ; /* connection closed */
+}
+
+int packet_read(SSH_SESSION *session){
+ u32 len;
+ void *packet=NULL;
+ char mac[30];
+ char buffer[16];
+ int be_read,i;
+ int to_be_read;
+ u8 padding;
+ unsigned int blocksize=(session->current_crypto?session->current_crypto->in_cipher->blocksize:8);
+ session->datatoread=0; /* clear the dataavailable flag */
+ memset(&session->in_packet,0,sizeof(PACKET));
+ if(session->in_buffer)
+ buffer_free(session->in_buffer);
+ session->in_buffer=buffer_new();
+
+ be_read=completeread(session->fd,buffer,blocksize);
+ if(be_read!=blocksize){
+ if(be_read<=0){
+ session->alive=0;
+ close(session->fd);
+ session->fd=-1;
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,
+ (be_read==0)?"Connection closed by remote host" : "Error reading socket");
+ return -1;
+ }
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"read_packet(): asked %d bytes, received %d",blocksize,be_read);
+ return -1;
+ }
+ len=packet_decrypt_len(session,buffer);
+ buffer_add_data(session->in_buffer,buffer,blocksize);
+
+ if(len> MAX_PACKET_LEN){
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"read_packet(): Packet len too high(%uld %.8lx)",len,len);
+ return -1;
+ }
+ to_be_read=len-be_read+sizeof(u32);
+ if(to_be_read<0){
+ /* remote sshd is trying to get me ?*/
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"given numbers of bytes left to be read <0 (%d)!",to_be_read);
+ return -1;
+ }
+ /* handle the case in which the whole packet size = blocksize */
+ if(to_be_read !=0){
+ packet=malloc(to_be_read);
+ i=completeread(session->fd,packet,to_be_read);
+ if(i<=0){
+ session->alive=0;
+ close(session->fd);
+ session->fd=-1;
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"Server closed connection");
+ return -1;
+ }
+ if(i!=to_be_read){
+ free(packet);
+ packet=NULL;
+ ssh_say(3,"Read only %d, wanted %d\n",i,to_be_read);
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"read_packet(): read only %d, wanted %d",i,to_be_read);
+ return -1;
+ }
+ ssh_say(3,"Read a %d bytes packet\n",len);
+ buffer_add_data(session->in_buffer,packet,to_be_read);
+ free(packet);
+ }
+ if(session->current_crypto){
+ packet_decrypt(session,buffer_get(session->in_buffer)+blocksize,buffer_get_len(session->in_buffer)-blocksize);
+ if((i=completeread(session->fd,mac,macsize))!=macsize){
+ if(i<=0){
+ session->alive=0;
+ close(session->fd);
+ session->fd=-1;
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"Server closed connection");
+ return -1;
+ }
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"read_packet(): wanted %d, had %d",i,macsize);
+ return -1;
+ }
+ if(packet_hmac_verify(session,session->in_buffer,mac)){
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"HMAC error");
+ return -1;
+ }
+ }
+ buffer_pass_bytes(session->in_buffer,sizeof(u32)); /*pass the size which has been processed before*/
+ if(!buffer_get_u8(session->in_buffer,&padding)){
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"Packet too short to read padding");
+ return -1;
+ }
+ ssh_say(3,"%hhd bytes padding\n",padding);
+ if(padding > buffer_get_rest_len(session->in_buffer)){
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"invalid padding: %d (%d resting)",padding,buffer_get_rest_len(session->in_buffer));
+ ssh_print_hexa("incrimined packet",buffer_get(session->in_buffer),buffer_get_len(session->in_buffer));
+ return -1;
+ }
+ buffer_pass_bytes_end(session->in_buffer,padding);
+#ifdef HAVE_LIBZ
+ if(session->current_crypto && session->current_crypto->do_compress_in){
+ decompress_buffer(session,session->in_buffer);
+ }
+#endif
+ session->recv_seq++;
+ return 0;
+}
+
+int packet_translate(SSH_SESSION *session){
+ memset(&session->in_packet,0,sizeof(PACKET));
+ if(!session->in_buffer)
+ return -1;
+ ssh_say(3,"Final size %d\n",buffer_get_rest_len(session->in_buffer));
+ if(!buffer_get_u8(session->in_buffer,&session->in_packet.type)){
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"Packet too short to read type");
+ return -1;
+ }
+ ssh_say(3,"type %hhd\n",session->in_packet.type);
+ session->in_packet.valid=1;
+ return 0;
+}
+
+static int atomic_write(int fd, void *buffer, int len){
+ int written;
+ int total=0;
+ do {
+ written=write(fd,buffer,len);
+ if(written==0)
+ return 0;
+ if(written==-1)
+ return total;
+ total+=written;
+ len-=written;
+ buffer+=written;
+ } while (len > 0);
+ return total;
+}
+
+int packet_send(SSH_SESSION *session){
+ char padstring[32];
+ u32 finallen;
+ u8 padding;
+ u32 currentlen=buffer_get_len(session->out_buffer);
+ char *hmac;
+ int ret=0;
+ unsigned int blocksize=(session->current_crypto?session->current_crypto->out_cipher->blocksize:8);
+ ssh_say(3,"Writing on the wire a packet having %ld bytes before",currentlen);
+#ifdef HAVE_LIBZ
+ if(session->current_crypto && session->current_crypto->do_compress_out){
+ compress_buffer(session,session->out_buffer);
+ currentlen=buffer_get_len(session->out_buffer);
+ }
+#endif
+ padding=(blocksize- ((currentlen+5) % blocksize));
+ if(padding<4)
+ padding+=blocksize;
+ if(session->current_crypto)
+ ssh_get_random(padstring,padding);
+ else
+ memset(padstring,0,padding);
+ finallen=htonl(currentlen+padding+1);
+ ssh_say(3,",%d bytes after comp + %d padding bytes = %d bytes packet\n",currentlen,padding,(ntohl(finallen)));
+ buffer_add_data_begin(session->out_buffer,&padding,sizeof(u8));
+ buffer_add_data_begin(session->out_buffer,&finallen,sizeof(u32));
+ buffer_add_data(session->out_buffer,padstring,padding);
+ hmac=packet_encrypt(session,buffer_get(session->out_buffer),buffer_get_len(session->out_buffer));
+ if(hmac)
+ buffer_add_data(session->out_buffer,hmac,20);
+ if(atomic_write(session->fd,buffer_get(session->out_buffer),buffer_get_len(session->out_buffer))!=buffer_get_len(session->out_buffer)){
+ session->alive=0;
+ close(session->fd);
+ session->fd=-1;
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"Writing packet : error on socket (or connection closed): %s",
+ strerror(errno));
+ ret=-1;
+ }
+ session->send_seq++;
+ buffer_reinit(session->out_buffer);
+ return ret;
+}
+
+void packet_parse(SSH_SESSION *session){
+ int type=session->in_packet.type;
+ u32 foo;
+ STRING *error_s;
+ char *error=NULL;
+
+ switch(type){
+ case SSH2_MSG_DISCONNECT:
+ buffer_get_u32(session->in_buffer,&foo);
+ error_s=buffer_get_ssh_string(session->in_buffer);
+ if(error_s)
+ error=string_to_char(error_s);
+ ssh_say(2,"Received SSH_MSG_DISCONNECT\n");
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"Received SSH_MSG_DISCONNECT : %s",error);
+ if(error_s){
+ free(error_s);
+ free(error);
+ }
+ close(session->fd);
+ session->fd=-1;
+ session->alive=0;
+ return;
+ case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
+ case SSH2_MSG_CHANNEL_DATA:
+ case SSH2_MSG_CHANNEL_EXTENDED_DATA:
+ case SSH2_MSG_CHANNEL_REQUEST:
+ case SSH2_MSG_CHANNEL_EOF:
+ case SSH2_MSG_CHANNEL_CLOSE:
+
+ channel_handle(session,type);
+ case SSH2_MSG_IGNORE:
+ return;
+ default:
+ ssh_say(0,"Received unhandled msg %d\n",type);
+ }
+}
+int packet_wait(SSH_SESSION *session,int type,int blocking){
+ while(1){
+ if(packet_read(session))
+ return -1;
+ if(packet_translate(session))
+ return -1;
+ switch(session->in_packet.type){
+ case SSH2_MSG_DISCONNECT:
+ packet_parse(session);
+ return -1;
+ case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
+ case SSH2_MSG_CHANNEL_DATA:
+ case SSH2_MSG_CHANNEL_EXTENDED_DATA:
+ case SSH2_MSG_CHANNEL_REQUEST:
+ case SSH2_MSG_CHANNEL_EOF:
+ case SSH2_MSG_CHANNEL_CLOSE:
+ packet_parse(session);
+ break;;
+ case SSH2_MSG_IGNORE:
+ break;
+ default:
+ if(type && (type != session->in_packet.type)){
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"waitpacket(): Received a %d type packet, was waiting for a %d\n",session->in_packet.type,type);
+ return -1;
+ }
+ return 0;
+ }
+ if(blocking==0)
+ return 0;
+ }
+ return 0;
+}
+
+void packet_clear_out(SSH_SESSION *session){
+ if(session->out_buffer)
+ buffer_reinit(session->out_buffer);
+ else
+ session->out_buffer=buffer_new();
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/priv.h b/kftpgrabber/src/misc/libs/ssh/priv.h
new file mode 100644
index 0000000..2c93081
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/priv.h
@@ -0,0 +1,384 @@
+/*
+Copyright 2003,04 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. */
+
+/* priv.h file */
+/* This include file contains everything you shouldn't deal with in user programs. */
+/* Consider that anything in this file might change without notice; libssh.h file will keep */
+/* backward compatibility on binary & source */
+
+#ifndef _LIBSSH_PRIV_H
+#define _LIBSSH_PRIV_H
+#include "libssh.h"
+
+/* Debugging constants */
+
+/* Define this if you want to debug crypto systems */
+/* it's usefull when you are debugging the lib */
+/*#define DEBUG_CRYPTO */
+
+/* some constants */
+#define MAX_PACKET_LEN 262144
+#define ERROR_BUFFERLEN 1024
+#define CLIENTBANNER "SSH-2.0-" LIBSSH_VERSION
+#define KBDINT_MAX_PROMPT 256 /* more than openssh's :) */
+/* some types for public keys */
+#define TYPE_DSS 1
+#define TYPE_RSA 2
+#define TYPE_RSA1 3
+
+/* profiling constants. Don't touch them unless you know what you do */
+#define OPENSSL_CRYPTO
+#define OPENSSL_BIGNUMS
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* wrapper things */
+
+#ifdef OPENSSL_CRYPTO
+#include <openssl/dsa.h>
+#include <openssl/rsa.h>
+#include <openssl/sha.h>
+#include <openssl/md5.h>
+#include <openssl/hmac.h>
+typedef SHA_CTX SHACTX;
+typedef MD5_CTX MD5CTX;
+typedef HMAC_CTX HMACCTX;
+#ifdef MD5_DIGEST_LEN
+ #undef MD5_DIGEST_LEN
+#endif
+#define SHA_DIGEST_LEN SHA_DIGEST_LENGTH
+#define MD5_DIGEST_LEN MD5_DIGEST_LENGTH
+
+#endif /* OPENSSL_CRYPTO */
+#ifdef OPENSSL_BIGNUMS
+#include <openssl/bn.h>
+typedef BIGNUM* bignum;
+typedef BN_CTX* bignum_CTX;
+
+#define bignum_new() BN_new()
+#define bignum_free(num) BN_clear_free(num)
+#define bignum_set_word(bn,n) BN_set_word(bn,n)
+#define bignum_bin2bn(bn,datalen,data) BN_bin2bn(bn,datalen,data)
+#define bignum_bn2hex(num) BN_bn2hex(num)
+#define bignum_rand(rnd, bits, top, bottom) BN_rand(rnd,bits,top,bottom)
+#define bignum_ctx_new() BN_CTX_new()
+#define bignum_ctx_free(num) BN_CTX_free(num)
+#define bignum_mod_exp(dest,generator,exp,modulo,ctx) BN_mod_exp(dest,generator,exp,modulo,ctx)
+#define bignum_num_bytes(num) BN_num_bytes(num)
+#define bignum_num_bits(num) BN_num_bits(num)
+#define bignum_is_bit_set(num,bit) BN_is_bit_set(num,bit)
+#define bignum_bn2bin(num,ptr) BN_bn2bin(num,ptr)
+
+#endif /* OPENSSL_BIGNUMS */
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+/* wrapper.c */
+MD5CTX *md5_init(void);
+void md5_update(MD5CTX *c, const void *data, unsigned long len);
+void md5_final(unsigned char *md,MD5CTX *c);
+SHACTX *sha1_init(void);
+void sha1_update(SHACTX *c, const void *data, unsigned long len);
+void sha1_final(unsigned char *md,SHACTX *c);
+void sha1(unsigned char *digest,int len,unsigned char *hash);
+#define HMAC_SHA1 1
+#define HMAC_MD5 2
+HMACCTX *hmac_init(const void *key,int len,int type);
+void hmac_update(HMACCTX *c, const void *data, unsigned long len);
+void hmac_final(HMACCTX *ctx,unsigned char *hashmacbuf,int *len);
+
+/* strings and buffers */
+/* must be 32 bits number + immediatly our data */
+struct string_struct {
+ u32 size;
+ char string[MAX_PACKET_LEN];
+} __attribute__ ((packed));
+
+
+struct buffer_struct {
+ char *data;
+ int used;
+ int allocated;
+ int pos;
+};
+
+/* i should remove it one day */
+typedef struct packet_struct {
+ int valid;
+ u32 len;
+ u8 type;
+} PACKET;
+
+typedef struct kex_struct {
+ char cookie[16];
+ char **methods;
+} KEX;
+
+struct public_key_struct {
+ int type;
+ char *type_c; /* Don't free it ! it is static */
+ DSA *dsa_pub;
+ RSA *rsa_pub;
+};
+
+struct private_key_struct {
+ int type;
+ DSA *dsa_priv;
+ RSA *rsa_priv;
+};
+
+typedef struct signature_struct {
+ int type;
+ DSA_SIG *dsa_sign;
+ STRING *rsa_sign;
+} SIGNATURE;
+
+struct ssh_options_struct {
+ char *clientbanner; /* explicit banner to send */
+ char *username;
+ char *host;
+ char *bindaddr;
+ char *identity;
+ char *ssh_dir;
+ char *known_hosts_file;
+ int fd; /* specificaly wanted file descriptor, don't connect host */
+ int port;
+ int dont_verify_hostkey; /* Don't spare time, don't check host key ! unneeded to say it's dangerous and not safe */
+ int use_nonexisting_algo; /* if user sets a not supported algorithm for kex, don't complain */
+ char *wanted_methods[10]; /* the kex methods can be choosed. better use the kex fonctions to do that */
+ void *wanted_cookie; /* wants a specific cookie to be sent ? if null, generate a new one */
+ void *passphrase_function; /* this functions will be called if a keyphrase is needed. look keyfiles.c for more info */
+ void (*connect_status_function)(void *arg, float status); /* status callback function */
+ void *connect_status_arg; /* arbitrary argument */
+ long timeout; /* seconds */
+ long timeout_usec;
+ };
+
+typedef struct ssh_crypto_struct {
+ bignum e,f,x,k;
+ char session_id[SHA_DIGEST_LEN];
+
+ char encryptIV[SHA_DIGEST_LEN];
+ char decryptIV[SHA_DIGEST_LEN];
+
+ char decryptkey[SHA_DIGEST_LEN*2];
+ char encryptkey[SHA_DIGEST_LEN*2];
+
+ char encryptMAC[SHA_DIGEST_LEN];
+ char decryptMAC[SHA_DIGEST_LEN];
+ char hmacbuf[EVP_MAX_MD_SIZE];
+ struct crypto_struct *in_cipher, *out_cipher; /* the cipher structures/objects */
+ STRING *server_pubkey;
+ char *server_pubkey_type;
+ int do_compress_out; /* idem */
+ int do_compress_in; /* don't set them, set the option instead */
+ void *compress_out_ctx; /* don't touch it */
+ void *compress_in_ctx; /* really, don't */
+} CRYPTO;
+
+struct channel_struct {
+ struct channel_struct *prev;
+ struct channel_struct *next;
+ SSH_SESSION *session; /* SSH_SESSION pointer */
+ u32 local_channel;
+ u32 local_window;
+ int local_eof;
+ u32 local_maxpacket;
+ u32 remote_channel;
+ u32 remote_window;
+ int remote_eof; /* end of file received */
+ u32 remote_maxpacket;
+ int open; /* shows if the channel is still opened */
+ void (*write_fct)(struct channel_struct *channel, void *data, int len, void *userarg);
+ /* this write function is a callback on some userdefined function which is used for writing datas *coming from remote ssh* */
+ /* use channel_write() to write into a ssh pipe */
+ void (*write_err_fct)(struct channel_struct *channel, void *data, int len, void *userarg);
+ /* same as write_fct for stderr */
+ BUFFER *stdout_buffer;
+ BUFFER *stderr_buffer;
+ void *userarg;
+};
+
+struct ssh_session {
+ int fd;
+ SSH_OPTIONS *options;
+ char *serverbanner;
+ char *clientbanner;
+ int protoversion;
+ u32 send_seq;
+ u32 recv_seq;
+ int connected; /* !=0 when the user got a session handle */
+ int alive;
+ int auth_service_asked;
+ int datatoread; /* reading now on socket will not block */
+ STRING *banner; /* that's the issue banner from the server */
+ BUFFER *in_buffer;
+ PACKET in_packet;
+ BUFFER *out_buffer;
+ KEX server_kex;
+ KEX client_kex;
+ BUFFER *in_hashbuf;
+ BUFFER *out_hashbuf;
+ CRYPTO *current_crypto;
+ CRYPTO *next_crypto; /* next_crypto is going to be used after a SSH2_MSG_NEWKEYS */
+ CHANNEL *channels; /* linked list of channels */
+ int maxchannel;
+ int error_code;
+ char error_buffer[ERROR_BUFFERLEN];
+ struct ssh_kbdint *kbdint;
+};
+
+struct ssh_kbdint {
+ u32 nprompts;
+ char *name;
+ char *instruction;
+ char **prompts;
+ char *echo; /* bool array */
+ char **answers;
+};
+
+/* errors.c */
+void ssh_set_error(SSH_SESSION *session,enum ssh_error code,char *descr,...);
+
+/* in dh.c */
+/* DH key generation */
+void dh_generate_e(SSH_SESSION *session);
+void dh_generate_x(SSH_SESSION *session);
+STRING *dh_get_e(SSH_SESSION *session);
+void dh_import_f(SSH_SESSION *session,STRING *f_string);
+void dh_import_pubkey(SSH_SESSION *session,STRING *pubkey_string);
+void dh_build_k(SSH_SESSION *session);
+void make_sessionid(SSH_SESSION *session);
+/* add data for the final cookie */
+void hashbufin_add_cookie(SSH_SESSION *session,unsigned char *cookie);
+void hashbufout_add_cookie(SSH_SESSION *session);
+void generate_session_keys(SSH_SESSION *session);
+/* returns 1 if server signature ok, 0 otherwise. The NEXT crypto is checked, not the current one */
+int signature_verify(SSH_SESSION *session,STRING *signature);
+bignum make_string_bn(STRING *string);
+STRING *make_bignum_string(bignum num);
+
+/* in crypt.c */
+u32 packet_decrypt_len(SSH_SESSION *session,char *crypted);
+int packet_decrypt(SSH_SESSION *session, void *packet,unsigned int len);
+char *packet_encrypt(SSH_SESSION *session,void *packet,unsigned int len);
+ /* it returns the hmac buffer if exists*/
+int packet_hmac_verify(SSH_SESSION *session,BUFFER *buffer,char *mac);
+
+/* in packet.c */
+void packet_clear_out(SSH_SESSION *session);
+void packet_parse(SSH_SESSION *session);
+int packet_send(SSH_SESSION *session);
+int packet_read(SSH_SESSION *session);
+int packet_translate(SSH_SESSION *session);
+int packet_wait(SSH_SESSION *session,int type,int blocking);
+
+/* connect.c */
+SSH_SESSION *ssh_session_new();
+int ssh_connect_host(const char *host,const char *bind_addr, int port, long timeout, long usec);
+
+/* in kex.c */
+extern char *ssh_kex_nums[];
+void send_kex(SSH_SESSION *session,int server_kex);
+void list_kex(KEX *kex);
+int set_kex(SSH_SESSION *session);
+int ssh_get_kex(SSH_SESSION *session, int server_kex);
+int verify_existing_algo(int algo,char *name);
+char **space_tokenize(char *chain);
+
+/* in keys.c */
+char *ssh_type_to_char(int type);
+PUBLIC_KEY *publickey_make_dss(BUFFER *buffer);
+PUBLIC_KEY *publickey_make_rsa(BUFFER *buffer);
+PUBLIC_KEY *publickey_from_string(STRING *pubkey_s);
+SIGNATURE *signature_from_string(STRING *signature,PUBLIC_KEY *pubkey,int needed_type);
+void signature_free(SIGNATURE *sign);
+STRING *ssh_do_sign(SSH_SESSION *session,BUFFER *sigbuf, PRIVATE_KEY *privatekey);
+
+/* channel.c */
+void channel_handle(SSH_SESSION *session, int type);
+
+/* options.c */
+void options_free(SSH_OPTIONS *opt);
+/* this function must be called when no specific username has been asked. it has to guess it */
+int options_default_username(SSH_OPTIONS *opt);
+int options_default_ssh_dir(SSH_OPTIONS *opt);
+int options_default_known_hosts_file(SSH_OPTIONS *opt);
+
+/* buffer.c */
+void buffer_add_ssh_string(BUFFER *buffer,STRING *string);
+void buffer_add_u8(BUFFER *buffer, u8 data);
+void buffer_add_u32(BUFFER *buffer, u32 data);
+void buffer_add_u64(BUFFER *buffer,u64 data);
+void buffer_add_data(BUFFER *buffer, void *data, int len);
+void buffer_add_data_begin(BUFFER *buffer,void *data,int len);
+void buffer_add_buffer(BUFFER *buffer, BUFFER *source);
+void buffer_reinit(BUFFER *buffer);
+
+/* buffer_get_rest returns a pointer to the current position into the buffer */
+void *buffer_get_rest(BUFFER *buffer);
+/* buffer_get_rest_len returns the number of bytes which can be read */
+int buffer_get_rest_len(BUFFER *buffer);
+
+/* buffer_read_*() returns the number of bytes read, except for ssh strings */
+int buffer_get_u8(BUFFER *buffer,u8 *data);
+int buffer_get_u32(BUFFER *buffer,u32 *data);
+int buffer_get_u64(BUFFER *buffer, u64 *data);
+
+int buffer_get_data(BUFFER *buffer,void *data,int requestedlen);
+/* buffer_get_ssh_string() is an exception. if the String read is too large or invalid, it will answer NULL. */
+STRING *buffer_get_ssh_string(BUFFER *buffer);
+/* buffer_pass_bytes acts as if len bytes have been read (used for padding) */
+int buffer_pass_bytes_end(BUFFER *buffer,int len);
+int buffer_pass_bytes(BUFFER *buffer, int len);
+
+/* in base64.c */
+BUFFER *base64_to_bin(char *source);
+char *bin_to_base64(unsigned char *source, int len);
+
+/* gzip.c */
+int compress_buffer(SSH_SESSION *session,BUFFER *buf);
+int decompress_buffer(SSH_SESSION *session,BUFFER *buf);
+
+/* wrapper.c */
+int crypt_set_algorithms(SSH_SESSION *);
+CRYPTO *crypto_new();
+void crypto_free(CRYPTO *crypto);
+bignum bignum_new();
+
+/* in misc.c */
+/* gets the user home dir. */
+char *ssh_get_user_home_dir();
+int ssh_file_readaccess_ok(char *file);
+
+/* macro for byte ordering */
+u64 ntohll(u64);
+#define htonll(x) ntohll(x)
+
+
+#ifdef __cplusplus
+} ;
+#endif
+
+#endif /* _LIBSSH_PRIV_H */
diff --git a/kftpgrabber/src/misc/libs/ssh/sftp.c b/kftpgrabber/src/misc/libs/ssh/sftp.c
new file mode 100644
index 0000000..9895456
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/sftp.c
@@ -0,0 +1,1289 @@
+/* scp.c contains the needed function to work with file transfer protocol over ssh*/
+/* don't look further if you believe this is just FTP over some tunnel. It IS different */
+/* This file contains code written by Nick Zitzmann */
+/*
+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 <string.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include "priv.h"
+#include "ssh2.h"
+#include "sftp.h"
+#ifndef NO_SFTP
+/* here how it works : sftp commands are channeled by the ssh sftp subsystem. */
+/* every packet are sent/read using a SFTP_PACKET type structure. */
+/* into these packets, most of the server answers are messages having an ID and */
+/* having a message specific part. it is described by SFTP_MESSAGE */
+/* when reading a message, the sftp system puts it into the queue, so the process having asked for it */
+/* can fetch it, while continuing to read for other messages (it is inspecified in which order messages may */
+/* be sent back to the client */
+
+
+/* functions */
+static void sftp_packet_free(SFTP_PACKET *packet);
+void sftp_enqueue(SFTP_SESSION *session, SFTP_MESSAGE *msg);
+static void sftp_message_free(SFTP_MESSAGE *msg);
+
+SFTP_SESSION *sftp_new(SSH_SESSION *session){
+ SFTP_SESSION *sftp=malloc(sizeof(SFTP_SESSION));
+ memset(sftp,0,sizeof(SFTP_SESSION));
+ sftp->session=session;
+ sftp->channel=open_session_channel(session,131000,32000);
+ if(!sftp->channel){
+ free(sftp);
+ return NULL;
+ }
+ if(channel_request_sftp(sftp->channel)){
+ sftp_free(sftp);
+ return NULL;
+ }
+ return sftp;
+}
+
+void sftp_free(SFTP_SESSION *sftp){
+ struct request_queue *ptr;
+ channel_send_eof(sftp->channel);
+ /* let libssh handle the channel closing from the server reply */
+ ptr=sftp->queue;
+ while(ptr){
+ struct request_queue *old;
+ sftp_message_free(ptr->message);
+ old=ptr->next;
+ free(ptr);
+ ptr=old;
+ }
+ memset(sftp,0,sizeof(*sftp));
+ free(sftp);
+}
+
+int sftp_packet_write(SFTP_SESSION *sftp,u8 type, BUFFER *payload){
+ u32 size;
+ buffer_add_data_begin(payload,&type,sizeof(u8));
+ size=htonl(buffer_get_len(payload));
+ buffer_add_data_begin(payload,&size,sizeof(u32));
+ size=channel_write(sftp->channel,buffer_get(payload),buffer_get_len(payload));
+ if(size != buffer_get_len(payload)){
+ ssh_say(1,"had to write %d bytes, wrote only %d\n",buffer_get_len(payload),size);
+ }
+ return size;
+}
+
+SFTP_PACKET *sftp_packet_read(SFTP_SESSION *sftp){
+ SFTP_PACKET *packet=malloc(sizeof(SFTP_PACKET));
+ u32 size;
+ packet->sftp=sftp;
+ packet->payload=buffer_new();
+ if(channel_read(sftp->channel,packet->payload,4,0)<=0){
+ buffer_free(packet->payload);
+ free(packet);
+ return NULL;
+ }
+ buffer_get_u32(packet->payload,&size);
+ size=ntohl(size);
+ if(channel_read(sftp->channel,packet->payload,1,0)<=0){
+ buffer_free(packet->payload);
+ free(packet);
+ return NULL;
+ }
+ buffer_get_u8(packet->payload,&packet->type);
+ if(size>1)
+ if(channel_read(sftp->channel,packet->payload,size-1,0)<=0){
+ buffer_free(packet->payload);
+ free(packet);
+ return NULL;
+ }
+ return packet;
+}
+
+static SFTP_MESSAGE *sftp_message_new(){
+ SFTP_MESSAGE *msg=malloc(sizeof(SFTP_MESSAGE));
+ memset(msg,0,sizeof(*msg));
+ msg->payload=buffer_new();
+ return msg;
+}
+
+static void sftp_message_free(SFTP_MESSAGE *msg){
+ if(msg->payload)
+ buffer_free(msg->payload);
+ free(msg);
+}
+
+SFTP_MESSAGE *sftp_get_message(SFTP_PACKET *packet){
+ SFTP_MESSAGE *msg=sftp_message_new();
+ msg->sftp=packet->sftp;
+ msg->packet_type=packet->type;
+ if((packet->type!=SSH_FXP_STATUS)&&(packet->type!=SSH_FXP_HANDLE) &&
+ (packet->type != SSH_FXP_DATA) && (packet->type != SSH_FXP_ATTRS)
+ && (packet->type != SSH_FXP_NAME)){
+ ssh_set_error(packet->sftp->session,SSH_INVALID_DATA,"get_message : unknown packet type %d\n",packet->type);
+ sftp_message_free(msg);
+ return NULL;
+ }
+ if(buffer_get_u32(packet->payload,&msg->id)!=sizeof(u32)){
+ ssh_set_error(packet->sftp->session,SSH_INVALID_DATA,"invalid packet %d : no ID",packet->type);
+ sftp_message_free(msg);
+ return NULL;
+ }
+ ssh_say(2,"packet with id %d type %d\n",msg->id,msg->packet_type);
+ buffer_add_data(msg->payload,buffer_get_rest(packet->payload),buffer_get_rest_len(packet->payload));
+ return msg;
+}
+
+int sftp_read_and_dispatch(SFTP_SESSION *session){
+ SFTP_PACKET *packet;
+ SFTP_MESSAGE *message=NULL;
+ packet=sftp_packet_read(session);
+ if(!packet)
+ return -1; /* something nasty happened reading the packet */
+ message=sftp_get_message(packet);
+ sftp_packet_free(packet);
+ if(!message)
+ return -1;
+ sftp_enqueue(session,message);
+ return 0;
+}
+
+static void sftp_packet_free(SFTP_PACKET *packet){
+ if(packet->payload)
+ buffer_free(packet->payload);
+ free(packet);
+}
+
+int sftp_init(SFTP_SESSION *sftp){
+ SFTP_PACKET *packet;
+ BUFFER *buffer=buffer_new();
+ STRING *ext_name_s=NULL, *ext_data_s=NULL;
+ char *ext_name,*ext_data;
+ u32 version=htonl(LIBSFTP_VERSION);
+ buffer_add_u32(buffer,version);
+ sftp_packet_write(sftp,SSH_FXP_INIT,buffer);
+ buffer_free(buffer);
+ packet=sftp_packet_read(sftp);
+ if(!packet)
+ return -1;
+ if(packet->type != SSH_FXP_VERSION){
+ ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received a %d messages instead of SSH_FXP_VERSION",packet->type);
+ sftp_packet_free(packet);
+ return -1;
+ }
+ buffer_get_u32(packet->payload,&version);
+ version=ntohl(version);
+ if(!(ext_name_s=buffer_get_ssh_string(packet->payload))||!(ext_data_s=buffer_get_ssh_string(packet->payload)))
+ ssh_say(2,"sftp server version %d\n",version);
+ else{
+ ext_name=string_to_char(ext_name_s);
+ ext_data=string_to_char(ext_data_s);
+ ssh_say(2,"sftp server version %d (%s,%s)\n",version,ext_name,ext_data);
+ free(ext_name);
+ free(ext_data);
+ }
+ if(ext_name_s)
+ free(ext_name_s);
+ if(ext_data_s)
+ free(ext_data_s);
+ sftp_packet_free(packet);
+ sftp->server_version=version;
+ return 0;
+}
+
+REQUEST_QUEUE *request_queue_new(SFTP_MESSAGE *msg){
+ REQUEST_QUEUE *queue=malloc(sizeof(REQUEST_QUEUE));
+ memset(queue,0,sizeof(REQUEST_QUEUE));
+ queue->message=msg;
+ return queue;
+}
+
+void request_queue_free(REQUEST_QUEUE *queue){
+ memset(queue,0,sizeof(*queue));
+ free(queue);
+}
+
+void sftp_enqueue(SFTP_SESSION *session, SFTP_MESSAGE *msg){
+ REQUEST_QUEUE *queue=request_queue_new(msg);
+ REQUEST_QUEUE *ptr;
+ ssh_say(2,"queued msg type %d id %d\n",msg->id,msg->packet_type);
+ if(!session->queue)
+ session->queue=queue;
+ else {
+ ptr=session->queue;
+ while(ptr->next){
+ ptr=ptr->next; /* find end of linked list */
+ }
+ ptr->next=queue; /* add it on bottom */
+ }
+}
+
+/* pulls of a message from the queue based on the ID. returns null if no message has been found */
+SFTP_MESSAGE *sftp_dequeue(SFTP_SESSION *session, u32 id){
+ REQUEST_QUEUE *queue,*prev=NULL;
+ SFTP_MESSAGE *msg;
+ if(session->queue==NULL){
+ return NULL;
+ }
+ queue=session->queue;
+ while(queue){
+ if(queue->message->id==id){
+ /* remove from queue */
+ if(prev==NULL){
+ session->queue=queue->next;
+ } else {
+ prev->next=queue->next;
+ }
+ msg=queue->message;
+ request_queue_free(queue);
+ ssh_say(2,"dequeued msg id %d type %d\n",msg->id,msg->packet_type);
+ return msg;
+ }
+ prev=queue;
+ queue=queue->next;
+ }
+ return NULL;
+}
+
+/* assigns a new sftp ID for new requests and assures there is no collision between them. */
+u32 sftp_get_new_id(SFTP_SESSION *session){
+ return ++session->id_counter;
+}
+
+STATUS_MESSAGE *parse_status_msg(SFTP_MESSAGE *msg){
+ STATUS_MESSAGE *status;
+ if(msg->packet_type != SSH_FXP_STATUS){
+ ssh_set_error(msg->sftp->session, SSH_INVALID_DATA,"Not a ssh_fxp_status message passed in !");
+ return NULL;
+ }
+ status=malloc(sizeof(STATUS_MESSAGE));
+ memset(status,0,sizeof(*status));
+ status->id=msg->id;
+ if( (buffer_get_u32(msg->payload,&status->status)!= 4)
+ || !(status->error=buffer_get_ssh_string(msg->payload)) ||
+ !(status->lang=buffer_get_ssh_string(msg->payload))){
+ if(status->error)
+ free(status->error);
+ /* status->lang never get allocated if something failed */
+ free(status);
+ ssh_set_error(msg->sftp->session,SSH_INVALID_DATA,"invalid SSH_FXP_STATUS message");
+ return NULL;
+ }
+ status->status=ntohl(status->status);
+ status->errormsg=string_to_char(status->error);
+ status->langmsg=string_to_char(status->lang);
+ return status;
+}
+
+void status_msg_free(STATUS_MESSAGE *status){
+ if(status->errormsg)
+ free(status->errormsg);
+ if(status->error)
+ free(status->error);
+ if(status->langmsg)
+ free(status->langmsg);
+ if(status->lang)
+ free(status->lang);
+ free(status);
+}
+
+SFTP_FILE *parse_handle_msg(SFTP_MESSAGE *msg){
+ SFTP_FILE *file;
+ if(msg->packet_type != SSH_FXP_HANDLE){
+ ssh_set_error(msg->sftp->session,SSH_INVALID_DATA,"Not a ssh_fxp_handle message passed in !");
+ return NULL;
+ }
+ file=malloc(sizeof(SFTP_FILE));
+ memset(file,0,sizeof(*file));
+ file->sftp=msg->sftp;
+ file->handle=buffer_get_ssh_string(msg->payload);
+ file->offset=0;
+ file->eof=0;
+ if(!file->handle){
+ ssh_set_error(msg->sftp->session,SSH_INVALID_DATA,"Invalid SSH_FXP_HANDLE message");
+ free(file);
+ return NULL;
+ }
+ return file;
+}
+
+SFTP_DIR *sftp_opendir(SFTP_SESSION *sftp, char *path){
+ SFTP_DIR *dir=NULL;
+ SFTP_FILE *file;
+ STATUS_MESSAGE *status;
+ SFTP_MESSAGE *msg=NULL;
+ STRING *path_s;
+ BUFFER *payload=buffer_new();
+ u32 id=sftp_get_new_id(sftp);
+ buffer_add_u32(payload,id);
+ path_s=string_from_char(path);
+ buffer_add_ssh_string(payload,path_s);
+ free(path_s);
+ sftp_packet_write(sftp,SSH_FXP_OPENDIR,payload);
+ buffer_free(payload);
+ while(!msg){
+ if(sftp_read_and_dispatch(sftp))
+ /* something nasty has happened */
+ return NULL;
+ msg=sftp_dequeue(sftp,id);
+ }
+ switch (msg->packet_type){
+ case SSH_FXP_STATUS:
+ status=parse_status_msg(msg);
+ sftp_message_free(msg);
+ if(!status)
+ return NULL;
+ ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg);
+ status_msg_free(status);
+ return NULL;
+ case SSH_FXP_HANDLE:
+ file=parse_handle_msg(msg);
+ sftp_message_free(msg);
+ if(file){
+ dir=malloc(sizeof(SFTP_DIR));
+ memset(dir,0,sizeof(*dir));
+ dir->sftp=sftp;
+ dir->name=strdup(path);
+ dir->handle=file->handle;
+ free(file);
+ }
+ return dir;
+ default:
+ ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received message %d during opendir!",msg->packet_type);
+ sftp_message_free(msg);
+ }
+ return NULL;
+}
+
+/* parse the attributes from a payload from some messages */
+/* i coded it on baselines from the protocol version 4. */
+/* please excuse me for the inaccuracy of the code. it isn't my fault, it's sftp draft's one */
+/* this code is dead anyway ... */
+/* version 4 specific code */
+SFTP_ATTRIBUTES *sftp_parse_attr_4(SFTP_SESSION *sftp,BUFFER *buf,int expectnames){
+ u32 flags=0;
+ SFTP_ATTRIBUTES *attr=malloc(sizeof(SFTP_ATTRIBUTES));
+ STRING *owner=NULL;
+ STRING *group=NULL;
+ int ok=0;
+ memset(attr,0,sizeof(*attr));
+ /* it isn't really a loop, but i use it because it's like a try..catch.. construction in C */
+ do {
+ if(buffer_get_u32(buf,&flags)!=4)
+ break;
+ flags=ntohl(flags);
+ attr->flags=flags;
+ if(flags & SSH_FILEXFER_ATTR_SIZE){
+ if(buffer_get_u64(buf,&attr->size)!=8)
+ break;
+ attr->size=ntohll(attr->size);
+ }
+ if(flags & SSH_FILEXFER_ATTR_OWNERGROUP){
+ if(!(owner=buffer_get_ssh_string(buf)))
+ break;
+ if(!(group=buffer_get_ssh_string(buf)))
+ break;
+ }
+ if(flags & SSH_FILEXFER_ATTR_PERMISSIONS){
+ if(buffer_get_u32(buf,&attr->permissions)!=4)
+ break;
+ attr->permissions=ntohl(attr->permissions);
+ }
+ if(flags & SSH_FILEXFER_ATTR_ACCESSTIME){
+ if(buffer_get_u64(buf,&attr->atime64)!=8)
+ break;
+ attr->atime64=ntohll(attr->atime64);
+ }
+ if(flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES){
+ if(buffer_get_u32(buf,&attr->atime_nseconds)!=4)
+ break;
+ attr->atime_nseconds=ntohl(attr->atime_nseconds);
+ }
+ if(flags & SSH_FILEXFER_ATTR_CREATETIME){
+ if(buffer_get_u64(buf,&attr->createtime)!=8)
+ break;
+ attr->createtime=ntohll(attr->createtime);
+ }
+ if(flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES){
+ if(buffer_get_u32(buf,&attr->createtime_nseconds)!=4)
+ break;
+ attr->createtime_nseconds=ntohl(attr->createtime_nseconds);
+ }
+ if(flags & SSH_FILEXFER_ATTR_MODIFYTIME){
+ if(buffer_get_u64(buf,&attr->mtime64)!=8)
+ break;
+ attr->mtime64=ntohll(attr->mtime64);
+ }
+ if(flags & SSH_FILEXFER_ATTR_SUBSECOND_TIMES){
+ if(buffer_get_u32(buf,&attr->mtime_nseconds)!=4)
+ break;
+ attr->mtime_nseconds=ntohl(attr->mtime_nseconds);
+ }
+ if(flags & SSH_FILEXFER_ATTR_ACL){
+ if(!(attr->acl=buffer_get_ssh_string(buf)))
+ break;
+ }
+ if (flags & SSH_FILEXFER_ATTR_EXTENDED){
+ if(buffer_get_u32(buf,&attr->extended_count)!=4)
+ break;
+ attr->extended_count=ntohl(attr->extended_count);
+ while(attr->extended_count && (attr->extended_type=buffer_get_ssh_string(buf))
+ && (attr->extended_data=buffer_get_ssh_string(buf))){
+ attr->extended_count--;
+ }
+ if(attr->extended_count)
+ break;
+ }
+ ok=1;
+ } while (0);
+ if(!ok){
+ /* break issued somewhere */
+ if(owner)
+ free(owner);
+ if(group)
+ free(group);
+ if(attr->acl)
+ free(attr->acl);
+ if(attr->extended_type)
+ free(attr->extended_type);
+ if(attr->extended_data)
+ free(attr->extended_data);
+ free(attr);
+ ssh_set_error(sftp->session,SSH_INVALID_DATA,"Invalid ATTR structure");
+ return NULL;
+ }
+ /* everything went smoothly */
+ if(owner){
+ attr->owner=string_to_char(owner);
+ free(owner);
+ }
+ if(group){
+ attr->group=string_to_char(group);
+ free(group);
+ }
+ return attr;
+}
+
+/* Version 3 code. it is the only one really supported (the draft for the 4 misses clarifications) */
+/* maybe a paste of the draft is better than the code */
+/*
+ uint32 flags
+ uint64 size present only if flag SSH_FILEXFER_ATTR_SIZE
+ uint32 uid present only if flag SSH_FILEXFER_ATTR_UIDGID
+ uint32 gid present only if flag SSH_FILEXFER_ATTR_UIDGID
+ uint32 permissions present only if flag SSH_FILEXFER_ATTR_PERMISSIONS
+ uint32 atime present only if flag SSH_FILEXFER_ACMODTIME
+ uint32 mtime present only if flag SSH_FILEXFER_ACMODTIME
+ uint32 extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED
+ string extended_type
+ string extended_data
+ ... more extended data (extended_type - extended_data pairs),
+ so that number of pairs equals extended_count */
+SFTP_ATTRIBUTES *sftp_parse_attr_3(SFTP_SESSION *sftp,BUFFER *buf,int expectname){
+ u32 flags=0;
+ STRING *name;
+ STRING *longname;
+ SFTP_ATTRIBUTES *attr=malloc(sizeof(SFTP_ATTRIBUTES));
+ int ok=0;
+ memset(attr,0,sizeof(*attr));
+ /* it isn't really a loop, but i use it because it's like a try..catch.. construction in C */
+ do {
+ if(expectname){
+ if(!(name=buffer_get_ssh_string(buf)))
+ break;
+ attr->name=string_to_char(name);
+ free(name);
+ ssh_say(2,"name : %s\n",attr->name);
+ if(!(longname=buffer_get_ssh_string(buf)))
+ break;
+ attr->longname=string_to_char(longname);
+ free(longname);
+ }
+ if(buffer_get_u32(buf,&flags)!=sizeof(u32))
+ break;
+ flags=ntohl(flags);
+ attr->flags=flags;
+ ssh_say(2,"flags : %.8lx\n",flags);
+ if(flags & SSH_FILEXFER_ATTR_SIZE){
+ if(buffer_get_u64(buf,&attr->size)!=sizeof(u64))
+ break;
+ attr->size=ntohll(attr->size);
+ ssh_say(2,"size : %lld\n",attr->size);
+ }
+ if(flags & SSH_FILEXFER_ATTR_UIDGID){
+ if(buffer_get_u32(buf,&attr->uid)!=sizeof(u32))
+ break;
+ if(buffer_get_u32(buf,&attr->gid)!=sizeof(u32))
+ break;
+ attr->uid=ntohl(attr->uid);
+ attr->gid=ntohl(attr->gid);
+ }
+ if(flags & SSH_FILEXFER_ATTR_PERMISSIONS){
+ if(buffer_get_u32(buf,&attr->permissions)!=sizeof(u32))
+ break;
+ attr->permissions=ntohl(attr->permissions);
+ }
+ if(flags & SSH_FILEXFER_ATTR_ACMODTIME){
+ if(buffer_get_u32(buf,&attr->atime)!=sizeof(u32))
+ break;
+ attr->atime=ntohl(attr->atime);
+ if(buffer_get_u32(buf,&attr->mtime)!=sizeof(u32))
+ break;
+ attr->mtime=ntohl(attr->mtime);
+ }
+ if (flags & SSH_FILEXFER_ATTR_EXTENDED){
+ if(buffer_get_u32(buf,&attr->extended_count)!=sizeof(u32))
+ break;
+ attr->extended_count=ntohl(attr->extended_count);
+ while(attr->extended_count && (attr->extended_type=buffer_get_ssh_string(buf))
+ && (attr->extended_data=buffer_get_ssh_string(buf))){
+ attr->extended_count--;
+ }
+ if(attr->extended_count)
+ break;
+ }
+ ok=1;
+ } while (0);
+ if(!ok){
+ /* break issued somewhere */
+ if(attr->name)
+ free(attr->name);
+ if(attr->extended_type)
+ free(attr->extended_type);
+ if(attr->extended_data)
+ free(attr->extended_data);
+ free(attr);
+ ssh_set_error(sftp->session,SSH_INVALID_DATA,"Invalid ATTR structure");
+ return NULL;
+ }
+ /* everything went smoothly */
+ return attr;
+}
+
+void buffer_add_attributes(BUFFER *buffer, SFTP_ATTRIBUTES *attr){
+ u32 flags=(attr?attr->flags:0);
+ flags &= (SSH_FILEXFER_ATTR_SIZE | SSH_FILEXFER_ATTR_UIDGID | SSH_FILEXFER_ATTR_PERMISSIONS | SSH_FILEXFER_ATTR_ACMODTIME);
+ buffer_add_u32(buffer,htonl(flags));
+ if(attr){
+ if (flags & SSH_FILEXFER_ATTR_SIZE)
+ {
+ buffer_add_u64(buffer, htonll(attr->size));
+ }
+ if(flags & SSH_FILEXFER_ATTR_UIDGID){
+ buffer_add_u32(buffer,htonl(attr->uid));
+ buffer_add_u32(buffer,htonl(attr->gid));
+ }
+ if(flags & SSH_FILEXFER_ATTR_PERMISSIONS){
+ buffer_add_u32(buffer,htonl(attr->permissions));
+ }
+ if (flags & SSH_FILEXFER_ATTR_ACMODTIME)
+ {
+ buffer_add_u32(buffer, htonl(attr->atime));
+ buffer_add_u32(buffer, htonl(attr->mtime));
+ }
+ }
+}
+
+
+SFTP_ATTRIBUTES *sftp_parse_attr(SFTP_SESSION *session, BUFFER *buf,int expectname){
+ switch(session->server_version){
+ case 4:
+ return sftp_parse_attr_4(session,buf,expectname);
+ case 3:
+ return sftp_parse_attr_3(session,buf,expectname);
+ default:
+ ssh_set_error(session->session,SSH_INVALID_DATA,"Version %d unsupported by client",session->server_version);
+ return NULL;
+ }
+ return NULL;
+}
+
+int sftp_server_version(SFTP_SESSION *sftp){
+ return sftp->server_version;
+}
+
+SFTP_ATTRIBUTES *sftp_readdir(SFTP_SESSION *sftp, SFTP_DIR *dir){
+ BUFFER *payload;
+ u32 id;
+ SFTP_MESSAGE *msg=NULL;
+ STATUS_MESSAGE *status;
+ SFTP_ATTRIBUTES *attr;
+ if(!dir->buffer){
+ payload=buffer_new();
+ id=sftp_get_new_id(sftp);
+ buffer_add_u32(payload,id);
+ buffer_add_ssh_string(payload,dir->handle);
+ sftp_packet_write(sftp,SSH_FXP_READDIR,payload);
+ buffer_free(payload);
+ ssh_say(2,"sent a ssh_fxp_readdir with id %d\n",id);
+ while(!msg){
+ if(sftp_read_and_dispatch(sftp))
+ /* something nasty has happened */
+ return NULL;
+ msg=sftp_dequeue(sftp,id);
+ }
+ switch (msg->packet_type){
+ case SSH_FXP_STATUS:
+ status=parse_status_msg(msg);
+ sftp_message_free(msg);
+ if(!status)
+ return NULL;
+ if(status->status==SSH_FX_EOF){
+ dir->eof=1;
+ status_msg_free(status);
+ return NULL;
+ }
+ ssh_set_error(sftp->session,SSH_INVALID_DATA,"Unknown error status : %d",status->status);
+ status_msg_free(status);
+ return NULL;
+ case SSH_FXP_NAME:
+ buffer_get_u32(msg->payload,&dir->count);
+ dir->count=ntohl(dir->count);
+ dir->buffer=msg->payload;
+ msg->payload=NULL;
+ sftp_message_free(msg);
+ break;
+ default:
+ ssh_set_error(sftp->session,SSH_INVALID_DATA,"unsupported message back %d",msg->packet_type);
+ sftp_message_free(msg);
+ return NULL;
+ }
+ }
+ /* now dir->buffer contains a buffer and dir->count != 0 */
+ if(dir->count==0){
+ ssh_set_error(sftp->session,SSH_INVALID_DATA,"Count of files sent by the server is zero, which is invalid, or libsftp bug");
+ return NULL;
+ }
+ ssh_say(2,"Count is %d\n",dir->count);
+ attr=sftp_parse_attr(sftp,dir->buffer,1);
+ dir->count--;
+ if(dir->count==0){
+ buffer_free(dir->buffer);
+ dir->buffer=NULL;
+ }
+ return attr;
+}
+
+int sftp_dir_eof(SFTP_DIR *dir){
+ return (dir->eof);
+}
+
+void sftp_attributes_free(SFTP_ATTRIBUTES *file){
+ if(file->name)
+ free(file->name);
+ if(file->longname)
+ free(file->longname);
+ if(file->acl)
+ free(file->acl);
+ if(file->extended_data)
+ free(file->extended_data);
+ if(file->extended_type)
+ free(file->extended_type);
+ if(file->group)
+ free(file->group);
+ if(file->owner)
+ free(file->owner);
+ free(file);
+}
+
+static int sftp_handle_close(SFTP_SESSION *sftp, STRING *handle){
+ SFTP_MESSAGE *msg=NULL;
+ STATUS_MESSAGE *status;
+ int id=sftp_get_new_id(sftp);
+ int err=0;
+ BUFFER *buffer=buffer_new();
+ buffer_add_u32(buffer,id);
+ buffer_add_ssh_string(buffer,handle);
+ sftp_packet_write(sftp,SSH_FXP_CLOSE,buffer);
+ buffer_free(buffer);
+ while(!msg){
+ if(sftp_read_and_dispatch(sftp))
+ /* something nasty has happened */
+ return -1;
+ msg=sftp_dequeue(sftp,id);
+ }
+ switch (msg->packet_type){
+ case SSH_FXP_STATUS:
+ status=parse_status_msg(msg);
+ sftp_message_free(msg);
+ if(!status)
+ return -1;
+ if(status->status != SSH_FX_OK){
+ ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg);
+ err=-1;
+ }
+ status_msg_free(status);
+ return err;
+ default:
+ ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received message %d during sftp_handle_close!",msg->packet_type);
+ sftp_message_free(msg);
+ }
+ return -1;
+}
+
+int sftp_file_close(SFTP_FILE *file){
+ int err=0;
+ if(file->name)
+ free(file->name);
+ if(file->handle){
+ err=sftp_handle_close(file->sftp,file->handle);
+ free(file->handle);
+ }
+ free(file);
+ return err;
+}
+
+int sftp_dir_close(SFTP_DIR *dir){
+ int err=0;
+ if(dir->name)
+ free(dir->name);
+ if(dir->handle){
+ err=sftp_handle_close(dir->sftp,dir->handle);
+ free(dir->handle);
+ }
+ if(dir->buffer)
+ buffer_free(dir->buffer);
+ free(dir);
+ return err;
+}
+
+SFTP_FILE *sftp_open(SFTP_SESSION *sftp, char *file, int access, SFTP_ATTRIBUTES *attr){
+ SFTP_FILE *handle;
+ SFTP_MESSAGE *msg=NULL;
+ STATUS_MESSAGE *status;
+ u32 flags=0;
+ u32 id=sftp_get_new_id(sftp);
+ BUFFER *buffer=buffer_new();
+ STRING *filename;
+ if(access & O_RDONLY)
+ flags|=SSH_FXF_READ;
+ if(access & O_WRONLY)
+ flags |= SSH_FXF_WRITE;
+ if(access & O_RDWR)
+ flags|=(SSH_FXF_WRITE | SSH_FXF_READ);
+ if(access & O_CREAT)
+ flags |=SSH_FXF_CREAT;
+ if(access & O_TRUNC)
+ flags |=SSH_FXF_TRUNC;
+ if(access & O_EXCL)
+ flags |= SSH_FXF_EXCL;
+ buffer_add_u32(buffer,id);
+ filename=string_from_char(file);
+ buffer_add_ssh_string(buffer,filename);
+ free(filename);
+ buffer_add_u32(buffer,htonl(flags));
+ buffer_add_attributes(buffer,attr);
+ sftp_packet_write(sftp,SSH_FXP_OPEN,buffer);
+ buffer_free(buffer);
+ while(!msg){
+ if(sftp_read_and_dispatch(sftp))
+ /* something nasty has happened */
+ return NULL;
+ msg=sftp_dequeue(sftp,id);
+ }
+ switch (msg->packet_type){
+ case SSH_FXP_STATUS:
+ status=parse_status_msg(msg);
+ sftp_message_free(msg);
+ if(!status)
+ return NULL;
+ ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg);
+ status_msg_free(status);
+ return NULL;
+ case SSH_FXP_HANDLE:
+ handle=parse_handle_msg(msg);
+ sftp_message_free(msg);
+ return handle;
+ default:
+ ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received message %d during open!",msg->packet_type);
+ sftp_message_free(msg);
+ }
+ return NULL;
+}
+
+void sftp_file_set_nonblocking(SFTP_FILE *handle){
+ handle->nonblocking=1;
+}
+void sftp_file_set_blocking(SFTP_FILE *handle){
+ handle->nonblocking=0;
+}
+
+int sftp_read(SFTP_FILE *handle, void *data, int len){
+ SFTP_MESSAGE *msg=NULL;
+ STATUS_MESSAGE *status;
+ SFTP_SESSION *sftp=handle->sftp;
+ STRING *datastring;
+ int id;
+ int err=0;
+ BUFFER *buffer;
+ if(handle->eof)
+ return 0;
+ buffer=buffer_new();
+ id=sftp_get_new_id(handle->sftp);
+ buffer_add_u32(buffer,id);
+ buffer_add_ssh_string(buffer,handle->handle);
+ buffer_add_u64(buffer,htonll(handle->offset));
+ buffer_add_u32(buffer,htonl(len));
+ sftp_packet_write(handle->sftp,SSH_FXP_READ,buffer);
+ buffer_free(buffer);
+ while(!msg){
+ if (handle->nonblocking){
+ if(channel_poll(handle->sftp->channel,0)==0){
+ /* we cannot block */
+ return 0;
+ }
+ }
+ if(sftp_read_and_dispatch(handle->sftp))
+ /* something nasty has happened */
+ return -1;
+ msg=sftp_dequeue(handle->sftp,id);
+ }
+ switch (msg->packet_type){
+ case SSH_FXP_STATUS:
+ status=parse_status_msg(msg);
+ sftp_message_free(msg);
+ if(!status)
+ return -1;
+ if(status->status != SSH_FX_EOF){
+ ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg);
+ err=-1;
+ }
+ else
+ handle->eof=1;
+ status_msg_free(status);
+ return err?err:0;
+ case SSH_FXP_DATA:
+ datastring=buffer_get_ssh_string(msg->payload);
+ sftp_message_free(msg);
+ if(!datastring){
+ ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received invalid DATA packet from sftp server");
+ return -1;
+ }
+ if(string_len(datastring)>len){
+ ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received a too big DATA packet from sftp server : %d and asked for %d",
+ string_len(datastring),len);
+ free(datastring);
+ return -1;
+ }
+ len=string_len(datastring);
+ handle->offset+=len;
+ memcpy(data,datastring->string,len);
+ free(datastring);
+ return len;
+ default:
+ ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received message %d during read!",msg->packet_type);
+ sftp_message_free(msg);
+ return -1;
+ }
+ return -1; /* not reached */
+}
+
+int sftp_write(SFTP_FILE *file, void *data, int len){
+ SFTP_MESSAGE *msg=NULL;
+ STATUS_MESSAGE *status;
+ STRING *datastring;
+ SFTP_SESSION *sftp=file->sftp;
+ int id;
+ int err=0;
+ BUFFER *buffer;
+ buffer=buffer_new();
+ id=sftp_get_new_id(file->sftp);
+ buffer_add_u32(buffer,id);
+ buffer_add_ssh_string(buffer,file->handle);
+ buffer_add_u64(buffer,htonll(file->offset));
+ datastring=string_new(len);
+ string_fill(datastring,data,len);
+ buffer_add_ssh_string(buffer,datastring);
+ free(datastring);
+ if(sftp_packet_write(file->sftp,SSH_FXP_WRITE,buffer) != buffer_get_len(buffer)){
+ ssh_say(1,"sftp_packet_write did not write as much data as expected\n");
+ }
+ buffer_free(buffer);
+ while(!msg){
+ if(sftp_read_and_dispatch(file->sftp))
+ /* something nasty has happened */
+ return -1;
+ msg=sftp_dequeue(file->sftp,id);
+ }
+ switch (msg->packet_type){
+ case SSH_FXP_STATUS:
+ status=parse_status_msg(msg);
+ sftp_message_free(msg);
+ if(!status)
+ return -1;
+ if(status->status != SSH_FX_OK){
+ ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg);
+ err=-1;
+ }
+ file->offset+=len;
+ status_msg_free(status);
+ return (err?err:len);
+ default:
+ ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received message %d during write!",msg->packet_type);
+ sftp_message_free(msg);
+ return -1;
+ }
+ return -1; /* not reached */
+}
+
+void sftp_seek(SFTP_FILE *file, int new_offset){
+ file->offset=new_offset;
+}
+
+unsigned long sftp_tell(SFTP_FILE *file){
+ return file->offset;
+}
+
+void sftp_rewind(SFTP_FILE *file){
+ file->offset=0;
+}
+
+/* code written by Nick */
+int sftp_rm(SFTP_SESSION *sftp, char *file) {
+ u32 id = sftp_get_new_id(sftp);
+ BUFFER *buffer = buffer_new();
+ STRING *filename = string_from_char(file);
+ SFTP_MESSAGE *msg = NULL;
+ STATUS_MESSAGE *status = NULL;
+
+ buffer_add_u32(buffer, id);
+ buffer_add_ssh_string(buffer, filename);
+ free(filename);
+ sftp_packet_write(sftp, SSH_FXP_REMOVE, buffer);
+ buffer_free(buffer);
+ while (!msg) {
+ if (sftp_read_and_dispatch(sftp)) {
+ return -1;
+ }
+ msg = sftp_dequeue(sftp, id);
+ }
+ if (msg->packet_type == SSH_FXP_STATUS) {
+ /* by specification, this command's only supposed to return SSH_FXP_STATUS */
+ status = parse_status_msg(msg);
+ sftp_message_free(msg);
+ if (!status)
+ return -1;
+ if (status->status != SSH_FX_OK) {
+ /* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */
+ ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg);
+ status_msg_free(status);
+ return -1;
+ }
+ status_msg_free(status);
+ return 0; /* at this point, everything turned out OK */
+ } else {
+ ssh_set_error(sftp->session,SSH_INVALID_DATA, "Received message %d when attempting to remove file", msg->packet_type);
+ sftp_message_free(msg);
+ }
+ return -1;
+}
+
+/* code written by Nick */
+int sftp_rmdir(SFTP_SESSION *sftp, char *directory) {
+ u32 id = sftp_get_new_id(sftp);
+ BUFFER *buffer = buffer_new();
+ STRING *filename = string_from_char(directory);
+ SFTP_MESSAGE *msg = NULL;
+ STATUS_MESSAGE *status = NULL;
+
+ buffer_add_u32(buffer, id);
+ buffer_add_ssh_string(buffer, filename);
+ free(filename);
+ sftp_packet_write(sftp, SSH_FXP_RMDIR, buffer);
+ buffer_free(buffer);
+ while (!msg) {
+ if (sftp_read_and_dispatch(sftp))
+ {
+ return -1;
+ }
+ msg = sftp_dequeue(sftp, id);
+ }
+ if (msg->packet_type == SSH_FXP_STATUS) /* by specification, this command's only supposed to return SSH_FXP_STATUS */
+ {
+ status = parse_status_msg(msg);
+ sftp_message_free(msg);
+ if (!status)
+ {
+ return -1;
+ }
+ else if (status->status != SSH_FX_OK) /* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */
+ {
+ ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg);
+ status_msg_free(status);
+ return -1;
+ }
+ status_msg_free(status);
+ return 0; /* at this point, everything turned out OK */
+ }
+ else
+ {
+ ssh_set_error(sftp->session,SSH_INVALID_DATA, "Received message %d when attempting to remove directory", msg->packet_type);
+ sftp_message_free(msg);
+ }
+ return -1;
+}
+
+/* Code written by Nick */
+int sftp_mkdir(SFTP_SESSION *sftp, char *directory, SFTP_ATTRIBUTES *attr) {
+ u32 id = sftp_get_new_id(sftp);
+ BUFFER *buffer = buffer_new();
+ STRING *path = string_from_char(directory);
+ SFTP_MESSAGE *msg = NULL;
+ STATUS_MESSAGE *status = NULL;
+
+ buffer_add_u32(buffer, id);
+ buffer_add_ssh_string(buffer, path);
+ free(path);
+ buffer_add_attributes(buffer, attr);
+ sftp_packet_write(sftp, SSH_FXP_MKDIR, buffer);
+ buffer_free(buffer);
+ while (!msg) {
+ if (sftp_read_and_dispatch(sftp))
+ return -1;
+ msg = sftp_dequeue(sftp, id);
+ }
+ if (msg->packet_type == SSH_FXP_STATUS) {
+ /* by specification, this command's only supposed to return SSH_FXP_STATUS */
+ status = parse_status_msg(msg);
+ sftp_message_free(msg);
+ if (!status)
+ return -1;
+ else
+ if (status->status != SSH_FX_OK) {
+ /* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */
+ ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg);
+ status_msg_free(status);
+ return -1;
+ }
+ status_msg_free(status);
+ return 0; /* at this point, everything turned out OK */
+ } else {
+ ssh_set_error(sftp->session,SSH_INVALID_DATA, "Received message %d when attempting to make directory", msg->packet_type);
+ sftp_message_free(msg);
+ }
+ return -1;
+}
+
+/* code written by nick */
+int sftp_rename(SFTP_SESSION *sftp, char *original, char *newname) {
+ u32 id = sftp_get_new_id(sftp);
+ BUFFER *buffer = buffer_new();
+ STRING *oldpath = string_from_char(original);
+ STRING *newpath = string_from_char(newname);
+ SFTP_MESSAGE *msg = NULL;
+ STATUS_MESSAGE *status = NULL;
+
+ buffer_add_u32(buffer, id);
+ buffer_add_ssh_string(buffer, oldpath);
+ free(oldpath);
+ buffer_add_ssh_string(buffer, newpath);
+ free(newpath);
+ sftp_packet_write(sftp, SSH_FXP_RENAME, buffer);
+ buffer_free(buffer);
+ while (!msg) {
+ if (sftp_read_and_dispatch(sftp))
+ return -1;
+ msg = sftp_dequeue(sftp, id);
+ }
+ if (msg->packet_type == SSH_FXP_STATUS) {
+ /* by specification, this command's only supposed to return SSH_FXP_STATUS */
+ status = parse_status_msg(msg);
+ sftp_message_free(msg);
+ if (!status)
+ return -1;
+ else if (status->status != SSH_FX_OK) {
+ /* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */
+ ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg);
+ status_msg_free(status);
+ return -1;
+ }
+ status_msg_free(status);
+ return 0; /* at this point, everything turned out OK */
+ } else {
+ ssh_set_error(sftp->session,SSH_INVALID_DATA, "Received message %d when attempting to rename", msg->packet_type);
+ sftp_message_free(msg);
+ }
+ return -1;
+}
+
+/* Code written by Nick */
+int sftp_setstat(SFTP_SESSION *sftp, char *file, SFTP_ATTRIBUTES *attr) {
+ u32 id = sftp_get_new_id(sftp);
+ BUFFER *buffer = buffer_new();
+ STRING *path = string_from_char(file);
+ SFTP_MESSAGE *msg = NULL;
+ STATUS_MESSAGE *status = NULL;
+
+ buffer_add_u32(buffer, id);
+ buffer_add_ssh_string(buffer, path);
+ free(path);
+ buffer_add_attributes(buffer, attr);
+ sftp_packet_write(sftp, SSH_FXP_SETSTAT, buffer);
+ buffer_free(buffer);
+ while (!msg) {
+ if (sftp_read_and_dispatch(sftp))
+ return -1;
+ msg = sftp_dequeue(sftp, id);
+ }
+ if (msg->packet_type == SSH_FXP_STATUS) {
+ /* by specification, this command's only supposed to return SSH_FXP_STATUS */
+ status = parse_status_msg(msg);
+ sftp_message_free(msg);
+ if (!status)
+ return -1;
+ else if (status->status != SSH_FX_OK) {
+ /* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */
+ ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg);
+ status_msg_free(status);
+ return -1;
+ }
+ status_msg_free(status);
+ return 0; /* at this point, everything turned out OK */
+ } else {
+ ssh_set_error(sftp->session,SSH_INVALID_DATA, "Received message %d when attempting to set stats", msg->packet_type);
+ sftp_message_free(msg);
+ }
+ return -1;
+}
+
+/* another code written by Nick */
+char *sftp_canonicalize_path(SFTP_SESSION *sftp, char *path)
+{
+ u32 id = sftp_get_new_id(sftp);
+ BUFFER *buffer = buffer_new();
+ STRING *pathstr = string_from_char(path);
+ STRING *name = NULL;
+ SFTP_MESSAGE *msg = NULL;
+ STATUS_MESSAGE *status = NULL;
+ char *cname;
+ u32 ignored;
+
+ buffer_add_u32(buffer, id);
+ buffer_add_ssh_string(buffer, pathstr);
+ free(pathstr);
+ sftp_packet_write(sftp, SSH_FXP_REALPATH, buffer);
+ buffer_free(buffer);
+ while (!msg)
+ {
+ if (sftp_read_and_dispatch(sftp))
+ return NULL;
+ msg = sftp_dequeue(sftp, id);
+ }
+ if (msg->packet_type == SSH_FXP_NAME) /* good response */
+ {
+ buffer_get_u32(msg->payload, &ignored); /* we don't care about "count" */
+ name = buffer_get_ssh_string(msg->payload); /* we only care about the file name string */
+ cname = string_to_char(name);
+ free(name);
+ return cname;
+ }
+ else if (msg->packet_type == SSH_FXP_STATUS) /* bad response (error) */
+ {
+ status = parse_status_msg(msg);
+ sftp_message_free(msg);
+ if (!status)
+ return NULL;
+ ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg);
+ status_msg_free(status);
+ }
+ else /* this shouldn't happen */
+ {
+ ssh_set_error(sftp->session,SSH_INVALID_DATA, "Received message %d when attempting to set stats", msg->packet_type);
+ sftp_message_free(msg);
+ }
+ return NULL;
+}
+
+SFTP_ATTRIBUTES *sftp_xstat(SFTP_SESSION *sftp, char *path,int param){
+ u32 id=sftp_get_new_id(sftp);
+ BUFFER *buffer=buffer_new();
+ STRING *pathstr= string_from_char(path);
+ SFTP_MESSAGE *msg=NULL;
+ STATUS_MESSAGE *status=NULL;
+ SFTP_ATTRIBUTES *pattr=NULL;
+
+ buffer_add_u32(buffer,id);
+ buffer_add_ssh_string(buffer,pathstr);
+ free(pathstr);
+ sftp_packet_write(sftp,param,buffer);
+ buffer_free(buffer);
+ while(!msg){
+ if(sftp_read_and_dispatch(sftp))
+ return NULL;
+ msg=sftp_dequeue(sftp,id);
+ }
+ if(msg->packet_type==SSH_FXP_ATTRS){
+ pattr=sftp_parse_attr(sftp,msg->payload,0);
+ return pattr;
+ }
+ if(msg->packet_type== SSH_FXP_STATUS){
+ status=parse_status_msg(msg);
+ sftp_message_free(msg);
+ if(!status)
+ return NULL;
+ ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server: %s",status->errormsg);
+ status_msg_free(status);
+ return NULL;
+ }
+ ssh_set_error(sftp->session,SSH_INVALID_DATA,"Received mesg %d during stat(),mesg->packet_type");
+ sftp_message_free(msg);
+ return NULL;
+}
+
+SFTP_ATTRIBUTES *sftp_stat(SFTP_SESSION *session, char *path){
+ return sftp_xstat(session,path,SSH_FXP_STAT);
+}
+SFTP_ATTRIBUTES *sftp_lstat(SFTP_SESSION *session, char *path){
+ return sftp_xstat(session,path,SSH_FXP_LSTAT);
+}
+
+SFTP_ATTRIBUTES *sftp_fstat(SFTP_FILE *file) {
+ u32 id=sftp_get_new_id(file->sftp);
+ BUFFER *buffer=buffer_new();
+ SFTP_MESSAGE *msg=NULL;
+ STATUS_MESSAGE *status=NULL;
+ SFTP_ATTRIBUTES *pattr=NULL;
+
+ buffer_add_u32(buffer,id);
+ buffer_add_ssh_string(buffer,file->handle);
+ sftp_packet_write(file->sftp,SSH_FXP_FSTAT,buffer);
+ buffer_free(buffer);
+ while(!msg){
+ if(sftp_read_and_dispatch(file->sftp))
+ return NULL;
+ msg=sftp_dequeue(file->sftp,id);
+ }
+ if(msg->packet_type==SSH_FXP_ATTRS){
+ pattr=sftp_parse_attr(file->sftp,msg->payload,0);
+ return pattr;
+ }
+ if(msg->packet_type== SSH_FXP_STATUS){
+ status=parse_status_msg(msg);
+ sftp_message_free(msg);
+ if(!status)
+ return NULL;
+ ssh_set_error(file->sftp->session,SSH_REQUEST_DENIED,"sftp server: %s",status->errormsg);
+ status_msg_free(status);
+ return NULL;
+ }
+ ssh_set_error(file->sftp->session,SSH_INVALID_DATA,"Received mesg %d during fstat(),mesg->packet_type");
+ sftp_message_free(msg);
+ return NULL;
+}
+
+
+#endif /* NO_SFTP */
diff --git a/kftpgrabber/src/misc/libs/ssh/sftp.h b/kftpgrabber/src/misc/libs/ssh/sftp.h
new file mode 100644
index 0000000..10334ab
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/sftp.h
@@ -0,0 +1,225 @@
+/* sftp headers */
+/*
+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. */
+
+#ifndef SFTP_H
+#define SFTP_H
+#include "libssh.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct sftp_session_struct {
+ SSH_SESSION *session;
+ CHANNEL *channel;
+ int server_version;
+ struct request_queue *queue;
+ u32 id_counter;
+} SFTP_SESSION ;
+
+typedef struct {
+ SFTP_SESSION *sftp;
+ u8 type;
+ BUFFER *payload;
+} SFTP_PACKET;
+
+/* file handler */
+typedef struct sftp_file{
+ SFTP_SESSION *sftp;
+ char *name;
+ u64 offset;
+ STRING *handle;
+ int eof;
+ int nonblocking;
+} SFTP_FILE ;
+
+typedef struct sftp_dir {
+ SFTP_SESSION *sftp;
+ char *name;
+ STRING *handle; /* handle to directory */
+ BUFFER *buffer; /* contains raw attributes from server which haven't been parsed */
+ u32 count; /* counts the number of following attributes structures into buffer */
+ int eof; /* end of directory listing */
+} SFTP_DIR;
+
+typedef struct {
+ SFTP_SESSION *sftp;
+ u8 packet_type;
+ BUFFER *payload;
+ u32 id;
+} SFTP_MESSAGE;
+
+typedef struct request_queue{
+ struct request_queue *next;
+ SFTP_MESSAGE *message;
+} REQUEST_QUEUE;
+
+/* SSH_FXP_MESSAGE described into .7 page 26 */
+typedef struct {
+ u32 id;
+ u32 status;
+ STRING *error;
+ STRING *lang;
+ char *errormsg;
+ char *langmsg;
+} STATUS_MESSAGE;
+
+/* don't worry much of these aren't really used */
+typedef struct {
+ char *name;
+ char *longname; /* some weird stuff */
+ u32 flags;
+ u8 type;
+ u64 size;
+ u32 uid;
+ u32 gid;
+ char *owner;
+ char *group;
+ u32 permissions;
+ u64 atime64;
+ u32 atime;
+ u32 atime_nseconds;
+ u64 createtime;
+ u32 createtime_nseconds;
+ u64 mtime64;
+ u32 mtime;
+ u32 mtime_nseconds;
+ STRING *acl;
+ u32 extended_count;
+ STRING *extended_type;
+ STRING *extended_data;
+} SFTP_ATTRIBUTES;
+
+#define LIBSFTP_VERSION 3
+
+SFTP_SESSION *sftp_new(SSH_SESSION *session);
+void sftp_free(SFTP_SESSION *sftp);
+int sftp_init(SFTP_SESSION *sftp);
+SFTP_DIR *sftp_opendir(SFTP_SESSION *session, char *path);
+/* reads one file and attribute from opened directory. fails at end */
+SFTP_ATTRIBUTES *sftp_readdir(SFTP_SESSION *session, SFTP_DIR *dir);
+/* returns 1 if the directory was EOF */
+int sftp_dir_eof(SFTP_DIR *dir);
+SFTP_ATTRIBUTES *sftp_stat(SFTP_SESSION *session, char *path);
+SFTP_ATTRIBUTES *sftp_lstat(SFTP_SESSION *session, char *path);
+/* sftp_lstat stats a file but doesn't follow symlinks */
+SFTP_ATTRIBUTES *sftp_fstat(SFTP_FILE *file);
+void sftp_attributes_free(SFTP_ATTRIBUTES *file);
+int sftp_dir_close(SFTP_DIR *dir);
+int sftp_file_close(SFTP_FILE *file);
+/* access are the sames than the ones from ansi fopen() */
+SFTP_FILE *sftp_open(SFTP_SESSION *session, char *file, int access, SFTP_ATTRIBUTES *attr);
+int sftp_read(SFTP_FILE *file, void *dest, int len);
+int sftp_write(SFTP_FILE *file, void *source, int len);
+void sftp_seek(SFTP_FILE *file, int new_offset);
+unsigned long sftp_tell(SFTP_FILE *file);
+void sftp_rewind(SFTP_FILE *file);
+int sftp_rm(SFTP_SESSION *sftp, char *file);
+int sftp_rmdir(SFTP_SESSION *sftp, char *directory);
+int sftp_mkdir(SFTP_SESSION *sftp, char *directory, SFTP_ATTRIBUTES *attr);
+int sftp_rename(SFTP_SESSION *sftp, char *original, char *newname);
+int sftp_setstat(SFTP_SESSION *sftp, char *file, SFTP_ATTRIBUTES *attr);
+char *sftp_canonicalize_path(SFTP_SESSION *sftp, char *path);
+
+/* SFTP commands and constants */
+#define SSH_FXP_INIT 1
+#define SSH_FXP_VERSION 2
+#define SSH_FXP_OPEN 3
+#define SSH_FXP_CLOSE 4
+#define SSH_FXP_READ 5
+#define SSH_FXP_WRITE 6
+#define SSH_FXP_LSTAT 7
+#define SSH_FXP_FSTAT 8
+#define SSH_FXP_SETSTAT 9
+#define SSH_FXP_FSETSTAT 10
+#define SSH_FXP_OPENDIR 11
+#define SSH_FXP_READDIR 12
+#define SSH_FXP_REMOVE 13
+#define SSH_FXP_MKDIR 14
+#define SSH_FXP_RMDIR 15
+#define SSH_FXP_REALPATH 16
+#define SSH_FXP_STAT 17
+#define SSH_FXP_RENAME 18
+#define SSH_FXP_READLINK 19
+#define SSH_FXP_SYMLINK 20
+
+#define SSH_FXP_STATUS 101
+#define SSH_FXP_HANDLE 102
+#define SSH_FXP_DATA 103
+#define SSH_FXP_NAME 104
+#define SSH_FXP_ATTRS 105
+
+#define SSH_FXP_EXTENDED 200
+#define SSH_FXP_EXTENDED_REPLY 201
+
+/* attributes */
+/* sftp draft is completely braindead : version 3 and 4 have different flags for same constants */
+/* and even worst, version 4 has same flag for 2 different constants */
+/* follow up : i won't develop any sftp4 compliant library before having a clarification */
+
+#define SSH_FILEXFER_ATTR_SIZE 0x00000001
+#define SSH_FILEXFER_ATTR_PERMISSIONS 0x00000004
+#define SSH_FILEXFER_ATTR_ACCESSTIME 0x00000008
+#define SSH_FILEXFER_ATTR_ACMODTIME 0x00000008
+#define SSH_FILEXFER_ATTR_CREATETIME 0x00000010
+#define SSH_FILEXFER_ATTR_MODIFYTIME 0x00000020
+#define SSH_FILEXFER_ATTR_ACL 0x00000040
+#define SSH_FILEXFER_ATTR_OWNERGROUP 0x00000080
+#define SSH_FILEXFER_ATTR_SUBSECOND_TIMES 0x00000100
+#define SSH_FILEXFER_ATTR_EXTENDED 0x80000000
+#define SSH_FILEXFER_ATTR_UIDGID 0x00000002
+
+/* types */
+#define SSH_FILEXFER_TYPE_REGULAR 1
+#define SSH_FILEXFER_TYPE_DIRECTORY 2
+#define SSH_FILEXFER_TYPE_SYMLINK 3
+#define SSH_FILEXFER_TYPE_SPECIAL 4
+#define SSH_FILEXFER_TYPE_UNKNOWN 5
+
+/* server responses */
+#define SSH_FX_OK 0
+#define SSH_FX_EOF 1
+#define SSH_FX_NO_SUCH_FILE 2
+#define SSH_FX_PERMISSION_DENIED 3
+#define SSH_FX_FAILURE 4
+#define SSH_FX_BAD_MESSAGE 5
+#define SSH_FX_NO_CONNECTION 6
+#define SSH_FX_CONNECTION_LOST 7
+#define SSH_FX_OP_UNSUPPORTED 8
+#define SSH_FX_INVALID_HANDLE 9
+#define SSH_FX_NO_SUCH_PATH 10
+#define SSH_FX_FILE_ALREADY_EXISTS 11
+#define SSH_FX_WRITE_PROTECT 12
+#define SSH_FX_NO_MEDIA 13
+
+/* file flags */
+#define SSH_FXF_READ 0x01
+#define SSH_FXF_WRITE 0x02
+#define SSH_FXF_APPEND 0x04
+#define SSH_FXF_CREAT 0x08
+#define SSH_FXF_TRUNC 0x10
+#define SSH_FXF_EXCL 0x20
+#define SSH_FXF_TEXT 0x40
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SFTP_H */
diff --git a/kftpgrabber/src/misc/libs/ssh/ssh2.h b/kftpgrabber/src/misc/libs/ssh/ssh2.h
new file mode 100644
index 0000000..e6dc04f
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/ssh2.h
@@ -0,0 +1,69 @@
+#ifndef __SSH2_H
+#define __SSH2_H
+
+#define SSH2_MSG_DISCONNECT 1
+#define SSH2_MSG_IGNORE 2
+#define SSH2_MSG_UNIMPLEMENTED 3
+#define SSH2_MSG_DEBUG 4
+#define SSH2_MSG_SERVICE_REQUEST 5
+#define SSH2_MSG_SERVICE_ACCEPT 6
+
+#define SSH2_MSG_KEXINIT 20
+#define SSH2_MSG_NEWKEYS 21
+
+#define SSH2_MSG_KEXDH_INIT 30
+#define SSH2_MSG_KEXDH_REPLY 31
+
+#define SSH2_MSG_KEX_DH_GEX_REQUEST_OLD 30
+#define SSH2_MSG_KEX_DH_GEX_GROUP 31
+#define SSH2_MSG_KEX_DH_GEX_INIT 32
+#define SSH2_MSG_KEX_DH_GEX_REPLY 33
+#define SSH2_MSG_KEX_DH_GEX_REQUEST 34
+#define SSH2_MSG_USERAUTH_REQUEST 50
+#define SSH2_MSG_USERAUTH_FAILURE 51
+#define SSH2_MSG_USERAUTH_SUCCESS 52
+#define SSH2_MSG_USERAUTH_BANNER 53
+#define SSH2_MSG_USERAUTH_PK_OK 60
+#define SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ 60
+#define SSH2_MSG_USERAUTH_INFO_REQUEST 60
+#define SSH2_MSG_USERAUTH_INFO_RESPONSE 61
+#define SSH2_MSG_GLOBAL_REQUEST 80
+#define SSH2_MSG_REQUEST_SUCCESS 81
+#define SSH2_MSG_REQUEST_FAILURE 82
+#define SSH2_MSG_CHANNEL_OPEN 90
+#define SSH2_MSG_CHANNEL_OPEN_CONFIRMATION 91
+#define SSH2_MSG_CHANNEL_OPEN_FAILURE 92
+#define SSH2_MSG_CHANNEL_WINDOW_ADJUST 93
+#define SSH2_MSG_CHANNEL_DATA 94
+#define SSH2_MSG_CHANNEL_EXTENDED_DATA 95
+#define SSH2_MSG_CHANNEL_EOF 96
+#define SSH2_MSG_CHANNEL_CLOSE 97
+#define SSH2_MSG_CHANNEL_REQUEST 98
+#define SSH2_MSG_CHANNEL_SUCCESS 99
+#define SSH2_MSG_CHANNEL_FAILURE 100
+
+#define SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1
+#define SSH2_DISCONNECT_PROTOCOL_ERROR 2
+#define SSH2_DISCONNECT_KEY_EXCHANGE_FAILED 3
+#define SSH2_DISCONNECT_HOST_AUTHENTICATION_FAILED 4
+#define SSH2_DISCONNECT_RESERVED 4
+#define SSH2_DISCONNECT_MAC_ERROR 5
+#define SSH2_DISCONNECT_COMPRESSION_ERROR 6
+#define SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE 7
+#define SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8
+#define SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9
+#define SSH2_DISCONNECT_CONNECTION_LOST 10
+#define SSH2_DISCONNECT_BY_APPLICATION 11
+#define SSH2_DISCONNECT_TOO_MANY_CONNECTIONS 12
+#define SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER 13
+#define SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14
+#define SSH2_DISCONNECT_ILLEGAL_USER_NAME 15
+
+#define SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED 1
+#define SSH2_OPEN_CONNECT_FAILED 2
+#define SSH2_OPEN_UNKNOWN_CHANNEL_TYPE 3
+#define SSH2_OPEN_RESOURCE_SHORTAGE 4
+
+#define SSH2_EXTENDED_DATA_STDERR 1
+
+#endif
diff --git a/kftpgrabber/src/misc/libs/ssh/string.c b/kftpgrabber/src/misc/libs/ssh/string.c
new file mode 100644
index 0000000..1126e7a
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/string.c
@@ -0,0 +1,65 @@
+/*string.c */
+/* string manipulations... */
+/*
+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 <stdlib.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <string.h>
+#include "priv.h"
+
+STRING *string_new(u32 size){
+ STRING *str=malloc(size + 4);
+ str->size=htonl(size);
+ return str;
+}
+
+void string_fill(STRING *str,void *data,int len){
+ memcpy(str->string,data,len);
+}
+
+STRING *string_from_char(char *what){
+ STRING *ptr;
+ int len=strlen(what);
+ ptr=malloc(4 + len);
+ ptr->size=htonl(len);
+ memcpy(ptr->string,what,len);
+ return ptr;
+}
+
+int string_len(STRING *str){
+ return ntohl(str->size);
+}
+
+char *string_to_char(STRING *str){
+ int len=ntohl(str->size)+1;
+ char *string=malloc(len);
+ memcpy(string,str->string,len-1);
+ string[len-1]=0;
+ return string;
+}
+
+STRING *string_copy(STRING *str){
+ STRING *ret=malloc(ntohl(str->size)+4);
+ ret->size=str->size;
+ memcpy(ret->string,str->string,ntohl(str->size));
+ return ret;
+}
diff --git a/kftpgrabber/src/misc/libs/ssh/wrapper.c b/kftpgrabber/src/misc/libs/ssh/wrapper.c
new file mode 100644
index 0000000..b99beeb
--- /dev/null
+++ b/kftpgrabber/src/misc/libs/ssh/wrapper.c
@@ -0,0 +1,241 @@
+/* wrapper.c */
+/* wrapping functions for crypto functions. */
+/* why a wrapper ? let's say you want to port libssh from libcrypto of openssl to libfoo */
+/* you are going to spend hours to remove every references to SHA1_Update() to libfoo_sha1_update */
+/* after the work is finished, you're going to have only this file to modify */
+/* it's not needed to say that your modifications are welcome */
+
+/*
+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 "priv.h"
+#include "crypto.h"
+#include <string.h>
+#ifdef OPENSSL_CRYPTO
+#include <openssl/sha.h>
+#include <openssl/md5.h>
+#include <openssl/dsa.h>
+#include <openssl/rsa.h>
+#include <openssl/hmac.h>
+#include <openssl/opensslv.h>
+#ifdef HAVE_OPENSSL_AES_H
+#define HAS_AES
+#include <openssl/aes.h>
+#endif
+#ifdef HAVE_OPENSSL_BLOWFISH_H
+#define HAS_BLOWFISH
+#include <openssl/blowfish.h>
+#endif
+#if (OPENSSL_VERSION_NUMBER<0x009070000)
+#define OLD_CRYPTO
+#endif
+
+SHACTX *sha1_init(){
+ SHACTX *c=malloc(sizeof(SHACTX));
+ SHA1_Init(c);
+ return c;
+}
+void sha1_update(SHACTX *c, const void *data, unsigned long len){
+ SHA1_Update(c,data,len);
+}
+void sha1_final(unsigned char *md,SHACTX *c){
+ SHA1_Final(md,c);
+ free(c);
+}
+void sha1(unsigned char *digest,int len,unsigned char *hash){
+ SHA1(digest,len,hash);
+}
+
+MD5CTX *md5_init(){
+ MD5CTX *c=malloc(sizeof(MD5CTX));
+ MD5_Init(c);
+ return c;
+}
+void md5_update(MD5CTX *c, const void *data, unsigned long len){
+ MD5_Update(c,data,len);
+}
+void md5_final(unsigned char *md,MD5CTX *c){
+ MD5_Final(md,c);
+ free(c);
+}
+
+HMACCTX *hmac_init(const void *key, int len,int type){
+ HMAC_CTX *ctx;
+ ctx=malloc(sizeof(HMAC_CTX));
+#ifndef OLD_CRYPTO
+ HMAC_CTX_init(ctx); // openssl 0.9.7 requires it.
+#endif
+ switch(type){
+ case HMAC_SHA1:
+ HMAC_Init(ctx,key,len,EVP_sha1());
+ break;
+ case HMAC_MD5:
+ HMAC_Init(ctx,key,len,EVP_md5());
+ break;
+ default:
+ free(ctx);
+ ctx=NULL;
+ }
+ return ctx;
+}
+void hmac_update(HMACCTX *ctx,const void *data, unsigned long len){
+ HMAC_Update(ctx,data,len);
+}
+void hmac_final(HMACCTX *ctx,unsigned char *hashmacbuf,int *len){
+ HMAC_Final(ctx,hashmacbuf,len);
+#ifndef OLD_CRYPTO
+ HMAC_CTX_cleanup(ctx);
+#else
+ HMAC_cleanup(ctx);
+#endif
+ free(ctx);
+}
+
+static void alloc_key(struct crypto_struct *cipher){
+ cipher->key=malloc(cipher->keylen);
+}
+
+#ifdef HAS_BLOWFISH
+/* the wrapper functions for blowfish */
+static void blowfish_set_key(struct crypto_struct *cipher, void *key){
+ if(!cipher->key){
+ alloc_key(cipher);
+ BF_set_key(cipher->key,16,key);
+ }
+}
+
+static void blowfish_encrypt(struct crypto_struct *cipher, void *in, void *out,unsigned long len,void *IV){
+ BF_cbc_encrypt(in,out,len,cipher->key,IV,BF_ENCRYPT);
+}
+
+static void blowfish_decrypt(struct crypto_struct *cipher, void *in, void *out,unsigned long len,void *IV){
+ BF_cbc_encrypt(in,out,len,cipher->key,IV,BF_DECRYPT);
+}
+#endif
+#ifdef HAS_AES
+static void aes_set_encrypt_key(struct crypto_struct *cipher, void *key){
+ if(!cipher->key){
+ alloc_key(cipher);
+ AES_set_encrypt_key(key,cipher->keysize,cipher->key);
+ }
+}
+static void aes_set_decrypt_key(struct crypto_struct *cipher, void *key){
+ if(!cipher->key){
+ alloc_key(cipher);
+ AES_set_decrypt_key(key,cipher->keysize,cipher->key);
+ }
+}
+static void aes_encrypt(struct crypto_struct *cipher, void *in, void *out, unsigned long len, void *IV){
+ AES_cbc_encrypt(in,out,len,cipher->key,IV,AES_ENCRYPT);
+}
+static void aes_decrypt(struct crypto_struct *cipher, void *in, void *out, unsigned long len, void *IV){
+ AES_cbc_encrypt(in,out,len,cipher->key,IV,AES_DECRYPT);
+}
+#endif
+/* the table of supported ciphers */
+static struct crypto_struct ssh_ciphertab[]={
+#ifdef HAS_BLOWFISH
+ { "blowfish-cbc", 8 ,sizeof (BF_KEY),NULL,128,blowfish_set_key,blowfish_set_key,blowfish_encrypt, blowfish_decrypt},
+#endif
+#ifdef HAS_AES
+ { "aes128-cbc",16,sizeof(AES_KEY),NULL,128,aes_set_encrypt_key,aes_set_decrypt_key,aes_encrypt,aes_decrypt},
+ { "aes192-cbc",16,sizeof(AES_KEY),NULL,192,aes_set_encrypt_key,aes_set_decrypt_key,aes_encrypt,aes_decrypt},
+ { "aes256-cbc",16,sizeof(AES_KEY),NULL,256,aes_set_encrypt_key,aes_set_decrypt_key,aes_encrypt,aes_decrypt},
+#endif
+ { NULL,0,0,NULL,0,NULL,NULL,NULL}
+};
+#endif /* OPENSSL_CRYPTO */
+
+/* it allocates a new cipher structure based on its offset into the global table */
+struct crypto_struct *cipher_new(int offset){
+ struct crypto_struct *cipher=malloc(sizeof(struct crypto_struct));
+ /* note the memcpy will copy the pointers : so, you shouldn't free them */
+ memcpy(cipher,&ssh_ciphertab[offset],sizeof(*cipher));
+ return cipher;
+}
+
+void cipher_free(struct crypto_struct *cipher){
+ if(cipher->key){
+ /* destroy the key */
+ memset(cipher->key,0,cipher->keylen);
+ free(cipher->key);
+ }
+ free(cipher);
+}
+
+CRYPTO *crypto_new(){
+ CRYPTO *crypto=malloc(sizeof (CRYPTO));
+ memset(crypto,0,sizeof(*crypto));
+ return crypto;
+}
+
+void crypto_free(CRYPTO *crypto){
+ if(crypto->server_pubkey)
+ free(crypto->server_pubkey);
+ if(crypto->in_cipher)
+ cipher_free(crypto->in_cipher);
+ if(crypto->out_cipher)
+ cipher_free(crypto->out_cipher);
+ if(crypto->e)
+ bignum_free(crypto->e);
+ if(crypto->f)
+ bignum_free(crypto->f);
+ if(crypto->x)
+ bignum_free(crypto->x);
+ if(crypto->k)
+ bignum_free(crypto->k);
+ /* lot of other things */
+ /* i'm lost in my own code. good work */
+ memset(crypto,0,sizeof(*crypto));
+ free(crypto);
+}
+
+int crypt_set_algorithms(SSH_SESSION *session){
+ /* we must scan the kex entries to find crypto algorithms and set their appropriate structure */
+ int i=0;
+ /* out */
+ char *wanted=session->client_kex.methods[KEX_CRYPT_C_S];
+ while(ssh_ciphertab[i].name && strcmp(wanted,ssh_ciphertab[i].name))
+ i++;
+ if(!ssh_ciphertab[i].name){
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"Crypt_set_algorithms : no crypto algorithm function found for %s",wanted);
+ return -1;
+ }
+ ssh_say(2,"Set output algorithm %s\n",wanted);
+ session->next_crypto->out_cipher=cipher_new(i);
+ i=0;
+ /* in */
+ wanted=session->client_kex.methods[KEX_CRYPT_S_C];
+ while(ssh_ciphertab[i].name && strcmp(wanted,ssh_ciphertab[i].name))
+ i++;
+ if(!ssh_ciphertab[i].name){
+ ssh_set_error((session->connected?session:NULL),SSH_FATAL,"Crypt_set_algorithms : no crypto algorithm function found for %s",wanted);
+ return -1;
+ }
+ ssh_say(2,"Set input algorithm %s\n",wanted);
+ session->next_crypto->in_cipher=cipher_new(i);
+
+ /* compression */
+ if(strstr(session->client_kex.methods[KEX_COMP_C_S],"zlib"))
+ session->next_crypto->do_compress_out=1;
+ if(strstr(session->client_kex.methods[KEX_COMP_S_C],"zlib"))
+ session->next_crypto->do_compress_in=1;
+ return 0;
+}