/* * 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 #include #include #include #include #include #include #include #include #include #include #include #ifdef WITH_SSL #include #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 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) ; } }