check cpanel authorisation with perl script and write file - perl

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.

Related

Resolving issue with Net::OpenSSH and passing multiple commands to a router

I'm working on moving a Perl script that pushed commands to routers. We have turned off telnet, so I'm working on getting SSH to work. After looking at a number of SSH libraries in Perl, I've opted to use Net::OpenSSH. I have no problem logging in and passing commands to the routers, but the problem I'm having is with entering config mode and subsequently passing a command.
The problem is that with each command entered, the underlying system appears to logout then reenter with the next subsequent command. For example with a Juniper router I'm trying to do the following:
edit private
set interfaces xe-1/3/2 description "AVAIL: SOMETHING GOES HERE"
commit
exit
quit
Tailing the syslog from the router I'm seeing something like this...
(...)
UI_LOGIN_EVENT: User 'tools' login, class 'j-remote-user' [65151], ssh-connection 'xxx.xxx.xxx.xxx 42247 xxx.xxx.xxx.xxx 22', client-mode 'cli'
UI_CMDLINE_READ_LINE: User 'tools', command 'edit private '
UI_DBASE_LOGIN_EVENT: User 'tools' entering configuration mode
UI_DBASE_LOGOUT_EVENT: User 'tools' exiting configuration mode
UI_LOGOUT_EVENT: User 'tools' logout
UI_AUTH_EVENT: Authenticated user 'remote' at permission level 'j-remote-user'
UI_LOGIN_EVENT: User 'tools' login, class 'j-remote-user' [65153], ssh-connection 'xxx.xxx.xxx.xxx 42247 xxx.xxx.xxx.xxx 22', client-mode 'cli'
UI_CMDLINE_READ_LINE: User 'tools', command 'set interfaces '
UI_LOGOUT_EVENT: User 'tools' logout
(...)
As you notice I'm getting a LOGOUT_EVENT after each command entered. Of course exiting config mode immediately after entering it causes the set interfaces command to fail as it's no longer in config mode.
The Perl code I'm using is as follows...
#!/usr/bin/perl -w
use strict;
use lib qw(
/usr/local/admin/protect/perl
/usr/local/admin/protect/perl/share/perl/5.10.1
);
use Net::OpenSSH;
my $hostname = "XXXXX";
my $username = "tools";
my $password = "XXXXX";
my $timeout = 60;
my $cmd1 = "edit private";
my $cmd2 = 'set interfaces xe-1/3/2 description "AVAIL: SOMETHING GOES HERE"';
my $cmd3 = "commit";
my $cmd4 = "exit";
my $ssh = Net::OpenSSH->new($hostname, user => $username, password => $password, timeout => $timeout,
master_opts => [-o => "StrictHostKeyChecking=no"]);
$ssh->error and die "Unable to connect to remote host: " . $ssh->error;
my #lines = eval { $ssh->capture($cmd1) };
foreach (#lines) {
print $_;
};
#lines = eval { $ssh->capture($cmd2) };
foreach (#lines) {
print $_;
};
#lines = eval { $ssh->capture($cmd3) };
foreach (#lines) {
print $_;
};
#lines = eval { $ssh->capture($cmd4) };
foreach (#lines) {
print $_;
};
$ssh->system("quit");
The sequence of events is the same as when telnet was used. The only real change was in using SSH objects verses Telnet objects. I'm stumped. Any ideas you could provide would be quite helpful.
[SOLVED, sort of]
The suggestion let Net::Telnet do the driving was the correct one. The following code works...
#!/usr/bin/perl -w
use strict;
use Net::OpenSSH;
use Net::Telnet;
use Data::Dumper;
my $promptEnd = '/\w+[\$\%\#\>]\s{0,1}$/o';
my $cmd1 = "show system uptime | no-more";
my $cmd2 = "show version brief | no-more";
my $hostname = "xxx.xxx";
my $username = "xxxxxxx";
my $password = "xxxxxxx";
my $timeout = 60;
my $ssh = Net::OpenSSH->new(
$hostname,
user => $username,
password => $password,
timeout => $timeout,
master_opts => [ -o => "StrictHostKeyChecking=no" ]
);
$ssh->error and die "Unable to connect to remote host: " . $ssh->error;
my ( $fh, $pid ) = $ssh->open2pty( { stderr_to_stdout => 1 } );
my %params = (
fhopen => $fh,
timeout => $timeout,
errmode => 'return',
);
$conn = Net::Telnet->new(%params);
$conn->waitfor($promptEnd);
#lines = $conn->cmd($cmd1);
foreach (#lines) {
print $_;
}
#lines = $conn->cmd($cmd2);
foreach (#lines) {
print $_;
}
$conn->cmd("quit");
The problem I'm having is that I can't seem to separate the code into subroutines. Once the $conn object is returned from a subroutine, the underlying ssh connection drops. I need to separate this logic in order to not have to rewrite many, many programs and lines of code that relay on this pusher routine. However that problem I'll direct to another question.
[Edit, fully solved]
Just an update in case anyone needs to do something similar.
While the above worked very well when run under a single subroutine, I found that any time I passed the handle to another subroutine, the telnet handle remained open, but the ssh connection dropped.
To solve this I found that if I passed the ssh handle to another subroutine, then later attached the open2pty, and attached Net::Telnet, then I could pass the Net::Telnet handle between subroutines without the underlying ssh connection dropping. This also worked for Net::Telnet::Cisco as well. I have this code working well with Cisco, Juniper, and Brocade routers.
You should also consider adding a few more parameters to the Net::Telnet->new() because it is interacting with ssh rather than a TELNET server.
-telnetmode => 0
-output_record_separator => "\r",
-cmd_remove_mode => 1,
Because there is no TELNET server on remote side, -telnetmode => 0 turns off TELNET negotiation.
The end-of-line is most likely just a carriage-return (i.e. -output_record_separator => "\r") rather than the TCP or TELNET combination of carriage-return linefeed ("\r\n").
Always strip the echoed back input -cmd_remove_mode => 1
There are several possibilities:
Some routers accept having the sequence of commands sent up front via stdin:
my $out = $ssh->capture({stdin_data => join("\r\n", #cmds, '')})
In other cases you will have to use something like Expect to send a command, wait for the prompt to appear again, send another command, etc.
If you were using Net::Telnet before, the Net::OpenSSH docs explain how to integrate both (though I have to admit that combination is not very tested).
Also, some routers provide some way to escape to a full Unix-like shell. I.e., preppending the commands with a bang:
$ssh->capture("!ls");

use IO::Socket::IP ??? how to make a client in perl Ipv6

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.

Perl - DBI and .pgpass

I can successfully create a connection to a Postgres db using the following:
my $settings = {
host => 'myhost',
db => 'mydb',
user => 'myuser',
passwd => 'mypasswd'
};
my $connection = DBI->connect(
'DBI:Pg:dbname=' . $settings->{'db'} . ';host=' . $settings->{'host'},
$settings->{'user'},
$settings->{'passwd'},
{
RaiseError => 1,
ShowErrorStatement => 0,
AutoCommit => 0
}
) or die DBI->errstr;
But I'm left with valuable login credentials exposed (yes, I changed them) in my Perl module. Currently, I use psql to issue queries interactively. And to save on having to remember my username/password, I have placed the credentials in a file (~/.pgpass) with permissions 600. The file looks like this:
# host:port:database:user:passwd
myhost:5432:mydb:myuser:mypasswd
How can I safely use this file ("$ENV{HOME}/.pgpass") and the DBI module to hide my credentials? Can it be done? What is best practice?
YES! There IS a better way.
Change between test & live servers easily.
keep passwords in ~/.pgpass (for psql & pg_dump)
other config info in ~/.pg_service.conf (or /etc/pg_service.conf)
e.g:
#!/usr/bin/perl -T
use strict;
use warnings;
use DBI;
my $dbh = DBI->connect
(
#"dbi:Pg:service=live",
"dbi:Pg:service=test",
undef,
undef,
{
AutoCommit => 0,
RaiseError => 1,
PrintError => 0
}
) or die DBI->errstr;
~/.pg_service.conf:
# http://www.postgresql.org/docs/9.2/static/libpq-pgservice.html
# /usr/local/share/postgresql/pg_service.conf.sample
# http://search.cpan.org/dist/DBD-Pg/Pg.pm
#
[test]
dbname=hotapp_test
user=hotusr_test
# localhost, no TCP nonsense needed:
host=/tmp
[live]
dbname=hotapp_live
user=hotusr_live
host=pgsql-server.example.org
~/.pgpass:
# http://www.postgresql.org/docs/9.2/static/libpq-pgpass.html
# hostname:port:database:username:password
localhost:5432:hotapp_test:hotusr_test:kq[O2Px7=g1
pgsql-server.example.org:5432:hotapp_live:hotusr_live:Unm£a7D(H
Put your login credentials in a file called ~/.pgpass as per the question above.
To open a connection, you'll need to hard-code in the host, database and username. But that's ok, because at least you don't need to code in the password field. This field stays hidden in your ~/.pgpass file.
Make sure to set the connection instance's password field to undef.
Here's what worked for me:
my $settings = {
host => 'myhost',
db => 'mydb',
user => 'myuser'
};
my $connection = DBI->connect(
'DBI:Pg:dbname=' . $settings->{'db'} . ';host=' . $settings->{'host'},
$settings->{'user'},
undef,
{
RaiseError => 1,
ShowErrorStatement => 0,
AutoCommit => 0
}
) or die DBI->errstr;
The connections establishes successfully because for some reason, unknown to me at least, the instance searches the ~/.pgpass file when attempting the connection. I knew there was some magic with this file, I was just unsure about what to do with it. Doc link:
http://search.cpan.org/dist/DBI/DBI.pm#data_string_diff
Notice how a search for "pgpass" on that page does not return? And I refuse to read all of it. Well, one day maybe..
open(my $fh, '<', "$ENV{HOME}/.pgpass") or die $!;
my $settings;
while (<>) {
chomp;
next if /^\s*(?:#.*)?\z/s;
#{$settings}{qw( host port database user passwd )} = split /:/;
}
die "No settings" if !$settings;
Any user capable of running the script would still be able to see the creds.

how to parse request URL in simple server in Perl which listen to port

here is the request URL http://localhost:9009/?comd&user=kkc&mail=kkc#kkc.com
what are the modification need to do in the server perl script.
server-Perl-script
use IO::Socket;
use Net::hostent; # for OO version of gethostbyaddr
$PORT = 9009; # pick something not in use
$server = IO::Socket::INET->new( Proto => 'tcp',
LocalPort => $PORT,
Listen => SOMAXCONN,
Reuse => 1);
die "can't setup server" unless $server;
print "[Server $0 accepting clients]\n";
while ($client = $server->accept())
{
$client->autoflush(1);
print $client "Welcome to $0; type help for command list.\n";
$hostinfo = gethostbyaddr($client->peeraddr);
printf "[Connect from %s]\n", $hostinfo ? $hostinfo->name : $client->peerhost;
print $client "Command? ";
while ( <$client>) {
next unless /\S/; # blank line
if (/comd/i ) { print $client `dir`; }
} continue {
print $client "Command? ";
}
close $client;
print "client closed";
}
I assume that your script is not for production, but for homework or testing sometime. There are multiple very efficient web server solutions in/with Perl like Apache with CGIs or mod_perl, HTTP::Server::Simple and PSGI/Plack.
You'll also typically use a framework like Dancer, Mojo or Catalyst which does most of the boring standard stuff for you:
use Dancer;
get '/' => sub {
return 'Hi there, you just visited host '.request->host.
' at port '.request->port.' asking for '.request->uri;
};
Back to your question: Your script is a interactive server while HTTP has a strict request and response structure:
Client connects to server
Client sends a request
Server sends a response
You need to remove the interactive part and just wait for the client to start the conversation:
use IO::Socket;
use Net::hostent; # for OO version of gethostbyaddr
$PORT = 9009; # pick something not in use
$server = IO::Socket::INET->new( Proto => 'tcp',
LocalPort => $PORT,
Listen => SOMAXCONN,
Reuse => 1);
die "can't setup server" unless $server;
print "[Server $0 accepting clients]\n";
while ($client = $server->accept())
{
$hostinfo = gethostbyaddr($client->peeraddr);
# Read request up to a empty line
my $request;
while ( <$client>) {
last unless /\S/;
$request .= $_;
}
# Do something with the request
# Send response
print $client "Status: 200 OK\r\nContent-type: text/plain\r\n\r\n".$request;
close $client;
print "client closed";
}
The server reads the full request from the client and returns a minimized HTTP header plus the original request.

How do I authenticate into Gmail using Perl?

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;