PageRenderTime 54ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/Net-SSLGlue-1.01/lib/Net/SSLGlue/SMTP.pm

#
Perl | 203 lines | 133 code | 48 blank | 22 comment | 16 complexity | ab634f5aa6d308ef23fd0959b650903d MD5 | raw file
  1. use strict;
  2. use warnings;
  3. package Net::SSLGlue::SMTP;
  4. use IO::Socket::SSL 1.19;
  5. use Net::SMTP;
  6. our $VERSION = 1.0;
  7. ##############################################################################
  8. # mix starttls method into Net::SMTP which on SSL handshake success
  9. # upgrades the class to Net::SMTP::_SSLified
  10. ##############################################################################
  11. sub Net::SMTP::starttls {
  12. my $self = shift;
  13. $self->_STARTTLS or return;
  14. my $host = $self->host;
  15. # for name verification strip port from domain:port, ipv4:port, [ipv6]:port
  16. $host =~s{(?<!:):\d+$}{};
  17. Net::SMTP::_SSLified->start_SSL( $self,
  18. SSL_verify_mode => 1,
  19. SSL_verifycn_scheme => 'smtp',
  20. SSL_verifycn_name => $host,
  21. @_
  22. ) or return;
  23. # another hello after starttls to read new ESMTP capabilities
  24. return $self->hello(${*$self}{net_smtp_hello_domain});
  25. }
  26. sub Net::SMTP::_STARTTLS {
  27. shift->command("STARTTLS")->response() == Net::SMTP::CMD_OK
  28. }
  29. no warnings 'redefine';
  30. my $old_new = \&Net::SMTP::new;
  31. *Net::SMTP::new = sub {
  32. my $class = shift;
  33. my %arg = @_ % 2 == 0 ? @_ : ( Host => shift,@_ );
  34. if ( delete $arg{SSL} ) {
  35. $arg{Port} ||= 465;
  36. return Net::SMTP::_SSLified->new(%arg);
  37. } else {
  38. return $old_new->($class,%arg);
  39. }
  40. };
  41. my $old_hello = \&Net::SMTP::hello;
  42. *Net::SMTP::hello = sub {
  43. my ($self,$domain) = @_;
  44. ${*$self}{net_smtp_hello_domain} = $domain if $domain;
  45. goto &$old_hello;
  46. };
  47. ##############################################################################
  48. # Socket class derived from IO::Socket::SSL
  49. # strict certificate verification per default
  50. ##############################################################################
  51. our %SSLopts;
  52. {
  53. package Net::SMTP::_SSL_Socket;
  54. our @ISA = 'IO::Socket::SSL';
  55. sub configure_SSL {
  56. my ($self,$arg_hash) = @_;
  57. # set per default strict certificate verification
  58. $arg_hash->{SSL_verify_mode} = 1
  59. if ! exists $arg_hash->{SSL_verify_mode};
  60. $arg_hash->{SSL_verifycn_scheme} = 'smtp'
  61. if ! exists $arg_hash->{SSL_verifycn_scheme};
  62. $arg_hash->{SSL_verifycn_name} = $self->host
  63. if ! exists $arg_hash->{SSL_verifycn_name};
  64. # force keys from %SSLopts
  65. while ( my ($k,$v) = each %SSLopts ) {
  66. $arg_hash->{$k} = $v;
  67. }
  68. return $self->SUPER::configure_SSL($arg_hash)
  69. }
  70. }
  71. ##############################################################################
  72. # Net::SMTP derived from Net::SMTP::_SSL_Socket instead of IO::Socket::INET
  73. # this talks SSL to the peer
  74. ##############################################################################
  75. {
  76. package Net::SMTP::_SSLified;
  77. use Carp 'croak';
  78. # deriving does not work because we need to replace a superclass
  79. # from Net::SMTP, so just copy the class into the new one and then
  80. # change it
  81. # copy subs
  82. for ( keys %{Net::SMTP::} ) {
  83. no strict 'refs';
  84. *{$_} = \&{ "Net::SMTP::$_" } if *{$Net::SMTP::{$_}}{CODE};
  85. }
  86. # copy + fix @ISA
  87. our @ISA = @Net::SMTP::ISA;
  88. grep { s{^IO::Socket::INET$}{Net::SMTP::_SSL_Socket} } @ISA
  89. or die "cannot find and replace IO::Socket::INET superclass";
  90. # we are already sslified
  91. no warnings 'redefine';
  92. sub starttls { croak "have already TLS\n" }
  93. my $old_new = \&new;
  94. *Net::SMTP::_SSLified::new = sub {
  95. my $class = shift;
  96. my %arg = @_ % 2 == 0 ? @_ : ( Host => shift,@_ );
  97. local %SSLopts;
  98. $SSLopts{$_} = delete $arg{$_} for ( grep { /^SSL_/ } keys %arg );
  99. return $old_new->($class,%arg);
  100. };
  101. }
  102. 1;
  103. =head1 NAME
  104. Net::SSLGlue::SMTP - make Net::SMTP able to use SSL
  105. =head1 SYNOPSIS
  106. use Net::SSLGlue::SMTP;
  107. my $smtp_ssl = Net::SMTP->new( $host,
  108. SSL => 1,
  109. SSL_ca_path => ...
  110. );
  111. my $smtp_plain = Net::SMTP->new( $host );
  112. $smtp_plain->starttls( SSL_ca_path => ... );
  113. =head1 DESCRIPTION
  114. L<Net::SSLGlue::SMTP> extends L<Net::SMTP> so one can either start directly with SSL
  115. or switch later to SSL using the STARTTLS command.
  116. By default it will take care to verify the certificate according to the rules
  117. for SMTP implemented in L<IO::Socket::SSL>.
  118. =head1 METHODS
  119. =over 4
  120. =item new
  121. The method C<new> of L<Net::SMTP> is now able to start directly with SSL when
  122. the argument C<<SSL => 1>> is given. In this case it will not create an
  123. L<IO::Socket::INET> object but an L<IO::Socket::SSL> object. One can give the
  124. usual C<SSL_*> parameter of L<IO::Socket::SSL> to C<Net::SMTP::new>.
  125. =item starttls
  126. If the connection is not yet SSLified it will issue the STARTTLS command and
  127. change the object, so that SSL will now be used. The usual C<SSL_*> parameter of
  128. L<IO::Socket::SSL> will be given.
  129. =item peer_certificate ...
  130. Once the SSL connection is established the object is derived from
  131. L<IO::Socket::SSL> so that you can use this method to get information about the
  132. certificate. See the L<IO::Socket::SSL> documentation.
  133. =back
  134. All of these methods can take the C<SSL_*> parameter from L<IO::Socket::SSL> to
  135. change the behavior of the SSL connection. The following parameters are
  136. especially useful:
  137. =over 4
  138. =item SSL_ca_path, SSL_ca_file
  139. Specifies the path or a file where the CAs used for checking the certificates
  140. are located. This is typically L</etc/ssl/certs> on UNIX systems.
  141. =item SSL_verify_mode
  142. If set to 0, verification of the certificate will be disabled. By default
  143. it is set to 1 which means that the peer certificate is checked.
  144. =item SSL_verifycn_name
  145. Usually the name given as the hostname in the constructor is used to verify the
  146. identity of the certificate. If you want to check the certificate against
  147. another name you can specify it with this parameter.
  148. =back
  149. =head1 SEE ALSO
  150. IO::Socket::SSL, Net::SMTP
  151. =head1 COPYRIGHT
  152. This module is copyright (c) 2008, Steffen Ullrich.
  153. All Rights Reserved.
  154. This module is free software. It may be used, redistributed and/or modified
  155. under the same terms as Perl itself.