X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=fs_selfservice%2Ffreeside-selfservice-server;h=264cbc56df56094f2f4678d0cfe4424d38205ac2;hb=b1d4c3b5b5a05d38a4baf9c49bd7fdfb6990531d;hp=6146d3752bc8b2d66538cebcc257818a60b6601c;hpb=b4d172efa2225ef5070c1a6f168eb98fce8c5c62;p=freeside.git diff --git a/fs_selfservice/freeside-selfservice-server b/fs_selfservice/freeside-selfservice-server index 6146d3752..264cbc56d 100644 --- a/fs_selfservice/freeside-selfservice-server +++ b/fs_selfservice/freeside-selfservice-server @@ -8,21 +8,23 @@ # Proc::Daemon or somesuch use strict; -use vars qw( $kids $max_kids $shutdown $log_file ); -use vars qw($ssh_pid); +use vars qw( $Debug %kids $kids $max_kids $shutdown $log_file $ssh_pid ); use Fcntl qw(:flock); -use POSIX qw(setsid); +use POSIX qw(:sys_wait_h setsid); use IO::Handle; +use IO::Select; +use IO::File; use Storable qw(nstore_fd fd_retrieve); use Net::SSH qw(sshopen2); -use FS::UID qw(adminsuidsetup); +use FS::UID qw(adminsuidsetup forksuidsetup); +use FS::ClientAPI; -#use Tie::RefHash; -#use FS::Conf; -#use FS::Record qw( qsearch qsearchs ); -#use FS::cust_main_county; -#use FS::cust_main; -#use FS::Msgcat qw(gettext); +use FS::Conf; +use FS::cust_bill; +use FS::cust_pkg; + +$Debug = 2; # >= 2 will log packet contents, including potentially compromising + # information $shutdown = 0; $max_kids = '10'; #? @@ -35,77 +37,84 @@ my $pid_file = "/var/run/freeside-selfservice-server.$user.pid"; &init($user); -my $clientd = "/usr/local/sbin/freeside-selfservice-clientd"; #better name? +my $conf = new FS::Conf; -my %dispatch = ( - 'signup' => \&signup, - #'signup_init' => 'signup_init', - 'passwd' => \&passwd, +if ($conf->exists('selfservice_server-quiet')) { + $FS::cust_bill::quiet = 1; + $FS::cust_pkg::quiet = 1; +} -); +my $clientd = "/usr/local/sbin/freeside-selfservice-clientd"; #better name? my $warnkids=0; while (1) { - my($reader, $writer) = (new IO::Handle, new IO::Handle); - warn "connecting to $machine"; + my($writer,$reader,$error) = (new IO::Handle, new IO::Handle, new IO::Handle); + warn "connecting to $machine\n" if $Debug; + $ssh_pid = sshopen2($machine,$reader,$writer,$clientd); - warn "entering main loop"; +# nstore_fd(\*writer, {'hi'=>'there'}); + + warn "entering main loop\n" if $Debug; + my $undisp = 0; + my $s = IO::Select->new( $reader ); while (1) { - warn "waiting for packet from client"; - my $packet = eval { - local $SIG{__DIE__}; - local $SIG{ALRM} = sub { die "alarm\n" }; #NB: \n required - alarm 5; - my $p = fd_retrieve($reader); - alarm 0; - $p; - }; - if ($@) { - die $@ unless $@ eq "alarm\n"; - #timeout - next unless $shutdown; - &shutdown; + &reap_kids; + + warn "waiting for packet from client\n" if $Debug && !$undisp; + $undisp = 1; + my @handles = $s->can_read(5); + unless ( @handles ) { + &shutdown if $shutdown; + next; } - warn "packet received"; + + $undisp = 0; + + warn "receiving packet from client\n" if $Debug; + + my $packet = fd_retrieve($reader); + warn "packet received\n". + join('', map { " $_=>$packet->{$_}\n" } keys %$packet ) + if $Debug > 1; #prevent runaway forking my $warnkids = 0; while ( $kids >= $max_kids ) { - warn "WARNING: maximum $kids children reached" unless $warnkids++; + warn "WARNING: maximum $kids children reached\n" unless $warnkids++; + &reap_kids; sleep 1; } - warn "forking child"; + warn "forking child\n" if $Debug; defined( my $pid = fork ) or die "can't fork: $!"; if ( $pid ) { - warn "child $pid spawned"; $kids++; + $kids{$pid} = 1; + warn "child $pid spawned\n" if $Debug; } else { #kid time #get new db handle $FS::UID::dbh->{InactiveDestroy} = 1; forksuidsetup($user); - my $sub = $dispatch{$packet->{_packet}}; - my $rv; - if ( $sub ) { - warn "calling $sub handler"; - $rv = &{$sub}($packet); - } else { - warn my $error = "WARNING: unknown packet type ". $packet->{_packet}; + my $type = $packet->{_packet}; + warn "calling $type handler\n" if $Debug; + my $rv = eval { FS::ClientAPI->dispatch($type, $packet); }; + if ( $@ ) { + warn my $error = "WARNING: error dispatching $type: $@"; $rv = { _error => $error }; } $rv->{_token} = $packet->{_token}; #identifier - warn "sending response"; - flock($writer, LOCK_EX); #acquire write lock - nstore_fd($rv, $writer) or die "can't send response: $!"; - $writer->flush; - flock($writer, LOCK_UN); #release write lock + warn "sending response\n" if $Debug; + flock($writer, LOCK_EX) or die "FATAL: can't lock write stream: $!"; + nstore_fd($rv, $writer) or die "FATAL: can't send response: $!"; + $writer->flush or die "FATAL: can't flush: $!"; + flock($writer, LOCK_UN) or die "WARNING: can't release write lock: $!"; - warn "child exiting"; + warn "child exiting\n" if $Debug; exit; #end-of-kid } @@ -117,11 +126,23 @@ while (1) { # utility subroutines ### +sub reap_kids { + #warn "reaping kids\n"; + foreach my $pid ( keys %kids ) { + my $kid = waitpid($pid, WNOHANG); + if ( $kid > 0 ) { + $kids--; + delete $kids{$kid}; + } + } + #warn "done reaping\n"; +} + sub init { my $user = shift; chdir "/" or die "Can't chdir to /: $!"; - open STDIN, '/dev/null' or die "Can't read /dev/null: $!"; + open STDIN, '/dev/null' or die "Can't read /dev/null: $!"; defined(my $pid = fork) or die "Can't fork: $!"; if ( $pid ) { print "freeside-selfservice-server to $machine started with pid $pid\n"; #logging to $log_file @@ -131,8 +152,9 @@ sub init { exit; } - sub REAPER { my $pid = wait; $SIG{CHLD} = \&REAPER; $kids--; } - $SIG{CHLD} = \&REAPER; +# sub REAPER { my $pid = wait; $SIG{CHLD} = \&REAPER; $kids--; } +# #sub REAPER { my $pid = wait; $kids--; $SIG{CHLD} = \&REAPER; } +# $SIG{CHLD} = \&REAPER; $shutdown = 0; $SIG{HUP} = sub { warn "SIGHUP received; shutting down\n"; $shutdown++; }; @@ -141,8 +163,22 @@ sub init { $SIG{QUIT} = sub { warn "SIGQUIT received; shutting down\n"; $shutdown++; }; $SIG{PIPE} = sub { warn "SIGPIPE received; shutting down\n"; $shutdown++; }; - $> = $FS::UID::freeside_uid unless $>; - $< = $>; + #false laziness w/freeside-queued + my $freeside_gid = scalar(getgrnam('freeside')) + or die "can't setgid to freeside group\n"; + $) = $freeside_gid; + $( = $freeside_gid; + #if freebsd can't setuid(), presumably it can't setgid() either. grr fleabsd + ($(,$)) = ($),$(); + $) = $freeside_gid; + + $> = $FS::UID::freeside_uid; + $< = $FS::UID::freeside_uid; + #freebsd is sofa king broken, won't setuid() + ($<,$>) = ($>,$<); + $> = $FS::UID::freeside_uid; + #eslaf + $ENV{HOME} = (getpwuid($>))[7]; #for ssh adminsuidsetup $user; @@ -163,7 +199,7 @@ sub init { sub shutdown { my $wait = 12; #wait up to 1 minute - while ( $kids && $wait-- ) { + while ( $kids > 0 && $wait-- ) { warn "waiting for $kids children to terminate"; sleep 5; } @@ -180,10 +216,15 @@ sub _die { sub _logmsg { chomp( my $msg = shift ); + _do_logmsg( "[server] [". scalar(localtime). "] [$$] $msg\n" ); +} + +sub _do_logmsg { + chomp( my $msg = shift ); my $log = new IO::File ">>$log_file"; flock($log, LOCK_EX); seek($log, 0, 2); - print $log "[server] [". time2str("%a %b %e %T %Y",time). "] [$$] $msg\n"; + print $log "$msg\n"; flock($log, LOCK_UN); close $log; } @@ -192,7 +233,3 @@ sub usage { die "Usage:\n\n fs_signup_server user machine\n"; } -### -# handlers... should go in their own files eventually... -### -