5806362b52c559780bd2a540207417c19b92a2d1
[freeside.git] / FS / FS / part_export / broadband_sqlradius.pm
1 package FS::part_export::broadband_sqlradius;
2
3 use strict;
4 use vars qw($DEBUG @ISA @pw_set %options %info $conf);
5 use Tie::IxHash;
6 use FS::Conf;
7 use FS::Record qw( dbh str2time_sql ); #qsearch qsearchs );
8 use FS::part_export::sqlradius qw(sqlradius_connect);
9
10 FS::UID->install_callback(sub { $conf = new FS::Conf });
11
12 @ISA = qw(FS::part_export::sqlradius);
13
14 $DEBUG = 0;
15
16 @pw_set = ( 'a'..'z', 'A'..'Z', '0'..'9', '(', ')', '#', '.', ',' );
17
18 tie %options, 'Tie::IxHash',
19   'datasrc'  => { label=>'DBI data source ' },
20   'username' => { label=>'Database username' },
21   'password' => { label=>'Database password' },
22   'usergroup'=> { label   => 'Group table',
23                   type    => 'select',
24                   options => [qw( radusergroup usergroup )],
25                 },
26 # session report doesn't currently know about this export anyway
27 #  'hide_ip' => {
28 #    type  => 'checkbox',
29 #    label => 'Hide IP address on session reports',
30 #  },
31   'mac_case' => {
32     label => 'Export MAC address as',
33     type  => 'select',
34     options => [ qw(uppercase lowercase) ],
35   },
36   'mac_delimiter' => {
37     label => 'Separate MAC address octets with',
38     default => '-',
39   },
40   'mac_as_password' => { 
41     type => 'checkbox',
42     default => '1',
43     label => 'Use MAC address as password',
44   },
45   'radius_password' => { label=>'Fixed password' },
46   'ip_addr_as' => { label => 'Send IP address as',
47                     default => 'Framed-IP-Address' },
48   'export_attrs' => { 
49     type => 'checkbox', 
50     label => 'Export RADIUS group attributes to this database', 
51   },
52   ;
53
54 %info = (
55   'svc'      => 'svc_broadband',
56   'desc'     => 'Real-time export to SQL-backed RADIUS (such as FreeRadius) for broadband services',
57   'options'  => \%options,
58   'nas'      => 'Y',
59   'notes'    => <<END,
60 Real-time export of <b>radcheck</b>, <b>radreply</b>, and <b>usergroup</b> 
61 tables to any SQL database for 
62 <a href="http://www.freeradius.org/">FreeRADIUS</a>
63 or <a href="http://radius.innercite.com/">ICRADIUS</a>.
64 <br><br>
65
66 This export is for broadband service access control based on MAC address.  
67 For a more typical RADIUS export, see sqlradius.
68 <br><br>
69
70 See the
71 <a href="http://search.cpan.org/dist/DBI/DBI.pm#connect">DBI documentation</a>
72 and the
73 <a href="http://search.cpan.org/search?mode=module&query=DBD%3A%3A">documentation for your DBD</a>
74 for the exact syntax of a DBI data source.
75
76 END
77 );
78
79 sub rebless { shift; }
80
81 sub export_username {
82   my($self, $svc_broadband) = (shift, shift);
83   $svc_broadband->mac_addr_formatted(
84     $self->option('mac_case'), $self->option('mac_delimiter')
85   );
86 }
87
88 sub radius_reply {
89   my($self, $svc_broadband) = (shift, shift);
90   my %reply;
91   if (  length($self->option('ip_addr_as',1)) 
92     and length($svc_broadband->ip_addr) ) {
93     $reply{$self->option('ip_addr_as')} = $svc_broadband->ip_addr;
94   }
95   %reply;
96 }
97
98 sub radius_check {
99   my($self, $svc_broadband) = (shift, shift);
100   my $password_attrib = $conf->config('radius-password') || 'Password';
101   my %check;
102   if ( $self->option('mac_as_password') ) {
103     $check{$password_attrib} = $self->export_username($svc_broadband);
104   }
105   elsif ( length( $self->option('radius_password',1)) ) {
106     $check{$password_attrib} = $self->option('radius_password');
107   }
108   %check;
109 }
110
111 sub radius_check_suspended {
112   my($self, $svc_broadband) = (shift, shift);
113
114   return () unless $self->option('mac_as_password')
115                 || length( $self->option('radius_password',1));
116
117   my $password_attrib = $conf->config('radius-password') || 'Password';
118   (
119     $password_attrib => join('',map($pw_set[ int(rand $#pw_set) ], (0..7) ) )
120   );
121 }
122
123 #false laziness w/sqlradius.pm
124 sub _export_suspend {
125   my( $self, $svc_broadband ) = (shift, shift);
126
127   local $SIG{HUP} = 'IGNORE';
128   local $SIG{INT} = 'IGNORE';
129   local $SIG{QUIT} = 'IGNORE';
130   local $SIG{TERM} = 'IGNORE';
131   local $SIG{TSTP} = 'IGNORE';
132   local $SIG{PIPE} = 'IGNORE';
133
134   my $oldAutoCommit = $FS::UID::AutoCommit;
135   local $FS::UID::AutoCommit = 0;
136   my $dbh = dbh;
137
138   my @newgroups = $self->suspended_usergroups($svc_broadband);
139
140   unless (@newgroups) { #don't change password if assigning to a suspended group
141
142     my $err_or_queue = $self->sqlradius_queue(
143        $svc_broadband->svcnum, 'insert',
144       'check', $self->export_username($svc_broadband),
145       $self->radius_check_suspended($svc_broadband)
146     );
147     unless ( ref($err_or_queue) ) {
148       $dbh->rollback if $oldAutoCommit;
149       return $err_or_queue;
150     }
151
152   }
153
154   my $error =
155     $self->sqlreplace_usergroups(
156       $svc_broadband->svcnum,
157       $self->export_username($svc_broadband),
158       '',
159       [ $svc_broadband->radius_groups('hashref') ],
160       \@newgroups,
161     );
162   if ( $error ) {
163     $dbh->rollback if $oldAutoCommit;
164     return $error;
165   }
166   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
167
168   '';
169 }
170
171 sub update_svc {} #do nothing
172
173 1;
174