I wrote a Perl script that uses POP3 to retrieve mail from a Gmail account. A while ago, the script became broken, and I suspect it was because Gmail began requiring either SSL or TLS connections when using POP3.
I found this interesting post on Mike B's blog, which includes this sample code:
#!/usr/bin/env perl
use strict;
use warnings;
use Net::SSLGlue::POP3;
use Mozilla::CA;
my $host = 'pop.aol.com';
my $login = 'myusername#aol.com';
my $pass = '4Radfsai8fsfd9sdf9sdf';
my $pop3 = Net::POP3->new( $host) || die "Can't connect to $host: $!";
$pop3->starttls(
SSL_verify_mode => 1,
SSL_ca_file => Mozilla::CA::SSL_ca_file(),
) || die "Can't perform starttls: $!";
my $messages = $pop3->login( $login, $pass )
|| die "Failed to authenticate login $login on $host: $!";
print "There are $messages messages on $host for $login.\n";
Here's a portion of my exact code (some specifics changed for security reasons):
use YAML;
use Net::SSLGlue::POP3;
use Mozilla::CA;
use Email::Find;
use Data::Dumper;
use LWP::Simple;
my $email_finder = Email::Find->new(\&process_email);
my $verbose = 1;
my $email_account = 'my.email#mydomain.net';
my $email_password = 'somepassword';
my $mail_server = "mail.mydomain.net";
print("\nStarted\n") if ($verbose);
$pop = Net::POP3->new($mail_server) || die("Could not log on to server.");
print(" - starttls using " . Mozilla::CA::SSL_ca_file() . "\n") if ($verbose);
$pop->starttls(
SSL_verify_mode => 1,
SSL_ca_file => Mozilla::CA::SSL_ca_file()
) || die "Can't perform starttls: $!";
My issue is that...
$pop->starttls(
SSL_verify_mode => 1,
SSL_ca_file => Mozilla::CA::SSL_ca_file()
) || die "Can't perform starttls: $!";
... is failing, but I can't tell why. Any suggestions?
UPDATE...
Thank you Steffen. I've updated my code by adding Debug => 1 and outputting $IO::Socket::SSL::SSL_ERROR:
$pop = Net::POP3->new($mail_server, Debug => 1)
|| die("Could not log on to server.");
print(" - starttls using " . Mozilla::CA::SSL_ca_file() . "\n") if ($verbose);
$pop->starttls(
SSL_verify_mode => 1,
SSL_ca_file => Mozilla::CA::SSL_ca_file()
) || die "Can't perform starttls: $!\n" . $IO::Socket::SSL::SSL_ERROR;
The error message now is:
Net::POP3>>> Net::POP3(2.29)
Net::POP3>>> Net::Cmd(2.29)
Net::POP3>>> Exporter(5.63)
Net::POP3>>> IO::Socket::INET(1.31)
Net::POP3>>> IO::Socket(1.31)
Net::POP3>>> IO::Handle(1.28)
Net::POP3=GLOB(0xb41980)<<< +OK Dovecot ready.
- starttls using /usr/local/share/perl/5.10.1/Mozilla/CA/cacert.pem
Net::POP3=GLOB(0xb41980)>>> STLS
Net::POP3=GLOB(0xb41980)<<< +OK Begin TLS negotiation now.
Can't perform starttls:
**SSL connect attempt failed with unknown error error:14090086:SSL
routines:SSL3_GET_SERVER_CERTIFICATE:certificate
verify failed at (my script) line 26.**
Is this basically saying, "The Mozilla::CA certificate is not going to work for you."?
There might be several reasons it might fail and it would help if you add Debug => 1 within Net::POP3->new.
I could think of the following reasons:
The server does not support a STLS command. In this case you wou, would see an error message when running with the Debug flag, you can also could print $pop->message.
The servers supports STLS, but the SSL handshake fails. In this case you will find more information in the $IO::Socket::SSL::SSL_ERROR variable. Typical examples why the handshake might fail
the CA of the certificate is unknown (e.g. not in the CA store provided by Mozilla::CA). This is typically the case with servers from private persons, or inside companies or universities. They often don't use public CAs to sign their certificates or even use self-signed certificates
no shared cipher can be found. This can be the case with older servers, which like to do MD5. Recent versions of IO::Socket::SSL or OpenSSL disable these insecure ciphers by default.
If this does not help please post the output from Debug and maybe set $IO::Socket::SSL::DEBUG=10 too.
Steffen (author of Net::SSLGlue::POP3, current developer of IO::Socket::SSL)
Related
I am trying to connect to F5 load balancer through perl module Net::SSH2. I am unable to authentication error, whereas with the same credentials I am able to ssh to the device through putty. I have shared the Code and the error below for reference. Could somebody please help me with this.
use Net::SSH2;
$deviceipF5 = "x.x.x.x";
$username = "xx";
$encrPass = "xx";
my #deviceipF5List = split(',',$deviceipF5);
if(#deviceipF5List ne 0)
{
foreach my $deviceipF5(#deviceipF5List)
{
my #deviceipF5List1 = split (':', $deviceipF5);
my $ssh2 = Net::SSH2->new();
$ssh2->debug(0);
$ssh2->connect($deviceipF5List1[0]) or die $!;
$ssh2->auth(username => $username, password => $encrPass) or die "Unable to login \n".$ssh2->die_with_error;
print "Connected to '$deviceipF5List1[0]' as '$username' \n";
my $channel = $ssh2->channel() or do { print "Unable to create channnel ssh channel to Device $deviceipF5List[0]";$ssh2->disconnect(); last;};
$channel->blocking(0);
$channel->shell() ;
print "SSH Success \n";
sleep(2);
I have even tried to use auth_password instead of auth but no Luck.
Below is the error I am getting:
Bad file descriptor at line 16
I tried removing $! from line number 16 but it lead to another error:
Died at line 16
i was working on a perl script that check multi cpanel accounts authorisation for weak passwords , like that a server owner can check if his users are using a weak password and when connected to one write a file in the /public_html/ dir to informe the user .
i was thinking of using cPanel::PublicAPI :
my $cp = cPanel::PublicAPI->new(
'user' => $username,
'pass' => $password,
'host' => $host,
);
but i didn't know how to check if connected and how to write file in it ( i've looked here)
i found a script that check for authorisation :
$authx = encode_base64($user.":".$passwd);
my $sock = IO::Socket::INET->new(Proto => "tcp",PeerAddr => "$host", PeerPort => "$port") || print " [-] Can not connect to the host";
print $sock "GET / HTTP/1.1";
print $sock "Authorization: Basic $authx";
print $sock "Connection: Close";
read $sock, $answer, 128;
close($sock);
if ($answer =~ /Moved/) {
print " passord is : $passwd\n";
}
but this is too slow and can't write file using it .
sorry for my english :) . regards
i didn't know how to check if connected
Just make a request/method call on the $cp object. If it fails, the $cp->{error} attribute is set.
how to write file
use autodie qw(:all);
open my $fh, '>', '/home/user/message_from_the_admin';
$fh->print('You made a boo-boo.');
See chapter 9.3: Files in Modern Perl.
I have been trying to find a simple client ipv6 script
that would work with Evens server script , of course I
dont know what Im doing, so all I can do is rewrite someone
else's work until I know what Im doing ...
so here is a server script that works on Microsoft widows server
use IO::Socket::IP -register;
my $sock = IO::Socket->new(
Domain => PF_INET6,
LocalHost => "::1",
Listen => 1,
) or die "Cannot create socket - $#\n";
print "Created a socket of type " . ref($sock) . "\n";
{
$in = <STDIN>;
print $in->$sock;
redo }
of course the $in->$sock is not working, cause I dont know how to send
data using just $sock ???
so I need to know how to send information properly and
what I need is A client script to connect to the above script
using the ipv6 protocol
can anyone help with this ???
I would like to be able to send information from one
perl program to another perl program using this
being able to send information back and forth would
be Ideal ...
Thanks in advance
-Mark
That's a server socket (Listen => 1), so you have to accept a connection.
use IO::Socket::IP -register;
my $listen_sock = IO::Socket::IP->new(
LocalHost => "::1", # bind()
Listen => 1, # listen()
) or die "Cannot create socket - $#\n";
print("Listening to ".$listen_sock->sockhost()." "
.$listen_sock->sockport()."\n");
while (1) {
my $sock = $listen_sock->accept()
or die $!;
print("Connection received from ".$sock->peerhost()." "
.$sock->peerport()."\n");
while (<$sock>) {
print $sock "echo: $_";
}
}
A client:
use IO::Socket::IP -register;
#ARGV == 2 or die("usage");
my ($host, $port) = #ARGV;
my $sock = IO::Socket::IP->new(
PeerHost => $host, # \ bind()
PeerPort => $port, # /
) or die "Cannot create socket - $#\n";
print $sock "Hello, world!\n";
$sock->shutdown(1); # Done writing.
print while <$sock>;
The comments indicate the underlying system call used to perform the action.
My client.pl
#!/usr/bin/perl
use IO::Socket::INET;
use strict;
my $name = '172.20.10.189'; #Server IP
my $port = '7890';
my $socket = IO::Socket::INET->new('PeerAddr' => $name,
'PeerPort' => $port,
'Proto' => 'tcp') or die "Can't create socket ($!)\n";
print "Client sending\n";
while (1) {
my $msg = <STDIN>;
print $socket $msg;
print scalar <$socket>;
}
close $socket
or die "Can't close socket ($!)\n";
My server.pl
#!/usr/bin/perl
use IO::Socket::INET;
use strict;
my $port = "7890";
my $socket = IO::Socket::INET->new('LocalPort' => $port,
'Proto' => 'tcp',
'Listen' => SOMAXCONN)
or die "Can't create socket ($!)\n";
while (my $client = $socket->accept) {
my $name = gethostbyaddr($client->peeraddr, AF_INET);
my $port = $client->peerport;
while (<$client>) {
print "[$name $port] $_";
my #out = `$_`;
print #out;
print $client "$.: #out";
}
close $client
or die "Can't close ($!)\n";
}
die "Can't accept socket ($!)\n";
My client is sending a command (ls -lrt /) to the server and Server is supposed to run that command and send output to the client back.
Problem:-
The command is executed successfully on the server but it sends only first line to the client. If I press any key from client again the next line of output is sent to the client.
Or tell me how to send multiple line output to back to client.
Any help would be appreciated.
Thanks
Abhishek
The Server sends all lines to the client, the client however chooses to read only one line:
print scalar <$socket>;
If you remove the scalar, it should work. However, your architecture is still a security nightmare.
All servers should run in taint mode (-T switch).
Never blindly execute commands that a clients sends you. Only execute commands that pass a very strict validation test, do not run commands that just don't look malicious.
Perhaps you are trying to duplicate SSH, you might want to look at that program instead.
Your server doesn't do any kind of authentication. At least it logs all inputs.
It was a silly mistake... and I have fixed the first issue as follows and got multi-line output on the client side...
Client.pl
#!/usr/bin/perl
use IO::Socket::INET;
use strict;
my $name = '172.20.10.189'; #Server IP
my $port = '7890';
my $socket = IO::Socket::INET->new('PeerAddr' => $name,
'PeerPort' => $port,
'Proto' => 'tcp')
or die "Can't create socket ($!)\n";
print "Client sending\n";
while (1) {
my $msg = <STDIN>;
print $socket $msg;
while (<$socket>)
{
print "\n$_";
}
}
close $socket
or die "Can't close socket ($!)\n";
BUT there is one more issue -
I want my client to keep sending few other commands one after another until I close the client manually and receive output.
The problem is - It receives output of the first command only..
Can anyone now help me on this?
I've installed this module to gain access and controls within a Gmail inbox. However, when I try to connect through a small Perl script and test the functionality, I get this error message.
Error: Could not login with those credentials - could not find final URL
Additionally, HTTP error: 200 OK
This is an error built within the Gmail.pm module.
I can ping the URL in question ( https://www.google.com/accounts/ServiceLoginBoxAuth ) so I feel that the trouble isn't finding the URL. Furthermore, I know the credentials are correct and work at that URL because I have tried them manually.
I'm using this script for testing. I have supplied my credentials in the appropriate places.
I've also installed this module with the same type of error.
Any idea why I'm getting blocked?
Use Mail::IMAPClient as shown below. To get pass SSL authentication through Mail::IMAPClient, you should have IO::Socket::SSL from Net::SSLeay installed. If so this works like a charm.
#!/usr/bin/env perl
use strict; use warnings;
use Mail::IMAPClient;
# Connect to IMAP server
my $client = Mail::IMAPClient->new(
Server => 'imap.gmail.com',
User => 'yourusername',
Password => 'yourp4a55w0r&',
Port => 993,
Ssl => 1,
)
or die "Cannot connect through IMAPClient: $!";
# List folders on remote server (see if all is ok)
if ( $client->IsAuthenticated() ) {
print "Folders:\n";
print "- ", $_, "\n" for #{ $client->folders() };
};
# Say so long
$client->logout();
I am successfully accessing a gmail account (google apps account to be precise) using Mail::POP3Client
If you cannot access gmail through normal POP3 or IMAP either, then you have a configuration problem rather than a programming problem.
I fetch my mail from gmail (actually Google Apps, which uses the same interface), using configuration details described here: http://download.gna.org/hpr/fetchmail/FAQ/gmail-pop-howto.html
(This answer is far more appropriate for Super User though!)
You can tried with the following module
Mail::Webmail::Gmail
You can use the following code also
use warnings;
use strict;
use Mail::POP3Client;
use IO::Socket::SSL;
use CGI qw(:standard);
my $cgi = new CGI;
my $LOG ;
open $LOG , ">>filename" ;
my $username = 'name#gmail.com';
my $password = '*******' ;
chomp($password);
my $mailhost = 'pop.gmail.com';
my $port = '995';
$cgi->header();
my $pop = new Mail::POP3Client(
USER => $username,
PASSWORD => $password,
HOST => $mailhost,
PORT => $port,
USESSL => 'true',
DEBUG => 0,
);
if (($pop->Count()) < 1) {
exit;
}
print $pop->Count() . " messages found!:$!\n";
for(my $i = 1; $i <= $pop->Count(); $i++) {
foreach($pop->Head($i)) {
/^(From|Subject|Email):\s+/i && print $_, "\n";
}
$pop->BodyToFile($LOG,$i);
}
$pop->Close();
exit;