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