c88a4000e3d63514d975798c70bcdd443cdf81de
[freeradius.git] / dialup_admin / bin / log_badlogins
1 #!/usr/bin/perl
2 #
3 # Log failed logins in the sql database
4 # Works with mysql and postgresql
5 # It will read the sql parameters from the admin.conf file
6 #
7 # Usage:
8 # log_badlogins <radius.log> [<admin.conf>] [all]
9 #
10 # Defaults:
11 # radius.log: none
12 # admin.conf: /usr/local/dialup_admin/conf/admin.conf 
13 # all:        no. Go to the end of the file. Don't read it all.
14
15 use Date::Manip qw(ParseDate UnixDate);
16 use Digest::MD5;
17 $|=1;
18
19 $file=shift||'none';
20 $conf=shift||'/usr/local/dialup_admin/conf/admin.conf';
21 $all_file=shift||'no';
22 #
23 # Uncomment to force inserts even if there are sql errors. That can
24 # help in case there is one sql query which stops the whole failed
25 # logins logging system from working
26 #$force=1;
27 #
28 #
29 # CHANGE THESE TO MATCH YOUR SETUP
30 #
31 #$regexp = 'from client localhost port 135|from client blabla ';
32 $tmpfile='/var/tmp/sql.input';
33 #
34 #
35
36 open CONF, "<$conf"
37         or die "Could not open configuration file\n";
38 while(<CONF>){
39         chomp;
40         ($key,$val)=(split /:\s*/,$_);
41         # Fixme : recursivly solve %{.*} replacement for $val
42         # Fixme: Conf should be put in an associative array
43         $sql_type = $val if ($key eq 'sql_type');
44         $sql_server = $val if ($key eq 'sql_server');
45         $sql_username = $val if ($key eq 'sql_username');
46         $sql_password = $val if ($key eq 'sql_password');
47         $sql_database = $val if ($key eq 'sql_database');
48         $sql_accounting_table = $val if ($key eq 'sql_accounting_table');
49         $realm_strip = $val if ($key eq 'general_strip_realms');
50         $realm_del = $val if ($key eq 'general_realm_delimiter');
51         $realm_for = $val if ($key eq 'general_realm_format');
52         $domain = $val if ($key eq 'general_domain');
53         $sql_timeout = $val if ($key eq 'sql_connect_timeout');
54         $sql_extra = $val if ($key eq 'sql_extra_servers');
55         $sqlcmd = $val if ($key eq 'sql_command');
56         $clients= $val if ($key eq 'general_clients_conf');
57 }
58 close CONF;
59
60 open CLIENTS, "<$clients"
61         or die "Could not open $clients file\n";
62 while(<CLIENTS>){
63         chomp;
64         s/^\s*//g;
65         s/\s*#.*//g;
66         if (!/^\s*$/ && /=/) {
67                 ($key,$val)=(split /\s*=\s*/,$_);
68                 $client_short = $val if ($key eq 'shortname');
69         } else {
70                 if (/\{/) {
71                         s/.*client\s+([^\s]*)\s+\{.*$/\1/;
72                         if (/^\d+\.\d+\.\d+\.\d+/) {
73                                 $client = $_;
74                         } else {
75                                 if (/\./ || /localhost/) {
76                                         $name = $_ ;
77                                 } else {
78                                         $name = $_.".".$domain;
79                                 }
80                                 $addr = gethostbyname $name;
81                                 ($a,$b,$c,$d)=unpack('C4',$addr);
82                                 $client = "$a.$b.$c.$d";
83 #DEBUG#                         print $name." = ".$client."\n";
84                         }
85                 } else {
86                         if (/\}/) {
87                                 $client_array{$client_short} .= $client;
88                         }
89                 }
90         }
91 }
92 close CLIENTS;
93
94 $realm_del = '@' if ($realm_del eq '');
95 $realm_for = 'suffix' if ($realm_for eq '');
96 $pass = ($sql_password ne '') ? "-p$sql_password" : '';
97 die "SQL server not defined\n" if ($sql_server eq '');
98
99 die "sql_command directive is not set in admin.conf\n" if ($sqlcmd eq '');
100 die "Could not find sql binary. Please make sure that the \$sqlcmd variable points to the right location\n" if (! -x $sqlcmd);
101
102 $opt = "";
103 $opt = "-O connect_timeout=$sql_timeout" if ($sql_timeout);
104 $opt .= " -f" if ($force);
105 @servers = (split /\s+/,$sql_extra) if ($sql_extra ne '');
106 unshift @servers, $sql_server;
107
108 open LOG, "<$file"
109         or die "Could not open file $file\n";
110
111 seek LOG, 0, 2 if ($all_file eq 'no');
112 for(;;){
113         while(<LOG>){
114                 $do=0;  
115                 chomp;
116                 next if ($regexp ne '' && !/$regexp/);
117                 if ($_ ne ''){
118                         $user = $nas = $port = $caller = '-';
119                         if (/Login incorrect/){
120                                 if (/Login incorrect \((.+?)\):/){
121                                         $cause = "Login-Incorrect ($1)";
122                                 }else{
123                                         $cause='Login-Incorrect';
124                                 }
125                                 $do=1;
126                         }
127                         elsif (/Invalid user/){
128                                 if (/Invalid user \((.+?)\):/){
129                                         $cause = "Invalid-User ($1)";
130                                 }else{
131                                         $cause='Invalid-User';
132                                 }
133                                 $do=1;
134                         }
135                         elsif (/Multiple logins/){
136                                 if (/MPP attempt/){
137                                         $cause='Multiple-Logins (MPP Attempt)';
138                                 }else{
139                                         $cause='Multiple-Logins';
140                                 }
141                                 $do=1;
142                         }
143                         elsif (/(Outside allowed timespan \(.+?\)):/){
144                                 $cause = "$1";
145                                 $do=1;
146                         }
147                         if ($do){
148                                 $date = (split / : /,$_)[0];
149                                 $date2 = ParseDate($date);
150                                 if ($date2){
151                                         ($year,$mon,$mday,$hour,$min,$sec)=UnixDate($date2,'%Y','%m','%d','%H','%M','%S');
152                                 }
153                                 $time = "$year-$mon-$mday $hour:$min:$sec";
154                                 if (/\[([\w\-\.\!\@\s]+?)\]\s+\(from (.+?)\)/){
155                                         $user = $1;
156                                         ($nas,$port) = (split /\s+/,$2)[1,3];
157                                         if ($2 =~ /cli (.+?)$/){
158                                                 $caller = $1;
159                                         }
160                                 }
161                                 elsif (/\[([\w\-\.\!\@\s]+?)\/.+?\]\s+\(from (.+?)\)/){
162                                         $user = $1;
163                                         ($nas,$port) = (split /\s+/,$2)[1,3];
164                                         if ($2 =~ /cli (.+?)$/){
165                                                 $caller = $1;
166                                         }
167                                 }
168                                 $caller='' if (!defined($caller));
169                                 $user =~s/[^\w\-\.\d\!\@\s]//g;
170                                 $nas =~s/[^\w\.\-]//g;
171                                 $port =~s/[^\d]//g;
172                                 $addr = $client_array{$nas};
173                                 if ($user ne '' && $realm_strip eq 'yes'){
174                                         ($one,$two) = (split /$realm_del/, $user)[0,1];
175                                         if ($two ne ''){
176                                                 $user = ($realm_for eq 'suffix') ? $one : $two;
177                                         }
178                                 }
179                                 foreach $server (@servers){
180                                         unlink "$tmpfile.$server" if ($delete{$server});
181                                         open TMP, ">>$tmpfile.$server"
182                                                 or die "Could not open temporary file\n";
183                                         $ctx = Digest::MD5->new;
184                                         $ctx->add($user);
185                                         $ctx->add($addr);
186                                         $ctx->add($port);
187                                         $ctx->add($time);
188                                         $ctx->add('badlogin');
189                                         $uniqueid = $ctx->hexdigest;
190 #DEBUG#                                 print "INSERT INTO $sql_accounting_table (UserName,AcctUniqueId,NASIPAddress,NASPortId,AcctStartTime,AcctStopTime,AcctSessionTime,AcctInputOctets,AcctOutputOctets,CallingStationId,AcctTerminateCause) VALUES ('$user','$uniqueid','$addr','$port','$time','$time','0','0','0','$caller','$cause');\n";
191                                         print TMP "INSERT INTO $sql_accounting_table (UserName,AcctUniqueId,NASIPAddress,NASPortId,AcctStartTime,AcctStopTime,AcctSessionTime,AcctInputOctets,AcctOutputOctets,CallingStationId,AcctTerminateCause) VALUES ('$user','$uniqueid','$addr','$port','$time','$time','0','0','0','$caller','$cause');\n";
192                                         close TMP;
193                                         $command = "$sqlcmd -h$server $opt -u$sql_username $pass $sql_database <$tmpfile.$server" if ($sql_type eq 'mysql');
194                                         $command = "$sqlcmd  -U $sql_username -f $tmpfile.$server $sql_database" if ($sql_type eq 'pg');
195                                         `$command`;
196
197                                         $exit = $? >> 8;
198                                         $delete{$server} = ($exit == 0) ? 1 : 0;
199                                         print "ERROR: SQL query failed for host $server\n" if ($exit != 0);
200                                 }
201                         }
202                 }
203         }
204         if ($all_file ne 'once') {
205                 sleep 2;
206                 seek LOG,0,1;
207         } else {
208                 exit(0);
209         }
210 }