From: ivan Date: Fri, 27 Oct 2000 20:15:50 +0000 (+0000) Subject: session monitor X-Git-Tag: freeside_1_3_0~72 X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=commitdiff_plain;h=52b07e8abd3946578a6c2701ec9e5195ec6b17e6 session monitor --- diff --git a/FS/FS/Record.pm b/FS/FS/Record.pm index 12cc77ebf..b0bfb0b3c 100644 --- a/FS/FS/Record.pm +++ b/FS/FS/Record.pm @@ -723,6 +723,54 @@ sub ut_phonen { ''; } +=item ut_ip COLUMN + +Check/untaint ip addresses. IPv4 only for now. + +=cut + +sub ut_ip { + my( $self, $field ) = @_; + $self->getfield($field) =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/; + or return "Illegal (IP address) $field: ". $self->getfield($field); + for ( $1 $2 $3 $4 ) { return "Illegal (IP address) $field" if $_ > 255; }; + $self->$setfield($field, "$1.$2.$3.$3"); + ''; +} + +=item ut_ipn COLUMN + +Check/untaint ip addresses. IPv4 only for now. May be null. + +=cut + +sub ut_ipn { + my( $self, $field ) = @_; + if ( $self->getfield($field) =~ /^()$/ ) { + $self->setfield($field,''); + ''; + } else { + $self->ut_ip($field); + } +} + +=item ut_domain COLUMN + +Check/untaint host and domain names. + +=cut + +sub ut_domain { + my( $self, $field ) = @_; + #$self->getfield($field) =~/^(\w+\.)*\w+$/ + $self->getfield($field) =~/^(\w+\.)*\w+$/ + or return "Illegal (domain) $field: ". $self->getfield($field); + $self->setfield($field,$1); + ''; +} + +=cut + =item ut_anything COLUMN Untaints arbitrary data. Be careful. @@ -847,7 +895,7 @@ sub hfields { =head1 VERSION -$Id: Record.pm,v 1.7 2000-06-27 12:15:37 ivan Exp $ +$Id: Record.pm,v 1.8 2000-10-27 20:15:50 ivan Exp $ =head1 BUGS diff --git a/TODO b/TODO index d6fa5678f..c6d7e4362 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,4 @@ -$Id: TODO,v 1.51 2000-10-15 12:58:25 ivan Exp $ +$Id: TODO,v 1.52 2000-10-27 20:15:50 ivan Exp $ If you are interested in helping with any of these, please join the *development* mailing list (send a blank message to @@ -6,6 +6,24 @@ ivan-freeside-devel-subscribe@sisd.com) to avoid duplication of effort. --- +> 1. A Web Form to the user get his account added automatically . The +> /etc/raddb/users and /etc/passwd would be updated automatically (these +> file are on the same machine Freeside is). I guess the the Add +> Customer +> page with some customization could be the work. +> 2. A Canceling Account Web Form available to user cancel his account +> at +> any time he wants. +> 3. A Password Changing Web Form where the user could change your +> password by sending your username, old and new password. +> 4. Additional POP Accounts Creation where the user supply only his +> main +> username/password (probably provided from a PPP Account already +> created) +> and his POP username/password for this specific account. +(actually need something more general i guess - probably need some way to say +which accounts (svc_acct) can log in and make changes per customer (cust_main) ) + this is awfully vauge, perhaps email for more info? don't want to alientate someone with accounting experience, but i just don't have time right now. . diff --git a/bin/fs-setup b/bin/fs-setup index ac8ff5eb7..cabeb2859 100755 --- a/bin/fs-setup +++ b/bin/fs-setup @@ -1,6 +1,6 @@ #!/usr/bin/perl -Tw # -# $Id: fs-setup,v 1.26 2000-07-06 08:57:27 ivan Exp $ +# $Id: fs-setup,v 1.27 2000-10-27 20:15:50 ivan Exp $ # # ivan@sisd.com 97-nov-8,9 # @@ -32,7 +32,10 @@ # fix radius attributes ivan@sisd.com 98-sep-27 # # $Log: fs-setup,v $ -# Revision 1.26 2000-07-06 08:57:27 ivan +# Revision 1.27 2000-10-27 20:15:50 ivan +# session monitor +# +# Revision 1.26 2000/07/06 08:57:27 ivan # support for radius check attributes (except importing). poorly documented. # # Revision 1.25 2000/06/29 12:00:49 ivan @@ -730,6 +733,49 @@ sub tables_hash_hack { 'index' => [ [] ], }, + 'port' => { + 'columns' => [ + 'portnum', 'int', '', '', + 'ip', 'varchar', NULL, 15, + 'nasport' 'int', NULL, '', + 'nasnum', 'int', '', '', + ], + 'primary_key' => 'portnum', + 'unique' => [], + 'index' => [], + }, + + 'nas' => { + 'columns' => [ + 'nasnum', 'int', '', '', + 'nas', 'varchar', '', $char_d, + 'nasip', 'varchar', '', 15, + 'nasfqdn', 'varchar', '', $char_d, +# 'last', 'timestamp', NULL, '', +#change to above when move to DBIx::DBSchema!!! + 'last', 'datetime', NULL, '', + ], + 'primary_key' => 'nasnum', + 'unique' => [ [ 'nas' ], [ 'nasip' ] ], + 'index' => [ [ 'last' ] ], + }, + + 'session' => { + 'columns' => [ + 'sessionnum', 'int', '', '', + 'portnum', 'int', '', '', + 'svcnum', 'int', '', '', +# 'login', 'timestamp', '', '', +# 'logout', 'timestamp', '', '', +#change to above when move to DBIx::DBSchema!!! + 'login', 'datetime', '', '', + 'logout', 'datetime', NULL, '', + ], + 'primary_key' => 'sessionnum', + 'unique' => [], + 'index' => [ [ 'portnum' ] ], + }, + ); %tables; diff --git a/eg/table_template.pm b/eg/table_template.pm index 7f74ac342..2cc1e1d6e 100644 --- a/eg/table_template.pm +++ b/eg/table_template.pm @@ -100,7 +100,7 @@ sub check { =head1 VERSION -$Id: table_template.pm,v 1.1 1999-08-04 08:03:03 ivan Exp $ +$Id: table_template.pm,v 1.2 2000-10-27 20:15:50 ivan Exp $ =head1 BUGS @@ -110,27 +110,6 @@ The author forgot to customize this manpage. L, schema.html from the base documentation. -=head1 HISTORY - -ivan@voicenet.com 97-jul-1 - -added hfields -ivan@sisd.com 97-nov-13 - -$Log: table_template.pm,v $ -Revision 1.1 1999-08-04 08:03:03 ivan -move table subclass examples out of production directory - -Revision 1.4 1998/12/29 11:59:57 ivan -mostly properly OO, some work still to be done with svc_ stuff - -Revision 1.3 1998/11/15 04:33:00 ivan -updates for newest versoin - -Revision 1.2 1998/11/15 03:48:49 ivan -update for current version - - =cut 1; diff --git a/fs_sesmon/FS-SessionClient/Changes b/fs_sesmon/FS-SessionClient/Changes new file mode 100644 index 000000000..390a7b946 --- /dev/null +++ b/fs_sesmon/FS-SessionClient/Changes @@ -0,0 +1,5 @@ +Revision history for Perl extension FS::SessionClient + +0.01 Wed Oct 18 16:34:36 1999 + - original version; created by ivan 1.0 + diff --git a/fs_sesmon/FS-SessionClient/MANIFEST b/fs_sesmon/FS-SessionClient/MANIFEST new file mode 100644 index 000000000..3ced1df17 --- /dev/null +++ b/fs_sesmon/FS-SessionClient/MANIFEST @@ -0,0 +1,9 @@ +Changes +MANIFEST +MANIFEST.SKIP +Makefile.PL +SessionClient.pm +test.pl +fs_sessiond +cgi/logon.cgi +cgi/logoff.cgi diff --git a/fs_sesmon/FS-SessionClient/MANIFEST.SKIP b/fs_sesmon/FS-SessionClient/MANIFEST.SKIP new file mode 100644 index 000000000..ae335e78a --- /dev/null +++ b/fs_sesmon/FS-SessionClient/MANIFEST.SKIP @@ -0,0 +1 @@ +CVS/ diff --git a/fs_sesmon/FS-SessionClient/Makefile.PL b/fs_sesmon/FS-SessionClient/Makefile.PL new file mode 100644 index 000000000..8dff176a7 --- /dev/null +++ b/fs_sesmon/FS-SessionClient/Makefile.PL @@ -0,0 +1,10 @@ +use ExtUtils::MakeMaker; +# See lib/ExtUtils/MakeMaker.pm for details of how to influence +# the contents of the Makefile that is written. +WriteMakefile( + 'NAME' => 'FS::SessionClient', + 'VERSION_FROM' => 'SessionClient.pm', # finds $VERSION + 'EXE_FILES' => [ 'fs_sessiond' ], + 'INSTALLSCRIPT' => '/usr/local/sbin', + 'PERM_RWX' => '750', +); diff --git a/fs_sesmon/FS-SessionClient/SessionClient.pm b/fs_sesmon/FS-SessionClient/SessionClient.pm new file mode 100644 index 000000000..fd50e8908 --- /dev/null +++ b/fs_sesmon/FS-SessionClient/SessionClient.pm @@ -0,0 +1,120 @@ +package FS::SessionClient; + +use strict; +use vars qw($VERSION @ISA @EXPORT_OK $fs_sessiond_socket); +use Exporter; +use Socket; +use FileHandle; +use IO::Handle; + +$VERSION = '0.01'; + +@ISA = qw( Exporter ); +@EXPORT_OK = qw( login logoff ); + +$fs_sessiond_socket = "/usr/local/freeside/fs_sessiond_socket"; + +$ENV{'PATH'} ='/usr/bin:/bin'; +$ENV{'SHELL'} = '/bin/sh'; +$ENV{'IFS'} = " \t\n"; +$ENV{'CDPATH'} = ''; +$ENV{'ENV'} = ''; +$ENV{'BASH_ENV'} = ''; + +my $freeside_uid = scalar(getpwnam('freeside')); +die "not running as the freeside user\n" if $> != $freeside_uid; + +=head1 NAME + +FS::SessionClient - Freeside session client API + +=head1 SYNOPSIS + + use FS::SessionClient qw( login portnum logoff ); + + $error = login ( { + 'username' => $username, + 'password' => $password, + 'login' => $timestamp, + 'portnum' => $portnum, + } ); + + $portnum = portnum( { 'ip' => $ip } ) or die "unknown ip!" + $portnum = portnum( { 'nasnum' => $nasnum, 'nasport' => $nasport } ) + or die "unknown nasnum/nasport"; + + $error = logoff ( { + 'username' => $username, + 'password' => $password, + 'logoff' => $timestamp, + 'portnum' => $portnum, + } ); + +=head1 DESCRIPTION + +This modules provides an API for a remote session application. + +It needs to be run as the freeside user. Because of this, the program which +calls these subroutines should be written very carefully. + +=head1 SUBROUTINES + +=over 4 + +=item login HASHREF + +HASHREF should have the following keys: username, password, login and portnum. +login is a UNIX timestamp; if not specified, will default to the current time. +Starts a new session for the specified user and portnum. The password is +optional, but must be correct if specified. + +Returns a scalar error message, or the empty string for success. + +=item portnum + +HASHREF should contain a single key: ip, or the two keys: nasnum and nasport. +Returns a portnum suitable for the login and logoff subroutines, or false +on error. + +=item logoff HASHREF + +HASHREF should have the following keys: usrename, password, logoff and portnum. +logoff is a UNIX timestamp; if not specified, will default to the current time. +Starts a new session for the specified user and portnum. The password is +optional, but must be correct if specified. + +Returns a scalar error message, or the empty string for success. + +=cut + +sub AUTOLOAD { + my $hashref = shift; + socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!"; + connect(SOCK, sockaddr_un($fs_sessiond_socket)) or die "connect: $!"; + print SOCK "$AUTOLOAD\n"; + + print SOCK join("\n", %{$hashref}, 'END' ), "\n"; + SOCK->flush; + + chomp( my $r = ); + $r; +} + +=back + +=head1 VERSION + +$Id: SessionClient.pm,v 1.1 2000-10-27 20:15:50 ivan Exp $ + +=head1 BUGS + +=head1 SEE ALSO + +L + +=cut + +1; + + + diff --git a/fs_sesmon/FS-SessionClient/fs_sessiond b/fs_sesmon/FS-SessionClient/fs_sessiond new file mode 100644 index 000000000..74d3aab31 --- /dev/null +++ b/fs_sesmon/FS-SessionClient/fs_sessiond @@ -0,0 +1,64 @@ +#!/usr/bin/perl -Tw +# +# fs_sessiond +# +# This is run REMOTELY over ssh by fs_session_server +# + +use strict; +use Socket; + +use vars qw( $Debug ); + +$Debug = 1; + +my $fs_session_socket = "/usr/local/freeside/fs_sessiond_socket"; + +$ENV{'PATH'} ='/usr/local/bin:/usr/bin:/usr/ucb:/bin'; +$ENV{'SHELL'} = '/bin/sh'; +$ENV{'IFS'} = " \t\n"; +$ENV{'CDPATH'} = ''; +$ENV{'ENV'} = ''; +$ENV{'BASH_ENV'} = ''; + +$|=1; + +my $me = "[fs_sessiond]"; + +warn "$me starting\n" if $Debug; +#nothing to read from server + +warn "$me creating $fs_sessiond_socket\n" if $Debug; +my $uaddr = sockaddr_un($fs_signupd_socket); +my $proto = getprotobyname('tcp'); +socket(Server,PF_UNIX,SOCK_STREAM,0) or die "socket: $!"; +unlink($fs_signup_socket); +bind(Server, $uaddr) or die "bind: $!"; +listen(Server,SOMAXCONN) or die "listen: $!"; + +warn "$me entering main loop\n" if $Debug; +my $paddr; +for ( ; $paddr = accept(Client,Server); close Client) { + + chomp( my $command = ); + + if ( $command eq 'login' || $command eq 'logout' || $command eq 'portnum' ) { + warn "$me reading data from local client\n" if $Debug; + my @data, $dos; + push @data, scalar() until $dos++ == 99 || $data[$#data] != "END\n"; + if ( $dos == 99 ) { + warn "$me WARNING: DoS attempt!" + } else { + warn "$me sending data to remote server\n" if $Debug; + print "$command\n", @data; + warn "$me reading result from remote server\n" if $Debug; + my $error = ; + warn "$me sending error to local client\n" if $Debug; + print Client $error; + } + } else { + warn "$me WARNING: unexpected command from client: $command"; + } + +} + diff --git a/fs_sesmon/FS-SessionClient/test.pl b/fs_sesmon/FS-SessionClient/test.pl new file mode 100644 index 000000000..d05201b66 --- /dev/null +++ b/fs_sesmon/FS-SessionClient/test.pl @@ -0,0 +1,20 @@ +# Before `make install' is performed this script should be runnable with +# `make test'. After `make install' it should work as `perl test.pl' + +######################### We start with some black magic to print on failure. + +# Change 1..1 below to 1..last_test_to_print . +# (It may become useful if the test is moved to ./t subdirectory.) + +BEGIN { $| = 1; print "1..1\n"; } +END {print "not ok 1\n" unless $loaded;} +use FS::SessionClient; +$loaded = 1; +print "ok 1\n"; + +######################### End of black magic. + +# Insert your test code below (better if it prints "ok 13" +# (correspondingly "not ok 13") depending on the success of chunk 13 +# of the test code): + diff --git a/fs_sesmon/fs_session_server b/fs_sesmon/fs_session_server new file mode 100644 index 000000000..be0a01710 --- /dev/null +++ b/fs_sesmon/fs_session_server @@ -0,0 +1,53 @@ +#!/usr/bin/perl -Tw +# +# fs_session_server +# + +use strict; +use vars qw( $opt $Debug ); +use IO::Handle; +use Net::SSH qw(sshopen3) +use FS::UID qw(adminsuidsetup); +use FS::Record qw( qsearch qsearchs ); +#use FS::cust_main_county; +#use FS::cust_main; +use FS::session; + +#require "configfile"; +$Debug = 1; + +my $user = shift or die &usage; +&adminsuidsetup( $user ); + +my $machine = shift or die &usage; + +my $fs_sessiond = "/usr/local/sbin/fs_sessiond"; + +my $me = "[fs_session_server]"; + +while (1) { + my($reader, $writer) = (new IO::Handle, new IO::Handle); + $writer->autoflush(1); + warn "$me Connecting to $machine\n" if $Debug; + sshopen2($machine,$reader,$writer,$fs_signupd); + + warn "$me Entering main loop\n" if $Debug; + while (1) { + warn "$me Reading (waiting for) data\n" if $Debug; + my $command = scalar(<$reader)); + #DoS protection here too, to protect against a compromised client? *sigh* + while ( ( my $key = scalar(<$reader>) ) != "END\n" ) { + chomp $key; + chomp( $hash{$key} = scalar(<$reader>) ); + } + + if ( $command eq 'login' ) { + + } elsif ( $command eq 'logoff' ) { + + } elsif ( $command eq 'portnum' ) { + + } else { + warn "$me WARNING: unrecognized command"; + } +