1 package FS::part_export::ldap;
4 use FS::Record qw( dbh );
7 @ISA = qw(FS::part_export);
12 my($self, $svc_acct) = (shift, shift);
14 #false laziness w/shellcommands.pm
17 ${$_} = $svc_acct->getfield($_) foreach $svc_acct->fields;
18 ${$_} = $svc_acct->$_() foreach qw( domain );
19 my $cust_pkg = $svc_acct->cust_svc->cust_pkg;
21 my $cust_main = $cust_pkg->cust_main;
22 ${$_} = $cust_main->getfield($_) foreach qw(first last);
25 $crypt_password = ''; #surpress "used only once" warnings
26 $crypt_password = crypt( $svc_acct->_password,
27 $saltset[int(rand(64))].$saltset[int(rand(64))] );
31 my %attrib = map { /^\s*(\w+)\s+(.*\S)\s*$/;
32 $username_attrib = $1 if $2 eq '$username';
33 ( $1 => eval(qq("$2")) ); }
34 grep { /^\s*(\w+)\s+(.*\S)\s*$/ }
35 split("\n", $self->option('attributes'));
37 if ( $self->option('radius') ) {
38 foreach my $table (qw(reply check)) {
39 my $method = "radius_$table";
40 my %radius = $svc_acct->$method();
41 foreach my $radius ( keys %radius ) {
42 ( my $ldap = $radius ) =~ s/\-//g;
43 $attrib{$ldap} = $radius{$radius};
48 my $err_or_queue = $self->ldap_queue( $svc_acct->svcnum, 'insert',
52 return $err_or_queue unless ref($err_or_queue);
55 #my @groups = $svc_acct->radius_groups;
57 # my $err_or_queue = $self->ldap_queue(
58 # $svc_acct->svcnum, 'usergroup_insert',
59 # $svc_acct->username, @groups );
60 # return $err_or_queue unless ref($err_or_queue);
67 my( $self, $new, $old ) = (shift, shift, shift);
69 local $SIG{HUP} = 'IGNORE';
70 local $SIG{INT} = 'IGNORE';
71 local $SIG{QUIT} = 'IGNORE';
72 local $SIG{TERM} = 'IGNORE';
73 local $SIG{TSTP} = 'IGNORE';
74 local $SIG{PIPE} = 'IGNORE';
76 return "can't (yet?) change username with ldap"
77 if $old->username ne $new->username;
79 return "ldap replace unimplemented";
81 my $oldAutoCommit = $FS::UID::AutoCommit;
82 local $FS::UID::AutoCommit = 0;
86 #if ( $old->username ne $new->username ) {
87 # my $err_or_queue = $self->ldap_queue( $new->svcnum, 'rename',
88 # $new->username, $old->username );
89 # unless ( ref($err_or_queue) ) {
90 # $dbh->rollback if $oldAutoCommit;
91 # return $err_or_queue;
93 # $jobnum = $err_or_queue->jobnum;
96 foreach my $table (qw(reply check)) {
97 my $method = "radius_$table";
98 my %new = $new->$method();
99 my %old = $old->$method();
100 if ( grep { !exists $old{$_} #new attributes
101 || $new{$_} ne $old{$_} #changed
104 my $err_or_queue = $self->ldap_queue( $new->svcnum, 'insert',
105 $table, $new->username, %new );
106 unless ( ref($err_or_queue) ) {
107 $dbh->rollback if $oldAutoCommit;
108 return $err_or_queue;
111 my $error = $err_or_queue->depend_insert( $jobnum );
113 $dbh->rollback if $oldAutoCommit;
119 my @del = grep { !exists $new{$_} } keys %old;
121 my $err_or_queue = $self->ldap_queue( $new->svcnum, 'attrib_delete',
122 $table, $new->username, @del );
123 unless ( ref($err_or_queue) ) {
124 $dbh->rollback if $oldAutoCommit;
125 return $err_or_queue;
128 my $error = $err_or_queue->depend_insert( $jobnum );
130 $dbh->rollback if $oldAutoCommit;
137 # (sorta) false laziness with FS::svc_acct::replace
138 my @oldgroups = @{$old->usergroup}; #uuuh
139 my @newgroups = $new->radius_groups;
141 foreach my $oldgroup ( @oldgroups ) {
142 if ( grep { $oldgroup eq $_ } @newgroups ) {
143 @newgroups = grep { $oldgroup ne $_ } @newgroups;
146 push @delgroups, $oldgroup;
150 my $err_or_queue = $self->ldap_queue( $new->svcnum, 'usergroup_delete',
151 $new->username, @delgroups );
152 unless ( ref($err_or_queue) ) {
153 $dbh->rollback if $oldAutoCommit;
154 return $err_or_queue;
157 my $error = $err_or_queue->depend_insert( $jobnum );
159 $dbh->rollback if $oldAutoCommit;
166 my $err_or_queue = $self->ldap_queue( $new->svcnum, 'usergroup_insert',
167 $new->username, @newgroups );
168 unless ( ref($err_or_queue) ) {
169 $dbh->rollback if $oldAutoCommit;
170 return $err_or_queue;
173 my $error = $err_or_queue->depend_insert( $jobnum );
175 $dbh->rollback if $oldAutoCommit;
181 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
187 my( $self, $svc_acct ) = (shift, shift);
188 return "ldap delete unimplemented";
189 my $err_or_queue = $self->ldap_queue( $svc_acct->svcnum, 'delete',
190 $svc_acct->username );
191 ref($err_or_queue) ? '' : $err_or_queue;
195 my( $self, $svcnum, $method ) = (shift, shift, shift);
196 my $queue = new FS::queue {
198 'job' => "FS::part_export::ldap::ldap_$method",
203 $self->option('password'),
208 sub ldap_insert { #subroutine, not method
209 my $ldap = ldap_connect(shift, (my $dn = shift), shift);
210 my( $username_attrib, %attrib ) = @_;
212 $dn = "$username_attrib=$attrib{$username_attrib}, $dn" if $username_attrib;
213 #icky hack, but should be unsurprising to the LDAPers
214 foreach my $key ( grep { $attrib{$_} =~ /,/ } keys %attrib ) {
215 $attrib{$key} = [ split(/,/, $attrib{$key}) ];
218 my $status = $ldap->add( $dn, attrs => [ %attrib ] );
219 die $status->error if $status->is_error;
224 #sub ldap_delete { #subroutine, not method
225 # my $dbh = ldap_connect(shift, shift, shift);
226 # my $username = shift;
228 # foreach my $table (qw( radcheck radreply usergroup )) {
229 # my $sth = $dbh->prepare( "DELETE FROM $table WHERE UserName = ?" );
230 # $sth->execute($username)
231 # or die "can't delete from $table table: ". $sth->errstr;
237 my( $machine, $dn, $password ) = @_;
239 $bind_options{password} = $password if length($password);
241 eval "use Net::LDAP";
244 my $ldap = Net::LDAP->new($machine) or die $@;
245 my $status = $ldap->bind( $dn, %bind_options );
246 die $status->error if $status->is_error;