X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2Fpart_export%2Fsqlradius.pm;h=18ee3048828ffe78e48e413a272dd5b10b850b5b;hb=130b7fb03bc8fcc6c6a1b29b36f65d53333ec05a;hp=752bf12a2f9dcac4f67f13012918a3e7196ecaec;hpb=0642c1b5d97d0987491424736054c1abc9d579b1;p=freeside.git diff --git a/FS/FS/part_export/sqlradius.pm b/FS/FS/part_export/sqlradius.pm index 752bf12a2..18ee30488 100644 --- a/FS/FS/part_export/sqlradius.pm +++ b/FS/FS/part_export/sqlradius.pm @@ -110,7 +110,9 @@ END 'desc' => 'Real-time export to SQL-backed RADIUS (FreeRADIUS, ICRADIUS)', 'options' => \%options, 'nodomain' => 'Y', + 'no_machine' => 1, 'nas' => 'Y', # show export_nas selection in UI + 'default_svc_class' => 'Internet', 'notes' => $notes1. 'This export does not export RADIUS realms (see also '. 'sqlradius_withdomain). '. @@ -211,6 +213,7 @@ sub _export_replace { return $error; } } + $jobnum = $err_or_queue->jobnum; # chain all of these dependencies } my @del = grep { !exists $new{$_} } keys %old; @@ -228,6 +231,7 @@ sub _export_replace { return $error; } } + $jobnum = $err_or_queue->jobnum; # chain all of these dependencies } } @@ -250,6 +254,7 @@ sub _export_replace { ''; } +#false laziness w/broadband_sqlradius.pm sub _export_suspend { my( $self, $svc_acct ) = (shift, shift); @@ -297,7 +302,7 @@ sub _export_suspend { } sub _export_unsuspend { - my( $self, $svc_acct ) = (shift, shift); + my( $self, $svc_x ) = (shift, shift); local $SIG{HUP} = 'IGNORE'; local $SIG{INT} = 'IGNORE'; @@ -310,21 +315,21 @@ sub _export_unsuspend { local $FS::UID::AutoCommit = 0; my $dbh = dbh; - my $err_or_queue = $self->sqlradius_queue( $svc_acct->svcnum, 'insert', - 'check', $self->export_username($svc_acct), $svc_acct->radius_check ); + my $err_or_queue = $self->sqlradius_queue( $svc_x->svcnum, 'insert', + 'check', $self->export_username($svc_x), $self->radius_check($svc_x) ); unless ( ref($err_or_queue) ) { $dbh->rollback if $oldAutoCommit; return $err_or_queue; } my $error; - my (@oldgroups) = $self->suspended_usergroups($svc_acct); + my (@oldgroups) = $self->suspended_usergroups($svc_x); $error = $self->sqlreplace_usergroups( - $svc_acct->svcnum, - $self->export_username($svc_acct), + $svc_x->svcnum, + $self->export_username($svc_x), '', \@oldgroups, - [ $svc_acct->radius_groups('hashref') ], + [ $svc_x->radius_groups('hashref') ], ); if ( $error ) { $dbh->rollback if $oldAutoCommit; @@ -345,6 +350,7 @@ sub _export_delete { sub sqlradius_queue { my( $self, $svcnum, $method ) = (shift, shift, shift); + #my %args = @_; my $queue = new FS::queue { 'svcnum' => $svcnum, 'job' => "FS::part_export::sqlradius::sqlradius_$method", @@ -358,14 +364,16 @@ sub sqlradius_queue { } sub suspended_usergroups { - my ($self, $svc_acct) = (shift, shift); + my ($self, $svc_x) = (shift, shift); - return () unless $svc_acct; + return () unless $svc_x; + + my $svc_table = $svc_x->table; #false laziness with FS::part_export::shellcommands #subclass part_export? - my $r = $svc_acct->cust_svc->cust_pkg->last_reason('susp'); + my $r = $svc_x->cust_svc->cust_pkg->last_reason('susp'); my %reasonmap = $self->_groups_susp_reason_map; my $userspec = ''; if ($r) { @@ -374,19 +382,19 @@ sub suspended_usergroups { $userspec = $reasonmap{$r->reason} if (!$userspec && exists($reasonmap{$r->reason})); } - my $suspend_user; - if ($userspec =~ /^\d+$/ ){ - $suspend_user = qsearchs( 'svc_acct', { 'svcnum' => $userspec } ); - }elsif ($userspec =~ /^\S+\@\S+$/){ + my $suspend_svc; + if ( $userspec =~ /^\d+$/ ){ + $suspend_svc = qsearchs( $svc_table, { 'svcnum' => $userspec } ); + } elsif ( $userspec =~ /^\S+\@\S+$/ && $svc_table eq 'svc_acct' ){ my ($username,$domain) = split(/\@/, $userspec); for my $user (qsearch( 'svc_acct', { 'username' => $username } )){ - $suspend_user = $user if $userspec eq $user->email; + $suspend_svc = $user if $userspec eq $user->email; } - }elsif ($userspec){ - $suspend_user = qsearchs( 'svc_acct', { 'username' => $userspec } ); + }elsif ( $userspec && $svc_table eq 'svc_acct' ){ + $suspend_svc = qsearchs( 'svc_acct', { 'username' => $userspec } ); } #esalf - return $suspend_user->radius_groups('hashref') if $suspend_user; + return $suspend_svc->radius_groups('hashref') if $suspend_svc; (); } @@ -555,6 +563,7 @@ sub sqlreplace_usergroups { my $error = $err_or_queue->depend_insert( $jobnum ); return $error if $error; } + $jobnum = $err_or_queue->jobnum; # chain all of these dependencies } if ( @newgroups ) { @@ -718,17 +727,21 @@ sub usage_sessions { push @where, " CalledStationID LIKE 'sip:$prefix\%'"; } - if ( $start ) { - push @where, "$str2time AcctStopTime ) >= ?"; - push @param, $start; - } - if ( $end ) { - push @where, "$str2time AcctStopTime ) <= ?"; - push @param, $end; - } if ( $opt->{open_sessions} ) { push @where, 'AcctStopTime IS NULL'; + } else { + + if ( $start ) { + push @where, "$str2time AcctStopTime ) >= ?"; + push @param, $start; + } + if ( $end ) { + push @where, "$str2time AcctStopTime ) <= ?"; + push @param, $end; + } + } + if ( $opt->{starttime_start} ) { push @where, "$str2time AcctStartTime ) >= ?"; push @param, $opt->{starttime_start}; @@ -747,16 +760,20 @@ sub usage_sessions { my $orderby = 'ORDER BY AcctStartTime DESC'; $orderby = '' if $summarize; - my $sth = $dbh->prepare('SELECT '. join(', ', @fields). - " FROM radacct $where $groupby $orderby - ") or die $dbh->errstr; - $sth->execute(@param) or die $sth->errstr; + my $sql = 'SELECT '. join(', ', @fields). + " FROM radacct $where $groupby $orderby"; + if ( $DEBUG ) { + warn $sql; + warn join(',', @param); + } + my $sth = $dbh->prepare($sql) or die $dbh->errstr; + $sth->execute(@param) or die $sth->errstr; [ map { { %$_ } } @{ $sth->fetchall_arrayref({}) } ]; } -=item update_svc_acct +=item update_svc =cut @@ -962,8 +979,7 @@ are identified by the combination of group name and attribute name. In the special case where attributes are being replaced because a group name (L->groupname) is changing, the pseudo-field -'groupname' must be set in OLD_RADIUS_ATTR. It's probably best to do this - +'groupname' must be set in OLD_RADIUS_ATTR. =cut @@ -978,41 +994,43 @@ sub export_attr_replace { shift->export_attr_action('replace', @_); } sub export_attr_action { my $self = shift; my ($action, $new, $old) = @_; - my ($attrname, $attrtype, $groupname) = - ($new->attrname, $new->attrtype, $new->radius_group->groupname); - if ( $action eq 'replace' ) { - - if ( $new->attrtype ne $old->attrtype ) { - # they're in separate tables in the target - return $self->export_attr_action('delete', $old) - || $self->export_attr_action('insert', $new) - ; - } + my $err_or_queue; - # otherwise, just make sure we know the old attribute/group names - # so we can find the existing record - $attrname = $old->attrname; - $groupname = $old->groupname || $old->radius_group->groupname; - # maybe this should be enforced more strictly - warn "WARNING: attribute replace without 'groupname' set; assuming '$groupname'\n" - if !defined($old->groupname); + if ( $action eq 'delete' ) { + $old = $new; + } + if ( $action eq 'delete' or $action eq 'replace' ) { + # delete based on an exact match + my %opt = ( + attrname => $old->attrname, + attrtype => $old->attrtype, + groupname => $old->groupname || $old->radius_group->groupname, + op => $old->op, + value => $old->value, + ); + $err_or_queue = $self->sqlradius_queue('', 'attr_delete', %opt); + return $err_or_queue unless ref $err_or_queue; + } + # this probably doesn't matter, but just to be safe... + my $jobnum = $err_or_queue->jobnum if $action eq 'replace'; + if ( $action eq 'replace' or $action eq 'insert' ) { + my %opt = ( + attrname => $new->attrname, + attrtype => $new->attrtype, + groupname => $new->radius_group->groupname, + op => $new->op, + value => $new->value, + ); + $err_or_queue = $self->sqlradius_queue('', 'attr_insert', %opt); + $err_or_queue->depend_insert($jobnum) if $jobnum; + return $err_or_queue unless ref $err_or_queue; } - - my $err_or_queue = $self->sqlradius_queue('', "attr_$action", - attrnum => $new->attrnum, - attrname => $attrname, - attrtype => $attrtype, - groupname => $groupname, - ); - return $err_or_queue unless ref $err_or_queue; ''; } sub sqlradius_attr_insert { my $dbh = sqlradius_connect(shift, shift, shift); my %opt = @_; - my $radius_attr = qsearchs('radius_attr', { attrnum => $opt{'attrnum'} }) - or die 'attrnum '.$opt{'attrnum'}.' not found'; my $table; # make sure $table is completely safe @@ -1023,12 +1041,10 @@ sub sqlradius_attr_insert { $table = 'radgroupreply'; } else { - die "unknown attribute type '".$radius_attr->attrtype."'"; + die "unknown attribute type '$opt{attrtype}'"; } - my @values = ( - $opt{'groupname'}, map { $radius_attr->$_ } qw(attrname op value) - ); + my @values = @opt{ qw(groupname attrname op value) }; my $sth = $dbh->prepare( 'INSERT INTO '.$table.' (groupname, attribute, op, value) VALUES (?,?,?,?)' ); @@ -1050,41 +1066,16 @@ sub sqlradius_attr_delete { die "unknown attribute type '".$opt{'attrtype'}."'"; } + my @values = @opt{ qw(groupname attrname op value) }; my $sth = $dbh->prepare( - 'DELETE FROM '.$table.' WHERE groupname = ? AND attribute = ?' + 'DELETE FROM '.$table. + ' WHERE groupname = ? AND attribute = ? AND op = ? AND value = ?'. + ' LIMIT 1' ); - $sth->execute( @opt{'groupname', 'attrname'} ) or die $dbh->errstr; + $sth->execute(@values) or die $dbh->errstr; } -sub sqlradius_attr_replace { - my $dbh = sqlradius_connect(shift, shift, shift); - my %opt = @_; - my $radius_attr = qsearchs('radius_attr', { attrnum => $opt{'attrnum'} }) - or die 'attrnum '.$opt{'attrnum'}.' not found'; - - my $table; - if ( $opt{'attrtype'} eq 'C' ) { - $table = 'radgroupcheck'; - } - elsif ( $opt{'attrtype'} eq 'R' ) { - $table = 'radgroupreply'; - } - else { - die "unknown attribute type '".$opt{'attrtype'}."'"; - } - - my $sth = $dbh->prepare( - 'UPDATE '.$table.' SET groupname = ?, attribute = ?, op = ?, value = ? - WHERE groupname = ? AND attribute = ?' - ); - - my $new_groupname = $radius_attr->radius_group->groupname; - my @new_values = ( - $new_groupname, map { $radius_attr->$_ } qw(attrname op value) - ); - $sth->execute( @new_values, @opt{'groupname', 'attrname'} ) - or die $dbh->errstr; -} +#sub sqlradius_attr_replace { no longer needed =item export_group_replace NEW OLD @@ -1154,8 +1145,13 @@ sub _upgrade_exporttype { sub import_attrs { my $self = shift; - my $dbh = sqlradius_connect( map $self->option($_), + my $dbh = DBI->connect( map $self->option($_), qw( datasrc username password ) ); + unless ( $dbh ) { + warn "Error connecting to RADIUS server: $DBI::errstr\n"; + return; + } + my $usergroup = $self->option('usergroup') || 'usergroup'; my $error; warn "Importing RADIUS groups and attributes from ".$self->option('datasrc'). @@ -1176,6 +1172,7 @@ sub import_attrs { SELECT groupname, attribute, op, value, \'C\' FROM radgroupcheck UNION SELECT groupname, attribute, op, value, \'R\' FROM radgroupreply'; + my @fixes; # things that need to be changed on the radius db foreach my $row ( @{ $dbh->selectall_arrayref($sql) } ) { my ($groupname, $attrname, $op, $value, $attrtype) = @$row; warn "$groupname.$attrname\n"; @@ -1185,7 +1182,10 @@ SELECT groupname, attribute, op, value, \'R\' FROM radgroupreply'; 'priority' => 1, }; $error = $radius_group->insert; - return "error inserting group $groupname: $error" if $error; + if ( $error ) { + warn "error inserting group $groupname: $error"; + next;#don't continue trying to insert the attribute + } $attrs_of{$groupname} = {}; $groupnum_of{$groupname} = $radius_group->groupnum; } @@ -1194,6 +1194,20 @@ SELECT groupname, attribute, op, value, \'R\' FROM radgroupreply'; my $old = $a->{$attrname}; my $new; + if ( $attrtype eq 'R' ) { + # Freeradius tolerates illegal operators in reply attributes. We don't. + if ( !grep ($_ eq $op, FS::radius_attr->ops('R')) ) { + warn "$groupname.$attrname: changing $op to +=\n"; + # Make a note to change it in the db + push @fixes, [ + 'UPDATE radgroupreply SET op = \'+=\' WHERE groupname = ? AND attribute = ? AND op = ? AND VALUE = ?', + $groupname, $attrname, $op, $value + ]; + # and import it correctly. + $op = '+='; + } + } + if ( defined $old ) { # replace $new = new FS::radius_attr { @@ -1202,7 +1216,10 @@ SELECT groupname, attribute, op, value, \'R\' FROM radgroupreply'; 'value' => $value, }; $error = $new->replace($old); - return "error modifying attr $attrname: $error" if $error; + if ( $error ) { + warn "error modifying attr $attrname: $error"; + next; + } } else { $new = new FS::radius_attr { @@ -1213,10 +1230,20 @@ SELECT groupname, attribute, op, value, \'R\' FROM radgroupreply'; 'value' => $value, }; $error = $new->insert; - return "error inserting attr $attrname: $error" if $error; + if ( $error ) { + warn "error inserting attr $attrname: $error" if $error; + next; + } } $attrs_of{$groupname}->{$attrname} = $new; } #foreach $row + + foreach (@fixes) { + my ($sql, @args) = @$_; + my $sth = $dbh->prepare($sql); + $sth->execute(@args) or warn $sth->errstr; + } + return; }