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