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,
21 'default_svc_class' => 'Internet',
23 This will edit a text RADIUS users file in place on a remote server.
24 Requires installation of
25 <a href="http://search.cpan.org/dist/RADIUS-UserFile">RADIUS::UserFile</a>
26 from CPAN. If using RADIUS::UserFile 1.01, make sure to apply
27 <a href="http://rt.cpan.org/NoAuth/Bug.html?id=1210">this patch</a>. Also
28 make sure <a href="http://rsync.samba.org/">rsync</a> is installed on the
29 remote machine, and <a href="http://www.freeside.biz/mediawiki/index.php/Freeside:1.9:Documentation:Administration:SSH_Keys">SSH is setup for unattended
34 $prefix = "%%%FREESIDE_CONF%%%/export.";
36 sub rebless { shift; }
39 my($self, $svc_acct) = (shift, shift);
40 $err_or_queue = $self->textradius_queue( $svc_acct->svcnum, 'insert',
41 $svc_acct->username, $svc_acct->radius_check, '-', $svc_acct->radius_reply);
42 ref($err_or_queue) ? '' : $err_or_queue;
46 my( $self, $new, $old ) = (shift, shift, shift);
47 return "can't (yet?) change username with textradius"
48 if $old->username ne $new->username;
49 #return '' unless $old->_password ne $new->_password;
50 $err_or_queue = $self->textradius_queue( $new->svcnum, 'insert',
51 $new->username, $new->radius_check, '-', $new->radius_reply);
52 ref($err_or_queue) ? '' : $err_or_queue;
56 my( $self, $svc_acct ) = (shift, shift);
57 $err_or_queue = $self->textradius_queue( $svc_acct->svcnum, 'delete',
58 $svc_acct->username );
59 ref($err_or_queue) ? '' : $err_or_queue;
62 #a good idea to queue anything that could fail or take any time
63 sub textradius_queue {
64 my( $self, $svcnum, $method ) = (shift, shift, shift);
65 my $queue = new FS::queue {
67 'job' => "FS::part_export::textradius::textradius_$method",
70 $self->option('user')||'root',
72 $self->option('users'),
77 sub textradius_insert { #subroutine, not method
78 my( $user, $host, $users, $username, @attributes ) = @_;
82 push @check, $att while @attributes && ($att=shift @attributes) ne '-';
84 my %reply = @attributes;
86 my $file = textradius_download($user, $host, $users);
88 eval "use RADIUS::UserFile;";
91 my $userfile = new RADIUS::UserFile(
94 Check_Items => [ keys %check ],
95 ) or die "error parsing $file";
97 $userfile->remove($username);
100 Attributes => { %check, %reply },
101 Comment => 'user added by Freeside',
102 ) or die "error adding to $file";
104 $userfile->update( Who => [ $username ] )
105 or die "error updating $file";
107 textradius_upload($user, $host, $users);
111 sub textradius_delete { #subroutine, not method
112 my( $user, $host, $users, $username ) = @_;
114 my $file = textradius_download($user, $host, $users);
116 eval "use RADIUS::UserFile;";
119 my $userfile = new RADIUS::UserFile(
121 Who => [ $username ],
122 ) or die "error parsing $file";
124 $userfile->remove($username);
126 $userfile->update( Who => [ $username ] )
127 or die "error updating $file";
129 textradius_upload($user, $host, $users);
132 sub textradius_download {
133 my( $user, $host, $users ) = @_;
135 my $dir = $prefix. datasrc;
136 mkdir $dir, 0700 or die $! unless -d $dir;
138 mkdir $dir, 0700 or die $! unless -d $dir;
140 my $dest = "$dir/users";
142 eval "use File::Rsync;";
144 my $rsync = File::Rsync->new({ rsh => 'ssh' });
146 open(LOCK, "+>>$dest.lock")
147 and flock(LOCK,LOCK_EX)
148 or die "can't open $dest.lock: $!";
151 src => "$user\@$host:$users",
153 } ); # true/false return value from exec is not working, alas
155 die "error downloading $user\@$host:$users : ".
156 'exit status: '. $rsync->status. ', '.
157 'STDERR: '. join(" / ", $rsync->err). ', '.
158 'STDOUT: '. join(" / ", $rsync->out);
164 sub textradius_upload {
165 my( $user, $host, $users ) = @_;
167 my $dir = $prefix. datasrc. "/$host";
169 eval "use File::Rsync;";
171 my $rsync = File::Rsync->new({
177 dest => "$user\@$host:$users",
178 } ); # true/false return value from exec is not working, alas
180 die "error uploading to $user\@$host:$users : ".
181 'exit status: '. $rsync->status. ', '.
182 'STDERR: '. join(" / ", $rsync->err). ', '.
183 'STDOUT: '. join(" / ", $rsync->out);