X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=blobdiff_plain;f=FS%2FFS%2Fsvc_acct.pm;h=71c47d6cdb8d522227fd41603dac7d88b667d570;hp=d7dbcfaf228419052eefa8d9d57eae6cba47ff7a;hb=44e51a5c50be350fa698bcdcf86ad5c01a7631a2;hpb=e92e1a168b8fc6f6fcba9fd06f72e88ed9780457 diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm index d7dbcfaf2..71c47d6cd 100644 --- a/FS/FS/svc_acct.pm +++ b/FS/FS/svc_acct.pm @@ -3,15 +3,17 @@ package FS::svc_acct; use strict; use vars qw( @ISA $nossh_hack $conf $dir_prefix @shells $usernamemin $usernamemax $passwordmin $username_letter $username_letterfirst - $username_noperiod + $username_noperiod $username_uppercase $shellmachine $useradd $usermod $userdel $mydomain $cyrus_server $cyrus_admin_user $cyrus_admin_pass + $dirhash + $icradius_dbh @saltset @pw_set); use Carp; use FS::Conf; use FS::Record qw( qsearch qsearchs fields dbh ); use FS::svc_Common; -use Net::SSH qw(ssh); +use Net::SSH; use FS::part_svc; use FS::svc_acct_pop; use FS::svc_acct_sm; @@ -55,6 +57,7 @@ $FS::UID::callback{'FS::svc_acct'} = sub { $username_letter = $conf->exists('username-letter'); $username_letterfirst = $conf->exists('username-letterfirst'); $username_noperiod = $conf->exists('username-noperiod'); + $username_uppercase = $conf->exists('username-uppercase'); $mydomain = $conf->config('domain'); if ( $conf->exists('cyrus') ) { ($cyrus_server, $cyrus_admin_user, $cyrus_admin_pass) = @@ -65,6 +68,13 @@ $FS::UID::callback{'FS::svc_acct'} = sub { $cyrus_admin_user = ''; $cyrus_admin_pass = ''; } + if ( $conf->exists('icradius_secrets') ) { + $icradius_dbh = DBI->connect($conf->config('icradius_secrets')) + or die $DBI::errstr; + } else { + $icradius_dbh = ''; + } + $dirhash = $conf->config('dirhash') || 0; }; @saltset = ( 'a'..'z' , 'A'..'Z' , '0'..'9' , '.' , '/' ); @@ -231,7 +241,7 @@ sub insert { $self->shell, ); if ( $username && $uid && $dir && $shellmachine && ! $nossh_hack ) { - my $queue = new FS::queue { 'job' => 'Net::SSH::ssh' }; + my $queue = new FS::queue { 'job' => 'FS::svc_acct::ssh' }; $error = $queue->insert("root\@$shellmachine", eval qq("$useradd") ); if ( $error ) { $dbh->rollback if $oldAutoCommit; @@ -247,6 +257,17 @@ sub insert { return "queueing job (transaction rolled back): $error"; } } + if ( $icradius_dbh ) { + my $queue = new FS::queue { 'job' => 'FS::svc_acct::icradius_rc_insert' }; + $error = $queue->insert( $self->username, + $self->_password, + $self->radius_check + ); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "queueing job (transaction rolled back): $error"; + } + } $dbh->commit or die $dbh->errstr if $oldAutoCommit; ''; #no error @@ -275,13 +296,43 @@ sub cyrus_insert { warn "cyrus_insert: setacl user.$username, $username => all\n"; $rc = $client->setacl("user.$username", $username => 'all' ); $error = $client->error; - die $error if $error; + die "cyrus_insert: error setacl user.$username: $error" if $error; if ( $quota ) { warn "cyrus_insert: setquota user.$username, STORAGE => $quota\n"; $rc = $client->setquota("user.$username", 'STORAGE' => $quota ); $error = $client->error; - die $error if $error; + die "cyrus_insert: error setquota user.$username: $error" if $error; + } + + 1; +} + +sub icradius_rc_insert { + my( $username, $password, %radcheck ) = @_; + + my $sth = $icradius_dbh->prepare( + "INSERT INTO radcheck ( id, UserName, Attribute, Value ) VALUES ( ". + join(", ", map { $icradius_dbh->quote($_) } ( + '', + $username, + "Password", + $password, + ) ). " )" + ); + $sth->execute or die "can't insert into radcheck table: ". $sth->errstr; + + foreach my $attribute ( keys %radcheck ) { + my $sth = $icradius_dbh->prepare( + "INSERT INTO radcheck ( id, UserName, Attribute, Value ) VALUES ( ". + join(", ", map { $icradius_dbh->quote($_) } ( + '', + $username, + $attribute, + $radcheck{$attribute}, + ) ). " )" + ); + $sth->execute or die "can't insert into radcheck table: ". $sth->errstr; } 1; @@ -319,8 +370,10 @@ $username and $dir. sub delete { my $self = shift; - return "Can't delete an account which has (svc_acct_sm) mail aliases!" - if $self->uid && qsearch( 'svc_acct_sm', { 'domuid' => $self->uid } ); + if ( defined( $FS::Record::dbdef->table('svc_acct_sm') ) ) { + return "Can't delete an account which has (svc_acct_sm) mail aliases!" + if $self->uid && qsearch( 'svc_acct_sm', { 'domuid' => $self->uid } ); + } return "Can't delete an account which is a (svc_forward) source!" if qsearch( 'svc_forward', { 'srcsvc' => $self->svcnum } ); @@ -347,6 +400,9 @@ sub delete { foreach my $cust_main_invoice ( qsearch( 'cust_main_invoice', { 'dest' => $self->svcnum } ) ) { + #next unless defined; #wtf is up with qsearch? + warn $cust_main_invoice; + next unless defined $cust_main_invoice; my %hash = $cust_main_invoice->hash; $hash{'dest'} = $self->email; my $new = new FS::cust_main_invoice \%hash; @@ -381,7 +437,7 @@ sub delete { $self->dir, ); if ( $username && $shellmachine && ! $nossh_hack ) { - my $queue = new FS::queue { 'job' => 'Net::SSH::ssh' }; + my $queue = new FS::queue { 'job' => 'FS::svc_acct::ssh' }; $error = $queue->insert("root\@$shellmachine", eval qq("$userdel") ); if ( $error ) { $dbh->rollback if $oldAutoCommit; @@ -398,6 +454,14 @@ sub delete { return "queueing job (transaction rolled back): $error"; } } + if ( $icradius_dbh ) { + my $queue = new FS::queue { 'job' => 'FS::svc_acct::icradius_rc_delete' }; + $error = $queue->insert( $self->username ); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "queueing job (transaction rolled back): $error"; + } + } $dbh->commit or die $dbh->errstr if $oldAutoCommit; ''; @@ -424,6 +488,18 @@ sub cyrus_delete { 1; } +sub icradius_rc_delete { + my $username = shift; + + my $sth = $icradius_dbh->prepare( + 'DELETE FROM radcheck WHERE UserName = ?' + ); + $sth->execute($username) + or die "can't delete from radcheck table: ". $sth->errstr; + + 1; +} + =item replace OLD_RECORD Replaces OLD_RECORD with this one in the database. If there is an error, @@ -491,7 +567,7 @@ sub replace { $new->getfield('gid'), ); if ( $old_dir && $new_dir && $old_dir ne $new_dir && ! $nossh_hack ) { - my $queue = new FS::queue { 'job' => 'Net::SSH::ssh' }; + my $queue = new FS::queue { 'job' => 'FS::svc_acct::ssh' }; $error = $queue->insert("root\@$shellmachine", eval qq("$usermod") ); if ( $error ) { $dbh->rollback if $oldAutoCommit; @@ -499,10 +575,33 @@ sub replace { } } + if ( $icradius_dbh ) { + my $queue = new FS::queue { 'job' => 'FS::svc_acct::icradius_rc_replace' }; + $error = $queue->insert( $new->username, + $new->_password, + ); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return "queueing job (transaction rolled back): $error"; + } + } + $dbh->commit or die $dbh->errstr if $oldAutoCommit; ''; #no error } +sub icradius_rc_replace { + my( $username, $new_password ) = @_; + + my $sth = $icradius_dbh->prepare( + "UPDATE radcheck SET Value = ? WHERE UserName = ? and Attribute = ?" + ); + $sth->execute($new_password, $username, 'Password' ) + or die "can't update radcheck table: ". $sth->errstr; + + 1; +} + =item suspend Suspends this account by prefixing *SUSPENDED* to the password. If there is an @@ -576,9 +675,16 @@ sub check { return $error if $error; my $ulen = $usernamemax || $self->dbdef_table->column('username')->length; - $recref->{username} =~ /^([a-z0-9_\-\.]{$usernamemin,$ulen})$/ - or return "Illegal username"; - $recref->{username} = $1; + if ( $username_uppercase ) { + $recref->{username} =~ /^([a-z0-9_\-\.]{$usernamemin,$ulen})$/i + or return "Illegal username: ". $recref->{username}; + $recref->{username} = $1; + } else { + $recref->{username} =~ /^([a-z0-9_\-\.]{$usernamemin,$ulen})$/ + or return "Illegal username: ". $recref->{username}; + $recref->{username} = $1; + } + if ( $username_letterfirst ) { $recref->{username} =~ /^[a-z]/ or return "Illegal username"; } elsif ( $username_letter ) { @@ -607,15 +713,30 @@ sub check { return "Only root can have uid 0" if $recref->{uid} == 0 && $recref->{username} ne 'root'; - $error = $self->ut_textn('finger'); - return $error if $error; +# $error = $self->ut_textn('finger'); +# return $error if $error; + $self->getfield('finger') =~ + /^([\w \t\!\@\#\$\%\&\(\)\-\+\;\:\'\"\,\.\?\/\*\<\>]*)$/ + or return "Illegal finger: ". $self->getfield('finger'); + $self->setfield('finger', $1); $recref->{dir} =~ /^([\/\w\-]*)$/ or return "Illegal directory"; - $recref->{dir} = $1 || - $dir_prefix . '/' . $recref->{username} - #$dir_prefix . '/' . substr($recref->{username},0,1). '/' . $recref->{username} + $recref->{dir} = $1; + unless ( $recref->{dir} ) { + $recref->{dir} = $dir_prefix . '/'; + if ( $dirhash > 0 ) { + for my $h ( 1 .. $dirhash ) { + $recref->{dir} .= substr($recref->{username}, $h-1, 1). '/'; + } + } elsif ( $dirhash < 0 ) { + for my $h ( reverse $dirhash .. -1 ) { + $recref->{dir} .= substr($recref->{username}, $h, 1). '/'; + } + } + $recref->{dir} .= $recref->{username}; ; + } unless ( $recref->{username} eq 'sync' ) { if ( grep $_ eq $recref->{shell}, @shells ) { @@ -767,11 +888,39 @@ sub email { $self->username. '@'. $self->domain; } +=item ssh + +=cut + +sub ssh { + my ( $host, @cmd_and_args ) = @_; + + use IO::File; + my $reader = IO::File->new(); + my $writer = IO::File->new(); + my $error = IO::File->new(); + + &Net::SSH::sshopen3( $host, $reader, $writer, $error, @cmd_and_args) or die $!; + + local $/ = undef; + my $output_stream = <$writer>; + my $error_stream = <$error>; + if ( length $error_stream ) { + #warn "[FS::svc_acct::ssh] STDERR $error_stream"; + die "[FS::svc_acct::ssh] STDERR $error_stream"; + } + if ( length $output_stream ) { + warn "[FS::svc_acct::ssh] STDOUT $output_stream"; + } + +# &Net::SSH::ssh(@args,">>/usr/local/etc/freeside/sshoutput 2>&1"); +} + =back =head1 VERSION -$Id: svc_acct.pm,v 1.37 2001-09-11 12:06:57 ivan Exp $ +$Id: svc_acct.pm,v 1.50 2001-10-02 11:10:19 ivan Exp $ =head1 BUGS