/*
* bbftpc/connecttoserver.c
* Copyright (C) 1999, 2000, 2001, 2002 IN2P3, CNRS
* bbftp@in2p3.fr
* http://doc.in2p3.fr/bbftp
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/****************************************************************************
In case of repeated errors this routine exits the program.
connecttoserver.c v 2.0.0 2001/03/07 - Routine rewriting
v 2.0.1 2001/04/19 - Correct indentation
- Port to IRIX
v 2.1.0 2001/05/25 - Add private authentication mode
v 2.1.2 2001/11/19 - Fix COS 0 case
v 2.2.0 2001/10/03 - Add certificate authentication mode
- Send negative COS to server
*****************************************************************************/
#include <errno.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <bbftp.h>
#include <client.h>
#include <client_proto.h>
#include <common.h>
#include <structures.h>
#include <config.h>
#ifdef WITH_SSL
#include <openssl/rsa.h>
#endif
#define SETTOZERO 0
#define SETTOONE 1
extern int timestamp ;
extern int usessh ;
extern int usecert ;
extern int sshbatchmode ;
extern int sshchildpid ;
extern char *sshidentityfile ;
extern char *sshremotecmd ;
extern char *sshcmd ;
extern char *hostname ;
extern char *username ;
extern char *password ;
extern int incontrolsock ;
extern int outcontrolsock ;
extern int recvcontrolto ;
extern int sendcontrolto ;
extern int globaltrymax ;
extern int warning ;
extern int debug ;
extern int verbose ;
extern int newcontrolport ;
extern int transferoption ;
extern int remoteumask ;
extern int remotecos ;
extern char *remotedir ;
extern struct sockaddr_in hisctladdr ;
extern struct sockaddr_in myctladdr ;
/****************************************************************************
Separate STR into arguments, respecting quote and escaped characters.
Returns the number of arguments (or < 0 if limits are passed), which are
copied into BUF and referenced from ARGV.
*****************************************************************************/
static int splitargs (const char* s, char** argv, size_t maxargs,
char* buf, size_t maxbuf)
{
char c, quote= 0;
static const char esc[]= "abfnrtv";
static const char rep[]= "\a\b\f\n\r\t\v";
const char *p;
size_t argc= 0, i= 0;
int sp= 1;
int c2;
char *r;
char num[4];
if (!argv) return -1;
if (!buf) return -2;
maxargs--; /* leave room for final NULL */
maxbuf--; /* leave room for final '\0' */
for (p= s; (c= *p); p++) {
if (sp) {
if (isspace (c)) continue;
if (argc >= maxargs) return -1;
argv[argc++]= &buf[i];
sp= 0;
}
if (c == '\\') {
c= *(++p);
if (c == 'x') {
strncpy (num, p+1, 2); num[2]= '\0';
c2= (int) strtol (num, &r, 16);
if (c2 && r && r>num) {
p += r-num;
c= c2;
}
} else if (isdigit (c)) {
strncpy (num, p, 3); num[3]= '\0';
c2= (int) strtol (num, &r, 8);
if (c2 && r && r>num) {
p += r-num-1;
c= c2;
}
} else {
r= (char *) strchr (esc, c);
if (r) c= rep[r-esc];
}
} else if (quote) {
if (c == quote) {
quote= 0;
continue;
}
} else if (c == '\'' || c == '\"') {
quote= c;
continue;
} else if (isspace (c)) {
c= '\0';
sp= 1;
}
if (i>=maxbuf) return -2;
buf[i++]= c;
}
if (!sp) buf[i]= '\0';
argv[argc]= NULL;
return argc;
}
/****************************************************************************
connectviassh is based on ideas from do_ssh.c written by Tim Adye
<T.J.Adye@rl.ac.uk> in version bbftp v 1.9.4. It has been adapted
in order to fit bbftp version 2.0.0 design.
Some variable have been left in order to add further possibilities
*****************************************************************************/
int connectviassh()
{
/*
** This is set to non-zero if compression is desired.
*/
int sshcompress = SETTOZERO;
/*
** This is to call ssh with argument -P (for using non-privileged
** ports to get through some firewalls.)
*/
int use_privileged_port = SETTOONE ;
/*
** This is set to the cipher type string if given on the command line.
*/
char *cipher = NULL;
/*
** Ssh options
*/
char **ssh_options = NULL;
int ssh_options_cnt = 0;
int pin[2], pout[2], reserved[2];
int retcode ;
char buffer[MINMESSLEN] ;
struct message *msg ;
int tmpctrlsock ;
#ifdef SUNOS
int addrlen ;
#else
size_t addrlen ;
#endif
struct sockaddr_in data_source ;
int on = 1 ;
/*
** Reserve two descriptors so that the real pipes won't get descriptors
** 0 and 1 because that will screw up dup2 below.
*/
pipe(reserved);
/*
** Create a socket pair for communicating with ssh.
*/
if (pipe(pin) < 0)
printmessage(stderr,CASE_FATAL_ERROR,41,timestamp,"Pipe for ssh failed : %s", strerror(errno)) ;
if (pipe(pout) < 0)
printmessage(stderr,CASE_FATAL_ERROR,41,timestamp,"Pipe for ssh failed : %s", strerror(errno)) ;
/*
** Free the reserved descriptors.
*/
close(reserved[0]);
close(reserved[1]);
sshchildpid = 0 ;
/*
** Fork a child to execute the command on the remote host using ssh.
*/
if ( (retcode = fork()) == 0 ) {
/*
** We are in child
*/
char *args[256], *argbuf;
unsigned int i, j, largbuf;
int ntok;
close(pin[1]);
close(pout[0]);
dup2(pin[0], 0);
dup2(pout[1], 1);
close(pin[0]);
close(pout[1]);
i = 0;
largbuf= strlen (sshcmd)+1;
argbuf= (char*) malloc (largbuf * sizeof (char));
ntok= splitargs(sshcmd,args,250,argbuf,largbuf);
if (ntok<0)
printmessage(stderr,CASE_FATAL_ERROR,42,timestamp,"Too many arguments in ssh command :%s \n",sshcmd) ;
if (ntok==0)
printmessage(stderr,CASE_FATAL_ERROR,43,timestamp,"No ssh command specified\n") ;
i += ntok;
for(j = 0; j < ssh_options_cnt; j++) {
args[i++] = "-o";
args[i++] = ssh_options[j];
if (i > 250)
printmessage(stderr,CASE_FATAL_ERROR,44,timestamp,"Too many -o options (total number of arguments is more than 256)");
}
args[i++] = "-x";
args[i++] = "-a";
args[i++] = "-oFallBackToRsh no";
if (sshcompress) args[i++] = "-C";
if (!use_privileged_port) args[i++] = "-P";
if (sshbatchmode) {
args[i++] = "-oBatchMode yes";
args[i++] = "-oStrictHostKeyChecking no" ;
}
if (cipher != NULL) {
args[i++] = "-c";
args[i++] = cipher;
}
if (sshidentityfile != NULL) {
args[i++] = "-i";
args[i++] = sshidentityfile;
}
args[i++] = "-l";
args[i++] = username;
args[i++] = hostname;
args[i++] = sshremotecmd;
args[i++] = NULL;
if ( debug ) {
/*
** We write on stderr and not on stdout because writing on
** stdout will cause problem on the contrlo connection
*/
printmessage(stderr,CASE_NORMAL,0,timestamp,"Executing :%s",args[0]) ;
for (j= 1; args[j]; j++) printmessage(stderr,CASE_NORMAL,0,timestamp," %s", args[j]);
printmessage(stderr,CASE_NORMAL,0,timestamp,"\n");
}
execvp(args[0], args);
printmessage(stderr,CASE_FATAL_ERROR,46,timestamp,"Error while execvp ssh command (%s) : %s\n",sshcmd,strerror(errno)) ;
} else if ( retcode < 0 ) {
/*
** fork error
*/
printmessage(stderr,CASE_ERROR,45,timestamp,"Fork for ssh command failed\n");
return -1 ;
} else {
/*
** We are in father
*/
close(pin[0]);
outcontrolsock = pin[1];
close(pout[1]);
incontrolsock = pout[0];
sshchildpid = retcode ;
/*
** Now we are going to wait for the remote port to connect to
*/
if ( readmessage(incontrolsock,buffer,MINMESSLEN,recvcontrolto,0) < 0 ) {
printmessage(stderr,CASE_ERROR,61,timestamp,"Error waiting %s message\n","MSG_LOGGED_STDIN");
kill(sshchildpid,SIGKILL) ;
close(incontrolsock) ;
close(outcontrolsock) ;
return -1 ;
}
msg = (struct message *)buffer ;
if ( msg->code != MSG_LOGGED_STDIN) {
printmessage(stderr,CASE_ERROR,62,timestamp,"Unknown message while waiting for %s message\n","MSG_LOGGED_STDIN");
if ( debug ) {
printmessage(stdout,CASE_NORMAL,0,timestamp,"Incorrect message is : ") ;
buffer[MINMESSLEN] = '\0' ;
printmessage(stdout,CASE_NORMAL,0,timestamp,"%s",buffer) ;
discardandprintmessage(incontrolsock,recvcontrolto,0) ;
}
kill(sshchildpid,SIGKILL) ;
close(incontrolsock) ;
close(outcontrolsock) ;
return -1 ;
}
#ifndef WORDS_BIGENDIAN
msg->msglen = ntohl(msg->msglen) ;
#endif
if ( msg->msglen != 4) {
printmessage(stderr,CASE_ERROR,63,timestamp,"Unexpected message length while waiting for %s message\n","MSG_LOGGED_STDIN");
kill(sshchildpid,SIGKILL) ;
close(incontrolsock) ;
close(outcontrolsock) ;
return -1 ;
}
/*
** Read for the port number
*/
if ( readmessage(incontrolsock,buffer,4,recvcontrolto,0) < 0 ) {
printmessage(stderr,CASE_ERROR,67,timestamp,"Error reading data for %s message\n","MSG_LOGGED_STDIN");
kill(sshchildpid,SIGKILL) ;
close(incontrolsock) ;
close(outcontrolsock) ;
return -1 ;
}
#ifndef WORDS_BIGENDIAN
msg->code = ntohl(msg->code) ;
#endif
if (debug)
printmessage(stderr,CASE_NORMAL,0,timestamp,"Port number = %d\n",msg->code) ;
if ( (tmpctrlsock = socket ( AF_INET, SOCK_STREAM, IPPROTO_TCP )) < 0 ) {
printmessage(stderr,CASE_ERROR,47,timestamp,"Cannot get socket for MSG_IPADDR message : %s\n",strerror(errno));
kill(sshchildpid,SIGKILL) ;
close(incontrolsock) ;
close(outcontrolsock) ;
return -1 ;
}
if ( setsockopt(tmpctrlsock,SOL_SOCKET, SO_REUSEADDR,(char *)&on,sizeof(on)) < 0 ) {
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,47,timestamp,"Cannot set SO_REUSEADDR on socket for MSG_IPADDR message : %s\n",strerror(errno));
kill(sshchildpid,SIGKILL) ;
close(incontrolsock) ;
close(outcontrolsock) ;
return -1 ;
}
data_source.sin_family = AF_INET;
data_source.sin_addr.s_addr = INADDR_ANY;
/*
data_source.sin_port = htons(newcontrolport+1);
*/
data_source.sin_port = 0;
if ( bind(tmpctrlsock, (struct sockaddr *) &data_source,sizeof(data_source)) < 0) {
printmessage(stderr,CASE_ERROR,49,timestamp,"Cannot bind socket for MSG_IPADDR message : %s\n",strerror(errno));
close(tmpctrlsock) ;
kill(sshchildpid,SIGKILL) ;
close(incontrolsock) ;
close(outcontrolsock) ;
}
hisctladdr.sin_family = AF_INET ;
hisctladdr.sin_port = htons(msg->code);
addrlen = sizeof(hisctladdr) ;
if ( connect(tmpctrlsock,(struct sockaddr*)&hisctladdr,addrlen) < 0 ) {
printmessage(stderr,CASE_ERROR,48,timestamp,"Cannot connect socket for MSG_IPADDR message : %s\n",strerror(errno));
close(tmpctrlsock) ;
kill(sshchildpid,SIGKILL) ;
close(incontrolsock) ;
close(outcontrolsock) ;
return -1 ;
}
msg->code = MSG_IPADDR ;
msg->msglen = 0 ;
/*
** Read the message
*/
if ( writemessage(tmpctrlsock,buffer,MINMESSLEN,sendcontrolto,0) < 0 ) {
printmessage(stderr,CASE_ERROR,64,timestamp,"Error sending %s message\n","MSG_IPADDR");
kill(sshchildpid,SIGKILL) ;
close(tmpctrlsock) ;
close(incontrolsock) ;
close(outcontrolsock) ;
return -1 ;
}
/*
** And wait for MSG_IPADDR_OK
*/
if ( readmessage(tmpctrlsock,buffer,MINMESSLEN,recvcontrolto,0) < 0 ) {
printmessage(stderr,CASE_ERROR,61,timestamp,"Error waiting %s message\n","MSG_IPADDR_OK");
kill(sshchildpid,SIGKILL) ;
close(tmpctrlsock) ;
close(incontrolsock) ;
close(outcontrolsock) ;
return -1 ;
}
if ( msg->code != MSG_IPADDR_OK) {
printmessage(stderr,CASE_ERROR,65,timestamp,"Unknown message while waiting for %s message\n","MSG_IPADDR_OK");
close(tmpctrlsock) ;
kill(sshchildpid,SIGKILL) ;
close(incontrolsock) ;
close(outcontrolsock) ;
return -1 ;
}
close(tmpctrlsock) ;
return 0;
}
/*
** Never reach this point but to in order to avoid stupid messages
** from IRIX compiler set a return code to -1
*/
return -1 ;
}
/****************************************************************************
connectviapassword is the standart method to connect to bbftpd
*****************************************************************************/
int connectviapassword()
{
#if defined(SUNOS) || defined(_HPUX_SOURCE) || defined(IRIX)
int addrlen ;
#else
size_t addrlen ;
#endif
int tmpctrlsock ;
char minbuffer[MINMESSLEN] ;
struct message *msg ;
struct mess_sec *msg_sec ;
struct mess_rsa *msg_rsa ;
char *readbuffer ;
int msglen ;
int crtype ;
int code ;
unsigned int seed ;
struct timeval tp ;
char buffrand[NBITSINKEY] ;
unsigned char *pubkey ;
unsigned char *pubexponent ;
char rsabuffer[RSAMESSLEN] ;
char cryptbuffer[CRYPTMESSLEN] ;
int lenkey ;
int lenexpo ;
int i ;
#ifdef WITH_SSL
RSA *hisrsa ;
int lenrsa ;
#endif
/*
** Get the socket
*/
hisctladdr.sin_family = AF_INET;
hisctladdr.sin_port = htons(newcontrolport);
if ( (tmpctrlsock = socket ( AF_INET, SOCK_STREAM, IPPROTO_TCP )) < 0 ) {
printmessage(stderr,CASE_ERROR,51,timestamp, "Cannot create control socket : %s\n",strerror(errno));
return -1 ;
}
/*
** Connect to the server
*/
addrlen = sizeof(hisctladdr) ;
if ( connect(tmpctrlsock,(struct sockaddr*)&hisctladdr,addrlen) < 0 ) {
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,52,timestamp, "Cannot connect to control socket: %s\n",strerror(errno));
return -1 ;
}
/*
** Get the socket name
*/
addrlen = sizeof(myctladdr) ;
if (getsockname(tmpctrlsock,(struct sockaddr*) &myctladdr, &addrlen) < 0) {
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,53,timestamp,"Error getsockname on control socket: %s\n",strerror(errno)) ;
return -1 ;
}
/*
** Connection is correct so start the login procedure
*/
/*
** Read the encryption supported
*/
if ( readmessage(tmpctrlsock,minbuffer,MINMESSLEN,recvcontrolto,0) < 0 ) {
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,54,timestamp,"Error reading encryption message\n") ;
return -1 ;
}
msg = (struct message *) minbuffer ;
if ( msg->code != MSG_CRYPT) {
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,55,timestamp,"No encryption message \n") ;
return -1 ;
}
/*
** Get the message length and alloc readbuffer
*/
#ifndef WORDS_BIGENDIAN
msglen = ntohl(msg->msglen) ;
#else
msglen = msg->msglen ;
#endif
if ( ( readbuffer = (char *) malloc (msglen + 1) ) == NULL ) {
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,54,timestamp,"Error reading encryption message : malloc failed (%s)\n",strerror(errno)) ;
return -1 ;
}
if ( readmessage(tmpctrlsock,readbuffer,msglen,recvcontrolto,0) < 0 ) {
free(readbuffer) ;
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,56,timestamp,"Error reading encrypted message : %s\n","type") ;
return -1 ;
}
msg_sec = (struct mess_sec *) readbuffer ;
#ifdef WITH_SSL
if ( (msg_sec->crtype & CRYPT_RSA_PKCS1_OAEP_PADDING ) == CRYPT_RSA_PKCS1_OAEP_PADDING) {
/*
** RSA
*/
/*
** Load the error message from the crypto lib
*/
ERR_load_crypto_strings() ;
/*
** Initialize the buffrand buffer which is giong to be used to initialize the
** random generator
*/
/*
** Take the usec to initialize the random session
*/
gettimeofday(&tp,NULL) ;
seed = tp.tv_usec ;
srandom(seed) ;
for (i=0; i < sizeof(buffrand) ; i++) {
buffrand[i] = random() ;
}
/*
** Initialize the random generator
*/
RAND_seed(buffrand,NBITSINKEY) ;
#ifndef WORDS_BIGENDIAN
lenkey = ntohl(msg_sec->pubkeylen) ;
lenexpo = ntohl(msg_sec->expolen) ;
#else
lenkey = msg_sec->pubkeylen ;
lenexpo = msg_sec->expolen ;
#endif
pubkey = (unsigned char *) readbuffer + CRYPTMESSLEN ;
pubexponent = pubkey + lenkey ;
if ( (hisrsa = RSA_new()) == NULL) {
free(readbuffer) ;
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,56,timestamp,"Error reading encrypted message : %s (%s)\n","getting RSA",(char *) ERR_error_string(ERR_get_error(),NULL)) ;
return -1 ;
}
/*
** Getting BIGNUM structures to store the key and exponent
*/
if ( (hisrsa->n = BN_new()) == NULL) {
free(readbuffer) ;
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,56,timestamp,"Error reading encrypted message : %s (%s)\n","getting BIGNUM",(char *) ERR_error_string(ERR_get_error(),NULL)) ;
return -1 ;
}
if ( (hisrsa->e = BN_new()) == NULL) {
free(readbuffer) ;
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,56,timestamp,"Error reading encrypted message : %s (%s)\n","getting BIGNUM",(char *) ERR_error_string(ERR_get_error(),NULL)) ;
return -1 ;
}
/*
** Copy the key and exponent received
*/
if ( BN_mpi2bn(pubkey,lenkey,hisrsa->n) == NULL ) {
free(readbuffer) ;
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,56,timestamp,"Error reading encrypted message : %s (%s)\n","copying pubkey",(char *) ERR_error_string(ERR_get_error(),NULL)) ;
return -1 ;
}
if ( BN_mpi2bn(pubexponent,lenexpo,hisrsa->e) == NULL ) {
free(readbuffer) ;
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,56,timestamp,"Error reading encrypted message : %s (%s)\n","copying pubexponent",(char *) ERR_error_string(ERR_get_error(),NULL)) ;
return -1 ;
}
lenrsa = RSA_size(hisrsa) ;
if (strlen(username) > lenrsa - 41 ) {
free(readbuffer) ;
close(tmpctrlsock) ;
printmessage(stderr,CASE_FATAL_ERROR,56,timestamp,"Error reading encrypted message : %s (%d/%d)\n","username too long",strlen(username),lenrsa-41) ;
}
if (strlen(password) > lenrsa - 41 ) {
free(readbuffer) ;
close(tmpctrlsock) ;
printmessage(stderr,CASE_FATAL_ERROR,56,timestamp,"Error reading encrypted message : %s (%d/%d)\n","password too long",strlen(password),lenrsa-41) ;
return -2 ;
}
msg_rsa = ( struct mess_rsa *) rsabuffer ;
if ( (msg_rsa->numuser = RSA_public_encrypt(strlen(username),(unsigned char *)username,msg_rsa->cryptuser,hisrsa,RSA_PKCS1_OAEP_PADDING)) < 0 ) {
free(readbuffer) ;
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,56,timestamp,"Error reading encrypted message : %s (%s)\n","RSA_public_encrypt username",(char *) ERR_error_string(ERR_get_error(),NULL)) ;
return -1 ;
}
#ifndef WORDS_BIGENDIAN
msg_rsa->numuser = ntohl(msg_rsa->numuser) ;
#endif
if ( (msg_rsa->numpass = RSA_public_encrypt(strlen(password),(unsigned char *)password,msg_rsa->cryptpass,hisrsa,RSA_PKCS1_OAEP_PADDING)) < 0 ) {
free(readbuffer) ;
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,56,timestamp,"Error reading encrypted message : %s (%s)\n","RSA_public_encrypt password",(char *) ERR_error_string(ERR_get_error(),NULL)) ;
return -1 ;
}
#ifndef WORDS_BIGENDIAN
msg_rsa->numpass = ntohl(msg_rsa->numpass) ;
#endif
crtype = CRYPT_RSA_PKCS1_OAEP_PADDING ;
} else {
free(readbuffer) ;
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,57,timestamp,"Unkown encryption method \n") ;
return -1 ;
}
free(readbuffer) ;
/*
** Send login information
*/
/*
** First message code
*/
msg = (struct message *)minbuffer ;
msg->code = MSG_LOG ;
#ifndef WORDS_BIGENDIAN
msg->msglen = ntohl(CRYPTMESSLEN+RSAMESSLEN) ;
#else
msg->msglen = CRYPTMESSLEN+RSAMESSLEN ;
#endif
if ( writemessage(tmpctrlsock,minbuffer,MINMESSLEN,recvcontrolto,0) < 0) {
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,58,timestamp,"Error sending username : %s\n",strerror(errno)) ;
return -1 ;
}
/*
** Then crypte type
*/
msg_sec = (struct mess_sec *)cryptbuffer ;
msg_sec->crtype = crtype ;
if ( writemessage(tmpctrlsock,cryptbuffer,CRYPTMESSLEN,recvcontrolto,0) < 0 ) {
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,58,timestamp,"Error sending username : %s\n",strerror(errno)) ;
return -1 ;
}
/*
** Then real informations
*/
if ( writemessage(tmpctrlsock,rsabuffer,RSAMESSLEN,recvcontrolto,0) < 0) {
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,58,timestamp,"Error sending username : %s\n",strerror(errno)) ;
return -1 ;
}
if ( verbose) printmessage(stdout,CASE_NORMAL,0,timestamp,">> USER %s PASS\n",username) ;
/*
** Now wait for the OK message
*/
if ( readmessage(tmpctrlsock,minbuffer,MINMESSLEN,recvcontrolto,0) < 0 ) {
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,59,timestamp,"Error reading login message answer : %s\n","") ;
return -1 ;
}
msg = (struct message *) minbuffer ;
code = msg->code ;
if ( code == MSG_BAD || code == MSG_BAD_NO_RETRY) {
#ifndef WORDS_BIGENDIAN
msglen = ntohl(msg->msglen) ;
#else
msglen = msg->msglen ;
#endif
if ( ( readbuffer = (char *) malloc(msglen + 1) ) == NULL ) {
printmessage(stderr,CASE_ERROR,59,timestamp,"Error reading login message answer : malloc failed (%s) BAD message\n",strerror(errno)) ;
return -1 ;
}
if ( readmessage(tmpctrlsock,readbuffer,msglen,recvcontrolto,0) < 0 ) {
close(tmpctrlsock) ;
free(readbuffer) ;
if ( code == MSG_BAD ) {
printmessage(stderr,CASE_ERROR,59,timestamp,"Error reading login message answer : %s\n","BAD message") ;
return -1 ;
} else {
printmessage(stderr,CASE_FATAL_ERROR,59,timestamp,"Error reading login message answer : %s\n","BAD NO RETRY message") ;
}
} else {
close(tmpctrlsock) ;
readbuffer[msglen] = '\0' ;
if ( code == MSG_BAD ) {
printmessage(stderr,CASE_ERROR,100,timestamp,"%s\n",readbuffer) ;
free(readbuffer) ;
return -1 ;
} else {
printmessage(stderr,CASE_FATAL_ERROR,100,timestamp,"%s\n",readbuffer) ;
}
}
} else if ( code == MSG_OK ) {
#ifndef WORDS_BIGENDIAN
msglen = ntohl(msg->msglen) ;
#else
msglen = msg->msglen ;
#endif
if ( ( readbuffer = (char *) malloc(msglen + 1) ) == NULL ) {
printmessage(stderr,CASE_ERROR,59,timestamp,"Error reading login message answer : OK message : malloc failed (%s)\n",strerror(errno)) ;
return -1 ;
}
if ( readmessage(tmpctrlsock,readbuffer,msglen,recvcontrolto,0) < 0 ) {
free(readbuffer) ;
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,59,timestamp,"Error reading login message answer : %s\n","OK message") ;
return -1 ;
} else {
readbuffer[msglen] = '\0' ;
if ( verbose) printmessage(stdout,CASE_NORMAL,0,timestamp,"<< %s\n",readbuffer) ;
free(readbuffer) ;
}
} else {
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,59,timestamp,"Error reading login message answer : %s\n","Unkown answer message") ;
return -1 ;
}
#else
/* Client does not support encryption */
if ( (msg_sec->crtype & CRYPT_RSA_PKCS1_OAEP_PADDING ) == CRYPT_RSA_PKCS1_OAEP_PADDING) {
crtype = NO_CRYPT ;
} else {
free(readbuffer) ;
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,57,timestamp,"Unkown encryption method \n") ;
return -1 ;
}
free(readbuffer) ;
/*
** Send message to tell the server we can't encode
*/
msg = (struct message *)minbuffer ;
msg->code = MSG_CRYPT ;
#ifndef WORDS_BIGENDIAN
msg->msglen = ntohl(CRYPTMESSLEN+RSAMESSLEN) ;
#else
msg->msglen = CRYPTMESSLEN+RSAMESSLEN ;
#endif
if ( writemessage(tmpctrlsock,minbuffer,MINMESSLEN,recvcontrolto,0) < 0) {
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,58,timestamp,"Error sending username : %s\n",strerror(errno)) ;
return -1 ;
}
if ( verbose) printmessage(stdout,CASE_NORMAL,0,timestamp,">> MSG_CRYPT message sent\n") ;
/*
** Now wait for the server decision
*/
if ( readmessage(tmpctrlsock,minbuffer,MINMESSLEN,recvcontrolto,0) < 0 ) {
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,59,timestamp,"Error reading login message answer : %s\n","") ;
return -1 ;
}
msg = (struct message *) minbuffer ;
code = msg->code ;
if ( code == MSG_BAD || code == MSG_BAD_NO_RETRY) {
#ifndef WORDS_BIGENDIAN
msglen = ntohl(msg->msglen) ;
#else
msglen = msg->msglen ;
#endif
if ( ( readbuffer = (char *) malloc(msglen + 1) ) == NULL ) {
printmessage(stderr,CASE_ERROR,59,timestamp,"Error reading login message answer : malloc failed (%s) BAD message\n",strerror(errno)) ;
return -1 ;
}
if ( readmessage(tmpctrlsock,readbuffer,msglen,recvcontrolto,0) < 0 ) {
close(tmpctrlsock) ;
free(readbuffer) ;
if ( code == MSG_BAD ) {
printmessage(stderr,CASE_ERROR,59,timestamp,"Error reading login message answer : %s\n","BAD message") ;
return -1 ;
} else {
printmessage(stderr,CASE_FATAL_ERROR,59,timestamp,"Error reading login message answer : %s\n","BAD NO RETRY message") ;
}
} else {
close(tmpctrlsock) ;
readbuffer[msglen] = '\0' ;
if ( code == MSG_BAD ) {
printmessage(stderr,CASE_ERROR,100,timestamp,"%s\n",readbuffer) ;
free(readbuffer) ;
return -1 ;
} else {
printmessage(stderr,CASE_FATAL_ERROR,100,timestamp,"%s\n",readbuffer) ;
}
}
} else if ( code == MSG_OK ) {
#ifndef WORDS_BIGENDIAN
msglen = ntohl(msg->msglen) ;
#else
msglen = msg->msglen ;
#endif
if ( ( readbuffer = (char *) malloc(msglen + 1) ) == NULL ) {
printmessage(stderr,CASE_ERROR,59,timestamp,"Error reading login message answer : OK message : malloc failed (%s)\n",strerror(errno)) ;
return -1 ;
}
if ( readmessage(tmpctrlsock,readbuffer,msglen,recvcontrolto,0) < 0 ) {
free(readbuffer) ;
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,59,timestamp,"Error reading login message answer : %s\n","OK message") ;
return -1 ;
} else {
readbuffer[msglen] = '\0' ;
if ( verbose) printmessage(stdout,CASE_NORMAL,0,timestamp,"%s\n", readbuffer) ;
free(readbuffer) ;
}
} else {
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,59,timestamp,"Error reading login message answer : %s\n","Unkown answer message") ;
return -1 ;
}
/*
** Send new MSG_LOG message
*/
msg = (struct message *)minbuffer ;
msg->code = MSG_LOG ;
#ifndef WORDS_BIGENDIAN
msg->msglen = ntohl(CRYPTMESSLEN+RSAMESSLEN) ;
#else
msg->msglen = CRYPTMESSLEN+RSAMESSLEN ;
#endif
if ( writemessage(tmpctrlsock,minbuffer,MINMESSLEN,recvcontrolto,0) < 0) {
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,58,timestamp,"Error sending username : %s\n",strerror(errno)) ;
return -1 ;
}
/*
** send crypt type
*/
msg_sec = (struct mess_sec *)cryptbuffer ;
msg_sec->crtype = NO_CRYPT ;
if ( writemessage(tmpctrlsock,cryptbuffer,CRYPTMESSLEN,recvcontrolto,0) < 0 ) {
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,58,timestamp,"Error sending username : %s\n",strerror(errno)) ;
return -1 ;
}
/*
** Send uncrypted logon and password
*/
msg_rsa = ( struct mess_rsa *) rsabuffer ;
msg_rsa->numuser = strlen(username) ;
strcpy(msg_rsa->cryptuser, (unsigned char *)username) ;
#ifndef WORDS_BIGENDIAN
msg_rsa->numuser = ntohl(msg_rsa->numuser) ;
#endif
msg_rsa->numpass = strlen(password) ;
strcpy(msg_rsa->cryptpass, (unsigned char *)password) ;
#ifndef WORDS_BIGENDIAN
msg_rsa->numpass = ntohl(msg_rsa->numpass) ;
#endif
/*
** Then real informations
*/
if ( writemessage(tmpctrlsock,rsabuffer,RSAMESSLEN,recvcontrolto,0) < 0) {
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,58,timestamp,"Error sending username : %s\n",strerror(errno)) ;
return -1 ;
}
if ( verbose) printmessage(stdout,CASE_NORMAL,0,timestamp,">> USERNAME %s PASS\n",username) ;
/*
** Now wait for the OK message
*/
if ( readmessage(tmpctrlsock,minbuffer,MINMESSLEN,recvcontrolto,0) < 0 ) {
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,59,timestamp,"Error reading login message answer : %s\n","") ;
return -1 ;
}
msg = (struct message *) minbuffer ;
code = msg->code ;
if ( code == MSG_BAD || code == MSG_BAD_NO_RETRY) {
#ifndef WORDS_BIGENDIAN
msglen = ntohl(msg->msglen) ;
#else
msglen = msg->msglen ;
#endif
if ( ( readbuffer = (char *) malloc(msglen + 1) ) == NULL ) {
printmessage(stderr,CASE_ERROR,59,timestamp,"Error reading login message answer : malloc failed (%s) BAD message\n",strerror(errno)) ;
return -1 ;
}
if ( readmessage(tmpctrlsock,readbuffer,msglen,recvcontrolto,0) < 0 ) {
close(tmpctrlsock) ;
free(readbuffer) ;
if ( code == MSG_BAD ) {
printmessage(stderr,CASE_ERROR,59,timestamp,"Error reading login message answer : %s\n","BAD message") ;
return -1 ;
} else {
printmessage(stderr,CASE_FATAL_ERROR,59,timestamp,"Error reading login message answer : %s\n","BAD NO RETRY message") ;
}
} else {
close(tmpctrlsock) ;
readbuffer[msglen] = '\0' ;
if ( code == MSG_BAD ) {
printmessage(stderr,CASE_ERROR,100,timestamp,"%s\n",readbuffer) ;
free(readbuffer) ;
return -1 ;
} else {
printmessage(stderr,CASE_FATAL_ERROR,100,timestamp,"%s\n",readbuffer) ;
}
}
} else if ( code == MSG_OK ) {
#ifndef WORDS_BIGENDIAN
msglen = ntohl(msg->msglen) ;
#else
msglen = msg->msglen ;
#endif
if ( ( readbuffer = (char *) malloc(msglen + 1) ) == NULL ) {
printmessage(stderr,CASE_ERROR,59,timestamp,"Error reading login message answer : OK message : malloc failed (%s)\n",strerror(errno)) ;
return -1 ;
}
if ( readmessage(tmpctrlsock,readbuffer,msglen,recvcontrolto,0) < 0 ) {
free(readbuffer) ;
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,59,timestamp,"Error reading login message answer : %s\n","OK message") ;
return -1 ;
} else {
readbuffer[msglen] = '\0' ;
if ( verbose) printmessage(stdout,CASE_NORMAL,0,timestamp,"<< %s\n",readbuffer) ;
free(readbuffer) ;
}
} else {
close(tmpctrlsock) ;
printmessage(stderr,CASE_ERROR,59,timestamp,"Error reading login message answer : %s\n","Unkown answer message") ;
return -1 ;
}
#endif
incontrolsock = tmpctrlsock ;
outcontrolsock = tmpctrlsock ;
return 0 ;
}
int todoafterconnection()
{
int errcode ;
int oldtransferoption ;
int retcode ;
/*
** Things to do are :
** chdir remote if remotedir != NULL
** chumask remote if remoteumask !=0
** remotecos
*/
if ( remoteumask !=0 ) {
if ( bbftp_setremoteumask(remoteumask,&errcode) != 0 ) {
return -1 ;
}
}
if ( bbftp_setremotecos(remotecos,&errcode) != 0 ) {
return -1 ;
}
if ( remotedir != NULL ) {
/*
** Care has to be taken if we are under remoterfio
** We have first to change the option to noremoterfio,
** make the cd command and reset the option
*/
oldtransferoption = transferoption ;
transferoption = transferoption & ~TROPT_RFIO ;
retcode = bbftp_cd(remotedir,&errcode) ;
transferoption = oldtransferoption ;
if ( retcode != 0 ) return -1 ;
}
return 0 ;
}
void reconnecttoserver()
{
int nbtrycon ;
int retcode ;
for ( nbtrycon = 1 ; nbtrycon <= globaltrymax ; nbtrycon++ ) {
#if defined(PRIVATE_AUTH)
if ( debug ) printmessage(stdout,CASE_NORMAL,0,timestamp,"Private authentication...\n") ;
retcode = bbftp_private_connect() ;
#else
# ifdef CERTIFICATE_AUTH
if (usecert) {
if ( debug ) printmessage(stdout,CASE_NORMAL,0,timestamp,"Certificate authentication...\n") ;
retcode = bbftp_cert_connect() ;
/* stop at the first try */
if (retcode != 0) {
printmessage(stderr,CASE_FATAL_ERROR,33,timestamp,"Connection not established\n") ;
}
} else
# endif
if (usessh) {
if ( debug ) printmessage(stdout,CASE_NORMAL,0,timestamp,"SSH connection...\n") ;
retcode = connectviassh() ;
} else {
if ( debug ) printmessage(stdout,CASE_NORMAL,0,timestamp,"Password authentication...\n") ;
retcode = connectviapassword() ;
}
#endif
if ( retcode == 0 ) {
if ( debug ) printmessage(stdout,CASE_NORMAL,0,timestamp,"Connection and authentication correct\n") ;
if ( sendproto() == 0 ) {
retcode = todoafterconnection() ;
if ( retcode == 0 ) {
return ;
} else {
bbftp_close_control() ;
}
} else {
bbftp_close_control() ;
}
}
if ( nbtrycon != globaltrymax ) {
if (warning) printmessage(stderr,CASE_WARNING,22,timestamp,"Retrying connection waiting %d s\n",WAITRETRYTIME) ;
sleep(WAITRETRYTIME) ;
}
}
if (nbtrycon == globaltrymax+1) {
printmessage(stderr,CASE_FATAL_ERROR,33,timestamp,"Maximum try on connection reached (%d) aborting\n",globaltrymax) ;
}
}
syntax highlighted by Code2HTML, v. 0.9.1