export host selection per service, RT#17914
[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   'no_machine' => 1,
59   'nas'      => 'Y',
60   'notes'    => <<END,
61 Real-time export of <b>radcheck</b>, <b>radreply</b>, and <b>usergroup</b> 
62 tables to any SQL database for 
63 <a href="http://www.freeradius.org/">FreeRADIUS</a>
64 or <a href="http://radius.innercite.com/">ICRADIUS</a>.
65 <br><br>
66
67 This export is for broadband service access control based on MAC address.  
68 For a more typical RADIUS export, see sqlradius.
69 <br><br>
70
71 See the
72 <a href="http://search.cpan.org/dist/DBI/DBI.pm#connect">DBI documentation</a>
73 and the
74 <a href="http://search.cpan.org/search?mode=module&query=DBD%3A%3A">documentation for your DBD</a>
75 for the exact syntax of a DBI data source.
76
77 END
78 );
79
80 sub rebless { shift; }
81
82 sub export_username {
83   my($self, $svc_broadband) = (shift, shift);
84   $svc_broadband->mac_addr_formatted(
85     $self->option('mac_case'), $self->option('mac_delimiter')
86   );
87 }
88
89 sub radius_reply {
90   my($self, $svc_broadband) = (shift, shift);
91   my %reply;
92   if (  length($self->option('ip_addr_as',1)) 
93     and length($svc_broadband->ip_addr) ) {
94     $reply{$self->option('ip_addr_as')} = $svc_broadband->ip_addr;
95   }
96   %reply;
97 }
98
99 sub radius_check {
100   my($self, $svc_broadband) = (shift, shift);
101   my $password_attrib = $conf->config('radius-password') || 'Password';
102   my %check;
103   if ( $self->option('mac_as_password') ) {
104     $check{$password_attrib} = $self->export_username($svc_broadband);
105   }
106   elsif ( length( $self->option('radius_password',1)) ) {
107     $check{$password_attrib} = $self->option('radius_password');
108   }
109   %check;
110 }
111
112 sub radius_check_suspended {
113   my($self, $svc_broadband) = (shift, shift);
114
115   return () unless $self->option('mac_as_password')
116                 || length( $self->option('radius_password',1));
117
118   my $password_attrib = $conf->config('radius-password') || 'Password';
119   (
120     $password_attrib => join('',map($pw_set[ int(rand $#pw_set) ], (0..7) ) )
121   );
122 }
123
124 #false laziness w/sqlradius.pm
125 sub _export_suspend {
126   my( $self, $svc_broadband ) = (shift, shift);
127
128   local $SIG{HUP} = 'IGNORE';
129   local $SIG{INT} = 'IGNORE';
130   local $SIG{QUIT} = 'IGNORE';
131   local $SIG{TERM} = 'IGNORE';
132   local $SIG{TSTP} = 'IGNORE';
133   local $SIG{PIPE} = 'IGNORE';
134
135   my $oldAutoCommit = $FS::UID::AutoCommit;
136   local $FS::UID::AutoCommit = 0;
137   my $dbh = dbh;
138
139   my @newgroups = $self->suspended_usergroups($svc_broadband);
140
141   unless (@newgroups) { #don't change password if assigning to a suspended group
142
143     my $err_or_queue = $self->sqlradius_queue(
144        $svc_broadband->svcnum, 'insert',
145       'check', $self->export_username($svc_broadband),
146       $self->radius_check_suspended($svc_broadband)
147     );
148     unless ( ref($err_or_queue) ) {
149       $dbh->rollback if $oldAutoCommit;
150       return $err_or_queue;
151     }
152
153   }
154
155   my $error =
156     $self->sqlreplace_usergroups(
157       $svc_broadband->svcnum,
158       $self->export_username($svc_broadband),
159       '',
160       [ $svc_broadband->radius_groups('hashref') ],
161       \@newgroups,
162     );
163   if ( $error ) {
164     $dbh->rollback if $oldAutoCommit;
165     return $error;
166   }
167   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
168
169   '';
170 }
171
172 sub update_svc {} #do nothing
173
174 1;
175