File Coverage

blib/lib/Net/Nessus/XMLRPC.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package Net::Nessus::XMLRPC;
2              
3 1     1   192440 use XML::Simple;
  0            
  0            
4             use LWP::UserAgent;
5             use HTTP::Request::Common;
6              
7             use warnings;
8             use strict;
9              
10             =head1 NAME
11              
12             Net::Nessus::XMLRPC - Communicate with Nessus scanner(v4.2+) via XMLRPC
13              
14             =head1 VERSION
15              
16             Version 0.30
17              
18             =cut
19              
20             our $VERSION = '0.30';
21              
22              
23             =head1 SYNOPSIS
24              
25             This is Perl interface for communication with Nessus scanner over XMLRPC.
26             You can start, stop, pause and resume scan. Watch progress and status of
27             scan, download report, etc.
28              
29             use Net::Nessus::XMLRPC;
30              
31             # '' is same as https://localhost:8834/
32             my $n = Net::Nessus::XMLRPC->new ('','user','pass');
33              
34             die "Cannot login to: ".$n->nurl."\n" unless ($n->logged_in);
35              
36             print "Logged in\n";
37             my $polid=$n->policy_get_first;
38             print "Using policy ID: $polid ";
39             my $polname=$n->policy_get_name($polid);
40             print "with name: $polname\n";
41             my $scanid=$n->scan_new($polid,"perl-test","127.0.0.1");
42              
43             while (not $n->scan_finished($scanid)) {
44             print "$scanid: ".$n->scan_status($scanid)."\n";
45             sleep 15;
46             }
47             print "$scanid: ".$n->scan_status($scanid)."\n";
48             my $reportcont=$n->report_file_download($scanid);
49             my $reportfile="report.xml";
50             open (FILE,">$reportfile") or die "Cannot open file $reportfile: $!";
51             print FILE $reportcont;
52             close (FILE);
53              
54             =head1 NOTICE
55              
56             This CPAN module uses LWP for communicating with Nessus over XMLRPC via https.
57             Therefore, make sure that you have Net::SSL (provided by Crypt::SSLeay):
58             http://search.cpan.org/perldoc?Crypt::SSLeay
59             or IO::Socket::SSL:
60             http://search.cpan.org/perldoc?IO::Socket::SSL
61              
62             If you think you have login problems, check this first!
63              
64             =head1 METHODS
65              
66             =head2 new ([$nessus_url], [$user], [$pass])
67              
68             creates new object Net::Nessus::XMLRPC
69             =cut
70             sub new {
71             my $class = shift;
72              
73             my $self;
74              
75             $self->{_nurl} = shift;
76             if ($self->{_nurl} eq '') {
77             $self->{_nurl}='https://localhost:8834/';
78             } elsif (substr($self->{_nurl},-1,1) ne '/') {
79             $self->{_nurl}= $self->{_nurl}.'/';
80             }
81             my $user = shift;
82             my $password = shift;
83             $self->{_token} = undef;
84             $self->{_name} = undef;
85             $self->{_admin} = undef;
86             $self->{_ua} = LWP::UserAgent->new;
87             bless $self, $class;
88             if ($user and $password) {
89             $self->login($user,$password);
90             }
91             return $self;
92             }
93              
94             =head2 DESTROY
95              
96             destructor, calls logout method on destruction
97             =cut
98             sub DESTROY {
99             my ($self) = @_;
100             $self->logout();
101             }
102              
103             =head2 nurl ( [$nessus_url] )
104              
105             get/set Nessus base URL
106             =cut
107             sub nurl {
108             my ( $self, $nurl ) = @_;
109             $self->{_nurl} = $nurl if defined($nurl);
110             return ( $self->{_nurl} );
111             }
112              
113             =head2 token ( [$nessus_token] )
114              
115             get/set Nessus login token
116             =cut
117             sub token {
118             my ( $self, $token ) = @_;
119             $self->{_token} = $token if defined($token);
120             return ( $self->{_token} );
121             }
122              
123             =head2 nessus_http_request ( $uri, $post_data )
124              
125             low-level function, makes HTTP request to Nessus URL
126             =cut
127             sub nessus_http_request {
128             my ( $self, $uri, $post_data ) = @_;
129             my $ua = $self->{_ua};
130             # my $ua = LWP::UserAgent->new;
131             my $furl = $self->nurl.$uri;
132             my $r = POST $furl, $post_data;
133             my $result = $ua->request($r);
134             # my $filename="n-".time; open (FILE,">$filename");
135             # print FILE $result->as_string; close (FILE);
136             if ($result->is_success) {
137             return $result->content;
138             } else {
139             return '';
140             }
141             }
142              
143             =head2 nessus_request ($uri, $post_data)
144              
145             low-level function, makes XMLRPC request to Nessus URL and returns XML
146             =cut
147             sub nessus_request {
148             my ( $self, $uri, $post_data ) = @_;
149             my $cont=$self->nessus_http_request($uri,$post_data);
150             if ($cont eq '') {
151             return ''
152             }
153             my $xmls;
154             eval {
155             $xmls=XMLin($cont, ForceArray => 1, KeyAttr => '', SuppressEmpty => '' );
156             } or return '';
157             if ($xmls->{'status'}->[0] eq "OK") {
158             return $xmls;
159             } else {
160             return ''
161             }
162             }
163              
164             =head2 login ( $user, $password )
165              
166             login to Nessus server via $user and $password
167             =cut
168             sub login {
169             my ( $self, $user, $password ) = @_;
170              
171             my $post=[ login => $user, password => $password ];
172             my $xmls = $self->nessus_request("login",$post);
173              
174             if ($xmls eq '' or not defined($xmls->{'contents'}->[0]->{'token'}->[0])) {
175             $self->token('');
176             } else {
177             $self->token ($xmls->{'contents'}->[0]->{'token'}->[0]);
178             }
179             return $self->token;
180             }
181              
182             =head2 logout
183              
184             logout from Nessus server
185             =cut
186             sub logout {
187             my ($self) = @_;
188             my $post=[ "token" => $self->token ];
189             my $xmls = $self->nessus_request("logout",$post);
190             $self->token('');
191             }
192              
193             =head2 logged_in
194              
195             returns true if we're logged in
196             =cut
197             sub logged_in {
198             my ($self) = @_;
199             return $self->token;
200             }
201              
202             =head2 scan_new ( $policy_id, $scan_name, $targets )
203              
204             initiates new scan
205             =cut
206             sub scan_new {
207             my ( $self, $policy_id, $scan_name, $target ) = @_;
208              
209             my $post=[
210             "token" => $self->token,
211             "policy_id" => $policy_id,
212             "scan_name" => $scan_name,
213             "target" => $target
214             ];
215              
216             my $xmls = $self->nessus_request("scan/new",$post);
217             if ($xmls) {
218             return ($xmls->{'contents'}->[0]->{'scan'}->[0]->{'uuid'}->[0]);
219             } else {
220             return $xmls
221             }
222             }
223              
224             =head2 scan_new_file ( $policy_id, $scan_name, $targets, $filename )
225              
226             initiates new scan with hosts from file named $filename
227             =cut
228             sub scan_new_file {
229             my ( $self, $policy_id, $scan_name, $target, $filename ) = @_;
230              
231             my $post={
232             "token" => $self->token,
233             "policy_id" => $policy_id,
234             "scan_name" => $scan_name,
235             "target" => $target
236             };
237             $post->{"target_file_name"} = $self->file_upload($filename);
238             my $xmls = $self->nessus_request("scan/new",$post);
239             if ($xmls) {
240             return ($xmls->{'contents'}->[0]->{'scan'}->[0]->{'uuid'}->[0]);
241             } else {
242             return $xmls
243             }
244             }
245              
246             =head2 scan_stop ( $scan_id )
247              
248             stops the scan identified by $scan_id
249             =cut
250             sub scan_stop {
251             my ( $self, $scan_uuid ) = @_;
252              
253             my $post=[
254             "token" => $self->token,
255             "scan_uuid" => $scan_uuid,
256             ];
257              
258             my $xmls = $self->nessus_request("scan/stop",$post);
259             return $xmls;
260             }
261              
262             =head2 scan_stop_all
263              
264             stops all scans
265             =cut
266             sub scan_stop_all {
267             my ( $self ) = @_;
268              
269             my $list = $self->scan_list_uids;
270              
271             foreach my $uuid (@$list) {
272             $self->scan_stop($uuid);
273             }
274             return $list;
275             }
276              
277             =head2 scan_pause ( $scan_id )
278              
279             pauses the scan identified by $scan_id
280             =cut
281             sub scan_pause {
282             my ( $self, $scan_uuid ) = @_;
283              
284             my $post=[
285             "token" => $self->token,
286             "scan_uuid" => $scan_uuid,
287             ];
288              
289             my $xmls = $self->nessus_request("scan/pause",$post);
290             return $xmls;
291             }
292              
293             =head2 scan_pause_all
294              
295             pauses all scans
296             =cut
297             sub scan_pause_all {
298             my ( $self ) = @_;
299              
300             my $list = $self->scan_list_uids;
301              
302             foreach my $uuid (@$list) {
303             $self->scan_pause($uuid);
304             }
305             return $list;
306             }
307              
308             =head2 scan_resume ( $scan_id )
309              
310             resumes the scan identified by $scan_id
311             =cut
312             sub scan_resume {
313             my ( $self, $scan_uuid ) = @_;
314              
315             my $post=[
316             "token" => $self->token,
317             "scan_uuid" => $scan_uuid,
318             ];
319              
320             my $xmls = $self->nessus_request("scan/resume",$post);
321             return $xmls;
322             }
323              
324             =head2 scan_resume_all
325              
326             resumes all scans
327             =cut
328             sub scan_resume_all {
329             my ( $self ) = @_;
330              
331             my $list = $self->scan_list_uids;
332              
333             foreach my $uuid (@$list) {
334             $self->scan_resume($uuid);
335             }
336             return $list;
337             }
338              
339             =head2 scan_list_uids
340              
341             returns array of IDs of (active) scans
342             =cut
343             sub scan_list_uids {
344             my ( $self ) = @_;
345              
346             my $post=[
347             "token" => $self->token
348             ];
349              
350             my $xmls = $self->nessus_request("scan/list",$post);
351             my @list;
352             if ($xmls->{'contents'}->[0]->{'scans'}->[0]->{'scanList'}->[0]->{'scan'}) {
353             foreach my $scan (@{$xmls->{'contents'}->[0]->{'scans'}->[0]->{'scanList'}->[0]->{'scan'}}) {
354             push @list, $scan->{'uuid'}->[0];
355             } # foreach
356             return \@list;
357             } # if
358             }
359              
360             =head2 scan_get_name ( $uuid )
361              
362             returns name of the scan identified by $uuid
363             =cut
364             sub scan_get_name {
365             my ( $self, $uuid ) = @_;
366              
367             my $post=[
368             "token" => $self->token
369             ];
370              
371             my $xmls = $self->nessus_request("scan/list",$post);
372             if ($xmls->{'contents'}->[0]->{'scans'}->[0]->{'scanList'}->[0]->{'scan'}) {
373             foreach my $scan (@{$xmls->{'contents'}->[0]->{'scans'}->[0]->{'scanList'}->[0]->{'scan'}}) {
374             if ($scan->{'uuid'}->[0] eq $uuid) {
375             return $scan->{'readableName'}->[0];
376             }
377             } # foreach
378             } # if
379             }
380              
381             =head2 scan_status ( $uuid )
382              
383             returns status of the scan identified by $uuid
384             =cut
385             sub scan_status {
386             my ( $self, $uuid ) = @_;
387              
388             my $post=[
389             "token" => $self->token,
390             "report" => $uuid,
391             ];
392              
393             my $xmls = $self->nessus_request("report/list",$post);
394             if ($xmls->{'contents'}->[0]->{'reports'}->[0]->{'report'}) {
395             foreach my $report (@{$xmls->{'contents'}->[0]->{'reports'}->[0]->{'report'}}) {
396             if ($report->{'name'}->[0] eq $uuid) {
397             return $report->{'status'}->[0];
398             }
399             } # foreach
400             } # if
401             return ''; # nothing found
402             }
403              
404             =head2 scan_finished ( $uuid )
405              
406             returns true if scan is finished/completed (identified by $uuid)
407             =cut
408             sub scan_finished {
409             my ( $self, $uuid ) = @_;
410             my $status = $self->scan_status($uuid);
411             if ( $status eq "completed" ) {
412             return $status;
413             } else {
414             return '';
415             }
416             }
417              
418             =head2 nessus_http_upload_request ( $uri, $post_data )
419              
420             low-level function, makes HTTP upload request to URI specified
421             =cut
422             sub nessus_http_upload_request {
423             my ( $self, $uri, $post_data ) = @_;
424             my $ua = $self->{_ua};
425             # my $ua = LWP::UserAgent->new;
426             my $furl = $self->nurl.$uri;
427             my $r = POST $furl, Content_Type => 'form-data', Content => $post_data;
428             my $result = $ua->request($r);
429             # my $filename="u-".time; open (FILE,">$filename");
430             # print FILE $result->as_string; close (FILE);
431             if ($result->is_success) {
432             return $result->content;
433             } else {
434             return '';
435             }
436             }
437              
438             =head2 file_upload ( $filename )
439              
440             uploads $filename to nessus server, returns filename of file uploaded
441             or '' if failed
442              
443             Note that uploaded file is per session (i.e. it will be there until logout/attack.)
444             So, don't logout or login again and use the filename! You need to upload it
445             again!
446             =cut
447             sub file_upload {
448             my ( $self, $filename ) = @_;
449             my $post=[ "token" => $self->token, Filedata => [ $filename] ];
450             my $cont=$self->nessus_http_upload_request("file/upload",$post);
451             if ($cont eq '') {
452             return ''
453             }
454             my $xmls;
455             eval {
456             $xmls=XMLin($cont, ForceArray => 1, KeyAttr => '', SuppressEmpty => '');
457             } or return '';
458             if ($xmls->{'status'}->[0] eq "OK") {
459             return $xmls->{'contents'}->[0]->{'fileUploaded'}->[0];
460             } else {
461             return ''
462             }
463             }
464              
465             =head2 upload ( $filename, $content )
466              
467             uploads $filename to nessus server using $content as content of file, returns filename of file uploaded
468             or '' if failed
469              
470             Note that uploaded file is per session (i.e. it will be there until logout/attack.)
471             So, don't logout or login again and use the filename! You need to upload it
472             again!
473             =cut
474             sub upload {
475             my ( $self, $filename, $content ) = @_;
476             # Content => [ $PARAM => [undef,$FILENAME, Content => $CONTENTS ] ]);
477             my $post=[ "token" => $self->token, Filedata => [ undef, $filename, Content => $content] ];
478             my $cont=$self->nessus_http_upload_request("file/upload",$post);
479             if ($cont eq '') {
480             return ''
481             }
482             my $xmls;
483             eval {
484             $xmls=XMLin($cont, ForceArray => 1, KeyAttr => '', SuppressEmpty => '');
485             } or return '';
486             if ($xmls->{'status'}->[0] eq "OK") {
487             return $xmls->{'contents'}->[0]->{'fileUploaded'}->[0];
488             } else {
489             return ''
490             }
491             }
492              
493             =head2 policy_get_first
494              
495             returns policy id for the first policy found
496             =cut
497             sub policy_get_first {
498             my ( $self ) = @_;
499              
500             my $post=[
501             "token" => $self->token,
502             ];
503            
504             my $xmls = $self->nessus_request("policy/list",$post);
505             if ($xmls->{'contents'}->[0]->{'policies'}->[0]->{'policy'}) {
506             foreach my $report (@{$xmls->{'contents'}->[0]->{'policies'}->[0]->{'policy'}}) {
507             return $report->{'policyID'}->[0];
508             } # foreach
509             } # if
510             return '';
511             }
512              
513             =head2 policy_get_firsth
514              
515             returns ref to hash %value with basic info of first policy/scan
516             returned by the server
517              
518             $value{'id'}, $value{'name'}, $value{'owner'}, $value{'visibility'},
519             $value{'comment'}
520             =cut
521             sub policy_get_firsth {
522             my ( $self ) = @_;
523              
524             my $post=[
525             "token" => $self->token,
526             ];
527              
528             my %info;
529             my $xmls = $self->nessus_request("policy/list",$post);
530             if ($xmls->{'contents'}->[0]->{'policies'}->[0]->{'policy'}) {
531             foreach my $report (@{$xmls->{'contents'}->[0]->{'policies'}->[0]->{'policy'}}) {
532             $info{'id'} = $report->{'policyID'}->[0];
533             $info{'name'} = $report->{'policyName'}->[0];
534             $info{'owner'} = $report->{'policyOwner'}->[0];
535             $info{'visibility'} = $report->{'visibility'}->[0];
536             $info{'comment'} = $report->{'policyContents'}->[0]->{'policyComments'}->[0];
537             return \%info;
538             } # foreach
539             } # if
540             return \%info;
541             }
542              
543             =head2 policy_list_hash
544              
545             returns ref to array of hashes %value with basic info of first policy/scan
546             returned by the server
547              
548             $value{'id'}, $value{'name'}, $value{'owner'}, $value{'visibility'},
549             $value{'comment'}
550             =cut
551             sub policy_list_hash {
552             my ( $self ) = @_;
553              
554             my $post=[
555             "token" => $self->token,
556             ];
557              
558             my @list;
559             my $xmls = $self->nessus_request("policy/list",$post);
560             if ($xmls->{'contents'}->[0]->{'policies'}->[0]->{'policy'}) {
561             foreach my $report (@{$xmls->{'contents'}->[0]->{'policies'}->[0]->{'policy'}}) {
562             my %info;
563             $info{'id'} = $report->{'policyID'}->[0];
564             $info{'name'} = $report->{'policyName'}->[0];
565             $info{'owner'} = $report->{'policyOwner'}->[0];
566             $info{'visibility'} = $report->{'visibility'}->[0];
567             $info{'comment'} = $report->{'policyContents'}->[0]->{'policyComments'}->[0];
568             push @list, \%info;
569             } # foreach
570             } # if
571             return \@list;
572             }
573              
574             =head2 policy_list_uids
575              
576             returns ref to array of IDs of policies available
577             =cut
578             sub policy_list_uids {
579             my ( $self ) = @_;
580              
581             my $post=[
582             "token" => $self->token,
583             ];
584              
585             my $xmls = $self->nessus_request("policy/list",$post);
586             my @list;
587             if ($xmls->{'contents'}->[0]->{'policies'}->[0]->{'policy'}) {
588             foreach my $report (@{$xmls->{'contents'}->[0]->{'policies'}->[0]->{'policy'}}) {
589             push @list,$report->{'policyID'}->[0];
590             } # foreach
591             return \@list;
592             } # if
593             return '';
594             }
595              
596             =head2 policy_list_names
597              
598             returns ref to array of names of policies available
599             =cut
600             sub policy_list_names {
601             my ( $self ) = @_;
602              
603             my $post=[
604             "token" => $self->token,
605             ];
606              
607             my $xmls = $self->nessus_request("policy/list",$post);
608             my @list;
609             if ($xmls->{'contents'}->[0]->{'policies'}->[0]->{'policy'}) {
610             foreach my $report (@{$xmls->{'contents'}->[0]->{'policies'}->[0]->{'policy'}}) {
611             push @list,$report->{'policyName'}->[0];
612             } # foreach
613             return \@list;
614             } # if
615             return '';
616             }
617              
618             =head2 policy_get_info ( $policy_id )
619              
620             returns ref to hash %value with basic info of policy/scan identified by $policy_id
621              
622             $value{'id'}, $value{'name'}, $value{'owner'}, $value{'visibility'},
623             $value{'comment'}
624             =cut
625             sub policy_get_info {
626             my ( $self, $policy_id ) = @_;
627              
628             my $post=[
629             "token" => $self->token,
630             ];
631             my %info;
632             my $xmls = $self->nessus_request("policy/list",$post);
633             if ($xmls->{'contents'}->[0]->{'policies'}->[0]->{'policy'}) {
634             foreach my $report (@{$xmls->{'contents'}->[0]->{'policies'}->[0]->{'policy'}}) {
635             if ($report->{'policyID'}->[0] eq $policy_id) {
636             $info{'id'} = $report->{'policyID'}->[0];
637             $info{'name'} = $report->{'policyName'}->[0];
638             $info{'owner'} = $report->{'policyOwner'}->[0];
639             $info{'visibility'} = $report->{'visibility'}->[0];
640             $info{'comment'} = $report->{'policyContents'}->[0]->{'policyComments'}->[0];
641             return \%info;
642             }
643             } # foreach
644             } # if
645             return \%info;
646             }
647              
648             =head2 policy_get_id ( $policy_name )
649              
650             returns ID of the scan/policy identified by $policy_name
651             =cut
652             sub policy_get_id {
653             my ( $self, $policy_name ) = @_;
654              
655             my $post=[
656             "token" => $self->token,
657             ];
658             my $xmls = $self->nessus_request("policy/list",$post);
659             if ($xmls->{'contents'}->[0]->{'policies'}->[0]->{'policy'}) {
660             foreach my $report (@{$xmls->{'contents'}->[0]->{'policies'}->[0]->{'policy'}}) {
661             if ($report->{'policyName'}->[0] eq $policy_name) {
662             return $report->{'policyID'}->[0];
663             }
664             } # foreach
665             } # if
666             return '';
667             }
668              
669             =head2 policy_get_name ( $policy_id )
670              
671             returns name of the scan/policy identified by $policy_id
672             =cut
673             sub policy_get_name {
674             my ( $self, $policy_id ) = @_;
675              
676             my $post=[
677             "token" => $self->token,
678             ];
679             my $xmls = $self->nessus_request("policy/list",$post);
680             if ($xmls->{'contents'}->[0]->{'policies'}->[0]->{'policy'}) {
681             foreach my $report (@{$xmls->{'contents'}->[0]->{'policies'}->[0]->{'policy'}}) {
682             if ($report->{'policyID'}->[0] eq $policy_id) {
683             return $report->{'policyName'}->[0];
684             }
685             } # foreach
686             } # if
687             return '';
688             }
689              
690             =head2 policy_delete ( $policy_id )
691              
692             delete policy identified by $policy_id
693             =cut
694             sub policy_delete {
695             my ( $self, $policy_id ) = @_;
696              
697             my $post=[
698             "token" => $self->token,
699             "policy_id" => $policy_id,
700             ];
701              
702             my $xmls = $self->nessus_request("policy/delete",$post);
703             return $xmls;
704             }
705              
706             =head2 policy_copy ( $policy_id )
707              
708             copy policy identified by $policy_id, returns $policy_id of new copied policy
709             =cut
710             sub policy_copy {
711             my ( $self, $policy_id ) = @_;
712              
713             my $post=[
714             "token" => $self->token,
715             "policy_id" => $policy_id,
716             ];
717              
718             my $xmls = $self->nessus_request("policy/copy",$post);
719             if ($xmls->{'contents'}->[0]->{'policy'}->[0]) {
720             return $xmls->{'contents'}->[0]->{'policy'}->[0]->{'policyID'}->[0];
721             } # if
722             return '';
723             }
724              
725             =head2 policy_rename ( $policy_id, $policy_name )
726              
727             rename policy to $policy_name identified by $policy_id
728             =cut
729             sub policy_rename {
730             my ( $self, $policy_id, $policy_name ) = @_;
731              
732             my $post=[
733             "token" => $self->token,
734             "policy_id" => $policy_id,
735             "policy_name" => $policy_name
736             ];
737              
738             my $xmls = $self->nessus_request("policy/rename",$post);
739             return $xmls;
740             }
741              
742             =head2 policy_edit ( $policy_id, $params )
743              
744             edit policy identified by $policy_id
745              
746             %params (must be present):
747             policy_name => name
748             policy_shared => 1
749              
750             %params can be (examples)
751             max_hosts => 50,
752             max_checks=> 10,
753             use_mac_addr => no,
754             throttle_scan => yes,
755             optimize_test => yes,
756             log_whole_attack => no,
757             ssl_cipher_list => strong,
758             save_knowledge_base => no,
759             port_range => 1-65535
760             =cut
761             sub policy_edit {
762             my ( $self, $policy_id, $params ) = @_;
763              
764             my $post={
765             "token" => $self->token,
766             "policy_id" => $policy_id
767             };
768             while (my ($key, $value) = each(%{$params}))
769             {
770             $post->{$key} = $value;
771             }
772              
773             my $xmls = $self->nessus_request("policy/add",$post);
774             return $xmls;
775             }
776              
777             =head2 policy_new ( $params )
778              
779             create new policy with $params,
780             %params must be present:
781             policy_name
782             policy_shared
783              
784             the others parameters are same as policy_edit
785             =cut
786             sub policy_new {
787             my ( $self, $params ) = @_;
788              
789             my $xmls = $self->policy_edit(0, %{$params});
790             return $xmls;
791             }
792              
793             =head2 policy_get_opts ( $policy_id )
794              
795             returns hashref with different options for policy identified by $policy_id
796             =cut
797             sub policy_get_opts {
798             my ( $self, $policy_id ) = @_;
799              
800             my $post=[
801             "token" => $self->token,
802             ];
803             my $xmls = $self->nessus_request("policy/list",$post);
804              
805             if ($xmls->{'contents'}->[0]->{'policies'}->[0]->{'policy'}) {
806             my %opts;
807             foreach my $report (@{$xmls->{'contents'}->[0]->{'policies'}->[0]->{'policy'}}) {
808             if ($report->{'policyID'}->[0] eq $policy_id) {
809             $opts{'policy_name'}=$report->{'policyName'}->[0];
810             if ($report->{'visibility'}->[0] eq "shared") {
811             $opts{'policy_shared'}=1;
812             } else {
813             $opts{'policy_shared'}=0;
814             }
815             if ($report->{'policyContents'}->[0]->{'policyComments'}->[0]) {
816             $opts{'policy_comments'}=$report->{'policyContents'}->[0]->{'policyComments'}->[0];
817             }
818             foreach my $prefs (@{$report->{'policyContents'}->[0]->{'Preferences'}->[0]->{'ServerPreferences'}->[0]->{'preference'}}) {
819             $opts{$prefs->{'name'}->[0]} = $prefs->{'value'}->[0] if ($prefs->{'name'}->[0]);
820             }
821             foreach my $prefp (@{$report->{'policyContents'}->[0]->{'Preferences'}->[0]->{'PluginsPreferences'}->[0]->{'item'}}) {
822             $opts{$prefp->{'fullName'}->[0]} = $prefp->{'selectedValue'}->[0] if ($prefp->{'fullName'}->[0]);
823             }
824             foreach my $plugf (@{$report->{'policyContents'}->[0]->{'FamilySelection'}->[0]->{'FamilyItem'}}) {
825             $opts{"plugin_selection.family.".$plugf->{'FamilyName'}->[0]} = $plugf->{'Status'}->[0] if ($plugf->{'FamilyName'}->[0]);
826             }
827             foreach my $plugi (@{$report->{'policyContents'}->[0]->{'IndividualPluginSelection'}->[0]->{'PluginItem'}}) {
828             $opts{"plugin_selection.individual_plugin.".$plugi->{'PluginId'}->[0]} = $plugi->{'Status'}->[0] if ($plugi->{'PluginId'}->[0]);
829             }
830             return \%opts;
831             }
832             } # foreach
833             } # if
834             return '';
835             }
836              
837             =head2 policy_set_opts ( $policy_id , $params )
838              
839             sets policy options via hashref $params identified by $policy_id
840             =cut
841             sub policy_set_opts {
842             my ( $self, $policy_id, $params ) = @_;
843              
844             my $post = $self->policy_get_opts ($policy_id);
845             while (my ($key, $value) = each(%{$params}))
846             {
847             $post->{$key} = $value;
848             }
849             $post->{"token"} = $self->token;
850             $post->{"policy_id"} = $policy_id;
851              
852             my $xmls = $self->nessus_request("policy/edit",$post);
853             return $xmls;
854             }
855              
856             =head2 report_list_uids
857              
858             returns ref to array of IDs of reports available
859             =cut
860             sub report_list_uids {
861             my ( $self ) = @_;
862              
863             my $post=[
864             "token" => $self->token
865             ];
866              
867             my $xmls = $self->nessus_request("report/list",$post);
868             my @list;
869             if ($xmls->{'contents'}->[0]->{'reports'}->[0]->{'report'}) {
870             foreach my $report (@{$xmls->{'contents'}->[0]->{'reports'}->[0]->{'report'}}) {
871             push @list, $report->{'name'}->[0];
872             }
873             }
874              
875             return \@list;
876             }
877              
878             =head2 report_list_hash
879              
880             returns ref to array of hashes with basic info of reports
881             hash has following keys:
882             name
883             status
884             readableName
885             timestamp
886             =cut
887             sub report_list_hash {
888             my ( $self ) = @_;
889              
890             my $post=[
891             "token" => $self->token
892             ];
893              
894             my $xmls = $self->nessus_request("report/list",$post);
895             my @list;
896             if ($xmls->{'contents'}->[0]->{'reports'}->[0]->{'report'}) {
897             foreach my $report (@{$xmls->{'contents'}->[0]->{'reports'}->[0]->{'report'}}) {
898             my %r;
899             $r{'name'} = $report->{'name'}->[0];
900             $r{'status'} = $report->{'status'}->[0];
901             $r{'readableName'} = $report->{'readableName'}->[0];
902             $r{'timestamp'} = $report->{'timestamp'}->[0];
903            
904             push @list, \%r;
905             }
906             }
907              
908             return \@list;
909             }
910              
911             =head2 report_file_download ($report_id)
912              
913             returns XML report identified by $report_id (Nessus XML v2)
914             =cut
915             sub report_file_download {
916             my ( $self, $uuid ) = @_;
917              
918             my $post=[
919             "token" => $self->token,
920             "report" => $uuid,
921             ];
922              
923             my $file = $self->nessus_http_request("file/report/download", $post);
924             return $file;
925             }
926              
927             =head2 report_file1_download ($report_id)
928              
929             returns XML report identified by $report_id (Nessus XML v1)
930             =cut
931             sub report_file1_download {
932             my ( $self, $uuid ) = @_;
933              
934             my $post=[
935             "token" => $self->token,
936             "report" => $uuid,
937             "v1" => "true",
938             ];
939              
940             my $file = $self->nessus_http_request("file/report/download", $post);
941             return $file;
942             }
943              
944             =head2 report_delete ($report_id)
945              
946             delete report identified by $report_id
947             =cut
948             sub report_delete {
949             my ( $self, $uuid ) = @_;
950              
951             my $post=[
952             "token" => $self->token,
953             "report" => $uuid,
954             ];
955              
956             my $xmls = $self->nessus_request("report/delete", $post);
957             return $xmls;
958             }
959              
960             =head2 report_import ( $filename )
961              
962             tells nessus server to import already uploaded file named $filename
963             ( i.e. you already uploaded the file via file_upload() )
964             =cut
965             sub report_import {
966             my ( $self, $filename ) = @_;
967             my $post={ "token" => $self->token, "file" => $filename };
968             my $xmls = $self->nessus_request("file/report/import",$post);
969             return $xmls;
970             }
971              
972             =head2 report_import_file ( $filename )
973              
974             uploads $filename to nessus server and imports it as nessus report
975             =cut
976             sub report_import_file {
977             my ( $self, $filename ) = @_;
978             my $post={ "token" => $self->token};
979             $post->{"file"} = $self->file_upload($filename);
980             my $xmls = $self->nessus_request("file/report/import",$post);
981             return $xmls;
982             }
983              
984             =head2 users_list
985              
986             returns ref to array of hash %values with users info
987             $values{'name'}
988             $values{'admin'}
989             $values{'lastlogin'}
990             =cut
991             sub users_list {
992             my ( $self ) = @_;
993              
994             my $post=[
995             "token" => $self->token,
996             ];
997             my @users;
998             my $xmls = $self->nessus_request("users/list",$post);
999             if ($xmls->{'contents'}->[0]->{'users'}->[0]->{'user'}) {
1000             foreach my $user (@{$xmls->{'contents'}->[0]->{'users'}->[0]->{'user'}}) {
1001             my %info;
1002             $info{'name'} = $user->{'name'}->[0];
1003             $info{'admin'} = $user->{'admin'}->[0];
1004             $info{'lastlogin'} = $user->{'lastlogin'}->[0];
1005             push @users, \%info
1006              
1007             } # foreach
1008             } # if
1009             return \@users;
1010             }
1011              
1012             =head2 users_delete ( $login )
1013              
1014             deletes user with $login
1015              
1016             =cut
1017             sub users_delete {
1018             my ( $self, $login ) = @_;
1019              
1020             my $post=[
1021             "token" => $self->token,
1022             "login" => $login
1023             ];
1024             my $xmls = $self->nessus_request("users/delete",$post);
1025             my $user = '';
1026             if ($xmls->{'contents'}->[0]->{'user'}->[0]->{'name'}->[0]) {
1027             $user = $xmls->{'contents'}->[0]->{'user'}->[0]->{'name'}->[0];
1028             }
1029             return $user;
1030             }
1031              
1032             =head2 users_add ( $login, $password )
1033              
1034             deletes user with $login and $password, return username created, '' if not
1035              
1036             =cut
1037             sub users_add {
1038             my ( $self, $login, $password ) = @_;
1039              
1040             my $post=[
1041             "token" => $self->token,
1042             "login" => $login,
1043             "password" => $password
1044             ];
1045             my $xmls = $self->nessus_request("users/add",$post);
1046             my $user = '';
1047             if ($xmls->{'contents'}->[0]->{'user'}->[0]->{'name'}->[0]) {
1048             $user = $xmls->{'contents'}->[0]->{'user'}->[0]->{'name'}->[0];
1049             }
1050             return $user;
1051             }
1052              
1053             =head2 users_passwd ( $login, $password )
1054              
1055             change user password to $password identified with $login, return username, '' if not
1056              
1057             =cut
1058             sub users_passwd {
1059             my ( $self, $login, $password ) = @_;
1060              
1061             my $post=[
1062             "token" => $self->token,
1063             "login" => $login,
1064             "password" => $password
1065             ];
1066             my $xmls = $self->nessus_request("users/chpasswd",$post);
1067             my $user = '';
1068             if ($xmls->{'contents'}->[0]->{'user'}->[0]->{'name'}->[0]) {
1069             $user = $xmls->{'contents'}->[0]->{'user'}->[0]->{'name'}->[0];
1070             }
1071             return $user;
1072             }
1073              
1074             =head1 AUTHOR
1075              
1076             Vlatko Kosturjak, C<< >>
1077              
1078             =head1 BUGS
1079              
1080             Please report any bugs or feature requests to C, or through
1081             the web interface at L. I will be notified, and then you'll
1082             automatically be notified of progress on your bug as I make changes.
1083              
1084              
1085              
1086              
1087             =head1 SUPPORT
1088              
1089             You can find documentation for this module with the perldoc command.
1090              
1091             perldoc Net::Nessus::XMLRPC
1092              
1093              
1094             You can also look for information at:
1095              
1096             =over 4
1097              
1098             =item * RT: CPAN's request tracker
1099              
1100             L
1101              
1102             =item * AnnoCPAN: Annotated CPAN documentation
1103              
1104             L
1105              
1106             =item * CPAN Ratings
1107              
1108             L
1109              
1110             =item * Search CPAN
1111              
1112             L
1113              
1114             =back
1115              
1116              
1117             =head1 REPOSITORY
1118              
1119             Repository is available on GitHub: http://github.com/kost/nessus-xmlrpc-perl
1120              
1121             =head1 ACKNOWLEDGEMENTS
1122              
1123             I have made Ruby library as well: http://nessus-xmlrpc.rubyforge.org/
1124              
1125             There you can find some early documentation about XMLRPC protocol used.
1126              
1127             =head1 COPYRIGHT & LICENSE
1128              
1129             Copyright 2010 Vlatko Kosturjak, all rights reserved.
1130              
1131             This program is free software; you can redistribute it and/or modify it
1132             under the same terms as Perl itself.
1133              
1134              
1135             =cut
1136              
1137             1; # End of Net::Nessus::XMLRPC