1 package FS::part_export::textradius;
3 use vars qw(@ISA %info $prefix);
6 use FS::UID qw(datasrc);
9 @ISA = qw(FS::part_export);
11 tie my %options, 'Tie::IxHash',
12 'user' => { label=>'Remote username', default=>'root' },
13 'users' => { label=>'users file location', default=>'/etc/raddb/users' },
19 'Real-time export to a text /etc/raddb/users file (Livingston, Cistron)',
20 'options' => \%options,
22 This will edit a text RADIUS users file in place on a remote server.
23 Requires installation of
24 <a href="http://search.cpan.org/dist/RADIUS-UserFile">RADIUS::UserFile</a>
25 from CPAN. If using RADIUS::UserFile 1.01, make sure to apply
26 <a href="http://rt.cpan.org/NoAuth/Bug.html?id=1210">this patch</a>. Also
27 make sure <a href="http://rsync.samba.org/">rsync</a> is installed on the
28 remote machine, and <a href="http://www.freeside.biz/mediawiki/index.php/Freeside:1.9:Documentation:Administration:SSH_Keys">SSH is setup for unattended
33 $prefix = "%%%FREESIDE_CONF%%%/export.";
35 sub rebless { shift; }
38 my($self, $svc_acct) = (shift, shift);
39 $err_or_queue = $self->textradius_queue( $svc_acct->svcnum, 'insert',
40 $svc_acct->username, $svc_acct->radius_check, '-', $svc_acct->radius_reply);
41 ref($err_or_queue) ? '' : $err_or_queue;
45 my( $self, $new, $old ) = (shift, shift, shift);
46 return "can't (yet?) change username with textradius"
47 if $old->username ne $new->username;
48 #return '' unless $old->_password ne $new->_password;
49 $err_or_queue = $self->textradius_queue( $new->svcnum, 'insert',
50 $new->username, $new->radius_check, '-', $new->radius_reply);
51 ref($err_or_queue) ? '' : $err_or_queue;
55 my( $self, $svc_acct ) = (shift, shift);
56 $err_or_queue = $self->textradius_queue( $svc_acct->svcnum, 'delete',
57 $svc_acct->username );
58 ref($err_or_queue) ? '' : $err_or_queue;
61 #a good idea to queue anything that could fail or take any time
62 sub textradius_queue {
63 my( $self, $svcnum, $method ) = (shift, shift, shift);
64 my $queue = new FS::queue {
66 'job' => "FS::part_export::textradius::textradius_$method",
69 $self->option('user')||'root',
71 $self->option('users'),
76 sub textradius_insert { #subroutine, not method
77 my( $user, $host, $users, $username, @attributes ) = @_;
81 push @check, $att while @attributes && ($att=shift @attributes) ne '-';
83 my %reply = @attributes;
85 my $file = textradius_download($user, $host, $users);
87 eval "use RADIUS::UserFile;";
90 my $userfile = new RADIUS::UserFile(
93 Check_Items => [ keys %check ],
94 ) or die "error parsing $file";
96 $userfile->remove($username);
99 Attributes => { %check, %reply },
100 Comment => 'user added by Freeside',
101 ) or die "error adding to $file";
103 $userfile->update( Who => [ $username ] )
104 or die "error updating $file";
106 textradius_upload($user, $host, $users);
110 sub textradius_delete { #subroutine, not method
111 my( $user, $host, $users, $username ) = @_;
113 my $file = textradius_download($user, $host, $users);
115 eval "use RADIUS::UserFile;";
118 my $userfile = new RADIUS::UserFile(
120 Who => [ $username ],
121 ) or die "error parsing $file";
123 $userfile->remove($username);
125 $userfile->update( Who => [ $username ] )
126 or die "error updating $file";
128 textradius_upload($user, $host, $users);
131 sub textradius_download {
132 my( $user, $host, $users ) = @_;
134 my $dir = $prefix. datasrc;
135 mkdir $dir, 0700 or die $! unless -d $dir;
137 mkdir $dir, 0700 or die $! unless -d $dir;
139 my $dest = "$dir/users";
141 eval "use File::Rsync;";
143 my $rsync = File::Rsync->new({ rsh => 'ssh' });
145 open(LOCK, "+>>$dest.lock")
146 and flock(LOCK,LOCK_EX)
147 or die "can't open $dest.lock: $!";
150 src => "$user\@$host:$users",
152 } ); # true/false return value from exec is not working, alas
154 die "error downloading $user\@$host:$users : ".
155 'exit status: '. $rsync->status. ', '.
156 'STDERR: '. join(" / ", $rsync->err). ', '.
157 'STDOUT: '. join(" / ", $rsync->out);
163 sub textradius_upload {
164 my( $user, $host, $users ) = @_;
166 my $dir = $prefix. datasrc. "/$host";
168 eval "use File::Rsync;";
170 my $rsync = File::Rsync->new({
176 dest => "$user\@$host:$users",
177 } ); # true/false return value from exec is not working, alas
179 die "error uploading to $user\@$host:$users : ".
180 'exit status: '. $rsync->status. ', '.
181 'STDERR: '. join(" / ", $rsync->err). ', '.
182 'STDOUT: '. join(" / ", $rsync->out);