X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2Fpart_export%2Fsqlradius.pm;h=fd5bb89fd4d05cdddb7c3cc9dca756e105879aae;hb=04c0875f27d36309b6d8da8063a9254fef3a7398;hp=51a828001aea7500da87f3c6eee1c0173efd6895;hpb=eb7c552dd8290d6b33a4e026c5dc21ebf01105cf;p=freeside.git
diff --git a/FS/FS/part_export/sqlradius.pm b/FS/FS/part_export/sqlradius.pm
index 51a828001..fd5bb89fd 100644
--- a/FS/FS/part_export/sqlradius.pm
+++ b/FS/FS/part_export/sqlradius.pm
@@ -1,28 +1,87 @@
package FS::part_export::sqlradius;
-use vars qw(@ISA);
+use vars qw(@ISA %info %options $notes1 $notes2);
+use Tie::IxHash;
+use FS::Record qw( dbh );
use FS::part_export;
@ISA = qw(FS::part_export);
+tie %options, 'Tie::IxHash',
+ 'datasrc' => { label=>'DBI data source ' },
+ 'username' => { label=>'Database username' },
+ 'password' => { label=>'Database password' },
+ 'ignore_accounting' => {
+ type => 'checkbox',
+ label=>'Ignore accounting records from this database'
+ },
+;
+
+$notes1 = <<'END';
+Real-time export of radcheck, radreply and usergroup tables to any SQL database
+for FreeRADIUS,
+ICRADIUS
+or Radiator.
+END
+
+$notes2 = <<'END';
+An existing RADIUS database will be updated in realtime, but you can use
+freeside-sqlradius-reset
+to delete the entire RADIUS database and repopulate the tables from the
+Freeside database. See the
+DBI documentation
+and the
+documentation for your DBD
+for the exact syntax of a DBI data source.
+
+ - Using FreeRADIUS 0.9.0 with the PostgreSQL backend, the db_postgresql.sql schema and postgresql.conf queries contain incompatible changes. This is fixed in 0.9.1. Only new installs with 0.9.0 and PostgreSQL are affected - upgrades and other database backends and versions are unaffected.
+
- Using ICRADIUS, add a dummy "op" column to your database:
+
+ ALTER TABLE radcheck ADD COLUMN op VARCHAR(2) NOT NULL DEFAULT '=='
+ ALTER TABLE radreply ADD COLUMN op VARCHAR(2) NOT NULL DEFAULT '=='
+ ALTER TABLE radgroupcheck ADD COLUMN op VARCHAR(2) NOT NULL DEFAULT '=='
+ ALTER TABLE radgroupreply ADD COLUMN op VARCHAR(2) NOT NULL DEFAULT '=='
+
+ - Using Radiator, see the
+ Radiator FAQ
+ for configuration information.
+
+END
+
+%info = (
+ 'svc' => 'svc_acct',
+ 'desc' => 'Real-time export to SQL-backed RADIUS (FreeRADIUS, ICRADIUS, Radiator)',
+ 'options' => \%options,
+ 'nodomain' => 'Y',
+ 'notes' => $notes1.
+ 'This export does not export RADIUS realms (see also '.
+ 'sqlradius_withdomain). '.
+ $notes2
+);
+
sub rebless { shift; }
+sub export_username {
+ my($self, $svc_acct) = (shift, shift);
+ $svc_acct->username;
+}
+
sub _export_insert {
my($self, $svc_acct) = (shift, shift);
foreach my $table (qw(reply check)) {
my $method = "radius_$table";
- my %attrib = $svc_acct->$method;
+ my %attrib = $svc_acct->$method();
next unless keys %attrib;
my $err_or_queue = $self->sqlradius_queue( $svc_acct->svcnum, 'insert',
- $table, $svc_acct->username, %attrib );
+ $table, $self->export_username($svc_acct), %attrib );
return $err_or_queue unless ref($err_or_queue);
}
my @groups = $svc_acct->radius_groups;
if ( @groups ) {
my $err_or_queue = $self->sqlradius_queue(
$svc_acct->svcnum, 'usergroup_insert',
- $svc_acct->username, @groups );
+ $self->export_username($svc_acct), @groups );
return $err_or_queue unless ref($err_or_queue);
}
'';
@@ -31,32 +90,66 @@ sub _export_insert {
sub _export_replace {
my( $self, $new, $old ) = (shift, shift, shift);
- #return "can't (yet) change username with sqlradius"
- # if $old->username ne $new->username;
- if ( $old->username ne $new->username ) {
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ my $oldAutoCommit = $FS::UID::AutoCommit;
+ local $FS::UID::AutoCommit = 0;
+ my $dbh = dbh;
+
+ my $jobnum = '';
+ if ( $self->export_username($old) ne $self->export_username($new) ) {
my $err_or_queue = $self->sqlradius_queue( $new->svcnum, 'rename',
- $new->username, $old->username );
- return $err_or_queue unless ref($err_or_queue);
+ $self->export_username($new), $self->export_username($old) );
+ unless ( ref($err_or_queue) ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $err_or_queue;
+ }
+ $jobnum = $err_or_queue->jobnum;
}
foreach my $table (qw(reply check)) {
my $method = "radius_$table";
- my %new = $new->$method;
- my %old = $old->$method;
+ my %new = $new->$method();
+ my %old = $old->$method();
if ( grep { !exists $old{$_} #new attributes
|| $new{$_} ne $old{$_} #changed
} keys %new
) {
my $err_or_queue = $self->sqlradius_queue( $new->svcnum, 'insert',
- $table, $new->username, %new );
- return $err_or_queue unless ref($err_or_queue);
+ $table, $self->export_username($new), %new );
+ unless ( ref($err_or_queue) ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $err_or_queue;
+ }
+ if ( $jobnum ) {
+ my $error = $err_or_queue->depend_insert( $jobnum );
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
}
my @del = grep { !exists $new{$_} } keys %old;
if ( @del ) {
my $err_or_queue = $self->sqlradius_queue( $new->svcnum, 'attrib_delete',
- $table, $new->username, @del );
- return $err_or_queue unless ref($err_or_queue);
+ $table, $self->export_username($new), @del );
+ unless ( ref($err_or_queue) ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $err_or_queue;
+ }
+ if ( $jobnum ) {
+ my $error = $err_or_queue->depend_insert( $jobnum );
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
}
}
@@ -74,23 +167,45 @@ sub _export_replace {
if ( @delgroups ) {
my $err_or_queue = $self->sqlradius_queue( $new->svcnum, 'usergroup_delete',
- $new->username, @delgroups );
- return $err_or_queue unless ref($err_or_queue);
+ $self->export_username($new), @delgroups );
+ unless ( ref($err_or_queue) ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $err_or_queue;
+ }
+ if ( $jobnum ) {
+ my $error = $err_or_queue->depend_insert( $jobnum );
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
}
if ( @newgroups ) {
my $err_or_queue = $self->sqlradius_queue( $new->svcnum, 'usergroup_insert',
- $new->username, @newgroups );
- return $err_or_queue unless ref($err_or_queue);
+ $self->export_username($new), @newgroups );
+ unless ( ref($err_or_queue) ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $err_or_queue;
+ }
+ if ( $jobnum ) {
+ my $error = $err_or_queue->depend_insert( $jobnum );
+ if ( $error ) {
+ $dbh->rollback if $oldAutoCommit;
+ return $error;
+ }
+ }
}
+ $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+
'';
}
sub _export_delete {
my( $self, $svc_acct ) = (shift, shift);
my $err_or_queue = $self->sqlradius_queue( $svc_acct->svcnum, 'delete',
- $svc_acct->username );
+ $self->export_username($svc_acct) );
ref($err_or_queue) ? '' : $err_or_queue;
}
@@ -130,11 +245,15 @@ sub sqlradius_insert { #subroutine, not method
} else {
my $i_sth = $dbh->prepare(
- "INSERT INTO rad$table ( id, UserName, Attribute, Value ) ".
+ "INSERT INTO rad$table ( UserName, Attribute, op, Value ) ".
"VALUES ( ?, ?, ?, ? )"
) or die $dbh->errstr;
- $i_sth->execute( '', $username, $attribute, $attributes{$attribute} )
- or die $i_sth->errstr;
+ $i_sth->execute(
+ $username,
+ $attribute,
+ ( $attribute =~ /Password/i ? '==' : ':=' ),
+ $attributes{$attribute},
+ ) or die $i_sth->errstr;
}
@@ -147,10 +266,10 @@ sub sqlradius_usergroup_insert { #subroutine, not method
my( $username, @groups ) = @_;
my $sth = $dbh->prepare(
- "INSERT INTO usergroup ( id, UserName, GroupName ) VALUES ( ?, ?, ? )"
+ "INSERT INTO usergroup ( UserName, GroupName ) VALUES ( ?, ? )"
) or die $dbh->errstr;
foreach my $group ( @groups ) {
- $sth->execute( '', $username, $group )
+ $sth->execute( $username, $group )
or die "can't insert into groupname table: ". $sth->errstr;
}
$dbh->disconnect;
@@ -214,3 +333,5 @@ sub sqlradius_connect {
DBI->connect(@_) or die $DBI::errstr;
}
+1;
+