diff options
Diffstat (limited to 'bin')
-rw-r--r-- | bin/backup-freeside | 6 | ||||
-rwxr-xr-x | bin/bill | 188 | ||||
-rwxr-xr-x | bin/dbdef-create | 88 | ||||
-rwxr-xr-x | bin/freeside-session-kill | 100 | ||||
-rwxr-xr-x | bin/fs-migrate-svc_acct_sm | 242 | ||||
-rwxr-xr-x | bin/fs-radius-add-check | 52 | ||||
-rwxr-xr-x | bin/fs-radius-add-reply | 52 | ||||
-rwxr-xr-x | bin/fs-setup | 450 | ||||
-rwxr-xr-x | bin/generate-prepay | 35 | ||||
-rwxr-xr-x | bin/masonize | 70 | ||||
-rwxr-xr-x | bin/pod2x | 26 | ||||
-rwxr-xr-x | bin/svc_acct.export | 762 | ||||
-rwxr-xr-x | bin/svc_acct.import | 145 | ||||
-rwxr-xr-x | bin/svc_acct_sm.export | 221 | ||||
-rwxr-xr-x | bin/svc_acct_sm.import | 99 | ||||
-rw-r--r-- | bin/svc_domain.import | 92 |
16 files changed, 1800 insertions, 828 deletions
diff --git a/bin/backup-freeside b/bin/backup-freeside new file mode 100644 index 000000000..a39b04692 --- /dev/null +++ b/bin/backup-freeside @@ -0,0 +1,6 @@ +#!/bin/sh +/etc/init.d/apache stop +/etc/init.d/mysql stop +tar czvf var-lib-mysql-`date +%y%m%d%H%M%S`.tar.gz /var/lib/mysql +/etc/init.d/mysql start +/etc/init.d/apache start diff --git a/bin/bill b/bin/bill deleted file mode 100755 index 5c5be703d..000000000 --- a/bin/bill +++ /dev/null @@ -1,188 +0,0 @@ -#!/usr/local/bin/perl -Tw -# -# bill: Bill customer(s) -# -# Usage: bill [ -c [ i ] ] [ -d 'date' ] [ -b ] -# -# Bills all customers. -# -# Adds record to /dbin/cust_bill and /dbin/cust_pay (if payment made - -# CARD & COMP), prints invoice / charges card etc. -# -# -c: Turn on collecting (you probably want this). -# -# -i: real-time billing (as opposed to batch billing). only relevant -# for credit cards. -# -# -d: Pretent it's 'date'. Date is in any format Date::Parse is happy with, -# but be careful. -# -# ## n/a ## -b: send batch when done billing -# -# ivan@voicenet.com sep/oct 96 -# -# separated billing and collections, cleaned up code. -# ivan@voicenet.com 96-nov-11 -# -# added -d option -# ivan@voicenet.com 96-nov-13 -# -# added -v option and started to implement it, added 'd:' to getopts call -# (oops!) -# ivan@voicenet.com 97-jan-2 -# -# added more debug messages, moved some searches to fssearch.pl library (for -# speed) -# rewrote "all customer" finder to know about bill dates, for speed. -# ivan@voicenet.com 97-jan-8 -# -# thought about it a while, and removed passing of the -d option to collect...? -# ivan@voicenet.com 97-jan-14 -# -# make all -v stuff STDERR -# ivan@voicenet.com 97-feb-4 -# -# added pkgnum as argument to program from /db/part_pkg, with kludge for the -# "/bin/echo XX" 's already there. -# ivan@voicenet.com 97-feb-23 -# -# - general cleanup -# - customers who are suspended can still be billed for the setup fee -# - cust_pkg record is re-read after the package setup fee program is run. -# this way, -# that program can modify the record (for example, to start accounts off -# suspended) -# (best to think four or five times before modifying anything else!) -# ivan@voicenet.com 97-feb-26 -# -# don't bill recurring fee if its not time! (was removed) -# ivan@voicenet.com 97-mar-6 -# -# added -b option, send batch when done billing. -# ivan@voicenet.com 97-apr-4 -# -#insecure dependency on line 179ish below needs to be fixed before bill is -#used setuid -# ivan@voicenet.com 97-jun-2 -# -# removed running of setup program (depriciated) -# ivan@voicenet.com 97-jul-21 -# -# rewrote for new API, removed option to specify custnums (use FS::Bill -# instead), removed -v option (?) -# ivan@voicenet.com 97-jul-22 - 23 - 25 -28 -# (need to add back in email stuff, look in /home/ivan/old/dbin/collect) -# -# s/suidsetup/adminsuidsetup/, s/FS::Search/FS::Record/, added some batch -# exporting stuff (which still needs to be generalized) and removed &idiot -# ivan@sisd.com 98-may-27 - -# setup - -use strict; -use Fcntl qw(:flock); -use Date::Parse; -use Getopt::Std; -use FS::UID qw(adminsuidsetup swapuid); -use FS::Record qw(qsearch qsearchs); -use FS::Bill; - -my($batchfile)="/var/spool/freeside/batch"; -my($batchlock)="/var/spool/freeside/batch.lock"; - -adminsuidsetup; - -&untaint_argv; #what it sounds like (eww) -use vars qw($opt_b $opt_c $opt_i $opt_d); -getopts("bcid:"); #switches - -#we're at now now (and later). -my($time)= $main::opt_d ? str2time($main::opt_d) : $^T; - -# find packages w/ bill < time && cancel != '', and create corresponding -# customer objects - -my($cust_main,%saw); -foreach $cust_main ( - map { - if ( ( $_->getfield('bill') || 0 ) <= $time && - !$saw{ $_->getfield('custnum') }++ ) { - qsearchs('cust_main',{'custnum'=> $_->getfield('custnum') } ); - } else { - (); - } - } qsearch('cust_pkg',{'cancel'=>''}) -) { - - # and bill them - - print "Billing customer #" . $cust_main->getfield('custnum') . "\n"; - - bless($cust_main,"FS::Bill"); - - my($error); - - $error=$cust_main->bill('time'=>$time); - warn "Error billing, customer #" . $cust_main->getfield('custnum') . - ":" . $error if $error; - - if ($main::opt_c) { - $error=$cust_main->collect('invoice_time'=>$time, - 'batch_card' => $main::opt_i ? 'no' : 'yes', - ); - warn "Error collecting customer #" . $cust_main->getfield('custnum') . - ":" . $error if $error; - - #sleep 1; - - } - -} - -#if ($main::opt_b) { -# -# die "Batch still waiting for reply? ($batchlock exists)\n" if -e $batchlock; -# open(BATCHLOCK,"+>>$batchlock") or die "Can't open $batchlock: $!"; -# select(BATCHLOCK); $|=1; select(STDOUT); -# unless ( flock(BATCHLOCK,,LOCK_EX|LOCK_NB) ) { -# seek(BATCHLOCK,0,0); -# my($pid)=<BATCHLOCK>; -# chop($pid); -# die "Is a batch running? (pid $pid)\n"; -# } -# seek(BATCHLOCK,0,0); -# print BATCHLOCK $$,"\n"; -# -# ( open(BATCH,">$batchfile") -# and flock(BATCH,LOCK_EX|LOCK_NB) -# ) or die "Can't open $batchfile: $!"; -# -# my($cust_pay_batch); -# foreach $cust_pay_batch (qsearch('cust_pay_batch',{})) { -# print BATCH join(':', -# $_->getfield('cardnum'), -# $_->getfield('exp'), -# $_->getfield('amount'), -# $_->getfield('payname') -# || $_->getfield('first'). ' '. $_->getfield('last'), -# "Description", -# $_->getfield('zip'), -# ),"\n"; -# } -# -# flock(BATCH,LOCK_UN); -# close BATCH; -# -# flock(BATCHLOCK,LOCK_UN); -# close BATCHLOCK; -#} - -# subroutines - -sub untaint_argv { - foreach $_ ( $[ .. $#ARGV ) { #untaint @ARGV - $ARGV[$_] =~ /^([\w\-\/]*)$/ || die "Illegal arguement \"$ARGV[$_]\""; - $ARGV[$_]=$1; - } -} - diff --git a/bin/dbdef-create b/bin/dbdef-create index eb62c77e3..902f7f145 100755 --- a/bin/dbdef-create +++ b/bin/dbdef-create @@ -1,85 +1,37 @@ #!/usr/bin/perl -Tw # +# $Id: dbdef-create,v 1.3 2001-04-15 12:56:31 ivan Exp $ +# # create dbdef file for existing mySQL database (needs SHOW|DESCRIBE command # not in Pg) based on fs-setup # # ivan@sisd.com 98-jun-2 +# +# $Log: dbdef-create,v $ +# Revision 1.3 2001-04-15 12:56:31 ivan +# s/dbdef/DBIx::DBSchema/ +# +# Revision 1.2 1998/11/19 11:17:44 ivan +# adminsuidsetup requires argument +# use strict; use DBI; -use FS::dbdef; -use FS::UID qw(adminsuidsetup datasrc); - -#needs to match FS::Record -my($dbdef_file) = "/var/spool/freeside/dbdef.". datasrc; - -my($dbh)=adminsuidsetup; +use DBIx::DBSchema; +use FS::UID qw(adminsuidsetup datasrc driver_name); -my($tables_sth)=$dbh->prepare("SHOW TABLES"); -my($tables_rv)=$tables_sth->execute; +my $user = shift or die &usage; -my(@tables); -foreach ( @{$tables_sth->fetchall_arrayref} ) { - my($table)=${$_}[0]; - #print "TABLE\t$table\n"; +my($dbh)=adminsuidsetup $user; - my($index_sth)=$dbh->prepare("SHOW INDEX FROM $table"); - my($primary_key)=''; - my(%index,%unique); - for ( 1 .. $index_sth->execute ) { - my($row)=$index_sth->fetchrow_hashref; - if ( ${$row}{'Key_name'} eq "PRIMARY" ) { - $primary_key=${$row}{'Column_name'}; - next; - } - if ( ${$row}{'Non_unique'} ) { #index - push @{$index{${$row}{'Key_name'}}}, ${$row}{'Column_name'}; - } else { #unique - push @{$unique{${$row}{'Key_name'}}}, ${$row}{'Column_name'}; - } - } - - my(@index)=values %index; - my(@unique)=values %unique; - #print "\tPRIMARY KEY $primary_key\n"; - foreach (@index) { - #print "\tINDEX\t", join(', ', @{$_}), "\n"; - } - foreach (@unique) { - #print "\tUNIQUE\t", join(', ', @{$_}), "\n"; - } - - my($columns_sth)=$dbh->prepare("SHOW COLUMNS FROM $table"); - my(@columns); - for ( 1 .. $columns_sth->execute ) { - my($row)=$columns_sth->fetchrow_hashref; - #print "\t", ${$row}{'Field'}, "\n"; - ${$row}{'Type'} =~ /^(\w+)\(?([\d\,]+)?\)?( unsigned)?$/ - or die "Illegal type ${$row}{'Type'}\n"; - my($type,$length)=($1,$2); - my($null)=${$row}{'Null'}; - $null =~ s/YES/NULL/; - push @columns, new FS::dbdef_column ( - ${$row}{'Field'}, - $type, - $null, - $length, - ); - } - - #print "\n"; - push @tables, new FS::dbdef_table ( - $table, - $primary_key, - new FS::dbdef_unique (\@unique), - new FS::dbdef_index (\@index), - @columns, - ); - -} +#needs to match FS::Record +my($dbdef_file) = "/usr/local/etc/freeside/dbdef.". datasrc; -my($dbdef) = new FS::dbdef ( @tables ); +my $dbdef = new_native DBIx::DBSchema $dbh; #important $dbdef->save($dbdef_file); +sub usage { + die "Usage:\n dbdef-create user\n"; +} diff --git a/bin/freeside-session-kill b/bin/freeside-session-kill new file mode 100755 index 000000000..9f11abd5b --- /dev/null +++ b/bin/freeside-session-kill @@ -0,0 +1,100 @@ +#!/usr/bin/perl -w + +use strict; +use vars qw($conf); +use Fcntl qw(:flock); +use FS::UID qw(adminsuidsetup datasrc dbh); +use FS::Record qw(dbdef qsearch fields); +use FS::session; +use FS::svc_acct; + +my $user = shift or die &usage; +adminsuidsetup $user; + +my $sessionlock = "/usr/local/etc/freeside/session-kill.lock.". datasrc; + +open(LOCK,"+>>$sessionlock") or die "Can't open $sessionlock: $!"; +select(LOCK); $|=1; select(STDOUT); +unless ( flock(LOCK,LOCK_EX|LOCK_NB) ) { + seek(LOCK,0,0); + my($pid)=<LOCK>; + chop($pid); + #no reason to start loct of blocking processes + die "Is another session kill process running under pid $pid?\n"; +} +seek(LOCK,0,0); +print LOCK $$,"\n"; + +$FS::UID::AutoCommit = 0; + +my $now = time; + +#uhhhhh + +use DBIx::DBSchema; +use DBIx::DBSchema::Table; #down this path lies madness +use DBIx::DBSchema::Column; + +my $dbdef = dbdef or die; +#warn $dbdef; +#warn $dbdef->{'tables'}; +#warn keys %{$dbdef->{'tables'}}; +my $session_table = $dbdef->table('session') or die; +my $svc_acct_table = $dbdef->table('svc_acct') or die; + +my $session_svc_acct = new DBIx::DBSchema::Table ( 'session,svc_acct', '', '', '', + map( DBIx::DBSchema::Column->new( "session.$_", + $session_table->column($_)->type, + $session_table->column($_)->null, + $session_table->column($_)->length, + ), $session_table->columns() ), + map( DBIx::DBSchema::Column->new( "svc_acct.$_", + $svc_acct_table->column($_)->type, + $svc_acct_table->column($_)->null, + $svc_acct_table->column($_)->length, + ), $svc_acct_table->columns ), +# map("svc_acct.$_", $svc_acct_table->columns), +); + +$dbdef->addtable($session_svc_acct); #madness, i tell you + +$FS::Record::DEBUG = 1; +my @session = qsearch('session,svc_acct', {}, '', ' WHERE '. join(' AND ', + 'svc_acct.svcnum = session.svcnum', + '( session.logout IS NULL OR session.logout = 0 )', + "( $now - session.login ) >= svc_acct.seconds" +). " FOR UPDATE" ); + +my $dbh = dbh; + +foreach my $join ( @session ) { + + my $session = new FS::session ( { + map { $_ => $join->{'Hash'}{"session.$_"} } fields('session') + } ); #see no evil + + my $svc_acct = new FS::svc_acct ( { + map { $_ => $join->{'Hash'}{"svc_acct.$_"} } fields('svc_acct') + } ); + + #false laziness w/ fs_session_server + my $nsession = new FS::session ( { $session->hash } ); + my $error = $nsession->replace($session); + if ( $error ) { + $dbh->rollback; + die $error; + } + my $time = $nsession->logout - $nsession->login; + my $new_svc_acct = new FS::svc_acct ( { $svc_acct->hash } ); + my $seconds = $new_svc_acct->seconds; + $seconds -= $time; + $seconds = 0 if $seconds < 0; + $new_svc_acct->seconds( $seconds ); + $error = $new_svc_acct->replace( $svc_acct ); + warn "can't debit time from ". $svc_acct->username. ": $error\n"; #don't want to rollback, though + #ssenizal eslaf + +} + +$dbh->commit or die $dbh->errstr; + diff --git a/bin/fs-migrate-svc_acct_sm b/bin/fs-migrate-svc_acct_sm new file mode 100755 index 000000000..d0d4a94b6 --- /dev/null +++ b/bin/fs-migrate-svc_acct_sm @@ -0,0 +1,242 @@ +#!/usr/bin/perl -Tw +# +# $Id: fs-migrate-svc_acct_sm,v 1.2 2001-08-12 19:41:25 jeff Exp $ +# +# jeff@cmh.net 01-Jul-20 +# +# $Log: fs-migrate-svc_acct_sm,v $ +# Revision 1.2 2001-08-12 19:41:25 jeff +# merging vpopmail support branch +# +# Revision 1.1.2.1 2001/08/08 17:45:35 jeff +# initial vpopmail support +# +# +# +# Initial vpopmail changes +# + +#to delay loading dbdef until we're ready +#BEGIN { $FS::Record::setup_hack = 1; } + +use strict; +use Term::Query qw(query); +#use DBI; +#use DBIx::DBSchema; +#use DBIx::DBSchema::Table; +#use DBIx::DBSchema::Column; +#use DBIx::DBSchema::ColGroup::Unique; +#use DBIx::DBSchema::ColGroup::Index; +use FS::Conf; +use FS::UID qw(adminsuidsetup datasrc checkeuid getsecrets); +use FS::Record qw(qsearch qsearchs); +use FS::svc_domain; +use FS::svc_forward; +use vars qw( $conf $old_default_domain %part_domain_svc %part_acct_svc %part_forward_svc $svc_acct $svc_acct_sm $error); + +die "Not running uid freeside!" unless checkeuid(); + +my $user = shift or die &usage; +getsecrets($user); + +$conf = new FS::Conf; +$old_default_domain = $conf->config('domain'); + +#needs to match FS::Record +#my($dbdef_file) = "/usr/local/etc/freeside/dbdef.". datasrc; + +### +# This section would be the appropriate place to manipulate +# the schema & tables. +### + +## we need to add the domsvc to svc_acct +## we must add a svc_forward record.... +## I am thinking that the fields svcnum (int), destsvc (int), and +## dest (varchar (80)) are appropriate, with destsvc/dest an either/or +## much in the spirit of cust_main_invoice + +### +# massage the data +### + +my($dbh)=adminsuidsetup $user; + +$|=1; + +$FS::svc_acct::nossh_hack = 1; +$FS::svc_forward::nossh_hack = 1; +$FS::svc_domain::whois_hack = 1; + +%part_domain_svc=map { $_->svcpart, $_ } qsearch('part_svc',{'svcdb'=>'svc_domain'}); +%part_acct_svc=map { $_->svcpart, $_ } qsearch('part_svc',{'svcdb'=>'svc_acct'}); +%part_forward_svc=map { $_->svcpart, $_ } qsearch('part_svc',{'svcdb'=>'svc_forward'}); + +die "No services with svcdb svc_domain!\n" unless %part_domain_svc; +die "No services with svcdb svc_acct!\n" unless %part_acct_svc; +die "No services with svcdb svc_forward!\n" unless %part_forward_svc; + +my($svc_domain) = qsearchs('svc_domain', { 'domain' => $old_default_domain }); +if (! $svc_domain || $svc_domain->domain != $old_default_domain) { + print <<EOF; + +Your database currently does not contain a svc_domain record for the +domain $old_default_domain. Would you like me to add one for you? +EOF + + my($response)=scalar(<STDIN>); + chop $response; + if ($response =~ /^[yY]/) { + print "\n\n", &menu_domain_svc, "\n", <<END; +I need to create new domain accounts. Which service shall I use for that? +END + my($domain_svcpart)=&getdomainpart; + + $svc_domain = new FS::svc_domain { + 'domain' => $old_default_domain, + 'svcpart' => $domain_svcpart, + 'action' => 'M', + }; +# $error=$svc_domain->insert && die "Error adding domain $old_default_domain: $error"; + $error=$svc_domain->insert; + die "Error adding domain $old_default_domain: $error" if $error; + }else{ + print <<EOF; + + This program cannot function properly until a svc_domain record matching +your conf_dir/domain file exists. +EOF + + exit 1; + } +} + +print "\n\n", &menu_acct_svc, "\n", <<END; +I may need to create some new pop accounts and set up forwarding to them +for some users. Which service shall I use for that? +END +my($pop_svcpart)=&getacctpart; + +print "\n\n", &menu_forward_svc, "\n", <<END; +I may need to create some new forwarding for some users. Which service +shall I use for that? +END +my($forward_svcpart)=&getforwardpart; + +sub menu_domain_svc { + ( join "\n", map "$_: ".$part_domain_svc{$_}->svc, sort keys %part_domain_svc ). "\n"; +} +sub menu_acct_svc { + ( join "\n", map "$_: ".$part_acct_svc{$_}->svc, sort keys %part_acct_svc ). "\n"; +} +sub menu_forward_svc { + ( join "\n", map "$_: ".$part_forward_svc{$_}->svc, sort keys %part_forward_svc ). "\n"; +} +sub getdomainpart { + $^W=0; # Term::Query isn't -w-safe + my $return = query "Enter part number:", 'irk', [ keys %part_domain_svc ]; + $^W=1; + $return; +} +sub getacctpart { + $^W=0; # Term::Query isn't -w-safe + my $return = query "Enter part number:", 'irk', [ keys %part_acct_svc ]; + $^W=1; + $return; +} +sub getforwardpart { + $^W=0; # Term::Query isn't -w-safe + my $return = query "Enter part number:", 'irk', [ keys %part_forward_svc ]; + $^W=1; + $return; +} + + +#migrate data + +my(@svc_accts) = qsearch('svc_acct', {}); +foreach $svc_acct (@svc_accts) { + my(@svc_acct_sms) = qsearch('svc_acct_sm', { + domuid => $svc_acct->getfield('uid'), + } + ); + + # Ok.. we've got the svc_acct record, and an array of svc_acct_sm's + # What do we do from here? + + # The intuitive: + # plop the svc_acct into the 'default domain' + # and then represent the svc_acct_sm's with svc_forwards + # they can be gussied up manually, later + # + # Perhaps better: + # when no svc_acct_sm exists, place svc_acct in 'default domain' + # when one svc_acct_sm exists, place svc_acct in corresponding + # domain & possibly create a svc_forward in 'default domain' + # when multiple svc_acct_sm's exists (in different domains) we'd + # better use the 'intuitive' approach. + # + # Specific way: + # as 'perhaps better,' but we may be able to guess which domain + # is correct by comparing the svcnum of domains to the username + # of the svc_acct + # + + # The intuitive way: + + my $def_acct = new FS::svc_acct ( { $svc_acct->hash } ); + $def_acct->setfield('domsvc' => $svc_domain->getfield('svcnum')); + $error = $def_acct->replace($svc_acct); + die "Error replacing svc_acct for " . $def_acct->username . " : $error" if $error; + + foreach $svc_acct_sm (@svc_acct_sms) { + + my($domrec)=qsearchs('svc_domain', { + svcnum => $svc_acct_sm->getfield('domsvc'), + }) || die "svc_acct_sm references invalid domsvc $svc_acct_sm->getfield('domsvc')\n"; + + if ($svc_acct_sm->getfield('domuser') =~ /^\*$/) { + + my($newdom) = new FS::svc_domain ( { $domrec->hash } ); + $newdom->setfield('catchall', $svc_acct->svcnum); + $newdom->setfield('action', "M"); + $error = $newdom->replace($domrec); + die "Error replacing svc_domain for (anything)@" . $domrec->domain . " : $error" if $error; + + } else { + + my($newacct) = new FS::svc_acct { + 'svcpart' => $pop_svcpart, + 'username' => $svc_acct_sm->getfield('domuser'), + 'domsvc' => $svc_acct_sm->getfield('domsvc'), + 'dir' => '/dev/null', + }; + $error = $newacct->insert; + die "Error adding svc_acct for " . $newacct->username . " : $error" if $error; + + my($newforward) = new FS::svc_forward { + 'svcpart' => $forward_svcpart, + 'srcsvc' => $newacct->getfield('svcnum'), + 'dstsvc' => $def_acct->getfield('svcnum'), + }; + $error = $newforward->insert; + die "Error adding svc_forward for " . $newacct->username ." : $error" if $error; + } + + $error = $svc_acct_sm->delete; + die "Error deleting svc_acct_sm for " . $svc_acct_sm->domuser ." : $error" if $error; + + }; + +}; + + +$dbh->commit or die $dbh->errstr; +$dbh->disconnect or die $dbh->errstr; + +print "svc_acct_sm records sucessfully migrated\n"; + +sub usage { + die "Usage:\n fs-migrate-svc_acct_sm user\n"; +} + diff --git a/bin/fs-radius-add-check b/bin/fs-radius-add-check new file mode 100755 index 000000000..92523eb95 --- /dev/null +++ b/bin/fs-radius-add-check @@ -0,0 +1,52 @@ +#!/usr/bin/perl -Tw + +# quick'n'dirty hack of fs-setup to add radius attributes + +use strict; +use DBI; +use FS::UID qw(adminsuidsetup checkeuid getsecrets); +die "Not running uid freeside!" unless checkeuid(); + +my $user = shift or die &usage; +getsecrets($user); + +my $dbh = adminsuidsetup $user; + +### + +print "\n\n", <<END, ":"; +Enter the additional RADIUS check attributes you need to track for +each user, separated by whitespace. +END +my @attributes = map { s/\-/_/g; $_; } split(" ",&getvalue); + +sub getvalue { + my($x)=scalar(<STDIN>); + chop $x; + $x; +} + +### + +my($char_d) = 80; #default maxlength for text fields + +### + +foreach my $attribute ( @attributes ) { + foreach my $statement ( + "ALTER TABLE svc_acct ADD rc_$attribute varchar($char_d) NULL", + "ALTER TABLE part_svc ADD svc_acct__rc_$attribute varchar($char_d) NULL;", + "ALTER TABLE part_svc ADD svc_acct__rc_${attribute}_flag char(1) NULL;", + ) { + $dbh->do( $statement ) or warn "Error executing $statement: ". $dbh->errstr; } +} + +$dbh->disconnect or die $dbh->errstr; + +print "\n\n", "Now you must run dbdef-create.\n\n"; + +sub usage { + die "Usage:\n fs-radius-add user\n"; +} + + diff --git a/bin/fs-radius-add-reply b/bin/fs-radius-add-reply new file mode 100755 index 000000000..7938feac6 --- /dev/null +++ b/bin/fs-radius-add-reply @@ -0,0 +1,52 @@ +#!/usr/bin/perl -Tw + +# quick'n'dirty hack of fs-setup to add radius attributes + +use strict; +use DBI; +use FS::UID qw(adminsuidsetup checkeuid getsecrets); +die "Not running uid freeside!" unless checkeuid(); + +my $user = shift or die &usage; +getsecrets($user); + +my $dbh = adminsuidsetup $user; + +### + +print "\n\n", <<END, ":"; +Enter the additional RADIUS reply attributes you need to track for +each user, separated by whitespace. +END +my @attributes = map { s/\-/_/g; $_; } split(" ",&getvalue); + +sub getvalue { + my($x)=scalar(<STDIN>); + chop $x; + $x; +} + +### + +my($char_d) = 80; #default maxlength for text fields + +### + +foreach my $attribute ( @attributes ) { + foreach my $statement ( + "ALTER TABLE svc_acct ADD radius_$attribute varchar($char_d) NULL", + "ALTER TABLE part_svc ADD svc_acct__radius_$attribute varchar($char_d) NULL;", + "ALTER TABLE part_svc ADD svc_acct__radius_${attribute}_flag char(1) NULL;", + ) { + $dbh->do( $statement ) or warn "Error executing $statement: ". $dbh->errstr; } +} + +$dbh->disconnect or die $dbh->errstr; + +print "\n\n", "Now you must run dbdef-create.\n\n"; + +sub usage { + die "Usage:\n fs-radius-add user\n"; +} + + diff --git a/bin/fs-setup b/bin/fs-setup index 45332d85c..a3e067bec 100755 --- a/bin/fs-setup +++ b/bin/fs-setup @@ -1,6 +1,6 @@ #!/usr/bin/perl -Tw # -# create database and necessary tables, etc. DBI version. +# $Id: fs-setup,v 1.41 2001-08-12 19:41:25 jeff Exp $ # # ivan@sisd.com 97-nov-8,9 # @@ -30,19 +30,145 @@ # ivan@sisd.com 98-sep-4 # # fix radius attributes ivan@sisd.com 98-sep-27 +# +# $Log: fs-setup,v $ +# Revision 1.41 2001-08-12 19:41:25 jeff +# merging vpopmail support branch +# +# Revision 1.40 2001/08/11 05:53:42 ivan +# add comments field +# +# Revision 1.39 2001/07/30 07:42:39 ivan +# need an DBIx::DBSchema with delcolumn +# +# Revision 1.38 2001/07/30 07:36:04 ivan +# templates!!! +# +# Revision 1.37 2001/06/03 14:16:11 ivan +# allow empty refund reasons +# +# Revision 1.36 2001/04/15 12:56:31 ivan +# s/dbdef/DBIx::DBSchema/ +# +# Revision 1.35 2001/04/15 09:36:43 ivan +# http://www.sisd.com/freeside/list-archive/msg01450.html +# +# Revision 1.34 2001/04/09 23:05:16 ivan +# Transactions Part I!!! +# +# Revision 1.33 2001/02/03 14:03:50 ivan +# time-based prepaid cards, session monitor. woop! +# +# Revision 1.32 2000/12/04 00:13:02 ivan +# fix nas.last type +# +# Revision 1.31 2000/12/01 18:34:53 ivan +# another tyop +# +# Revision 1.30 2000/12/01 18:33:32 ivan +# tyop +# +# Revision 1.29 2000/11/07 15:00:37 ivan +# session monitor +# +# Revision 1.28 2000/10/30 10:47:26 ivan +# nas.last can't be defined NULL if indexed +# +# 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 +# support for pre-encrypted md5 passwords. +# +# Revision 1.24 2000/03/02 07:44:07 ivan +# typo forgot closing ' +# +# Revision 1.23 2000/02/03 05:16:52 ivan +# beginning of DNS and Apache support +# +# Revision 1.22 2000/01/31 05:22:23 ivan +# prepaid "internet cards" +# +# Revision 1.21 2000/01/30 06:03:26 ivan +# postgres 6.5 finally supports decimal(10,2) +# +# Revision 1.20 2000/01/28 22:53:33 ivan +# track full phone number +# +# Revision 1.19 1999/07/29 08:50:35 ivan +# wrong type for cust_pay_batch.exp +# +# Revision 1.18 1999/04/15 22:46:30 ivan +# TT isn't a state! +# +# Revision 1.17 1999/04/14 07:58:39 ivan +# export getsecrets from FS::UID instead of calling it explicitly +# +# Revision 1.16 1999/02/28 19:44:16 ivan +# constructors s/create/new/ pointed out by "Bao C. Ha" <bao@hacom.net> +# +# Revision 1.15 1999/02/27 21:06:21 ivan +# cust_main.paydate should be varchar(10), not @date_type ; problem reported +# by Ben Leibig <leibig@colorado.edu> +# +# Revision 1.14 1999/02/07 09:59:14 ivan +# more mod_perl fixes, and bugfixes Peter Wemm sent via email +# +# Revision 1.13 1999/02/04 06:09:23 ivan +# add AU provences +# +# Revision 1.12 1999/02/03 10:42:27 ivan +# *** empty log message *** +# +# Revision 1.11 1999/01/17 03:11:52 ivan +# remove preliminary completehost changes +# +# Revision 1.10 1998/12/16 06:05:38 ivan +# add table cust_main_invoice +# +# Revision 1.9 1998/12/15 04:36:29 ivan +# s/croak/die/; #oops +# +# Revision 1.8 1998/12/15 04:33:27 ivan +# dies if it isn't running as the freeside user +# +# Revision 1.7 1998/11/18 09:01:31 ivan +# i18n! i18n! +# +# Revision 1.6 1998/11/15 13:18:02 ivan +# remove debugging +# +# Revision 1.5 1998/11/15 09:43:03 ivan +# update for new config file syntax, new adminsuidsetup +# +# Revision 1.4 1998/10/22 15:51:23 ivan +# also varchar with no length specified - postgresql fix broke mysql. +# +# Revision 1.3 1998/10/22 15:46:28 ivan +# now smallint is illegal, so remove that too. +# #to delay loading dbdef until we're ready BEGIN { $FS::Record::setup_hack = 1; } use strict; use DBI; -use FS::dbdef; -use FS::UID qw(adminsuidsetup datasrc); +use DBIx::DBSchema 0.18; +use DBIx::DBSchema::Table; +use DBIx::DBSchema::Column; +use DBIx::DBSchema::ColGroup::Unique; +use DBIx::DBSchema::ColGroup::Index; +use FS::UID qw(adminsuidsetup datasrc checkeuid getsecrets); use FS::Record; use FS::cust_main_county; +die "Not running uid freeside!" unless checkeuid(); + +my $user = shift or die &usage; +getsecrets($user); + #needs to match FS::Record -my($dbdef_file) = "/var/spool/freeside/dbdef.". datasrc; +my($dbdef_file) = "/usr/local/etc/freeside/dbdef.". datasrc; ### @@ -50,31 +176,45 @@ print "\nEnter the maximum username length: "; my($username_len)=&getvalue; print "\n\n", <<END, ":"; -Freeside tracks the RADIUS attributes User-Name, Password and Framed-IP-Address -for each user. Enter any additional RADIUS attributes you need to track for -each user, separated by whitespace. +Freeside tracks the RADIUS attributes User-Name, check attribute Password and +reply attribute Framed-IP-Address for each user. You can specify additional +check and reply attributes. First enter any additional RADIUS check attributes +you need to track for each user, separated by whitespace. +END +my @check_attributes = map { s/\-/_/g; $_; } split(" ",&getvalue); + +print "\n\n", <<END, ":"; +Now enter any additional reply attributes you need to track for each user, +separated by whitespace. END my @attributes = map { s/\-/_/g; $_; } split(" ",&getvalue); +print "\n\n", <<END, ":"; +Do you wish to enable the tracking of a second, separate shipping/service +address? +END +my $ship = &_yesno; + sub getvalue { my($x)=scalar(<STDIN>); chop $x; $x; } +sub _yesno { + print " [y/N]:"; + my $x = scalar(<STDIN>); + $x =~ /^y/i; +} + ### my($char_d) = 80; #default maxlength for text fields #my(@date_type) = ( 'timestamp', '', '' ); my(@date_type) = ( 'int', 'NULL', '' ); -my(@perl_type) = ( 'long varchar', 'NULL', '' ); -my(@money_type); -if (datasrc =~ m/Pg/) { #Pg can't do decimal(10,2) - @money_type = ( 'money', '', '' ); -} else { - @money_type = ( 'decimal', '', '10,2' ); -} +my(@perl_type) = ( 'varchar', 'NULL', 255 ); +my @money_type = ( 'decimal', '', '10,2' ); ### # create a dbdef object from the old data structure @@ -83,30 +223,34 @@ if (datasrc =~ m/Pg/) { #Pg can't do decimal(10,2) my(%tables)=&tables_hash_hack; #turn it into objects -my($dbdef) = new FS::dbdef ( map { +my($dbdef) = new DBIx::DBSchema ( map { my(@columns); while (@{$tables{$_}{'columns'}}) { my($name,$type,$null,$length)=splice @{$tables{$_}{'columns'}}, 0, 4; - push @columns, new FS::dbdef_column ( $name,$type,$null,$length ); + push @columns, new DBIx::DBSchema::Column ( $name,$type,$null,$length ); } - FS::dbdef_table->new( + DBIx::DBSchema::Table->new( $_, $tables{$_}{'primary_key'}, - #FS::dbdef_unique->new(@{$tables{$_}{'unique'}}), - #FS::dbdef_index->new(@{$tables{$_}{'index'}}), - FS::dbdef_unique->new($tables{$_}{'unique'}), - FS::dbdef_index->new($tables{$_}{'index'}), + DBIx::DBSchema::ColGroup::Unique->new($tables{$_}{'unique'}), + DBIx::DBSchema::ColGroup::Index->new($tables{$_}{'index'}), @columns, ); } (keys %tables) ); +#remove ship_ from cust_main +unless ($ship) { + my $cust_main = $dbdef->table('cust_main'); + $cust_main->delcolumn($_) foreach ( grep /^ship_/, $cust_main->columns ); +} + #add radius attributes to svc_acct my($svc_acct)=$dbdef->table('svc_acct'); my($attribute); foreach $attribute (@attributes) { - $svc_acct->addcolumn ( new FS::dbdef_column ( + $svc_acct->addcolumn ( new DBIx::DBSchema::Column ( 'radius_'. $attribute, 'varchar', 'NULL', @@ -114,6 +258,15 @@ foreach $attribute (@attributes) { )); } +foreach $attribute (@check_attributes) { + $svc_acct->addcolumn( new DBIx::DBSchema::Column ( + 'rc_'. $attribute, + 'varchar', + 'NULL', + $char_d, + )); +} + #make part_svc table (but now as object) my($part_svc)=$dbdef->table('part_svc'); @@ -121,18 +274,18 @@ my($part_svc)=$dbdef->table('part_svc'); #because of svc_acct_pop #foreach (grep /^svc_/, $dbdef->tables) { #foreach (qw(svc_acct svc_acct_sm svc_charge svc_domain svc_wo)) { -foreach (qw(svc_acct svc_acct_sm svc_domain)) { +foreach (qw(svc_acct svc_acct_sm svc_domain svc_forward svc_www)) { my($table)=$dbdef->table($_); my($col); foreach $col ( $table->columns ) { next if $col =~ /^svcnum$/; - $part_svc->addcolumn( new FS::dbdef_column ( + $part_svc->addcolumn( new DBIx::DBSchema::Column ( $table->name. '__' . $table->column($col)->name, 'varchar', #$table->column($col)->type, 'NULL', $char_d, #$table->column($col)->length, )); - $part_svc->addcolumn ( new FS::dbdef_column ( + $part_svc->addcolumn ( new DBIx::DBSchema::Column ( $table->name. '__'. $table->column($col)->name . "_flag", 'char', 'NULL', @@ -143,45 +296,73 @@ foreach (qw(svc_acct svc_acct_sm svc_domain)) { #important $dbdef->save($dbdef_file); -FS::Record::reload_dbdef; +&FS::Record::reload_dbdef($dbdef_file); ### # create 'em ### -my($dbh)=adminsuidsetup; +my($dbh)=adminsuidsetup $user; #create tables $|=1; -my($table); -foreach ($dbdef->tables) { - my($table)=$dbdef->table($_); - print "Creating $_..."; - - my($statement); - - #create table - foreach $statement ($table->sql_create_table(datasrc)) { - #print $statement, "\n"; - $dbh->do( $statement ) - or die "CREATE error: ",$dbh->errstr, "\ndoing statement: $statement"; - } - - print "\n"; +my @sql = $dbdef->sql($dbh); +foreach my $statement ( $dbdef->sql($dbh) ) { + $dbh->do( $statement ) + or die "CREATE error: ",$dbh->errstr, "\ndoing statement: $statement"; } #not really sample data (and shouldn't default to US) #cust_main_county + +#USPS state codes foreach ( qw( AL AK AS AZ AR CA CO CT DC DE FM FL GA GU HI ID IL IN IA KS KY LA ME MH MD MA MI MN MS MO MT NC ND NE NH NJ NM NV NY MP OH OK OR PA PW PR RI -SC SD TN TX TT UT VT VI VA WA WV WI WY AE AA AP +SC SD TN TX UT VT VI VA WA WV WI WY AE AA AP +) ) { + my($cust_main_county)=new FS::cust_main_county({ + 'state' => $_, + 'tax' => 0, + 'country' => 'US', + }); + my($error); + $error=$cust_main_county->insert; + die $error if $error; +} + +#AU "offical" state codes ala mark.williamson@ebbs.com.au (Mark Williamson) +foreach ( qw( +VIC NSW NT QLD TAS ACT WA SA ) ) { - my($cust_main_county)=create FS::cust_main_county({ + my($cust_main_county)=new FS::cust_main_county({ 'state' => $_, 'tax' => 0, + 'country' => 'AU', + }); + my($error); + $error=$cust_main_county->insert; + die $error if $error; +} + +#ISO 2-letter country codes (same as country TLDs) except US and AU +foreach ( qw( +AF AL DZ AS AD AO AI AQ AG AR AM AW AT AZ BS BH BD BB BY BE BZ BJ BM BT BO +BA BW BV BR IO BN BG BF BI KH CM CA CV KY CF TD CL CN CX CC CO KM CG CK CR CI +HR CU CY CZ DK DJ DM DO TP EC EG SV GQ ER EE ET FK FO FJ FI FR FX GF PF TF GA +GM GE DE GH GI GR GL GD GP GU GT GN GW GY HT HM HN HK HU IS IN ID IR IQ IE IL +IT JM JP JO KZ KE KI KP KR KW KG LA LV LB LS LR LY LI LT LU MO MK MG MW MY MV +ML MT MH MQ MR MU YT MX FM MD MC MN MS MA MZ MM NA NR NP NL AN NC NZ NI NE NG +NU NF MP NO OM PK PW PA PG PY PE PH PN PL PT PR QA RE RO RU RW KN LC VC WS SM +ST SA SN SC SL SG SK SI SB SO ZA GS ES LK SH PM SD SR SJ SZ SE CH SY TW TJ TZ +TH TG TK TO TT TN TR TM TC TV UG UA AE GB UM UY UZ VU VA VE VN VG VI WF EH +YE YU ZR ZM ZW +) ) { + my($cust_main_county)=new FS::cust_main_county({ + 'tax' => 0, + 'country' => $_, }); my($error); $error=$cust_main_county->insert; @@ -190,6 +371,12 @@ SC SD TN TX TT UT VT VI VA WA WV WI WY AE AA AP $dbh->disconnect or die $dbh->errstr; +print "Freeside database initialized sucessfully\n"; + +sub usage { + die "Usage:\n fs-setup user\n"; +} + ### # Now it becomes an object. much better. ### @@ -206,7 +393,7 @@ sub tables_hash_hack { 'agentnum', 'int', '', '', 'agent', 'varchar', '', $char_d, 'typenum', 'int', '', '', - 'freq', 'smallint', 'NULL', '', + 'freq', 'int', 'NULL', '', 'prog', @perl_type, ], 'primary_key' => 'agentnum', @@ -240,7 +427,6 @@ sub tables_hash_hack { 'custnum', 'int', '', '', '_date', @date_type, 'charged', @money_type, - 'owed', @money_type, 'printed', 'int', '', '', ], 'primary_key' => 'invnum', @@ -268,9 +454,8 @@ sub tables_hash_hack { 'custnum', 'int', '', '', '_date', @date_type, 'amount', @money_type, - 'credited', @money_type, 'otaker', 'varchar', '', 8, - 'reason', 'varchar', '', 255, + 'reason', 'varchar', 'NULL', 255, ], 'primary_key' => 'crednum', 'unique' => [ [] ], @@ -281,7 +466,9 @@ sub tables_hash_hack { 'columns' => [ 'custnum', 'int', '', '', 'agentnum', 'int', '', '', +# 'titlenum', 'int', 'NULL', '', 'last', 'varchar', '', $char_d, +# 'middle', 'varchar', 'NULL', $char_d, 'first', 'varchar', '', $char_d, 'ss', 'char', 'NULL', 11, 'company', 'varchar', 'NULL', $char_d, @@ -289,19 +476,35 @@ sub tables_hash_hack { 'address2', 'varchar', 'NULL', $char_d, 'city', 'varchar', '', $char_d, 'county', 'varchar', 'NULL', $char_d, - 'state', 'char', '', 2, + 'state', 'varchar', 'NULL', $char_d, 'zip', 'varchar', '', 10, 'country', 'char', '', 2, 'daytime', 'varchar', 'NULL', 20, 'night', 'varchar', 'NULL', 20, 'fax', 'varchar', 'NULL', 12, + 'ship_last', 'varchar', 'NULL', $char_d, +# 'ship_middle', 'varchar', 'NULL', $char_d, + 'ship_first', 'varchar', 'NULL', $char_d, + 'ship_company', 'varchar', 'NULL', $char_d, + 'ship_address1', 'varchar', 'NULL', $char_d, + 'ship_address2', 'varchar', 'NULL', $char_d, + 'ship_city', 'varchar', 'NULL', $char_d, + 'ship_county', 'varchar', 'NULL', $char_d, + 'ship_state', 'varchar', 'NULL', $char_d, + 'ship_zip', 'varchar', 'NULL', 10, + 'ship_country', 'char', 'NULL', 2, + 'ship_daytime', 'varchar', 'NULL', 20, + 'ship_night', 'varchar', 'NULL', 20, + 'ship_fax', 'varchar', 'NULL', 12, 'payby', 'char', '', 4, 'payinfo', 'varchar', 'NULL', 16, - 'paydate', @date_type, + #'paydate', @date_type, + 'paydate', 'varchar', 'NULL', 10, 'payname', 'varchar', 'NULL', $char_d, 'tax', 'char', 'NULL', 1, 'otaker', 'varchar', '', 8, 'refnum', 'int', '', '', + 'comments', 'varchar', 'NULL', '', ], 'primary_key' => 'custnum', 'unique' => [ [] ], @@ -309,13 +512,25 @@ sub tables_hash_hack { 'index' => [ ['last'], ], }, - 'cust_main_county' => { #county+state are checked off the cust_main_county - #table for validation and to provide a tax rate. - #add country? + 'cust_main_invoice' => { + 'columns' => [ + 'destnum', 'int', '', '', + 'custnum', 'int', '', '', + 'dest', 'varchar', '', $char_d, + ], + 'primary_key' => 'destnum', + 'unique' => [ [] ], + 'index' => [ ['custnum'], ], + }, + + 'cust_main_county' => { #county+state+country are checked off the + #cust_main_county for validation and to provide + # a tax rate. 'columns' => [ 'taxnum', 'int', '', '', - 'state', 'char', '', 2, #two letters max in US... elsewhere? - 'county', 'varchar', '', $char_d, + 'state', 'varchar', 'NULL', $char_d, + 'county', 'varchar', 'NULL', $char_d, + 'country', 'char', '', 2, 'tax', 'real', '', '', #tax % ], 'primary_key' => 'taxnum', @@ -350,12 +565,13 @@ sub tables_hash_hack { 'address1', 'varchar', '', $char_d, 'address2', 'varchar', 'NULL', $char_d, 'city', 'varchar', '', $char_d, - 'state', 'char', '', 2, + 'state', 'varchar', '', $char_d, 'zip', 'varchar', '', 10, 'country', 'char', '', 2, - 'trancode', 'TINYINT', '', '', + 'trancode', 'int', '', '', 'cardnum', 'varchar', '', 16, - 'exp', @date_type, + #'exp', @date_type, + 'exp', 'varchar', '', 11, 'payname', 'varchar', 'NULL', $char_d, 'amount', @money_type, ], @@ -401,7 +617,7 @@ sub tables_hash_hack { 'cust_svc' => { 'columns' => [ 'svcnum', 'int', '', '', - 'pkgnum', 'int', '', '', + 'pkgnum', 'int', 'NULL', '', 'svcpart', 'int', '', '', ], 'primary_key' => 'svcnum', @@ -415,7 +631,7 @@ sub tables_hash_hack { 'pkg', 'varchar', '', $char_d, 'comment', 'varchar', '', $char_d, 'setup', @perl_type, - 'freq', 'smallint', '', '', #billing frequency (months) + 'freq', 'int', '', '', #billing frequency (months) 'recur', @perl_type, ], 'primary_key' => 'pkgpart', @@ -423,6 +639,16 @@ sub tables_hash_hack { 'index' => [ [] ], }, +# 'part_title' => { +# 'columns' => [ +# 'titlenum', 'int', '', '', +# 'title', 'varchar', '', $char_d, +# ], +# 'primary_key' => 'titlenum', +# 'unique' => [ [] ], +# 'index' => [ [] ], +# }, + 'pkg_svc' => { 'columns' => [ 'pkgpart', 'int', '', '', @@ -460,10 +686,10 @@ sub tables_hash_hack { 'columns' => [ 'popnum', 'int', '', '', 'city', 'varchar', '', $char_d, - 'state', 'char', '', 2, + 'state', 'varchar', '', $char_d, 'ac', 'char', '', 3, 'exch', 'char', '', 3, - #rest o' number? + 'loc', 'char', 'NULL', 4, #NULL for legacy purposes ], 'primary_key' => 'popnum', 'unique' => [ [] ], @@ -474,26 +700,28 @@ sub tables_hash_hack { 'columns' => [ 'svcnum', 'int', '', '', 'username', 'varchar', '', $username_len, #unique (& remove dup code) - '_password', 'varchar', '', 25, #13 for encryped pw's plus ' *SUSPENDED* + '_password', 'varchar', '', 50, #13 for encryped pw's plus ' *SUSPENDED* (mp5 passwords can be 34) 'popnum', 'int', 'NULL', '', - 'uid', 'bigint', 'NULL', '', - 'gid', 'bigint', 'NULL', '', + 'uid', 'int', 'NULL', '', + 'gid', 'int', 'NULL', '', 'finger', 'varchar', 'NULL', $char_d, 'dir', 'varchar', 'NULL', $char_d, 'shell', 'varchar', 'NULL', $char_d, 'quota', 'varchar', 'NULL', $char_d, 'slipip', 'varchar', 'NULL', 15, #four TINYINTs, bah. + 'seconds', 'int', 'NULL', '', #uhhhh + 'domsvc', 'int', '', '', ], 'primary_key' => 'svcnum', 'unique' => [ [] ], - 'index' => [ ['username'] ], + 'index' => [ ['username'], ['domsvc'] ], }, 'svc_acct_sm' => { 'columns' => [ 'svcnum', 'int', '', '', 'domsvc', 'int', '', '', - 'domuid', 'bigint', '', '', + 'domuid', 'int', '', '', 'domuser', 'varchar', '', $char_d, ], 'primary_key' => 'svcnum', @@ -515,12 +743,50 @@ sub tables_hash_hack { 'columns' => [ 'svcnum', 'int', '', '', 'domain', 'varchar', '', $char_d, + 'catchall', 'int', '', '', ], 'primary_key' => 'svcnum', 'unique' => [ ['domain'] ], 'index' => [ [] ], }, + 'domain_record' => { + 'columns' => [ + 'recnum', 'int', '', '', + 'svcnum', 'int', '', '', + 'reczone', 'varchar', '', $char_d, + 'recaf', 'char', '', 2, + 'rectype', 'char', '', 5, + 'recdata', 'varchar', '', $char_d, + ], + 'primary_key' => 'recnum', + 'unique' => [ [] ], + 'index' => [ ['svcnum'] ], + }, + + 'svc_forward' => { + 'columns' => [ + 'svcnum', 'int', '', '', + 'srcsvc', 'int', '', '', + 'dstsvc', 'int', '', '', + 'dst', 'varchar', 'NULL', $char_d, + ], + 'primary_key' => 'svcnum', + 'unique' => [ [] ], + 'index' => [ ['srcsvc'], ['dstsvc'] ], + }, + + 'svc_www' => { + 'columns' => [ + 'svcnum', 'int', '', '', + 'recnum', 'int', '', '', + 'usersvc', 'int', '', '', + ], + 'primary_key' => 'svcnum', + 'unique' => [ [] ], + 'index' => [ [] ], + }, + #'svc_wo' => { # 'columns' => [ # 'svcnum', 'int', '', '', @@ -534,6 +800,56 @@ sub tables_hash_hack { # 'index' => [ [] ], #}, + 'prepay_credit' => { + 'columns' => [ + 'prepaynum', 'int', '', '', + 'identifier', 'varchar', '', $char_d, + 'amount', @money_type, + 'seconds', 'int', 'NULL', '', + ], + 'primary_key' => 'prepaynum', + 'unique' => [ ['identifier'] ], + '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', 'int', '', '', + ], + 'primary_key' => 'nasnum', + 'unique' => [ [ 'nas' ], [ 'nasip' ] ], + 'index' => [ [ 'last' ] ], + }, + + 'session' => { + 'columns' => [ + 'sessionnum', 'int', '', '', + 'portnum', 'int', '', '', + 'svcnum', 'int', '', '', + 'login', @date_type, + 'logout', @date_type, + ], + 'primary_key' => 'sessionnum', + 'unique' => [], + 'index' => [ [ 'portnum' ] ], + }, + ); %tables; diff --git a/bin/generate-prepay b/bin/generate-prepay new file mode 100755 index 000000000..cb4ba7fc6 --- /dev/null +++ b/bin/generate-prepay @@ -0,0 +1,35 @@ +#!/usr/bin/perl -w + +use strict; +use FS::UID qw(adminsuidsetup); +use FS::prepay_credit; + +require 5.004; #srand(time|$$); + +my $user = shift or die &usage; +&adminsuidsetup( $user ); + +my $amount = shift or die &usage; + +my $seconds = shift or die &usage; + +my $num_digits = shift or die &usage; + +my $num_entries = shift or die &usage; + +for ( 1 .. $num_entries ) { + my $identifier = join( '', map int(rand(10)), ( 1 .. $num_digits ) ); + my $prepay_credit = new FS::prepay_credit { + 'identifier' => $identifier, + 'amount' => $amount, + 'seconds' => $seconds, + }; + my $error = $prepay_credit->insert; + die $error if $error; + print "$identifier\n"; +} + +sub usage { + die "Usage:\n\n generate-prepay user amount seconds num_digits num_entries"; +} + diff --git a/bin/masonize b/bin/masonize new file mode 100755 index 000000000..475c9a6bf --- /dev/null +++ b/bin/masonize @@ -0,0 +1,70 @@ +#!/usr/bin/perl + +foreach $file ( split(/\n/, `find . -depth -print | grep cgi\$`) ) { + open(F,$file) or die "can't open $file for reading: $!"; + @file = <F>; + #print "$file ". scalar(@file). "\n"; + close $file; + system("chmod u+w $file"); + open(W,">$file") or die "can't open $file for writing: $!"; + select W; $| = 1; select STDOUT; + $all = join('',@file); + + $mode = 'html'; + while ( length($all) ) { + + if ( $mode eq 'html' ) { + + if ( $all =~ /^(.+?)(<%=?.*)$/s && $1 !~ /<%/s ) { + print W $1; + $all = $2; + next; + } elsif ( $all =~ /^<%=(.*)$/s ) { + print W '<%'; + $all = $1; + $mode = 'perlv'; + #die; + next; + } elsif ( $all =~ /^<%(.*)$/s ) { + print W "\n"; + $all = $1; + $mode = 'perlc'; + next; + } elsif ( $all !~ /<%/s ) { + print W $all; + last; + } else { + warn length($all); die; + } + die; + + } elsif ( $mode eq 'perlv' ) { + + if ( $all =~ /^(.*?%>)(.*)$/s ) { + print W $1; + $all=$2; + $mode = 'html'; + next; + } + die 'unterminated <%= ???'; + + } elsif ( $mode eq 'perlc' ) { + + if ( $all =~ /^([^\n]*?)%>(.*)$/s ) { + print W "%$1\n"; + $all=$2; + $mode='html'; + next; + } + if ( $all =~ /^([^\n]*)\n(.*)$/s ) { + print W "%$1\n"; + $all=$2; + next; + } + + } else { die }; + + } + + close W; +} @@ -3,21 +3,29 @@ #use Pod::Text; #$Pod::Text::termcap=1; -my $site_perl = "./site_perl"; +my $site_perl = "./FS"; #my $catman = "./catman"; -my $catman = "./htdocs/docs/man"; +#my $catman = "./htdocs/docs/man"; #my $html = "./htdocs/docs/man"; +my $html = "./httemplate/docs/man"; $|=1; -die "Can't find $site_perl and $catman" - unless [ -d $site_perl ] && [ -d $catman ] && [ -d $html ]; +die "Can't find $site_perl" unless -d $site_perl; +#die "Can't find $catman" unless -d $catman; +die "Can't find $html" unless -d $html; -foreach my $file (glob("$site_perl/*.pm")) { - $file =~ /\/([\w\-]+)\.pm$/ or die "oops file $file"; +foreach my $file ( + glob("$site_perl/*.pm"), + glob("$site_perl/*/*.pm"), + glob("$site_perl/*/*/*.pm") +) { + #$file =~ /\/([\w\-]+)\.pm$/ or die "oops file $file"; + $file =~ /$site_perl\/(.*)\.pm$/ or die "oops file $file"; my $name = $1; - print "$name\n"; - system "pod2text $file >$catman/$name.txt"; -# system "pod2html --podpath=$site_perl $file >$html/$name.html"; + print "$name\n"; + my $htmlroot = join('/', map '..',1..(scalar($file =~ tr/\///)-2)) || '.'; +# system "pod2text $file >$catman/$name.txt"; + system "pod2html --podroot=$site_perl --podpath=./FS:./FS/UI:. --norecurse --htmlroot=$htmlroot $file >$html/$name.html"; # system "pod2html $file >$html/$name.html"; } diff --git a/bin/svc_acct.export b/bin/svc_acct.export index 3f65a08ba..a7a21b3e5 100755 --- a/bin/svc_acct.export +++ b/bin/svc_acct.export @@ -1,108 +1,106 @@ -#!/usr/bin/perl -Tw +#!/usr/bin/perl -w # -# Create and export password files: passwd, passwd.adjunct, shadow, -# acp_passwd, acp_userinfo, acp_dialup, users +# $Id: svc_acct.export,v 1.22 2001-08-12 19:41:25 jeff Exp $ # -# ivan@voicenet.com late august/september 96 -# (the password encryption bits were from melody) +# Create and export password, radius and vpopmail password files: +# passwd, passwd.adjunct, shadow, acp_passwd, acp_userinfo, acp_dialup +# users/assign, domains/vdomain/vpasswd +# Also export sendmail and qmail config files. # -# use a temporary copy of svc_acct to minimize lock time on the real file, -# and skip blank entries. # -# ivan@voicenet.com 96-Oct-6 +# $Log: svc_acct.export,v $ +# Revision 1.22 2001-08-12 19:41:25 jeff +# merging vpopmail support branch # -# change users / acp_dialup file formats -# ivan@voicenet.com 97-jan-28-31 # -# change priority (after copies) to 19, not 10 -# ivan@voicenet.com 97-feb-5 -# -# added exit if stuff is already locked 97-apr-15 -# -# rewrite ivan@sisd.com 98-mar-9 -# -# Changed 'password' to '_password' because Pg6.3 reserves this word -# Added code to create a FreeBSD style master.passwd file -# bmccane@maxbaud.net 98-Apr-3 -# -# don't export non-root 0 UID's, even if they get put in the database -# ivan@sisd.com 98-jul-14 -# -# Uses Idle_Timeout, Port_Limit, Framed_Netmask and Framed_Route if they -# exist; need some way to support arbitrary radius fields. also -# /var/spool/freeside/conf/ ivan@sisd.com 98-jul-26, aug-9 -# -# OOPS! added arbitrary radius fields (pry 98-aug-16) but forgot to say so. -# ivan@sisd.com 98-sep-18 use strict; +use vars qw($conf); +use Archive::Tar; use Fcntl qw(:flock); -use FS::SSH qw(scp ssh); -use FS::UID qw(adminsuidsetup); -use FS::Record qw(qsearch fields); - -my($fshellmachines)="/var/spool/freeside/conf/shellmachines"; -my(@shellmachines); -if ( -e $fshellmachines ) { - open(SHELLMACHINES,$fshellmachines); - @shellmachines=map { - /^(.*)$/ or die "Illegal line in conf/shellmachines"; #we trust the file - $1; - } grep $_ !~ /^(#|$)/, <SHELLMACHINES>; - close SHELLMACHINES; +use File::Path; +use IO::Handle; +use FS::Conf; +use Net::SSH qw(ssh); +use Net::SCP qw(scp); +use FS::UID qw(adminsuidsetup datasrc dbh); +use FS::Record qw(qsearch qsearchs fields); +use FS::svc_acct; +use FS::svc_domain; +use FS::svc_forward; + +my $user = shift or die &usage; +adminsuidsetup $user; + +$conf = new FS::Conf; + +my $userpolicy = $conf->config('username_policy') + if $conf->exists('username_policy'); + +my @shellmachines = $conf->config('shellmachines') + if $conf->exists('shellmachines'); + +my @bsdshellmachines = $conf->config('bsdshellmachines') + if $conf->exists('bsdshellmachines'); + +my @nismachines = $conf->config('nismachines') + if $conf->exists('nismachines'); + +my @erpcdmachines = $conf->config('erpcdmachines') + if $conf->exists('erpcdmachines'); + +my @radiusmachines = $conf->config('radiusmachines') + if $conf->exists('radiusmachines'); + +my $icradiusmachines = $conf->exists('icradiusmachines'); +my @icradiusmachines = $conf->config('icradiusmachines') if $icradiusmachines; +my $icradius_mysqldest = + $conf->config('icradius_mysqldest') || "/usr/local/var/" + if $icradiusmachines; +my $icradius_mysqlsource = + $conf->config('icradius_mysqlsource') || "/usr/local/var/freeside" + if $icradiusmachines; +my $icradius_dbh; +if ( $icradiusmachines && $conf->exists('icradius_secrets') ) { + $icradius_dbh = DBI->connect($conf->config('icradius_secrets')) + or die $DBI::errstr;; +} else { + $icradius_dbh = dbh; } -my($fbsdshellmachines)="/var/spool/freeside/conf/bsdshellmachines"; -my(@bsdshellmachines); -if ( -e $fbsdshellmachines ) { - open(BSDSHELLMACHINES,$fbsdshellmachines); - @bsdshellmachines=map { - /^(.*)$/ or die "Illegal line in conf/bsdshellmachines"; #we trust the file - $1; - } grep $_ !~ /^(#|$)/, <BSDSHELLMACHINES>; - close BSDSHELLMACHINES; -} +my $textradiusprepend = + $conf->exists('textradiusprepend') + ? $conf->config('textradiusprepend') + : ''; -my($fnismachines)="/var/spool/freeside/conf/nismachines"; -my(@nismachines); -if ( -e $fnismachines ) { - open(NISMACHINES,$fnismachines); - @nismachines=map { - /^(.*)$/ or die "Illegal line in conf/nismachines"; #we trust the file - $1; - } grep $_ !~ /^(#|$)/, <NISMACHINES>; - close NISMACHINES; -} +my @vpopmailmachines = $conf->config('vpopmailmachines') + if $conf->exists('vpopmailmachines'); + +my ($machine, $vpopdir, $vpopuid, $vpopgid) = split (/\s+/, $vpopmailmachines[0]); -my($ferpcdmachines)="/var/spool/freeside/conf/erpcdmachines"; -my(@erpcdmachines); -if ( -e $ferpcdmachines ) { - open(ERPCDMACHINES,$ferpcdmachines); - @erpcdmachines=map { - /^(.*)$/ or die "Illegal line in conf/erpcdmachines"; #we trust the file - $1; - } grep $_ !~ /^(#|$)/, <ERPCDMACHINES>; - close ERPCDMACHINES; +my($shellmachine, @qmailmachines); +if ( $conf->exists('qmailmachines') ) { + $shellmachine = $conf->config('shellmachine'); + @qmailmachines = $conf->config('qmailmachines'); } -my($fradiusmachines)="/var/spool/freeside/conf/radiusmachines"; -my(@radiusmachines); -if ( -e $fradiusmachines ) { - open(RADIUSMACHINES,$fradiusmachines); - @radiusmachines=map { - /^(.*)$/ or die "Illegal line in conf/radiusmachines"; #we trust the file - $1; - } grep $_ !~ /^(#|$)/, <RADIUSMACHINES>; - close RADIUSMACHINES; +my(@sendmailmachines, $sendmailconfigpath, $sendmailrestart); +if ( $conf->exists('sendmailmachines') ) { + @sendmailmachines = $conf->config('sendmailmachines'); + $sendmailconfigpath = $conf->config('sendmailconfigpath') || '/etc'; + $sendmailrestart = $conf->config('sendmailrestart'); } -my($spooldir)="/var/spool/freeside/export"; -my($spoollock)="/var/spool/freeside/svc_acct.export.lock"; +my $mydomain = $conf->config('domain') if $conf->exists('domain'); + + -adminsuidsetup; my(@saltset)= ( 'a'..'z' , 'A'..'Z' , '0'..'9' , '.' , '/' ); -srand(time|$$); +require 5.004; #srand(time|$$); + +my $spooldir = "/usr/local/etc/freeside/export.". datasrc; +my $spoollock = "/usr/local/etc/freeside/svc_acct.export.lock.". datasrc; open(EXPORT,"+>>$spoollock") or die "Can't open $spoollock: $!"; select(EXPORT); $|=1; select(STDOUT); @@ -110,159 +108,405 @@ unless ( flock(EXPORT,LOCK_EX|LOCK_NB) ) { seek(EXPORT,0,0); my($pid)=<EXPORT>; chop($pid); - #no reason to start loct of blocking processes + #no reason to start lots of blocking processes die "Is another export process running under pid $pid?\n"; } seek(EXPORT,0,0); print EXPORT $$,"\n"; -my(@svc_acct)=qsearch('svc_acct',{}); +my(@svc_domain)=qsearch('svc_domain',{}); ( open(MASTER,">$spooldir/master.passwd") - and flock(MASTER,LOCK_EX|LOCK_NB) -) or die "Can't open $spooldir/master.passwd: $!"; + and flock(MASTER,LOCK_EX|LOCK_NB) +) or die "Can't open $spooldir/.master.passwd: $!"; ( open(PASSWD,">$spooldir/passwd") and flock(PASSWD,LOCK_EX|LOCK_NB) ) or die "Can't open $spooldir/passwd: $!"; ( open(SHADOW,">$spooldir/shadow") - and flock(SHADOW,LOCK_EX|LOCK_NB) + and flock(SHADOW,LOCK_EX|LOCK_NB) ) or die "Can't open $spooldir/shadow: $!"; -( open(ACP_PASSWD,">$spooldir/acp_passwd") - and flock (ACP_PASSWD,LOCK_EX|LOCK_NB) +( open(ACP_PASSWD,">$spooldir/acp_passwd") + and flock(ACP_PASSWD,LOCK_EX|LOCK_NB) ) or die "Can't open $spooldir/acp_passwd: $!"; -( open (ACP_DIALUP,">$spooldir/acp_dialup") - and flock(ACP_DIALUP,LOCK_EX|LOCK_NB) +( open(ACP_DIALUP,">$spooldir/acp_dialup") + and flock(ACP_DIALUP,LOCK_EX|LOCK_NB) ) or die "Can't open $spooldir/acp_dialup: $!"; -( open (USERS,">$spooldir/users") - and flock(USERS,LOCK_EX|LOCK_NB) +( open(USERS,">$spooldir/users") + and flock(USERS,LOCK_EX|LOCK_NB) ) or die "Can't open $spooldir/users: $!"; +( open(ASSIGN,">$spooldir/assign") + and flock(ASSIGN,LOCK_EX|LOCK_NB) +) or die "Can't open $spooldir/assign: $!"; +( open(RCPTHOSTS,">$spooldir/rcpthosts") + and flock(RCPTHOSTS,LOCK_EX|LOCK_NB) +) or die "Can't open $spooldir/rcpthosts: $!"; +( open(VPOPRCPTHOSTS,">$spooldir/vpoprcpthosts") + and flock(VPOPRCPTHOSTS,LOCK_EX|LOCK_NB) +) or die "Can't open $spooldir/rcpthosts: $!"; +( open(RECIPIENTMAP,">$spooldir/recipientmap") + and flock(RECIPIENTMAP,LOCK_EX|LOCK_NB) +) or die "Can't open $spooldir/recipientmap: $!"; +( open(VIRTUALDOMAINS,">$spooldir/virtualdomains") + and flock(VIRTUALDOMAINS,LOCK_EX|LOCK_NB) +) or die "Can't open $spooldir/virtualdomains: $!"; +( open(VPOPVIRTUALDOMAINS,">$spooldir/vpopvirtualdomains") + and flock(VPOPVIRTUALDOMAINS,LOCK_EX|LOCK_NB) +) or die "Can't open $spooldir/virtualdomains: $!"; +( open(VIRTUSERTABLE,">$spooldir/virtusertable") + and flock(VIRTUSERTABLE,LOCK_EX|LOCK_NB) +) or die "Can't open $spooldir/virtusertable: $!"; +( open(SENDMAIL_CW,">$spooldir/sendmail.cw") + and flock(SENDMAIL_CW,LOCK_EX|LOCK_NB) +) or die "Can't open $spooldir/sendmail.cw: $!"; + + + chmod 0644, "$spooldir/passwd", "$spooldir/acp_dialup", + "$spooldir/assign", + "$spooldir/sendmail.cw", + "$spooldir/virtusertable", + "$spooldir/rcpthosts", + "$spooldir/vpoprcpthosts", + "$spooldir/recipientmap", + "$spooldir/virtualdomains", + "$spooldir/vpopvirtualdomains", + ; chmod 0600, "$spooldir/master.passwd", - "$spooldir/acp_passwd", + "$spooldir/acp_passwd", "$spooldir/shadow", "$spooldir/users", ; -setpriority(0,0,10); +rmtree"$spooldir/domains", 0, 1; +mkdir "$spooldir/domains", 0700; -my($svc_acct); -foreach $svc_acct (@svc_acct) { - - my($password)=$svc_acct->getfield('_password'); - my($cpassword,$rpassword); - if ( ( length($password) <= 8 ) - && ( $password ne '*' ) - && ( $password ne '' ) - ) { - $cpassword=crypt($password, - $saltset[int(rand(64))].$saltset[int(rand(64))] - ); - $rpassword=$password; - } else { - $cpassword=$password; - $rpassword='UNIX'; - } +if ( $icradiusmachines ) { + my $sth = $icradius_dbh->prepare("DELETE FROM radcheck"); + $sth->execute or die "Can't reset radcheck table: ". $sth->errstr; + my $sth2 = $icradius_dbh->prepare("DELETE FROM radreply"); + $sth2->execute or die "Can't reset radreply table: ". $sth2->errstr; +} - if ( $svc_acct->uid =~ /^(\d+)$/ ) { +setpriority(0,0,10); - die "Non-root user ". $svc_acct->username. " has 0 UID!" - if $svc_acct->uid == 0 && $svc_acct->username ne 'root'; +my %usernames; ## this hack helps keep the passwd files sane +my @sendmail; + +my $svc_domain; +foreach $svc_domain (sort {$a->domain cmp $b->domain} @svc_domain) { + + my($domain)=$svc_domain->domain; + print RCPTHOSTS "$domain\n.$domain\n"; + print VPOPRCPTHOSTS "$domain\n"; + print SENDMAIL_CW "$domain\n"; + + ### + # FORMAT OF THE ASSIGN/USERS FILE HERE + print ASSIGN join(":", + "+" . $domain . "-", + $domain, + $vpopuid, + $vpopgid, + $vpopdir . "/domains/" . $domain, + "-", + "", + "", + ), "\n"; + + (mkdir "$spooldir/domains/" . $domain, 0700) + or die "Can't create $spooldir/domains/" . $domain .": $!"; + + ( open(QMAILDEFAULT,">$spooldir/domains/" . $domain . "/.qmail-default") + and flock(QMAILDEFAULT,LOCK_EX|LOCK_NB) + ) or die "Can't open $spooldir/domains/" . $domain . "/.qmail-default: $!"; + + ( open(VPASSWD,">$spooldir/domains/" . $domain . "/vpasswd") + and flock(VPASSWD,LOCK_EX|LOCK_NB) + ) or die "Can't open $spooldir/domains/" . $domain . "/vpasswd: $!"; + + my ($svc_acct); + + if ($svc_domain->catchall) { + $svc_acct = qsearchs('svc_acct', {'svcnum' => $svc_domain->catchall}); + die "Cannot find catchall account for domain $domain\n" unless $svc_acct; + + my $username = $svc_acct->username; + push @sendmail, "\@$domain\t$username\n"; + print VIRTUALDOMAINS "$domain:$username-$domain\n", + ".$domain:$username-$domain\n", + ; ### - # FORMAT OF FreeBSD MASTER PASSWD FILE HERE - print MASTER join(":", - $svc_acct->username, # User name - $cpassword, # Encrypted password - $svc_acct->uid, # User ID - $svc_acct->gid, # Group ID - "", # Login Class - "0", # Password Change Time - "0", # Password Expiration Time - $svc_acct->finger, # Users name - $svc_acct->dir, # Users home directory - $svc_acct->shell, # shell - ), "\n" ; + # FORMAT OF THE .QMAIL-DEFAULT FILE HERE + print QMAILDEFAULT "| $vpopdir/bin/vdelivermail \"\" $username\@$domain\n"; + }else{ ### - # FORMAT OF THE PASSWD FILE HERE - print PASSWD join(":", - $svc_acct->username, - 'x', # "##". $svc_acct->$username, - $svc_acct->uid, - $svc_acct->gid, - $svc_acct->finger, - $svc_acct->dir, - $svc_acct->shell, - ), "\n"; + # FORMAT OF THE .QMAIL-DEFAULT FILE HERE + print QMAILDEFAULT "| $vpopdir/bin/vdelivermail \"\" bounce-no-mailbox\n"; + } - ### - # FORMAT OF THE SHADOW FILE HERE - print SHADOW join(":", - $svc_acct->username, - $cpassword, - '', - '', - '', - '', - '', - '', - '', - ), "\n"; + print VPOPVIRTUALDOMAINS "$domain:$domain\n"; + + foreach $svc_acct (qsearch('svc_acct', {'domsvc' => $svc_domain->svcnum})) { + my($password)=$svc_acct->getfield('_password'); + my($cpassword,$rpassword); + if ( ( length($password) <= 8 ) + && ( $password ne '*' ) + && ( $password ne '!!' ) + && ( $password ne '' ) + ) { + $cpassword=crypt($password, + $saltset[int(rand(64))].$saltset[int(rand(64))] + ); + $rpassword=$password; + } else { + $cpassword=$password; + $rpassword='UNIX'; + } - } + my $username; - if ( $svc_acct->slipip ne '' ) { + if ($mydomain && ($mydomain eq $svc_domain->domain)) { + $username=$svc_acct->username; + } elsif ($userpolicy =~ /^prepend domsvc$/) { + $username=$svc_acct->domsvc . $svc_acct->username; + } elsif ($userpolicy =~ /^append domsvc$/) { + $username=$svc_acct->username . $svc_acct->domsvc; + } elsif ($userpolicy =~ /^append domain$/) { + $username=$svc_acct->username . $svc_domain->domain; + } else { + die "Unknown policy in username_policy\n"; + } - ### - # FORMAT OF THE ACP_* FILES HERE - print ACP_PASSWD join(":", - $svc_acct->username, - $cpassword, - "0", - "0", - "", - "", - "", - ), "\n"; - - my($ip)=$svc_acct->slipip; - - unless ( $ip eq '0.0.0.0' || $svc_acct->slipip eq '0e0' ) { - print ACP_DIALUP $svc_acct->username, "\t*\t", $svc_acct->slipip, "\n"; + if ($svc_acct->dir ne '/dev/null' || $svc_acct->slipip ne '') { + if ($usernames{$username}++) { + die "Duplicate username detected: $username\n"; + } } + + if ( $svc_acct->uid =~ /^(\d+)$/ ) { + + die "Non-root user ". $svc_acct->username. " has 0 UID!" + if $svc_acct->uid == 0 && $svc_acct->username ne 'root'; + + if ( $svc_acct->dir ne "/dev/null") { + + ### + # FORMAT OF FreeBSD MASTER PASSWD FILE HERE + print MASTER join(":", + $username, # User name + $cpassword, # Encrypted password + $svc_acct->uid, # User ID + $svc_acct->gid, # Group ID + "", # Login Class + "0", # Password Change Time + "0", # Password Expiration Time + $svc_acct->finger, # Users name + $svc_acct->dir, # Users home directory + $svc_acct->shell, # shell + ), "\n" ; + + + ### + # FORMAT OF THE PASSWD FILE HERE + print PASSWD join(":", + $username, + 'x', # "##". $username, + $svc_acct->uid, + $svc_acct->gid, + $svc_acct->finger, + $svc_acct->dir, + $svc_acct->shell, + ), "\n"; + + ### + # FORMAT OF THE SHADOW FILE HERE + print SHADOW join(":", + $username, + $cpassword, + '', + '', + '', + '', + '', + '', + '', + ), "\n"; + } + + ### + # FORMAT OF THE VPASSWD FILE HERE + print VPASSWD join(":", + $svc_acct->username, + $cpassword, + '1', + '0', + $svc_acct->username, + "$vpopdir/domains/" . $svc_domain->domain ."/" . $svc_acct->username, + 'NOQUOTA', + ), "\n"; + } + + if ( $svc_acct->slipip ne '' ) { + + ### + # FORMAT OF THE ACP_* FILES HERE + print ACP_PASSWD join(":", + $username, + $cpassword, + "0", + "0", + "", + "", + "", + ), "\n"; + + my($ip)=$svc_acct->slipip; + + unless ( $ip eq '0.0.0.0' || $svc_acct->slipip eq '0e0' ) { + print ACP_DIALUP $username, "\t*\t", $svc_acct->slipip, "\n"; + } + + my %radreply = $svc_acct->radius_reply; + my %radcheck = $svc_acct->radius_check; + + my $radcheck = join ", ", map { qq($_ = "$radcheck{$_}") } keys %radcheck; + $radcheck .= ", " if $radcheck; + + ### + # FORMAT OF THE USERS FILE HERE + print USERS + $username, + qq(\t${textradiusprepend}), + $radcheck, + qq(Password = "$rpassword"\n\t), + join ",\n\t", map { qq($_ = "$radreply{$_}") } keys %radreply; + + if ( $ip && $ip ne '0e0' ) { + #print USERS qq(,\n\tFramed-Address = "$ip"\n\n); + print USERS qq(,\n\tFramed-IP-Address = "$ip"\n\n); + } else { + print USERS qq(\n\n); + } + + ### + # ICRADIUS export + if ( $icradiusmachines ) { + + my $sth = $icradius_dbh->prepare( + "INSERT INTO radcheck ( id, UserName, Attribute, Value ) VALUES ( ". + join(", ", map { $icradius_dbh->quote( $_ ) } ( + '', + $username, + "Password", + $svc_acct->_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; } + + foreach my $attribute ( keys %radreply ) { + my $sth = $icradius_dbh->prepare( + "INSERT INTO radreply (id, UserName, Attribute, Value) VALUES ( ". + join(", ", map { $icradius_dbh->quote( $_ ) } ( + '', + $username, + $attribute, + $radreply{$attribute}, + ) ). " )" + ); + $sth->execute or die "Can't insert into radreply table: ". $sth->errstr; } + } + } + ### - # FORMAT OF THE USERS FILE HERE - print USERS - $svc_acct->username, qq(\tPassword = "$rpassword"\n\t), - - join ",\n\t", - map { - /^(radius_(.*))$/; - my($field,$attrib)=($1,$2); - $attrib =~ s/_/\-/g; - "$attrib = \"". $svc_acct->getfield($field). "\""; - } grep /^radius_/ && $svc_acct->getfield($_), fields('svc_acct') - ; - if ( $ip && $ip ne '0e0' ) { - print USERS qq(,\n\tFramed-Address = "$ip"\n\n); - } else { - print USERS qq(\n\n); + # vpopmail directory structure creation + + (mkdir "$spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username, 0700) + or die "Can't create $spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . ": $!"; + (mkdir "$spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . "/Maildir", 0700) + or die "Can't create $spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . " /Maildir: $!"; + (mkdir "$spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . "/Maildir/cur", 0700) + or die "Can't create $spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . " /Maildir/cur: $!"; + (mkdir "$spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . "/Maildir/new", 0700) + or die "Can't create $spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . " /Maildir/new: $!"; + (mkdir "$spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . "/Maildir/tmp", 0700) + or die "Can't create $spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . " /Maildir/tmp: $!"; + + ( open(DOTQMAIL,">$spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . "/.qmail") + and flock(DOTQMAIL,LOCK_EX|LOCK_NB) + ) or die "Can't open $spooldir/domains/" . $svc_domain->domain . "/" . $svc_acct->username . "/.qmail: $!"; + + my($svc_forward); + foreach $svc_forward (qsearch('svc_forward', {'srcsvc' => $svc_acct->svcnum})) { + my($destination); + if ($svc_forward->dstsvc) { + my $dst_acct = qsearchs('svc_acct', {'svcnum' => $svc_forward->dstsvc}); + my $dst_domain = qsearchs('svc_domain', {'svcnum' => $dst_acct->domsvc}); + $destination = $dst_acct->username . '@' . $dst_domain->domain; + + if ($dst_domain->domain eq $mydomain) { + print VIRTUSERTABLE $svc_acct->username . "@" . $svc_domain->domain . + "\t" . $dst_acct->username . "\n"; + print RECIPIENTMAP $svc_acct->username . "@" . $svc_domain->domain . + ":$destination\n"; + } + } else { + $destination = $svc_forward->dst; + } + + ### + # FORMAT OF .QMAIL FILES HERE + print DOTQMAIL "$destination\n"; } + flock(DOTQMAIL,LOCK_UN); + close DOTQMAIL; + } + flock(VPASSWD,LOCK_UN); + flock(QMAILDEFAULT,LOCK_UN); + close VPASSWD; + close QMAILDEFAULT; + } +### +# FORMAT OF THE ASSIGN/USERS FILE FINAL LINE HERE +print ASSIGN ".\n"; + +print VIRTUSERTABLE @sendmail; + flock(MASTER,LOCK_UN); flock(PASSWD,LOCK_UN); flock(SHADOW,LOCK_UN); flock(ACP_DIALUP,LOCK_UN); flock(ACP_PASSWD,LOCK_UN); flock(USERS,LOCK_UN); +flock(ASSIGN,LOCK_UN); +flock(SENDMAIL_CW,LOCK_UN); +flock(VIRTUSERTABLE,LOCK_UN); +flock(RCPTHOSTS,LOCK_UN); +flock(VPOPRCPTHOSTS,LOCK_UN); +flock(RECIPIENTMAP,LOCK_UN); +flock(VPOPVIRTUALDOMAINS,LOCK_UN); close MASTER; close PASSWD; @@ -270,18 +514,26 @@ close SHADOW; close ACP_DIALUP; close ACP_PASSWD; close USERS; +close ASSIGN; +close SENDMAIL_CW; +close VIRTUSERTABLE; +close RCPTHOSTS; +close VPOPRCPTHOSTS; +close RECIPIENTMAP; +close VPOPVIRTUALDOMAINS; ### # export stuff # -my($shellmachine); -foreach $shellmachine (@shellmachines) { - scp("$spooldir/passwd","root\@$shellmachine:/etc/passwd.new") - == 0 or die "scp error: $!"; - scp("$spooldir/shadow","root\@$shellmachine:/etc/shadow.new") - == 0 or die "scp error: $!"; - ssh("root\@$shellmachine", +my($ashellmachine); +foreach $ashellmachine (@shellmachines) { + my $scp = new Net::SCP; + $scp->scp("$spooldir/passwd","root\@$ashellmachine:/etc/passwd.new") + or die "scp error: ". $scp->{errstr}; + $scp->scp("$spooldir/shadow","root\@$ashellmachine:/etc/shadow.new") + or die "scp error: ". $scp->{errstr}; + ssh("root\@$ashellmachine", "( ". "mv /etc/passwd.new /etc/passwd; ". "mv /etc/shadow.new /etc/shadow; ". @@ -292,10 +544,11 @@ foreach $shellmachine (@shellmachines) { my($bsdshellmachine); foreach $bsdshellmachine (@bsdshellmachines) { - scp("$spooldir/passwd","root\@$bsdshellmachine:/etc/passwd.new") - == 0 or die "scp error: $!"; - scp("$spooldir/master.passwd","root\@$bsdshellmachine:/etc/master.passwd.new") - == 0 or die "scp error: $!"; + my $scp = new Net::SCP; + $scp->scp("$spooldir/passwd","root\@$bsdshellmachine:/etc/passwd.new") + or die "scp error: ". $scp->{errstr}; + $scp->scp("$spooldir/master.passwd","root\@$bsdshellmachine:/etc/master.passwd.new") + or die "scp error: ". $scp->{errstr}; ssh("root\@$bsdshellmachine", "( ". "mv /etc/passwd.new /etc/passwd; ". @@ -307,10 +560,11 @@ foreach $bsdshellmachine (@bsdshellmachines) { my($nismachine); foreach $nismachine (@nismachines) { - scp("$spooldir/passwd","root\@$nismachine:/etc/global/passwd") - == 0 or die "scp error: $!"; - scp("$spooldir/shadow","root\@$nismachine:/etc/global/shadow") - == 0 or die "scp error: $!"; + my $scp = new Net::SCP; + $scp->scp("$spooldir/passwd","root\@$nismachine:/etc/global/passwd") + or die "scp error: ". $scp->{errstr}; + $scp->scp("$spooldir/shadow","root\@$nismachine:/etc/global/shadow") + or die "scp error: ". $scp->{errstr}; ssh("root\@$nismachine", "( ". "cd /var/yp; make; ". @@ -321,10 +575,11 @@ foreach $nismachine (@nismachines) { my($erpcdmachine); foreach $erpcdmachine (@erpcdmachines) { - scp("$spooldir/acp_passwd","root\@$erpcdmachine:/usr/annex/acp_passwd") - == 0 or die "scp error: $!"; - scp("$spooldir/acp_dialup","root\@$erpcdmachine:/usr/annex/acp_dialup") - == 0 or die "scp error: $!"; + my $scp = new Net::SCP; + $scp->scp("$spooldir/acp_passwd","root\@$erpcdmachine:/usr/annex/acp_passwd") + or die "scp error: ". $scp->{errstr}; + $scp->scp("$spooldir/acp_dialup","root\@$erpcdmachine:/usr/annex/acp_dialup") + or die "scp error: ". $scp->{errstr}; ssh("root\@$erpcdmachine", "( ". "kill -USR1 \`cat /usr/annex/erpcd.pid\'". @@ -335,9 +590,10 @@ foreach $erpcdmachine (@erpcdmachines) { my($radiusmachine); foreach $radiusmachine (@radiusmachines) { - scp("$spooldir/users","root\@$radiusmachine:/etc/raddb/users") - == 0 or die "scp error: $!"; - ssh("root\@$erpcdmachine", + my $scp = new Net::SCP; + $scp->scp("$spooldir/users","root\@$radiusmachine:/etc/raddb/users") + or die "scp error: ". $scp->{errstr}; + ssh("root\@$radiusmachine", "( ". "builddbm". " )" @@ -345,7 +601,93 @@ foreach $radiusmachine (@radiusmachines) { == 0 or die "ssh error: $!"; } +foreach my $icradiusmachine ( @icradiusmachines ) { + my( $machine, $db, $user, $pass ) = split(/\s+/, $icradiusmachine); + chdir $icradius_mysqlsource or die "Can't cd $icradius_mysqlsource: $!"; + open(WRITER,"|ssh root\@$machine mysql -v --user=$user -p $db"); + my $oldfh = select WRITER; $|=1; select $oldfh; + print WRITER "$pass\n"; + sleep 2; + print WRITER "LOCK TABLES radcheck WRITE, radreply WRITE;\n"; + foreach my $file ( glob("radcheck.*") ) { + my $scp = new Net::SCP; + $scp->scp($file,"root\@$machine:$icradius_mysqldest/$db/$file") + or die "scp error: ". $scp->{errstr}; + } + foreach my $file ( glob("radreply.*") ) { + my $scp = new Net::SCP; + $scp->scp($file,"root\@$machine:$icradius_mysqldest/$db/$file") + or die "scp error: ". $scp->{errstr}; + } + close WRITER; +} + +my @args = ("/bin/tar", "c", "--force-local", "-C", "$spooldir", "-f", "$spooldir/vpoptarball", "domains"); + +system {$args[0]} @args; + +my($vpopmailmachine); +foreach $vpopmailmachine (@vpopmailmachines) { + my ($machine, $vpopdir, $vpopuid, $vpopgid) = split (/\s+/, $vpopmailmachine); + my $scp = new Net::SCP; + $scp->scp("$spooldir/vpoptarball","root\@$machine:vpoptarball") + or die "scp error: ". $scp->{errstr}; + ssh("root\@$machine", + "( ". + "tar xf vpoptarball; ". + "chown -R $vpopuid:$vpopgid domains; ". + "tar cf vpoptarball domains; ". + "cd $vpopdir; ". + "tar xf ~/vpoptarball; ". + " )" + ) + == 0 or die "ssh error: $!"; + + $scp->scp("$spooldir/assign","root\@$machine:/var/qmail/users/assign") + or die "scp error: ". $scp->{errstr}; + $scp->scp("$spooldir/vpopvirtualdomains","root\@$machine:/var/qmail/control/virtualdomains") + or die "scp error: ". $scp->{errstr}; + $scp->scp("$spooldir/vpoprcpthosts","root\@$machine:/var/qmail/control/rcpthosts") + or die "scp error: ". $scp->{errstr}; +} + +my($sendmailmachine); +foreach $sendmailmachine (@sendmailmachines) { + my $scp = new Net::SCP; + $scp->scp("$spooldir/sendmail.cw","root\@$sendmailmachine:$sendmailconfigpath/sendmail.cw.new") + or die "scp error: ". $scp->{errstr}; + $scp->scp("$spooldir/virtusertable","root\@$sendmailmachine:$sendmailconfigpath/virtusertable.new") + or die "scp error: ". $scp->{errstr}; + ssh("root\@$sendmailmachine", + "( ". + "mv $sendmailconfigpath/sendmail.cw.new $sendmailconfigpath/sendmail.cw; ". + "mv $sendmailconfigpath/virtusertable.new $sendmailconfigpath/virtusertable; ". + $sendmailrestart. + " )" + ) + == 0 or die "ssh error: $!"; +} + +my($qmailmachine); +foreach $qmailmachine (@qmailmachines) { + my $scp = new Net::SCP; + $scp->scp("$spooldir/recipientmap","root\@$qmailmachine:/var/qmail/control/recipientmap") + or die "scp error: ". $scp->{errstr}; + $scp->scp("$spooldir/virtualdomains","root\@$qmailmachine:/var/qmail/control/virtualdomains") + or die "scp error: ". $scp->{errstr}; + $scp->scp("$spooldir/rcpthosts","root\@$qmailmachine:/var/qmail/control/rcpthosts") + or die "scp error: ". $scp->{errstr}; + #ssh("root\@$qmailmachine","/etc/init.d/qmail restart") + # == 0 or die "ssh error: $!"; +} + unlink $spoollock; flock(EXPORT,LOCK_UN); close EXPORT; +# + +sub usage { + die "Usage:\n\n svc_acct.export user\n"; +} + diff --git a/bin/svc_acct.import b/bin/svc_acct.import index c4b8c5ec5..eaf0c03c5 100755 --- a/bin/svc_acct.import +++ b/bin/svc_acct.import @@ -1,5 +1,7 @@ #!/usr/bin/perl -Tw # +# $Id: svc_acct.import,v 1.15 2001-07-30 06:07:47 ivan Exp $ +# # ivan@sisd.com 98-mar-9 # # changed 'password' field to '_password' because PgSQL 6.3 reserves this word @@ -13,19 +15,62 @@ # arbitrary radius attributes ivan@sisd.com 98-aug-9 # # don't import /var/spool/freeside/conf/shells! ivan@sisd.com 98-aug-13 +# +# $Log: svc_acct.import,v $ +# Revision 1.15 2001-07-30 06:07:47 ivan +# allow !! for locked accounts instead of changing to *SUSPENDED* +# +# Revision 1.14 2001/05/07 15:24:15 ivan +# s/!/*/ +# +# Revision 1.13 2001/05/05 08:51:16 ivan +# http://www.sisd.com/freeside/list-archive/msg01915.html +# +# Revision 1.12 2001/04/22 01:56:15 ivan +# get rid of FS::SSH.pm (became Net::SSH and Net::SCP on CPAN) +# +# Revision 1.11 2000/06/29 12:27:01 ivan +# s/password/_password/ for PostgreSQL wasn't done in the import. +# +# Revision 1.10 2000/06/28 12:32:30 ivan +# allow RADIUS lines with "Auth-Type = Local" too +# +# Revision 1.8 2000/02/03 05:16:52 ivan +# beginning of DNS and Apache support +# +# Revision 1.7 1999/07/08 02:32:26 ivan +# import fix, noticed by Ben Leibig and Joel Griffiths +# +# Revision 1.6 1999/07/08 01:49:00 ivan +# updates to avoid -w warnings from Joel Griffiths <griff@aver-computer.com> +# +# Revision 1.5 1999/03/25 08:42:19 ivan +# import stuff uses Term::Query and spits out (some kinds of) nonsensical input +# +# Revision 1.4 1999/03/24 00:43:38 ivan +# die if no relevant services +# +# Revision 1.3 1998/12/10 07:23:16 ivan +# use FS::Conf, need user (for datasrc) +# +# Revision 1.2 1998/10/13 12:07:51 ivan +# Assigns password from the shadow file for RADIUS password "UNIX" +# use strict; use vars qw(%part_svc); use Date::Parse; -use FS::SSH qw(iscp); -use FS::UID qw(adminsuidsetup); +use Term::Query qw(query); +use Net::SCP qw(iscp); +use FS::UID qw(adminsuidsetup datasrc); use FS::Record qw(qsearch); use FS::svc_acct; +use FS::part_svc; -adminsuidsetup; +my $user = shift or die &usage; +adminsuidsetup $user; -#my($spooldir)="/var/spool/freeside/export"; -my($spooldir)="unix/"; +my($spooldir)="/usr/local/etc/freeside/export.". datasrc; $FS::svc_acct::nossh_hack = 1; @@ -33,6 +78,8 @@ $FS::svc_acct::nossh_hack = 1; %part_svc=map { $_->svcpart, $_ } qsearch('part_svc',{'svcdb'=>'svc_acct'}); +die "No services with svcdb svc_acct!\n" unless %part_svc; + print "\n\n", &menu_svc, "\n", <<END; Most accounts probably have entries in passwd and users (with Port-Limit nonexistant or 1). @@ -58,8 +105,7 @@ my($oisdn_svcpart)=&getpart; print "\n\n", &menu_svc, "\n", <<END; POP mail accounts have entries in passwd only, and have a particular shell. END -print "Enter that shell: "; -my($pop_shell)=&getvalue; +my($pop_shell)=&getvalue("Enter that shell:"); my($popmail_svcpart)=&getpart; print "\n\n", &menu_svc, "\n", <<END; @@ -71,37 +117,38 @@ print "\n\n", <<END; Enter the location and name of your _user_ passwd file, for example "mail.isp.com:/etc/passwd" or "nis.isp.com:/etc/global/passwd" END -print ":"; -my($loc_passwd)=&getvalue; +my($loc_passwd)=&getvalue(":"); iscp("root\@$loc_passwd", "$spooldir/passwd.import"); print "\n\n", <<END; Enter the location and name of your _user_ shadow file, for example "mail.isp.com:/etc/shadow" or "bsd.isp.com:/etc/master.passwd" END -print ":"; -my($loc_shadow)=&getvalue; +my($loc_shadow)=&getvalue(":"); iscp("root\@$loc_shadow", "$spooldir/shadow.import"); print "\n\n", <<END; Enter the location and name of your radius "users" file, for example "radius.isp.com:/etc/raddb/users" END -print ":"; -my($loc_users)=&getvalue; +my($loc_users)=&getvalue(":"); iscp("root\@$loc_users", "$spooldir/users.import"); sub menu_svc { ( join "\n", map "$_: ".$part_svc{$_}->svc, sort keys %part_svc ). "\n"; } sub getpart { - print "Enter part number, or 0 for none: "; - &getvalue; + $^W=0; # Term::Query isn't -w-safe + my $return = query "Enter part number:", 'irk', [ keys %part_svc ]; + $^W=1; + $return; } sub getvalue { - my($x)=scalar(<STDIN>); - chop $x; - $x; + my $prompt = shift; + $^W=0; # Term::Query isn't -w-safe + my $return = query $prompt, ''; + $^W=1; + $return; } print "\n\n"; @@ -116,12 +163,14 @@ my(%upassword,%ip,%allparam); my(%param,$username); while (<USERS>) { chop; - next if /^$/; + next if /^\s*$/; + next if /^\s*#/; if ( /^\S/ ) { - /^(\w+)\s+Password\s+=\s+"([^"]+)"(,\s+Expiration\s+=\s+"([^"]*")\s*)?$/ + /^(\w+)\s+(Auth-Type\s+=\s+Local,\s+)Password\s+=\s+"([^"]+)"(,\s+Expiration\s+=\s+"([^"]*")\s*)?$/ or die "1Unexpected line in users.import: $_"; my($password,$expiration); - ($username,$password,$expiration)=(lc($1),$2,$4); + ($username,$password,$expiration)=(lc($1),$3,$5); + $password = '' if $password eq 'UNIX'; $upassword{$username}=$password; undef %param; } else { @@ -130,8 +179,12 @@ while (<USERS>) { while (<USERS>) { chop; if ( /^\s*$/ ) { - $ip{$username}=$param{'radius_Framed_IP_Address'}||'0e0'; - delete $param{'radius_Framed_IP_Address'}; + if ( defined $param{'radius_Framed_IP_Address'} ) { + $ip{$username} = $param{'radius_Framed_IP_Address'}; + delete $param{'radius_Framed_IP_Address'}; + } else { + $ip{$username} = '0e0'; + } $allparam{$username}={ %param }; last; } elsif ( /^\s+([\w\-]+)\s=\s"?([\w\.\-\s]+)"?,?\s*$/ ) { @@ -144,14 +197,20 @@ while (<USERS>) { } } #? incase there isn't a terminating blank line ? -$ip{$username}=$param{'radius_Framed_IP_Address'}||'0e0'; -delete $param{'radius_Framed_IP_Address'}; +if ( defined $param{'radius_Framed_IP_Address'} ) { + $ip{$username} = $param{'radius_Framed_IP_Address'}; + delete $param{'radius_Framed_IP_Address'}; +} else { + $ip{$username} = '0e0'; +} $allparam{$username}={ %param }; my(%password); while (<SHADOW>) { chop; my($username,$password)=split(/:/); + #$password =~ s/^\!$/\*/; + #$password =~ s/\!+/\*SUSPENDED\* /; $password{$username}=$password; } @@ -176,16 +235,16 @@ while (<PASSWD>) { $svcpart = $shell_svcpart; } - my($svc_acct) = create FS::svc_acct ({ - 'svcpart' => $svcpart, - 'username' => $username, - 'password' => $password, - 'uid' => $uid, - 'gid' => $gid, - 'finger' => $finger, - 'dir' => $dir, - 'shell' => $shell, - 'slipip' => $ip{$username}, + my($svc_acct) = new FS::svc_acct ({ + 'svcpart' => $svcpart, + 'username' => $username, + '_password' => $password, + 'uid' => $uid, + 'gid' => $gid, + 'finger' => $finger, + 'dir' => $dir, + 'shell' => $shell, + 'slipip' => $ip{$username}, %{$allparam{$username}}, }); my($error); @@ -210,11 +269,11 @@ foreach $username ( keys %upassword ) { die "Illegal Port-Limit in users!\n"; } - my($svc_acct) = create FS::svc_acct ({ - 'svcpart' => $svcpart, - 'username' => $username, - 'password' => $password, - 'slipip' => $ip{$username}, + my($svc_acct) = new FS::svc_acct ({ + 'svcpart' => $svcpart, + 'username' => $username, + '_password' => $password, + 'slipip' => $ip{$username}, %{$allparam{$username}}, }); my($error); @@ -225,3 +284,9 @@ foreach $username ( keys %upassword ) { delete $upassword{$username}; } +# + +sub usage { + die "Usage:\n\n svc_acct.import user\n"; +} + diff --git a/bin/svc_acct_sm.export b/bin/svc_acct_sm.export deleted file mode 100755 index c2ec1e53f..000000000 --- a/bin/svc_acct_sm.export +++ /dev/null @@ -1,221 +0,0 @@ -#!/usr/bin/perl -Tw -# -# Create and export VoiceNet_quasar.m4 -# -# ivan@voicenet.com late oct 96 -# -# change priority (after copies) to 19, not 10 -# ivan@voicenet.com 97-feb-5 -# -# put file in different place and run different script, as per matt and -# mohamed -# ivan@voicenet.com 97-mar-10 -# -# added exit if stuff is already locked ivan@voicenet.com 97-apr-15 -# -# removed mail2 -# ivan@voicenet.com 97-jul-10 -# -# rewrote lots of the bits, now exports qmail "virtualdomain", -# "recipientmap" and "rcpthosts" files as well -# -# ivan@voicenet.com 97-sep-4 -# -# adds ".extra" files -# -# ivan@voicenet.com 97-sep-29 -# -# added ".pp" files, ugh. -# -# ivan@voicenet.com 97-oct-1 -# -# rewrite ivan@sisd.com 98-mar-9 -# -# now can create .qmail-default files ivan@sisd.com 98-mar-10 -# -# put example $my_domain declaration in ivan@sisd.com 98-mar-23 -# -# /var/spool/freeside/conf and sendmail updates ivan@sisd.com 98-aug-14 - -use strict; -use Fcntl qw(:flock); -use FS::SSH qw(ssh scp); -use FS::UID qw(adminsuidsetup); -use FS::Record qw(qsearch qsearchs); - -my($conf_shellm)="/var/spool/freeside/conf/shellmachine"; -my($fqmailmachines)="/var/spool/freeside/conf/qmailmachines"; -my($shellmachine); -my(@qmailmachines); -if ( -e $fqmailmachines ) { - open(SHELLMACHINE,$conf_shellm) or die "Can't open $conf_shellm: $!"; - <SHELLMACHINE> =~ /^([\w\.\-]+)$/ or die "Illegal $conf_shellm"; - $shellmachine = $1; - close SHELLMACHINE; - open(QMAILMACHINES,$fqmailmachines); - @qmailmachines=map { - /^(.*)$/ or die "Illegal line in conf/qmailmachines"; #we trust the file - $1; - } grep $_ !~ /^(#|$)/, <QMAILMACHINES>; - close QMAILMACHINES; -} - -my($fsendmailmachines)="/var/spool/freeside/conf/sendmailmachines"; -my(@sendmailmachines); -if ( -e $fsendmailmachines ) { - open(SENDMAILMACHINES,$fsendmailmachines); - @sendmailmachines=map { - /^(.*)$/ or die "Illegal line in conf/sendmailmachines"; #we trust the file - $1; - } grep $_ !~ /^(#|$)/, <SENDMAILMACHINES>; - close SENDMAILMACHINES; -} - -my($conf_domain)="/var/spool/freeside/conf/domain"; -open(DOMAIN,$conf_domain) or die "Can't open $conf_domain: $!"; -my($mydomain)=map { - /^(.*)$/ or die "Illegal line in $conf_domain!"; #yes, we trust the file - $1 -} grep $_ !~ /^(#|$)/, <DOMAIN>; -close DOMAIN; - -my($spooldir)="/var/spool/freeside/export"; -my($spoollock)="/var/spool/freeside/svc_acct_sm.export.lock"; - -adminsuidsetup; -umask 066; - -open(EXPORT,"+>>$spoollock") or die "Can't open $spoollock: $!"; -select(EXPORT); $|=1; select(STDOUT); -unless ( flock(EXPORT,LOCK_EX|LOCK_NB) ) { - seek(EXPORT,0,0); - my($pid)=<EXPORT>; - chop($pid); - #no reason to start locks of blocking processes - die "Is another export process running under pid $pid?\n"; -} -seek(EXPORT,0,0); -print EXPORT $$,"\n"; - -my(@svc_acct_sm)=qsearch('svc_acct_sm',{}); - -( open(RCPTHOSTS,">$spooldir/rcpthosts") - and flock(RCPTHOSTS,LOCK_EX|LOCK_NB) -) or die "Can't open $spooldir/rcpthosts: $!"; -( open(RECIPIENTMAP,">$spooldir/recipientmap") - and flock(RECIPIENTMAP,LOCK_EX|LOCK_NB) -) or die "Can't open $spooldir/recipientmap: $!"; -( open(VIRTUALDOMAINS,">$spooldir/virtualdomains") - and flock(VIRTUALDOMAINS,LOCK_EX|LOCK_NB) -) or die "Can't open $spooldir/virtualdomains: $!"; -( open(VIRTUSERTABLE,">$spooldir/virtusertable") - and flock(VIRTUSERTABLE,LOCK_EX|LOCK_NB) -) or die "Can't open $spooldir/virtusertable: $!"; -( open(SENDMAIL_CW,">$spooldir/sendmail.cw") - and flock(SENDMAIL_CW,LOCK_EX|LOCK_NB) -) or die "Can't open $spooldir/sendmail.cw: $!"; - -setpriority(0,0,10); - -my($svc_domain,%domain); -foreach $svc_domain ( qsearch('svc_domain',{}) ) { - my($domain)=$svc_domain->domain; - $domain{$svc_domain->svcnum}=$domain; - print RCPTHOSTS "$domain\n.$domain\n"; - print SENDMAIL_CW "$domain\n"; -} - -my(@sendmail); - -my($svc_acct_sm); -foreach $svc_acct_sm ( qsearch('svc_acct_sm') ) { - my($domsvc,$domuid,$domuser)=( - $svc_acct_sm->domsvc, - $svc_acct_sm->domuid, - $svc_acct_sm->domuser, - ); - my($domain)=$domain{$domsvc}; - my($svc_acct)=qsearchs('svc_acct',{'uid'=>$domuid}); - my($username,$dir,$uid,$gid)=( - $svc_acct->username, - $svc_acct->dir, - $svc_acct->uid, - $svc_acct->gid, - ); - next unless $username && $domain && $domuser; - - if ($domuser eq '*') { - push @sendmail, "\@$domain\t$username\n"; - print VIRTUALDOMAINS "$domain:$username-$domain\n", - ".$domain:$username-$domain\n", - ; - ### - # qmail - ssh("root\@$shellmachine", - "[ -e $dir/.qmail-default ] || { touch $dir/.qmail-default; chown $uid:$gid $dir/.qmail-default; }" - ) if ( $shellmachine && $dir && $uid ); - - } else { - print VIRTUSERTABLE "$domuser\@$domain\t$username\n"; - print RECIPIENTMAP "$domuser\@$domain:$username\@$mydomain\n"; - } - - print VIRTUSERTABLE @sendmail; - -} - -chmod 0644, "$spooldir/sendmail.cw", - "$spooldir/virtusertable", - "$spooldir/rcpthosts", - "$spooldir/recipientmap", - "$spooldir/virtualdomains", -; - -flock(SENDMAIL_CW,LOCK_UN); -flock(VIRTUSERTABLE,LOCK_UN); -flock(RCPTHOSTS,LOCK_UN); -flock(RECIPIENTMAP,LOCK_UN); -flock(VIRTUALDOMAINS,LOCK_UN); - -close SENDMAIL_CW; -close VIRTUSERTABLE; -close RCPTHOSTS; -close RECIPIENTMAP; -close VIRTUALDOMAINS; - -### -# export stuff -# - -my($sendmailmachine); -foreach $sendmailmachine (@sendmailmachines) { - scp("$spooldir/sendmail.cw","root\@$sendmailmachine:/etc/sendmail.cw.new") - == 0 or die "scp error: $!"; - scp("$spooldir/virtusertable","root\@$sendmailmachine:/etc/virtusertable.new") - == 0 or die "scp error: $!"; - ssh("root\@$sendmailmachine", - "( ". - "mv /etc/sendmail.cw.new /etc/sendmail.cw; ". - "mv /etc/virtusertable.new /etc/virtusertable; ". - #"/etc/init.d/sendmail restart; ". - " )" - ) - == 0 or die "ssh error: $!"; -} - -my($qmailmachine); -foreach $qmailmachine (@qmailmachines) { - scp("$spooldir/recipientmap","root\@$qmailmachine:/var/qmail/control/recipientmap") - == 0 or die "scp error: $!"; - scp("$spooldir/virtualdomains","root\@$qmailmachine:/var/qmail/control/virtualdomains") - == 0 or die "scp error: $!"; - scp("$spooldir/rcpthosts","root\@$qmailmachine:/var/qmail/control/rcpthosts") - == 0 or die "scp error: $!"; - #ssh("root\@$qmailmachine","/etc/init.d/qmail restart") - # == 0 or die "ssh error: $!"; -} - -unlink $spoollock; -flock(EXPORT,LOCK_UN); -close EXPORT; - diff --git a/bin/svc_acct_sm.import b/bin/svc_acct_sm.import index 10d7e4c20..723fb029f 100755 --- a/bin/svc_acct_sm.import +++ b/bin/svc_acct_sm.import @@ -1,5 +1,7 @@ #!/usr/bin/perl -Tw # +# $Id: svc_acct_sm.import,v 1.9 2001-04-22 01:56:15 ivan Exp $ +# # ivan@sisd.com 98-mar-9 # # generalized svcparts ivan@sisd.com 98-mar-23 @@ -12,19 +14,48 @@ # has an (untested) section for sendmail, s/warn/die/g and generates a program # to run on your mail machine _later_ instead of ssh'ing for each user # ivan@sisd.com 98-jul-13 +# +# $Log: svc_acct_sm.import,v $ +# Revision 1.9 2001-04-22 01:56:15 ivan +# get rid of FS::SSH.pm (became Net::SSH and Net::SCP on CPAN) +# +# Revision 1.8 2000/12/03 15:14:00 ivan +# bugfixes from Jeff Finucane <jeff@cmh.net>, thanks! +# +# Revision 1.7 2000/06/29 10:51:52 ivan +# oops, silly mistake +# +# Revision 1.6 2000/06/29 10:48:25 ivan +# make svc_acct_sm skip blank lines in sendmail import +# +# Revision 1.5 2000/02/03 05:16:52 ivan +# beginning of DNS and Apache support +# +# Revision 1.4 1999/03/25 08:42:20 ivan +# import stuff uses Term::Query and spits out (some kinds of) nonsensical input +# +# Revision 1.3 1999/03/24 00:51:55 ivan +# die if no relevant services... cvspain +# +# Revision 1.2 1998/12/10 07:23:18 ivan +# use FS::Conf, need user (for datasrc) +# use strict; use vars qw(%d_part_svc %m_part_svc); -use FS::SSH qw(iscp); -use FS::UID qw(adminsuidsetup); +use Term::Query qw(query); +use Net::SCP qw(iscp); +use FS::UID qw(adminsuidsetup datasrc); use FS::Record qw(qsearch qsearchs); use FS::svc_acct_sm; use FS::svc_domain; +use FS::svc_acct; +use FS::part_svc; -adminsuidsetup; +my $user = shift or die &usage; +adminsuidsetup $user; -#my($spooldir)="/var/spool/freeside/export"; -my($spooldir)="unix"; +my($spooldir)="/usr/local/etc/freeside/export.". datasrc; my(%mta) = ( 1 => "qmail", @@ -38,22 +69,33 @@ my(%mta) = ( %m_part_svc = map { $_->svcpart, $_ } qsearch('part_svc',{'svcdb'=>'svc_acct_sm'}); +die "No services with svcdb svc_domain!\n" unless %d_part_svc; +die "No services with svcdb svc_svc_acct_sm!\n" unless %m_part_svc; + print "\n\n", ( join "\n", map "$_: ".$d_part_svc{$_}->svc, sort keys %d_part_svc ), - "\n\nEnter part number for domains: "; -my($domain_svcpart)=&getvalue; + "\n\n"; +$^W=0; #Term::Query isn't -w-safe +my $domain_svcpart = + query "Enter part number for domains: ", 'irk', [ keys %d_part_svc ]; +$^W=1; print "\n\n", ( join "\n", map "$_: ".$m_part_svc{$_}->svc, sort keys %m_part_svc ), - "\n\nEnter part number for mail aliases: "; -my($mailalias_svcpart)=&getvalue; + "\n\n"; +$^W=0; #Term::Query isn't -w-safe +my $mailalias_svcpart = + query "Enter part number for mail aliases: ", 'irk', [ keys %m_part_svc ]; +$^W=1; print "\n\n", <<END; Select your MTA from the following list. END print join "\n", map "$_: $mta{$_}", sort keys %mta; -print "\n\n:"; -my($mta)=&getvalue; +print "\n\n"; +$^W=0; #Term::Query isn't -w-safe +my $mta = query ":", 'irk', [ keys %mta ]; +$^W=1; if ( $mta{$mta} eq "qmail" ) { @@ -61,8 +103,7 @@ if ( $mta{$mta} eq "qmail" ) { Enter the location and name of your qmail control directory, for example "mail.isp.com:/var/qmail/control" END - print ":"; - my($control)=&getvalue; + my($control)=&getvalue(":"); iscp("root\@$control/rcpthosts","$spooldir/rcpthosts.import"); # iscp("root\@$control/recipientmap","$spooldir/recipientmap.import"); iscp("root\@$control/virtualdomains","$spooldir/virtualdomains.import"); @@ -80,16 +121,14 @@ END Enter the location and name of your sendmail virtual user table, for example "mail.isp.com:/etc/virtusertable" END - print ":"; - my($virtusertable)=&getvalue; + my($virtusertable)=&getvalue(":"); iscp("root\@$virtusertable","$spooldir/virtusertable.import"); print "\n\n", <<END; Enter the location and name of your sendmail.cw file, for example "mail.isp.com:/etc/sendmail.cw" END - print ":"; - my($sendmail_cw)=&getvalue; + my($sendmail_cw)=&getvalue(":"); iscp("root\@$sendmail_cw","$spooldir/sendmail.cw.import"); } else { @@ -97,9 +136,11 @@ END } sub getvalue { - my($x)=scalar(<STDIN>); - chop $x; - $x; + my $prompt = shift; + $^W=0; #Term::Query isn't -w-safe + my $data = query $prompt, ''; + $^W=1; + $data; } print "\n\n"; @@ -123,13 +164,14 @@ my(%svcnum); while (<RCPTHOSTS>) { next if /^(#|$)/; + next if $mta{$mta} eq 'sendmail' && /^\s*$/; #blank lines /^\.?([\w\-\.]+)$/ #or do { warn "Strange rcpthosts/sendmail.cw line: $_"; next; }; or die "Strange rcpthosts/sendmail.cw line: $_"; my $domain = $1; my($svc_domain); unless ( $svc_domain = qsearchs('svc_domain', {'domain'=>$domain} ) ) { - $svc_domain = create FS::svc_domain ({ + $svc_domain = new FS::svc_domain ({ 'domain' => $domain, 'svcpart' => $domain_svcpart, 'action' => 'N', @@ -184,7 +226,7 @@ END } unless ( exists $svcnum{$domain} ) { - my($svc_domain) = create FS::svc_domain ({ + my($svc_domain) = new FS::svc_domain ({ 'domain' => $domain, 'svcpart' => $domain_svcpart, 'action' => 'N', @@ -195,7 +237,7 @@ END $svcnum{$domain}=$svc_domain->svcnum; } - my($svc_acct_sm)=create FS::svc_acct_sm ({ + my($svc_acct_sm)=new FS::svc_acct_sm ({ 'domsvc' => $svcnum{$domain}, 'domuid' => $svc_acct->uid, 'domuser' => '*', @@ -215,7 +257,8 @@ END or die "Can't open $spooldir/virtusertable.import: $!"; while (<VIRTUSERTABLE>) { next if /^#/; #comments? - /^([\w\-\.]+)?\@([\w\-\.]+)\t([\w\-\.]+)$/ + next if /^\s*$/; #blank lines + /^([\w\-\.]+)?\@([\w\-\.]+)\t+([\w\-\.]+)$/ #or do { warn "Strange virtusertable line: $_"; next; }; or die "Strange virtusertable line: $_"; my($domuser,$domain,$username)=($1,$2,$3); @@ -225,7 +268,7 @@ END die "Unknown user $username in virtusertable"; next; } - my($svc_acct_sm)=create FS::svc_acct_sm ({ + my($svc_acct_sm)=new FS::svc_acct_sm ({ 'domsvc' => $svcnum{$domain}, 'domuid' => $svc_acct->uid, 'domuser' => $domuser || '*', @@ -250,3 +293,9 @@ Don\'t forget to run $spooldir/virtualdomains.FIX before using $spooldir/virtualdomains ! END +# + +sub usage { + die "Usage:\n\n svc_acct_sm.import user\n"; +} + diff --git a/bin/svc_domain.import b/bin/svc_domain.import new file mode 100644 index 000000000..3d3be9da5 --- /dev/null +++ b/bin/svc_domain.import @@ -0,0 +1,92 @@ +#!/usr/bin/perl -w +# +# $Id: svc_domain.import,v 1.2 2001-04-22 01:56:15 ivan Exp $ + +use strict; +use vars qw( %d_part_svc ); +use Term::Query qw(query); +use Net::SCP qw(iscp); +use FS::UID qw(adminsuidsetup datasrc); +#use FS::Record qw(qsearch qsearchs); +#use FS::svc_acct_sm; +use FS::svc_domain; +use FS::domain_record; +#use FS::svc_acct; +#use FS::part_svc; + +my $user = shift or die &usage; +adminsuidsetup $user; + +my($spooldir)="/usr/local/etc/freeside/export.". datasrc; + +%d_part_svc = + map { $_->svcpart, $_ } qsearch('part_svc',{'svcdb'=>'svc_domain'}); + +print "\n\n", + ( join "\n", map "$_: ".$d_part_svc{$_}->svc, sort keys %d_part_svc ), + "\n\n"; +$^W=0; #Term::Query isn't -w-safe +my $domain_svcpart = + query "Enter part number for domains: ", 'irk', [ keys %d_part_svc ]; +$^W=1; + + print "\n\n", <<END; +Enter the location and name of your primary named.conf file, for example +"ns.isp.com:/var/named/named.conf" +END + my($named_conf)=&getvalue(":"); + iscp("root\@$named_conf","$spooldir/named.conf.import"); + +my $named_machine = (split(/:/, $named_conf))[0]; + +print "\n\n"; + +## + +$FS::svc_domain::whois_hack=1; + +open(NAMED_CONF,"<$spooldir/named.conf.import") + or die "Can't open $spooldir/named.conf.import: $!"; + +while (<NAMED_CONF>) { + next unless /^\s*options/; +} +my $directory; +while (<NAMED_CONF>) { + last if /^\s*directory\s+\"([\/\w+]+)\";/; +} +$directory = $1 or die "can't locate directory in named.conf!"; +whlie (<NAMED_CONF>) { + next unless /^\s*zone\s+\"([\w\.\-]+)\"\s+\{/; + my $zone = $1; + while (<NAMED_CONF>) { + my $type; + if ( /^\s*type\s+(master|slave)\s*\;/ ) { + $type = $1; + } + if ( /^\s*file\s+\"([\w\.\-]+)\"\s*\;/ && $type eq 'master' ) { + + # + # (add svc_domain) + my $file = $1; + iscp("root\@$named_machine:$directory/$file","$spooldir/$file.import"); + open(ZONE,"<$spooldir/$file.import") + or die "Can't open $spooldir/$file.import: $!"; + while (<ZONE>) { + # (add domain_record) + } + + # + + } + + last if /^\s*\}\s*\;/; + } +} + +## + +sub usage { + die "Usage:\n\n svc_domain.import user\n"; +} + |