X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2Fpart_export%2Ftextradius.pm;h=07de875638f4107570ff6a78b10bf2459890d965;hb=2aa7cfda6c3936e1850d845e25ed88cf0a09330f;hp=9a0468f6ddea7661540df0540fd4c76fff835f4d;hpb=9554f2be960fdb511a4c9d8b519261614319f0aa;p=freeside.git
diff --git a/FS/FS/part_export/textradius.pm b/FS/FS/part_export/textradius.pm
index 9a0468f6d..07de87563 100644
--- a/FS/FS/part_export/textradius.pm
+++ b/FS/FS/part_export/textradius.pm
@@ -1,33 +1,61 @@
package FS::part_export::textradius;
-use vars qw(@ISA);
+use vars qw(@ISA %info $prefix);
+use Fcntl qw(:flock);
+use Tie::IxHash;
+use FS::UID qw(datasrc);
use FS::part_export;
@ISA = qw(FS::part_export);
+tie my %options, 'Tie::IxHash',
+ 'user' => { label=>'Remote username', default=>'root' },
+ 'users' => { label=>'users file location', default=>'/etc/raddb/users' },
+;
+
+%info = (
+ 'svc' => 'svc_acct',
+ 'desc' =>
+ 'Real-time export to a text /etc/raddb/users file (Livingston, Cistron)',
+ 'options' => \%options,
+ 'default_svc_class' => 'Internet',
+ 'notes' => <<'END'
+This will edit a text RADIUS users file in place on a remote server.
+Requires installation of
+RADIUS::UserFile
+from CPAN. If using RADIUS::UserFile 1.01, make sure to apply
+this patch. Also
+make sure rsync is installed on the
+remote machine, and SSH is setup for unattended
+operation.
+END
+);
+
+$prefix = "%%%FREESIDE_CONF%%%/export.";
+
sub rebless { shift; }
sub _export_insert {
my($self, $svc_acct) = (shift, shift);
$err_or_queue = $self->textradius_queue( $svc_acct->svcnum, 'insert',
- $svc_acct->username, $svc_acct->_password );
+ $svc_acct->username, $svc_acct->radius_check, '-', $svc_acct->radius_reply);
ref($err_or_queue) ? '' : $err_or_queue;
}
sub _export_replace {
my( $self, $new, $old ) = (shift, shift, shift);
- #return "can't change username with textradius"
- # if $old->username ne $new->username;
+ return "can't (yet?) change username with textradius"
+ if $old->username ne $new->username;
#return '' unless $old->_password ne $new->_password;
- $err_or_queue = $self->textradius_queue( $new->svcnum,
- 'replace', $new->username, $new->_password );
+ $err_or_queue = $self->textradius_queue( $new->svcnum, 'insert',
+ $new->username, $new->radius_check, '-', $new->radius_reply);
ref($err_or_queue) ? '' : $err_or_queue;
}
sub _export_delete {
my( $self, $svc_acct ) = (shift, shift);
- $err_or_queue = $self->textradius_queue( $svc_acct->svcnum,
- 'delete', $svc_acct->username );
+ $err_or_queue = $self->textradius_queue( $svc_acct->svcnum, 'delete',
+ $svc_acct->username );
ref($err_or_queue) ? '' : $err_or_queue;
}
@@ -38,13 +66,127 @@ sub textradius_queue {
'svcnum' => $svcnum,
'job' => "FS::part_export::textradius::textradius_$method",
};
- $queue->insert( @_ ) or $queue;
+ $queue->insert(
+ $self->option('user')||'root',
+ $self->machine,
+ $self->option('users'),
+ @_,
+ ) or $queue;
}
sub textradius_insert { #subroutine, not method
+ my( $user, $host, $users, $username, @attributes ) = @_;
+
+ #silly arg processing
+ my($att, @check);
+ push @check, $att while @attributes && ($att=shift @attributes) ne '-';
+ my %check = @check;
+ my %reply = @attributes;
+
+ my $file = textradius_download($user, $host, $users);
+
+ eval "use RADIUS::UserFile;";
+ die $@ if $@;
+
+ my $userfile = new RADIUS::UserFile(
+ File => $file,
+ Who => [ $username ],
+ Check_Items => [ keys %check ],
+ ) or die "error parsing $file";
+
+ $userfile->remove($username);
+ $userfile->add(
+ Who => $username,
+ Attributes => { %check, %reply },
+ Comment => 'user added by Freeside',
+ ) or die "error adding to $file";
+
+ $userfile->update( Who => [ $username ] )
+ or die "error updating $file";
+
+ textradius_upload($user, $host, $users);
+
}
-sub textradius_replace { #subroutine, not method
-}
+
sub textradius_delete { #subroutine, not method
+ my( $user, $host, $users, $username ) = @_;
+
+ my $file = textradius_download($user, $host, $users);
+
+ eval "use RADIUS::UserFile;";
+ die $@ if $@;
+
+ my $userfile = new RADIUS::UserFile(
+ File => $file,
+ Who => [ $username ],
+ ) or die "error parsing $file";
+
+ $userfile->remove($username);
+
+ $userfile->update( Who => [ $username ] )
+ or die "error updating $file";
+
+ textradius_upload($user, $host, $users);
}
+sub textradius_download {
+ my( $user, $host, $users ) = @_;
+
+ my $dir = $prefix. datasrc;
+ mkdir $dir, 0700 or die $! unless -d $dir;
+ $dir .= "/$host";
+ mkdir $dir, 0700 or die $! unless -d $dir;
+
+ my $dest = "$dir/users";
+
+ eval "use File::Rsync;";
+ die $@ if $@;
+ my $rsync = File::Rsync->new({ rsh => 'ssh' });
+
+ open(LOCK, "+>>$dest.lock")
+ and flock(LOCK,LOCK_EX)
+ or die "can't open $dest.lock: $!";
+
+ $rsync->exec( {
+ src => "$user\@$host:$users",
+ dest => $dest,
+ } ); # true/false return value from exec is not working, alas
+ if ( $rsync->err ) {
+ die "error downloading $user\@$host:$users : ".
+ 'exit status: '. $rsync->status. ', '.
+ 'STDERR: '. join(" / ", $rsync->err). ', '.
+ 'STDOUT: '. join(" / ", $rsync->out);
+ }
+
+ $dest;
+}
+
+sub textradius_upload {
+ my( $user, $host, $users ) = @_;
+
+ my $dir = $prefix. datasrc. "/$host";
+
+ eval "use File::Rsync;";
+ die $@ if $@;
+ my $rsync = File::Rsync->new({
+ rsh => 'ssh',
+ #dry_run => 1,
+ });
+ $rsync->exec( {
+ src => "$dir/users",
+ dest => "$user\@$host:$users",
+ } ); # true/false return value from exec is not working, alas
+ if ( $rsync->err ) {
+ die "error uploading to $user\@$host:$users : ".
+ 'exit status: '. $rsync->status. ', '.
+ 'STDERR: '. join(" / ", $rsync->err). ', '.
+ 'STDOUT: '. join(" / ", $rsync->out);
+ }
+
+ flock(LOCK,LOCK_UN);
+ close LOCK;
+
+}
+
+1;
+