Blame src/SSH_Access.cc.ssh-prompt

Packit 400ec7
/*
Packit 400ec7
 * lftp - file transfer program
Packit 400ec7
 *
Packit 400ec7
 * Copyright (c) 1996-2015 by Alexander V. Lukyanov (lav@yars.free.net)
Packit 400ec7
 *
Packit 400ec7
 * This program is free software; you can redistribute it and/or modify
Packit 400ec7
 * it under the terms of the GNU General Public License as published by
Packit 400ec7
 * the Free Software Foundation; either version 3 of the License, or
Packit 400ec7
 * (at your option) any later version.
Packit 400ec7
 *
Packit 400ec7
 * This program is distributed in the hope that it will be useful,
Packit 400ec7
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 400ec7
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 400ec7
 * GNU General Public License for more details.
Packit 400ec7
 *
Packit 400ec7
 * You should have received a copy of the GNU General Public License
Packit 400ec7
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit 400ec7
 */
Packit 400ec7
Packit 400ec7
#include <config.h>
Packit 400ec7
#include "SSH_Access.h"
Packit 400ec7
#include "misc.h"
Packit 400ec7
Packit 400ec7
void SSH_Access::MakePtyBuffers()
Packit 400ec7
{
Packit 400ec7
   int fd=ssh->getfd();
Packit 400ec7
   if(fd==-1)
Packit 400ec7
      return;
Packit 400ec7
   ssh->Kill(SIGCONT);
Packit 400ec7
   send_buf=new IOBufferFDStream(new FDStream(ssh->getfd_pipe_out(),"pipe-out"),IOBuffer::PUT);
Packit 400ec7
   recv_buf=new IOBufferFDStream(new FDStream(ssh->getfd_pipe_in(),"pipe-in"),IOBuffer::GET);
Packit 400ec7
   pty_send_buf=new IOBufferFDStream(ssh.borrow(),IOBuffer::PUT);
Packit 400ec7
   pty_recv_buf=new IOBufferFDStream(new FDStream(fd,"pseudo-tty"),IOBuffer::GET);
Packit 400ec7
}
Packit 400ec7
Packit 400ec7
static bool ends_with(const char *b,const char *e,const char *suffix)
Packit 400ec7
{
Packit 400ec7
   int len=strlen(suffix);
Packit 400ec7
   return (e-b>=len && !strncasecmp(e-len,suffix,len));
Packit 400ec7
}
Packit 400ec7
static bool begins_with(const char *b,const char *e,const char *suffix)
Packit 400ec7
{
Packit 400ec7
   int len=strlen(suffix);
Packit 400ec7
   return (e-b>=len && !strncasecmp(b,suffix,len));
Packit 400ec7
}
Packit 400ec7
Packit 400ec7
int SSH_Access::HandleSSHMessage()
Packit 400ec7
{
Packit 400ec7
   int m=STALL;
Packit 400ec7
   const char *b;
Packit 400ec7
   int s;
Packit 400ec7
   pty_recv_buf->Get(&b,&s);
Packit 400ec7
   const char *eol=find_char(b,s,'\n');
Packit 400ec7
   if(!eol)
Packit 400ec7
   {
Packit 400ec7
      if(s>0 && b[s-1]==' ')
Packit 400ec7
	 s--;
Packit 400ec7
      if(ends_with(b,b+s,"password:")
Packit 400ec7
      || (ends_with(b,b+s,"':") && s>10)
Packit 400ec7
      || (begins_with(b,b+s,"password for ") && b[s-1]==':'))
Packit 400ec7
      {
Packit 400ec7
	 if(!pass)
Packit 400ec7
	 {
Packit 400ec7
	    SetError(LOGIN_FAILED,_("Password required"));
Packit 400ec7
	    return MOVED;
Packit 400ec7
	 }
Packit 400ec7
	 if(password_sent>0)
Packit 400ec7
	 {
Packit 400ec7
	    SetError(LOGIN_FAILED,_("Login incorrect"));
Packit 400ec7
	    return MOVED;
Packit 400ec7
	 }
Packit 400ec7
	 pty_recv_buf->Put("XXXX");
Packit 400ec7
	 pty_send_buf->Put(pass);
Packit 400ec7
	 pty_send_buf->Put("\n");
Packit 400ec7
	 password_sent++;
Packit 400ec7
	 return m;
Packit 400ec7
      }
Packit 400ec7
      if(ends_with(b,b+s,"(yes/no)?"))
Packit 400ec7
      {
Packit 400ec7
	 const char *answer=QueryBool("auto-confirm",hostname)?"yes\n":"no\n";
Packit 400ec7
	 pty_recv_buf->Put(answer);
Packit 400ec7
	 pty_send_buf->Put(answer);
Packit 400ec7
	 return m;
Packit 400ec7
      }
Packit 400ec7
      if(!received_greeting && recv_buf->Size()>0)
Packit 400ec7
      {
Packit 400ec7
	 recv_buf->Get(&b,&s);
Packit 400ec7
	 eol=find_char(b,s,'\n');
Packit 400ec7
	 if(eol)
Packit 400ec7
	 {
Packit 400ec7
	    xstring &line=xstring::get_tmp(b,eol-b);
Packit 400ec7
	    if(line.eq(greeting))
Packit 400ec7
	       received_greeting=true;
Packit 400ec7
	    LogRecv(4,line);
Packit 400ec7
	    recv_buf->Skip(eol-b+1);
Packit 400ec7
	 }
Packit 400ec7
      }
Packit 400ec7
      LogSSHMessage();
Packit 400ec7
      return m;
Packit 400ec7
   }
Packit 400ec7
   if(begins_with(b,b+s,"Host key verification failed"))
Packit 400ec7
   {
Packit 400ec7
      LogSSHMessage();
Packit 400ec7
      SetError(FATAL,xstring::get_tmp(b,eol-b));
Packit 400ec7
      return MOVED;
Packit 400ec7
   }
Packit 400ec7
   if(eol>b && eol[-1]=='\r')
Packit 400ec7
      eol--;
Packit 400ec7
   if(!hostname_valid) {
Packit 400ec7
      if(ends_with(b,eol,"Name or service not known")
Packit 400ec7
      || ends_with(b,eol,"No address associated with hostname"))
Packit 400ec7
      {
Packit 400ec7
	 LogSSHMessage();
Packit 400ec7
	 SetError(LOOKUP_ERROR,xstring::get_tmp(b,eol-b));
Packit 400ec7
	 return MOVED;
Packit 400ec7
      }
Packit 400ec7
   }
Packit 400ec7
   LogSSHMessage();
Packit 400ec7
   return MOVED;
Packit 400ec7
}
Packit 400ec7
Packit 400ec7
void SSH_Access::LogSSHMessage()
Packit 400ec7
{
Packit 400ec7
   const char *b;
Packit 400ec7
   int s;
Packit 400ec7
   pty_recv_buf->Get(&b,&s);
Packit 400ec7
   const char *eol=find_char(b,s,'\n');
Packit 400ec7
   if(!eol)
Packit 400ec7
   {
Packit 400ec7
      if(pty_recv_buf->Eof())
Packit 400ec7
      {
Packit 400ec7
	 if(s>0)
Packit 400ec7
	    LogRecv(4,b);
Packit 400ec7
	 LogError(0,_("Peer closed connection"));
Packit 400ec7
      }
Packit 400ec7
      if(pty_recv_buf->Error())
Packit 400ec7
	 LogError(4,"pty read: %s",pty_recv_buf->ErrorText());
Packit 400ec7
      if(pty_recv_buf->Eof() || pty_recv_buf->Error()) {
Packit 400ec7
	 if(last_ssh_message && time_t(now)-last_ssh_message_time<4)
Packit 400ec7
	    LogError(0,"%s",last_ssh_message.get());
Packit 400ec7
	 Disconnect(last_ssh_message);
Packit 400ec7
      }
Packit 400ec7
      return;
Packit 400ec7
   }
Packit 400ec7
   s=eol-b+1;
Packit 400ec7
   int chomp_cr=(s>=2 && b[s-2]=='\r');
Packit 400ec7
   last_ssh_message.nset(b,s-1-chomp_cr);
Packit 400ec7
   last_ssh_message_time=now;
Packit 400ec7
   pty_recv_buf->Skip(s);
Packit 400ec7
   LogRecv(4,last_ssh_message);
Packit 400ec7
   if(last_ssh_message.begins_with("ssh: "))
Packit 400ec7
      last_ssh_message.set(last_ssh_message+5);
Packit 400ec7
Packit 400ec7
   if(!received_greeting && last_ssh_message.eq(greeting)) {
Packit 400ec7
      received_greeting=true;
Packit 400ec7
      hostname_valid=true;
Packit 400ec7
   }
Packit 400ec7
}
Packit 400ec7
Packit 400ec7
void SSH_Access::DisconnectLL()
Packit 400ec7
{
Packit 400ec7
   if(send_buf)
Packit 400ec7
      LogNote(9,_("Disconnecting"));
Packit 400ec7
   rate_limit=0;
Packit 400ec7
   send_buf=0;
Packit 400ec7
   recv_buf=0;
Packit 400ec7
   pty_send_buf=0;
Packit 400ec7
   pty_recv_buf=0;
Packit 400ec7
   ssh=0;
Packit 400ec7
   received_greeting=false;
Packit 400ec7
   password_sent=0;
Packit 400ec7
   last_ssh_message.unset();
Packit 400ec7
   last_ssh_message_time=0;
Packit 400ec7
}
Packit 400ec7
Packit 400ec7
void SSH_Access::MoveConnectionHere(SSH_Access *o)
Packit 400ec7
{
Packit 400ec7
   send_buf=o->send_buf.borrow();
Packit 400ec7
   recv_buf=o->recv_buf.borrow();
Packit 400ec7
   pty_send_buf=o->pty_send_buf.borrow();
Packit 400ec7
   pty_recv_buf=o->pty_recv_buf.borrow();
Packit 400ec7
   ssh=o->ssh.borrow();
Packit 400ec7
   received_greeting=o->received_greeting;
Packit 400ec7
   hostname_valid|=o->hostname_valid;
Packit 400ec7
   password_sent=o->password_sent;
Packit 400ec7
   last_ssh_message.move_here(o->last_ssh_message);
Packit 400ec7
   last_ssh_message_time=o->last_ssh_message_time; o->last_ssh_message_time=0;
Packit 400ec7
}