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