Net-FTPSSL

 view release on metacpan or  search on metacpan

FTPSSL.pm  view on Meta::CPAN

# File    : Net::FTPSSL
# Author  : cleach <cleach at cpan dot org>
# Created : 01 March 2005
# Version : 0.42
# Revision: -Id: FTPSSL.pm,v 1.24 2005/10/23 14:37:12 cleach Exp -

package Net::FTPSSL;

use strict;
use warnings;

# Enforce a minimum version of this module or Net::FTPSSL hangs!
# v1.08 works, v1.18 added ccc() support.
# Don't use v1.79 to v1.85 due to misleading warnings.
use IO::Socket::SSL 1.26;

use vars qw( $VERSION @EXPORT $ERRSTR );
use base ( 'Exporter', 'IO::Socket::SSL' );

# Only supports IPv4 (to also get IPv6 must use IO::Socket::IP instead. v0.20)
use IO::Socket::INET;

use Net::SSLeay::Handle;
use File::Basename;
use File::Copy;
use Time::Local;
use Sys::Hostname;
use Carp qw( carp croak );
use Errno qw/ EINTR /;

@EXPORT  = qw( IMP_CRYPT  EXP_CRYPT   CLR_CRYPT
               DATA_PROT_CLEAR   DATA_PROT_PRIVATE
               DATA_PROT_SAFE    DATA_PROT_CONFIDENTIAL
               CMD_INFO   CMD_OK      CMD_MORE    CMD_REJECT
               CMD_ERROR  CMD_PROTECT CMD_PENDING );
$ERRSTR = "No Errors Detected Yet.";

# Command Channel Protection Levels
use constant IMP_CRYPT => "I";
use constant EXP_CRYPT => "E";       # Default
use constant CLR_CRYPT => "C";

# Data Channel Protection Levels
use constant DATA_PROT_CLEAR        => "C";   # Least secure!
use constant DATA_PROT_SAFE         => "S";
use constant DATA_PROT_CONFIDENTIAL => "E";
use constant DATA_PROT_PRIVATE      => "P";   # Default & most secure!

# Valid FTP Result codes
use constant CMD_INFO    => 1;
use constant CMD_OK      => 2;
use constant CMD_MORE    => 3;
use constant CMD_REJECT  => 4;
use constant CMD_ERROR   => 5;
use constant CMD_PROTECT => 6;
use constant CMD_PENDING => 0;

# -------- Above Exported ---- Below don't bother to export --------

# File transfer modes (the mixed modes have no code)
use constant MODE_BINARY => "I";
use constant MODE_ASCII  => "A";   # Default

# The Data Connection Setup Commands ...
# Passive Options ... (All pasive modes are currently supported)
use constant FTPS_PASV   => 1;    # Default mode ...
use constant FTPS_EPSV_1 => 2;    # EPSV 1 - Internet Protocol Version 4
use constant FTPS_EPSV_2 => 3;    # EPSV 2 - Internet Protocol Version 6
# Active Options ... (No active modes are currently supported)
use constant FTPS_PORT   => 4;
use constant FTPS_EPRT_1 => 5;    # EPRT 1 - Internet Protocol Version 4
use constant FTPS_EPRT_2 => 6;    # EPRT 2 - Internet Protocol Version 6

# Misc constants
use constant TRACE_MOD => 10;  # How many iterations between ".".  Must be >= 5.

# Primarily used while the call to new() is still in scope!
my $FTPS_ERROR;

# Used to handle trapping all warnings accross class instances
my %warn_list;

# Tells if possible to use IPv6 in connections.
my $ipv6;
my $IOCLASS;
my $family_key;     # Domain or Family
my $debug_log_msg;  # Used if Debug is turned on


BEGIN {
    $VERSION = "0.42";              # The version of this module!

    my $type = "IO::Socket::SSL";
    $ipv6 = 0;                      # Assume IPv4 only ...
    $IOCLASS = "IO::Socket::INET";  # Assume IPv4 only ...
    $family_key = "Domain";         # Traditional ...
    my $msg;

    my $ioOrig = $IOCLASS;

    # Can we use IPv6 vs IPv4?  Let IO::Socket::SSL make the decision for us!
    # The logic gets real messy otherwise.
    if ( ! $type->can ("can_ipv6") ) {
       $msg = "No IPv6 support available.  You must 1st upgrade $type to support it!";

    } elsif ( $type->can_ipv6 () ) {
       $ipv6 = 1;                        # Yes!  IPv6 can be suporteed!
       $IOCLASS = $type->can_ipv6 ();    # Get which IPv6 module SSL uses.
       $family_key = "Family"   if ( $IOCLASS eq "IO::Socket::IP" );
       my $ver = $IOCLASS->VERSION;
       $msg = "IPv6 support available via $IOCLASS ($ver)  Key: ($family_key)";

    } else {
       $msg = "No IPv6 support available.  Missing required modules!";
    }

    # Now let's provide the logfile header information ...
    # Done here so only have to generate this information one time!
    my $pv = sprintf ("%s  [%vd]", $], $^V);   # The version of perl!

    # Required info when opening a CPAN ticket against this module ...
    $debug_log_msg = "\n"
                   . "Net-FTPSSL Version: $VERSION\n";

    # Print out versions of critical modules we depend on ...
    foreach ( "IO-Socket-SSL",  "Net-SSLeay",
              "IO-Socket-INET", "IO-Socket-INET6",
              "IO-Socket-IP",   "IO",
              "Socket" ) {
       my $mod = $_;
       $mod =~ s/-/::/g;
       my $ver = $mod->VERSION;
       if ( defined $ver ) {
          $debug_log_msg .= "$_ Version: $ver\n";
       } else {
          $debug_log_msg .= "$_ might not be installed.\n";
       }
    }

    $debug_log_msg .= "\n${msg}\n\n"
                    . "Perl: $pv,  OS: $^O\n\n";

    # Comment out/remove when ready to implement iIPv6 ...
    $IOCLASS = $ioOrig;  $family_key = "Domain";
    $debug_log_msg .= "***** IPv6 not yet supported in Net::FTPSSL! *****\n\n";
}

# ============================================================================

sub new {
  my $self         = shift;
  my $type         = ref($self) || $self;
  my $host         = shift;
  my $arg          = (ref ($_[0]) eq "HASH") ? $_[0] : {@_};


  # Make sure to reset in case previous call to new generated an error!
  $ERRSTR = "No Errors Detected Yet.";

  # Used as a quick way to detect if the caller passed us SSL_* arguments ...
  my $found_ssl_args = 0;

  # The hash to pass to start_ssl() ...
  my %ssl_args;

  # Depreciated in v0.18 (in 2011) and fatal in v0.26 (2015)
  # Will remove this test sometime in 2017/2018!
  if (ref ($arg->{SSL_Advanced}) eq "HASH") {
     %ssl_args = %{$arg->{SSL_Advanced}};
     $ERRSTR = "SSL_Advanced is no longer supported!  Using a separate hash is no longer required for adding SSL options!";
     croak ("\n" . $ERRSTR . "\n");
  }

  # May depreciate in the near future in favor of the "grep" loop below!
  # Debating the merrits of having two ways to do this.
  if (ref ($arg->{SSL_Client_Certificate}) eq "HASH") {
     # The main purpose of this option was to allow users to specify
     # client certificates when their FTPS server requires them.
     # This hash applies to both the command & data channels.
     # Tags specified here overrided normal options if any tags
     # conflict.
     # See IO::Socket::SSL for supported options.
     %ssl_args = %{$arg->{SSL_Client_Certificate}};
     $found_ssl_args = 1;
  }

  # See IO::Socket::SSL for supported options.
  # Provides a way to directly pass needed SSL_* arguments to this module.
  # There is only one Net::FTPSSL option that starts with SSL_, so skipping it!
  for (grep { m{^SSL_} } keys %{$arg}) {
     next  if ( $_ eq "SSL_Client_Certificate" );   # The FTPSSL opt to skip!
     $ssl_args{$_} = $arg->{$_};
     $found_ssl_args = 1;
  }

  # Only add if not using certificates & the caller didn't provide a value ...
  unless ( $ssl_args{SSL_use_cert} || $ssl_args{SSL_verify_mode} ) {
     # Stops the Man-In-The-Middle (MITM) security warning from start_ssl()
     # when it calls configure_SSL() in IO::Socket::SSL.
     # To plug that MITM security hole requires the use of certificates,
     # so all that's being done here is supressing the warning.  The MITM
     # security hole is still open!
     # That warning is now a fatal error in newer versions of IO::Socket::SSL.
     # warn "WARNING: Your connection is vunerable to the MITM attacks\n";
     $ssl_args{SSL_verify_mode} = Net::SSLeay::VERIFY_NONE();
  }

  # --------------------------------------------------------------------------
  # Will hold all the control options to this class
  # Similar in use as _SSL_arguments ...
  my %ftpssl_args;

  # Now onto processing the regular hash of arguments provided ...
  my $encrypt_mode = $arg->{Encryption} || EXP_CRYPT;
  my $port         = $arg->{Port}   || (($encrypt_mode eq IMP_CRYPT) ? 990 : 21);
  my $debug        = $arg->{Debug}  || 0;
  my $trace        = $arg->{Trace}  || 0;
  my $timeout      = $ssl_args{Timeout} || $arg->{Timeout} || 120;
  my $buf_size     = $arg->{Buffer} || 10240;
  my $data_prot    = ($encrypt_mode eq CLR_CRYPT) ? DATA_PROT_CLEAR
                                 : ($arg->{DataProtLevel} || DATA_PROT_PRIVATE);
  my $die          = $arg->{Croak}  || $arg->{Die};
  my $pres_ts      = $arg->{PreserveTimestamp} || 0;
  my $use__ssl     = $arg->{useSSL} || 0;       # Being depreciated.

  my ($use_logfile, $use_glob) = (0, 0);
  if ( $debug && defined $arg->{DebugLogFile} ) {
     $use_logfile  = (ref ($arg->{DebugLogFile}) eq "" &&
                      $arg->{DebugLogFile} ne "");
     $use_glob     = _isa_glob (undef, $arg->{DebugLogFile});
  }
  my $localaddr    = $ssl_args{LocalAddr} || $arg->{LocalAddr};
  my $pret         = $arg->{Pret} || 0;
  my $domain       = $arg->{Domain} || $arg->{Family};
  my $xWait        = $arg->{xWait} || 0;

  my $reuseSession = $arg->{ReuseSession} || 0;

  # Default to true unless you request to disable it or no encryption used ...
  my $enableCtx    = ($arg->{DisableContext} || $encrypt_mode eq CLR_CRYPT) ? 0 : 1;

  # Used to work arround some FTPS servers behaving badly!
  my $pasvHost     = $arg->{OverridePASV};
  my $fixHelp      = $arg->{OverrideHELP};

  # --------------------------------------------------------------------------
  # if ( $debug && ! exists $arg->{DebugLogFile} ) {
  #   # So will write any debug comments to STDERR ...
  #   $IO::Socket::SSL::DEBUG = 3;
  # }

  # A special case used for further debugging the response!
  # This special value is undocumented in the POD on purpose!
  my $debug_extra = ($debug == 99) ? 1 : 0;

  # Special case for eliminating listing help text during login!
  my $no_login_help = ($debug == 90) ? 1 : 0;

  my $f_exists = 0;

  # Determine where to write the Debug info to ...
  if ( $use_logfile ) {
     my $open_mode = ( $debug == 2 ) ? ">>" : ">";
     my $f = $arg->{DebugLogFile};
     unlink ( $f )  if ( -f $f && $open_mode ne ">>" );
     $f_exists = (-f $f);

     # Always calls die on failure to open the requested log file ...
     open ( $FTPS_ERROR, "$open_mode $f" ) or
               _croak_or_return (undef, 1, 0,
                                 "Can't create debug logfile: $f ($!)");

     $FTPS_ERROR->autoflush (1);

     $debug = 2;        # Save the file handle & later close it ...

  } elsif ( $use_glob ) {
     $FTPS_ERROR = $arg->{DebugLogFile};
     $debug = 3;        # Save the file handle, but never close it ...
  }

  if ( $use_logfile || $use_glob ) {
     unless ( $f_exists ) {
        print $FTPS_ERROR $debug_log_msg;
     } else {
        print $FTPS_ERROR "\n\n";
     }

  } elsif ( $debug ) {
     $debug = 1;                  # No file handle to save ...

#    open ( $FTPS_ERROR, ">&STDERR" ) or
#              _croak_or_return (undef, 1, 0,
#                             "Can't attach the debug logfile to STDERR. ($!)");
#    $FTPS_ERROR->autoflush (1);

     print STDERR $debug_log_msg;
  }

  if ( $debug ) {
     _print_LOG (undef, "Server (port): $host ($port)\n\n");
     _print_LOG (undef, "Keys: (",   join ("), (", keys %${arg}),   ")\n");
     _print_LOG (undef, "Values: (", join ("), (", values %${arg}), ")\n\n");
  }

  # Determines if we die if we will also need to write to the error log file ...
  my $dbg_flg = $die ? ( $debug >= 2 ? 1 : 0 ) : $debug;

  return _croak_or_return (undef, $die, $dbg_flg, "Host undefined")  unless $host;

FTPSSL.pm  view on Meta::CPAN

                        Timeout  => $timeout
                      );
     $socketArgs{LocalAddr} = $localaddr  if (defined $localaddr);
     $socketArgs{$family_key} = $domain   if ($ipv6 && defined $domain);

     $socket = $IOCLASS->new ( %socketArgs )
     # $socket = IO::Socket::INET->new ( %socketArgs )
                   or
            return _croak_or_return (undef, $die, $dbg_flg,
                                  "Can't open tcp connection! ($host:$port)");
     $ftpssl_args{mySocketOpts} = \%socketArgs;
  }

  _my_autoflush ( $socket );

  # Save so we can log socket activity if needed ...
  $ftpssl_args{debug}   = $debug;
  $ftpssl_args{debug_extra} = $debug_extra;
  $ftpssl_args{Croak}   = $die;
  $ftpssl_args{Timeout} = $timeout;

  # Bug Id: 120341 says this will be removed from socket by start_SSL() call.
  ${*$socket}{_FTPSSL_arguments} = \%ftpssl_args;

  my $obj;

  if ( $encrypt_mode eq CLR_CRYPT ) {
     # Catch the banner from the connection request ...
     return _croak_or_return ($socket)  unless ( response($socket) == CMD_OK );

     # Leave the command channel clear for regular FTP.
     $obj = $socket;
     bless ( $obj, $type );
     ${*$obj}{_SSL_opened} = 0;      # To get rid of SSL warning on quit ...

  } else {
     # Determine the options to use in start_SSL() ...
     # ------------------------------------------------------------------------
     # Reset SSL_version & Timeout in %ssl_args so these options can be
     # applied to the SSL_Client_Certificate functionality.
     # ------------------------------------------------------------------------
     my $mode;
     my $use_ssl_flag;
     if (defined $ssl_args{SSL_version}) {
        $mode = $ssl_args{SSL_version};             # Mode was overridden.
        $use_ssl_flag = ( $mode =~ m/^SSLv/i );     # Bug ID 115296
     } elsif ( $use__ssl ) {
        $mode = $ssl_args{SSL_version} = "SSLv23";  # SSL per override
        $use_ssl_flag = 1;
        warn ("Option useSSL has been depreciated.  Use option SSL_version instead.\n");
     } else {
        $mode = $ssl_args{SSL_version} = "TLSv12";  # TLS v1.2 per defaults
        $use_ssl_flag = 0;
     }
     $ssl_args{Timeout} = $timeout  unless (exists $ssl_args{Timeout});

     # ------------------------------------------------------------------------
     # The options for Reusing the Session ...
     # ------------------------------------------------------------------------
     if ( $reuseSession ) {
        $ssl_args{SSL_session_cache} = IO::Socket::SSL::Session_Cache->new (4 + $reuseSession);
        $ssl_args{SSL_session_key} = "Net-FTPSSL-${VERSION}-$$:${port}";
     }

     # _debug_print_hash (undef, "Socket call", "initialization", "?", $socket);
     # _debug_print_hash (undef, "Before start_SSL() call", "initialization", "?", \%ssl_args);
     # ------------------------------------------------------------------------

     # Can we use SNI?
     if ( $type->can ("can_client_sni") && $type->can_client_sni () ) {
        $ssl_args{SSL_hostname} = $host  if (! exists $ssl_args{SSL_hostname});
     }

     if ( $encrypt_mode eq EXP_CRYPT ) {
        # Catch the banner from the connection request ...
        return _croak_or_return ($socket) unless (response ($socket) == CMD_OK);

        # In explicit mode FTPSSL sends an AUTH TLS/SSL command, catch the msgs
        command( $socket, "AUTH", ($use_ssl_flag ? "SSL" : "TLS") );
        return _croak_or_return ($socket) unless (response ($socket) == CMD_OK);
     }

     # ------------------------------------------------------------------------
     # Now transform the clear connection into a SSL one on our end.
     # Messy since newer IO::Socket::SSL modules remove {_FTPSSL_arguments}!
     # Bug Id: 120341.
     # ------------------------------------------------------------------------
     $obj = $type->start_SSL( $socket, %ssl_args );
     unless ( $obj ) {
        unless ( exists ${*$socket}{_FTPSSL_arguments} ) {
           ${*$socket}{_FTPSSL_arguments} = \%ftpssl_args;
           _print_LOG (undef, "Restoring _FTPSSL_arguments to \$socket.\n")  if ( $debug );
        }
        return _croak_or_return ( $socket, undef,
                                  "$mode: " . IO::Socket::SSL::errstr () );
     }

     unless ( exists ${*$obj}{_FTPSSL_arguments} ) {
        ${*$obj}{_FTPSSL_arguments} = \%ftpssl_args;
        $obj->_print_LOG ("Restoring _FTPSSL_arguments to \$obj.\n")  if ( $debug );
     }
     # ------------------------------------------------------------------------

     if ( $encrypt_mode eq IMP_CRYPT ) {
        # Catch the banner from the implicit connection request ...
        return $obj->_croak_or_return ()  unless ( $obj->response() == CMD_OK );
     }

     $ftpssl_args{start_SSL_opts} = \%ssl_args;
  }


  # --------------------------------------
  # Check if overriding "_help()" ...
  # --------------------------------------
  if ( defined $fixHelp ) {
     my %helpHash;

     $ftpssl_args{OverrideHELP} = 0;     # So we know OverrideHELP was used ...
     if ( ref ($fixHelp) eq "ARRAY" ) {
        foreach (@{$fixHelp}) {
          my $k = uc ($_);
          $helpHash{$k} = 1  if ( $k ne "HELP" );
        }
     } elsif ( $fixHelp == -1 ) {
       $ftpssl_args{removeHELP} = 1;     # Uses FEAT to list commands supported!
     } elsif ( $fixHelp ) {
       $ftpssl_args{OverrideHELP} = 1;   # All FTP commands supported ...
     }

     # Set the "cache" tags used by "_help()" so that it can still be called!
     $ftpssl_args{help_cmds_found} = \%helpHash;
     $ftpssl_args{help_cmds_msg} = "214 HELP Command Overridden by request.";

     # Causes direct calls to _help($cmd) to skip the server hit. (HELP $cmd)
     $ftpssl_args{help_cmds_no_syntax_available} = 1;

     # When you get here, OverrideHELP is either "0" or "1"!
  }
  # --------------------------------------
  # End overriding "_help()" ...
  # --------------------------------------

  # These options control the behaviour of the Net::FTPSSL class ...
  $ftpssl_args{Host}          = $host;
  $ftpssl_args{Crypt}         = $encrypt_mode;
  $ftpssl_args{debug}         = $debug;
  $ftpssl_args{debug_extra}   = $debug_extra;
  $ftpssl_args{debug_no_help} = $no_login_help;
  $ftpssl_args{trace}         = $trace;
  $ftpssl_args{buf_size}      = $buf_size;
  $ftpssl_args{type}          = MODE_ASCII;
  $ftpssl_args{data_prot}     = $data_prot;
  $ftpssl_args{Croak}         = $die;
  $ftpssl_args{FixPutTs}      = $ftpssl_args{FixGetTs} = $pres_ts;

FTPSSL.pm  view on Meta::CPAN

  my $socket;

  if ( $ftps_ref->{data_prot} eq DATA_PROT_PRIVATE ) {
     if (exists $ftps_ref->{myProxyArgs} ) {
        # Set the proxy parameters for all future data connections ...
        Net::SSLeay::set_proxy ( $proxyArgs{'proxy-host'}, $proxyArgs{'proxy-port'},
                                 $proxyArgs{'proxy-user'}, $proxyArgs{'proxy-pass'} );
        $msg = " (via proxy $msg)";
     }

     # carp "MSG=($msg)\n" . "proxyhost=($Net::SSLeay::proxyhost--$Net::SSLeay::proxyport)\n" . "auth=($Net::SSLeay::proxyauth--$Net::SSLeay::CRLF)\n";

     $socket = Net::SSLeay::Handle->make_socket( $host, $port )
               or return $self->_croak_or_return (0,
                      "Can't open private data connection to $host:$port $msg");

  } elsif ( $ftps_ref->{data_prot} eq DATA_PROT_CLEAR && exists $ftps_ref->{myProxyArgs} ) {
     $socket = Net::HTTPTunnel->new ( %proxyArgs ) or
             return $self->_croak_or_return (0,
                   "Can't open HTTP Proxy data connection tunnel from $msg to $host:$port");

  } elsif ( $ftps_ref->{data_prot} eq DATA_PROT_CLEAR ) {
     my %socketArgs = %{$ftps_ref->{mySocketOpts}};
     $socketArgs{PeerAddr} = $host;
     $socketArgs{PeerPort} = $port;

     $socket = $IOCLASS->new ( %socketArgs ) or
     # $socket = IO::Socket::INET->new( %socketArgs ) or
                  return $self->_croak_or_return (0,
                             "Can't open clear data connection to $host:$port");

  } else {
     # TODO: Fix so DATA_PROT_SAFE & DATA_PROT_CONFIDENTIAL work.
     return $self->_croak_or_return (0, "Currently doesn't support mode $ftps_ref->{data_prot} for data channels to $host:$port");
  }

  $ftps_ref->{data_ch} = \*$socket;     # Must call _get_data_channel() before using.
  $ftps_ref->{data_host} = $host;       # Save the IP Address used ...

  return 1;   # Data Channel was established!
}

sub _get_data_channel {
   my $self = shift;

   # Makes it easier to refrence all those pesky values over & over again.
   my $ftps_ref = ${*$self}{_FTPSSL_arguments};

   # $self->_debug_print_hash ("host", "port", $ftps_ref->{data_prot}, $ftps_ref->{data_ch});

   my $io;
   if ( $ftps_ref->{data_prot} eq DATA_PROT_PRIVATE && exists ($ftps_ref->{myContext}) ) {
      my %ssl_opts = %{$ftps_ref->{myContext}};
      my $mode = ${*$self}{_SSL_arguments}->{SSL_version};

      # Can we use SNI?
      if ( $self->can ("can_client_sni") && $self->can_client_sni () ) {
         $ssl_opts{SSL_hostname} = $ftps_ref->{data_host};
      }

      $io = IO::Socket::SSL->start_SSL ( $ftps_ref->{data_ch}, \%ssl_opts )
               or return $self->_croak_or_return ( 0,
                                      "$mode: " . IO::Socket::SSL::errstr () );

   } elsif ( $ftps_ref->{data_prot} eq DATA_PROT_PRIVATE ) {
      $io = IO::Handle->new ();
      tie ( *$io, "Net::SSLeay::Handle", $ftps_ref->{data_ch} );

   } elsif ( $ftps_ref->{data_prot} eq DATA_PROT_CLEAR ) {
      $io = $ftps_ref->{data_ch};

   } else {
      # TODO: Fix so DATA_PROT_SAFE & DATA_PROT_CONFIDENTIAL work.
      return $self->_croak_or_return (0, "Currently doesn't support mode $ftps_ref->{data_prot} for data channels.");
   }

   _my_autoflush ( $io );

   # $self->_debug_print_hash ("host", "port", $ftps_ref->{data_prot}, $io, "=");

   return ( $io );
}

# Note: This doesn't reference $self on purpose! (so not a bug!)
#       See Bug Id 82094
sub _my_autoflush {
   my $skt = shift;

   if ( $skt->can ('autoflush') ) {
      $skt->autoflush (1);
   } else {
      # So turn it on manually instead ...
      my $oldFh = select $skt;
      $| = 1;
      select $oldFh;
   }

   return;
}

# Note: This doesn't reference $self on purpose! (so not a bug!)
#       See Bug Id 82094
sub _my_close {
   my $io = shift;

   if ( $io->can ('close') ) {
      $io->close ();
   } else {
      close ($io);
   }

   return;
}

# The Shell wild cards are "*" & "?" only.
# So want to convert a shell pattern into its equivalent RegExp.
# Which means disabling all RegExp chars with special meaning and
# converting shell wild cards into its RegExp wild equivalent.
# Handles them all even if they are not legal in a file's name.
sub _convert_shell_pattern_to_regexp
{
  my $self         = shift;
  my $pattern      = shift;

FTPSSL.pm  view on Meta::CPAN

for data sent as clear text.  B<DATA_PROT_SAFE> and B<DATA_PROT_CONFIDENTIAL>
are not currently supported.  If B<CLR_CRYPT> was selected, the data channel
is always B<DATA_PROT_CLEAR> and can't be overridden.

B<ProxyArgs> - A hash reference to pass to the proxy server.  When a proxy
server is encountered, this class uses I<Net::HTTPTunnel> to get through to
the server you need to talk to.  See I<Net::HTTPTunnel> for what values are
supported.  Options I<remote-host> and I<remote-port> are hard coded to the
same values as provided by I<HOST> and I<PORT> above and cannot be overridden.

B<PreserveTimestamp> - During all I<puts> and I<gets>, attempt to preserve the
file's timestamp.  By default it will not preserve the timestamps.

Set to a value B<E<gt>> zero if the I<MDTM> & I<MFMT> commands properly use GMT.
Set to a value B<E<lt>> zero if the server incorrectly uses it's local time zone
instead.  Using the wrong value can result in really wacky modify times on your
files if you choose the wrong one for your server.  F<t/10-complex.t> does
include a test to try to guess which one the server uses.

B<Pret> - Set if you are talking to a distributed FTPS server like I<DrFtpd>
that needs a B<PRET> command issued before all calls to B<PASV>.  You only need
to use this option if the server barfs at the B<PRET> auto-detect logic.

B<Trace> - Turns on/off (1/0) put/get download tracing to STDERR.  The default
is off.

B<Debug> - This turns the debug tracing option on/off. Default is off. (0,1,2)

B<DebugLogFile> - Redirects the output of B<Debug> from F<STDERR> to the
requested error log file name.  This option is ignored unless B<Debug> is also
turned on.  Enforced this way for backwards compatibility.  If B<Debug> is set
to B<2>, the log file will be opened in I<append> mode instead of creating a
new log file.  This log file is closed when this class instance goes out of
scope.

Instead of a file name, you may instead specify an open file handle or GLOB and
it will write the logs there insead.  (I<Not really recommended.>)

B<Croak> - Force most methods to call I<croak()> on failure instead of returning
I<FALSE>.  The default is to return I<FALSE> or I<undef> on failure.  When it
croaks, it will attempt to close the FTPS connection as well, preserving the
last message before it attempts to close the connection.  Allowing the server
to know the client is going away.  This will cause I<$Net::FTPSSL::ERRSTR> to
be set as well.

B<ReuseSession> - Tells the B<FTP/S> server that we wish to reuse the I<command
channel> session for all I<data channel> connections.  (0/1/2/etc.)  It defaults
to B<0>, no reuse.

When requested, it will use a default I<session cache size> of B<5>, but you
can increase the cache's size by setting the I<ReuseSession> to a larger value.
Where the I<session cache size> is (4 + the I<ReuseSession> value).

B<DisableContext> - Tells the B<FTP/S> server that we don't wish to reuse the
I<command channel> context for all I<data channel> connections.  (0/1)  If
option I<ReuseSession> or I<SSL_Client_Certificate> are also used, this option
is ignored!  By default the context is always reused on encrypted data channels
via B<SSL_reuse_ctx>.

B<SSL_*> - SSL arguments which can be applied when I<start_SSL()> is finally
called to encrypt the command channel.  See I<IO::Socket::SSL> for a list of
valid arguments.

This is an alternative to using the I<SSL_Client_Certificate> option.  But
any B<SSL_*> options provided here overrides what's provided in that hash.

B<SSL_Client_Certificate> - Expects a reference to a hash.  It's main purpose
is to allow you to use client certificates when talking to your I<FTP/S> server.
Options here apply to the creation of the command channel.  And when a data
channel is needed later, it uses the B<SSL_reuse_ctx> option to reuse the
command channel's context.

See I<start_SSL()> in I<IO::Socket::SSL> for more details on this and other
options available besides those for certificates.  If an option provided via
this hash conflicts with other options we would normally use, the entries in
this hash take precedence, except for any direct B<SSL_*> options provided in
both places.

B<Domain> - Specify the domain to use, i.e. I<AF_INET> or I<AF_INET6>.  This
argument will be passed to the I<IO::Socket::*> class when creating the socket
connection.  It's a way to enforce using I<IPv4> vs I<IPv6> even when it would
default to the other.  B<Family> is an accepted alias for the B<Domain> tag if
you prefer it.

B<Buffer> - This is the block size that I<Net::FTPSSL> will use when a transfer
is made over the I<Data Channel>. Default value is 10240.  It does not affect
the I<Command Channel>.

B<Timeout> - Set a connection timeout value. Default value is 120.

B<xWait> - Used with I<xput> & I<xtransfer>.  Tells how long to wait after the
upload has completed before renaming the file.  The default is no wait, but
if you specify a number here, it will wait that number of seconds before
issuing the rename command.  Some servers force you to wait a bit before it
will honor the I<RNTO> part of the rename command.

B<LocalAddr> - Local address to use for all socket connections, this argument
will be passed to all L<IO::Socket::INET> calls.

B<OverridePASV> - Some I<FTPS> servers sitting behind a firewall incorrectly
return their local IP Address instead of their external IP Address used
outside the firewall where the client is.  To use this option to correct this
problem, you must specify the correct host to use for the I<data channel>
connection.  This should usually match what you provided as the host!  But if
this server also does load balancing, you are out of luck.  This option may not
be able to help you if multiple IP Addresses can be returned.

B<OverrideHELP> - Some I<FTPS> servers on encrypted connections incorrectly send
back part of the response to the B<HELP> command in clear text instead of it all
being encrypted, breaking the command channel connection.  This module calls
B<HELP> internally via I<supported()> for some conditional logic, making a work
around necessary to be able to talk to such servers.

This option supports B<four> distinct modes to support your needs.  You can pass
a reference to an array that lists all the B<FTP> commands your sever supports,
you can set it to B<1> to say all commands are supported, set it to B<0> to say
none of the commands are supported, or finally set it to B<-1> to call B<FEAT>
instead of B<HELP> for the list of supported commands.  See I<supported()> or
I<fix_supported()> for more details.

This option can also be usefull when your server doesn't support the I<HELP>
command itself and you need to trigger some of the conditional logic.

B<useSSL> - This option is being depreciated in favor of L<IO::Socket::SSL>'s
B<SSL_version> option.  It's just a quick and dirty way to downgrade your
connection from B<TLS> to B<SSL> which is no longer recommended.

=back

=head1 METHODS

Most of the methods return I<true> or I<false>, true when the operation was
a success and false when failed. Methods like B<list> or B<nlst> return an
empty array when they fail.  This behavior can be modified by the B<Croak>
option.

=over 4

=item login( USER, PASSWORD )

Use the given information to log into the FTPS server.

=item quit()

This method breaks the connection to the FTPS server.

=item force_epsv( [1/2] )

Used to force B<EPSV> instead of B<PASV> when establishing a data channel.
Once this method is called, it is imposible to swap back to B<PASV>.  This
method should be called as soon as possible after you log in if B<EPSV> is
required.

It does this by sending "B<EPSV ALL>" to the server.  Afterwards the server
will reject all B<EPTR>, B<PORT> and B<PASV> commands.

After "B<EPSV ALL>" is sent, it will attempt to verify your choice of IP
Protocol to use: B<1> or B<2> (v4 or v6).  The default is B<1>.  It will use
the selected protocol for all future B<EPSV> calls.  If you need to change which
protocol to use, you may call this function a second time to swap to the other
B<EPSV> Protocol.

This method returns true if it succeeds, or false if it fails.

=item set_croak( [1/0] )

Used to turn the I<Croak> option on/off after the I<Net::FTPSSL> object has been
created.  It returns the previous I<Croak> settings before the change is made.
If you don't provide an argument, all it does is return the current setting.
Provided in case the I<Croak> option proves to be too restrictive in some cases.

=item list( [DIRECTORY [, PATTERN]] )

This method returns a list of files in a format similar to this: (Server
Specific)

 drwxrwx--- 1 owner group          512 May 31 11:16 .
 drwxrwx--- 1 owner group          512 May 31 11:16 ..
 -rwxrwx--- 1 owner group          512 Oct 27  2004 foo
 -rwxrwx--- 1 owner group          512 Oct 27  2004 pub
 drwxrwx--- 1 owner group          512 Mar 29 12:09 bar

If I<DIRECTORY> is omitted, the method will return the list of the current
directory.

FTPSSL.pm  view on Meta::CPAN

This method is only active if I<Debug> is turned on with I<DebugLogFile>
provided as well.  Otherwise calling it does nothing.  This trap for I<warnings>
is automatically turned off when the the instance of this class goes out of
scope.  It returns B<1> if the trap was turned on, else B<0> if it wasn't.

Calling this method causes all B<Perl> I<warnings> to be written to the log
file you specified when you called I<new()>.  The I<warnings> will appear in
the log file when they occur to assist in debugging this module.  It
automatically puts the word I<WARNING:> in front of the message being logged.

So this method is only really useful if you wish to open a B<CPAN> ticket to
report a problem with I<Net::FTPSSL> and you think having the generated warning
showing up in the logs will help in getting your issue resolved.

You may call this method for multiple I<Net::FTPSSL> instances and it will
cause the I<warning> to be written to multiple log files.

If your program already traps I<warnings> before you call this method, this
code will forward the warning to your trap logic as well.

=back

=head1 INTERPRETING THE LOGS

The logs generated by I<Net::FTPSSL> are very easy to interpret.  After you get
past the initial configuration information needed to support opening a I<CPAN>
ticket, it's basically the B<FTPS> traffic going back and forth between your
perl I<Client> and the I<FTPS Server> you are talking to.

Each line begins with a prefix that tells what is happening.

C<E<gt>E<gt>E<gt>> - Represents outbound traffic sent to the FTPS Server.

C<E<lt>E<lt>E<lt>> - Represents inbound traffic received from the FTPS Server.

C<E<lt>E<lt>+> - Represents messages from I<Net::FTPSSL> itself in response to
a request that doesn't hit the I<FTPS Server>.

C<WARNING:> - Represents a trapped I<perl warning> written to the logs.

C<SKT E<gt>E<gt>E<gt>> & C<SKT E<lt>E<lt>E<lt>> represent socket traffic
before the I<Net::FTPSSL> object gets created.

There are a couple of other rare variants to the above theme.  But they are
purely information only.  So this is basically it.

=head1 AUTHORS

Marco Dalla Stella - <kral at paranoici dot org>

Curtis Leach - <cleach at cpan dot org> - As of v0.05

=head1 SEE ALSO

I<Net::Cmd>

I<Net::FTP>

I<Net::SSLeay::Handle>

I<IO::Socket::SSL>

RFC 959 - L<http://www.rfc-editor.org/info/rfc959>

RFC 2228 - L<http://www.rfc-editor.org/info/rfc2228>

RFC 2246 - L<http://www.rfc-editor.org/info/rfc2246>

RFC 4217 - L<http://www.rfc-editor.org/info/rfc4217>

=head1 CREDITS

Graham Barr <gbarr at pobox dot com> - for have written such a great
collection of modules (libnet).

=head1 BUGS

Please report any bugs with a FTPS log file created via options B<Debug=E<gt>1>
and B<DebugLogFile=E<gt>"file.txt"> along with your sample code at
L<https://metacpan.org/pod/Net::FTPSSL>.

Patches are appreciated when a log file and sample code are also provided.

=head1 COPYRIGHT

Copyright (c) 2009 - 2019 Curtis Leach. All rights reserved.

Copyright (c) 2005 Marco Dalla Stella. All rights reserved.

This program is free software; you can redistribute it and/or modify it under
the same terms as Perl itself.

=cut



( run in 2.897 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )