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 | 83 | ||||
| -rwxr-xr-x | bin/freeside-init | 60 | ||||
| -rwxr-xr-x | bin/freeside-session-kill | 100 | ||||
| -rwxr-xr-x | bin/fs-migrate-part_svc | 41 | ||||
| -rwxr-xr-x | bin/fs-migrate-payref | 31 | ||||
| -rwxr-xr-x | bin/fs-migrate-svc_acct_sm | 230 | ||||
| -rwxr-xr-x | bin/fs-radius-add-check | 59 | ||||
| -rwxr-xr-x | bin/fs-radius-add-reply | 60 | ||||
| -rwxr-xr-x | bin/fs-setup | 644 | ||||
| -rwxr-xr-x | bin/generate-prepay | 35 | ||||
| -rwxr-xr-x | bin/generate-raddb | 37 | ||||
| -rwxr-xr-x | bin/generate-tests | 21 | ||||
| -rwxr-xr-x | bin/masonize | 70 | ||||
| -rwxr-xr-x | bin/pod2x | 53 | ||||
| -rwxr-xr-x | bin/svc_acct.export | 797 | ||||
| -rwxr-xr-x | bin/svc_acct.import | 119 | ||||
| -rwxr-xr-x | bin/svc_acct_sm.export | 221 | ||||
| -rwxr-xr-x | bin/svc_acct_sm.import | 84 | ||||
| -rw-r--r-- | bin/svc_domain.import | 92 | 
21 files changed, 2100 insertions, 931 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..0b297b9e6 100755 --- a/bin/dbdef-create +++ b/bin/dbdef-create @@ -1,85 +1,26 @@  #!/usr/bin/perl -Tw  # -# create dbdef file for existing mySQL database (needs SHOW|DESCRIBE command -# not in Pg) based on fs-setup -# -# ivan@sisd.com 98-jun-2 +# $Id: dbdef-create,v 1.5 2001-08-21 02:43:18 ivan Exp $  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; - -my($tables_sth)=$dbh->prepare("SHOW TABLES"); -my($tables_rv)=$tables_sth->execute; +use DBIx::DBSchema; +use FS::UID qw(adminsuidsetup datasrc driver_name); -my(@tables); -foreach ( @{$tables_sth->fetchall_arrayref} ) { -  my($table)=${$_}[0];  -  #print "TABLE\t$table\n"; +my $user = shift or die &usage; -  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($dbh)=adminsuidsetup $user; -  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, -    ); -  } +#needs to match FS::Record +my($dbdef_file) = "/usr/local/etc/freeside/dbdef.". datasrc; -  #print "\n"; -  push @tables, new FS::dbdef_table ( -    $table, -    $primary_key, -    new FS::dbdef_unique (\@unique), -    new FS::dbdef_index (\@index), -    @columns, -  ); +my $dbdef = new_native DBIx::DBSchema $dbh; -} - -my($dbdef) = new FS::dbdef ( @tables ); +#print $dbdef->pretty_print;  #important  $dbdef->save($dbdef_file); +sub usage { +  die "Usage:\n  dbdef-create user\n"; +} diff --git a/bin/freeside-init b/bin/freeside-init new file mode 100755 index 000000000..fe12931fc --- /dev/null +++ b/bin/freeside-init @@ -0,0 +1,60 @@ +#! /bin/sh +# +# start the freeside job queue daemon + +#PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/usr/local/bin/freeside-queued +NAME=freeside-queued +DESC="freeside job queue daemon" +USER="ivan" + +test -f $DAEMON || exit 0 + +set -e + +case "$1" in +  start) +	echo -n "Starting $DESC: " +#	start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid -b -m\ +#		--exec $DAEMON +	$DAEMON $USER & +	echo "$NAME." +	;; +  stop) +	echo -n "Stopping $DESC: " +	start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid \ +		--exec $DAEMON +	echo "$NAME." +        rm /var/run/$NAME.pid +	;; +  #reload) +	# +	#	If the daemon can reload its config files on the fly +	#	for example by sending it SIGHUP, do it here. +	# +	#	If the daemon responds to changes in its config file +	#	directly anyway, make this a do-nothing entry. +	# +	# echo "Reloading $DESC configuration files." +	# start-stop-daemon --stop --signal 1 --quiet --pidfile \ +	#	/var/run/$NAME.pid --exec $DAEMON +  #;; +  restart|force-reload) +	# +	#	If the "reload" option is implemented, move the "force-reload" +	#	option to the "reload" entry above. If not, "force-reload" is +	#	just the same as "restart". +	# +        $0 stop +	sleep 1 +        $0 start +	;; +  *) +	N=/etc/init.d/$NAME +	# echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2 +	echo "Usage: $N {start|stop|restart|force-reload}" >&2 +	exit 1 +	;; +esac + +exit 0 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-part_svc b/bin/fs-migrate-part_svc new file mode 100755 index 000000000..b0f3ac57e --- /dev/null +++ b/bin/fs-migrate-part_svc @@ -0,0 +1,41 @@ +#!/usr/bin/perl + +use strict; +use FS::UID qw(adminsuidsetup); +use FS::Record qw(qsearch fields); +use FS::part_svc; + +my $user = shift or die &usage; +my $dbh = adminsuidsetup $user; + +my $oldAutoCommit = $FS::UID::AutoCommit; +local $FS::UID::AutoCommit = 0; + +foreach my $part_svc ( qsearch('part_svc', {} ) ) { +  foreach my $field ( +    grep { defined($part_svc->getfield($part_svc->svcdb.'__'.$_.'_flag') ) } +      fields($part_svc->svcdb) +  ) { +    my $flag = $part_svc->getfield($part_svc->svcdb.'__'.$field.'_flag'); +    if ( uc($flag) =~ /^([DF])$/ ) { +      my $part_svc_column = new FS::part_svc_column { +        'svcpart' => $part_svc->svcpart, +        'columnname' => $field, +        'columnflag' => $1, +        'columnvalue' => $part_svc->getfield($part_svc->svcdb.'__'.$field), +      }; +      my $error = $part_svc_column->insert; +      if ( $error ) { +        $dbh->rollback if $oldAutoCommit; +        die $error; +      } +    } +  } +} + +$dbh->commit or die $dbh->errstr; + +sub usage { +  die "Usage:\n  fs-migrate-part_svc user\n";  +} + diff --git a/bin/fs-migrate-payref b/bin/fs-migrate-payref new file mode 100755 index 000000000..158419706 --- /dev/null +++ b/bin/fs-migrate-payref @@ -0,0 +1,31 @@ +#!/usr/bin/perl + +use strict; +use FS::UID qw(adminsuidsetup); +use FS::Record qw(qsearch); +use FS::cust_pay; +use FS::cust_refund; + +my $user = shift or die &usage; +my $dbh = adminsuidsetup $user; + +# apply payments to invoices + +foreach my $cust_pay ( qsearch('cust_pay', {} ) ) { +  my $error = $cust_pay->upgrade_replace; +  warn $error if $error; +} + +# apply refunds to credits + +foreach my $cust_refund ( qsearch('cust_refund') ) { +  my $error = $cust_refund->upgrade_replace; +  warn $error if $error; +} + +# ? apply credits to invoices + +sub usage { +  die "Usage:\n  fs-migrate-payref user\n";  +} + diff --git a/bin/fs-migrate-svc_acct_sm b/bin/fs-migrate-svc_acct_sm new file mode 100755 index 000000000..ae2dc764d --- /dev/null +++ b/bin/fs-migrate-svc_acct_sm @@ -0,0 +1,230 @@ +#!/usr/bin/perl -Tw +# +# $Id: fs-migrate-svc_acct_sm,v 1.3 2001-08-21 02:43:18 ivan Exp $ +# +# jeff@cmh.net 01-Jul-20 + +#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..35f4d3262 --- /dev/null +++ b/bin/fs-radius-add-check @@ -0,0 +1,59 @@ +#!/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); +use FS::raddb; + +die "Not running uid freeside!" unless checkeuid(); + +my %attrib2db = +  map { lc($FS::raddb::attrib{$_}) => $_ } keys %FS::raddb::attrib; + +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 { $attrib2db{lc($_)} or die "unknown attribute $_"; } +                   split(" ",&getvalue); + +sub getvalue { +  my($x)=scalar(<STDIN>); +  chop $x; +  $x; +} + +### + +my($char_d) = 80; #default maxlength for text fields + +### + +foreach my $attribute ( @attributes ) { +  my $statement = +    "ALTER TABLE svc_acct ADD COLUMN rc_$attribute varchar($char_d) NULL"; +  my $sth = $dbh->prepare( $statement ) +   or warn "Error preparing $statement: ". $dbh->errstr; +  my $rc = $sth->execute +    or warn "Error executing $statement: ". $sth->errstr; +} + +$dbh->commit or die $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-check user\n";  +} + diff --git a/bin/fs-radius-add-reply b/bin/fs-radius-add-reply new file mode 100755 index 000000000..6b9a39e49 --- /dev/null +++ b/bin/fs-radius-add-reply @@ -0,0 +1,60 @@ +#!/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); +use FS::raddb; + +die "Not running uid freeside!" unless checkeuid(); + +my %attrib2db = +  map { lc($FS::raddb::attrib{$_}) => $_ } keys %FS::raddb::attrib; + +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 { $attrib2db{lc($_)} or die "unknown attribute $_"; } +                   split(" ",&getvalue); + +sub getvalue { +  my($x)=scalar(<STDIN>); +  chop $x; +  $x; +} + +### + +my($char_d) = 80; #default maxlength for text fields + +### + +foreach my $attribute ( @attributes ) { +  my $statement = +    "ALTER TABLE svc_acct ADD COLUMN radius_$attribute varchar($char_d) NULL"; +  my $sth = $dbh->prepare( $statement ) +    or warn "Error preparing $statement: ". $dbh->errstr; +  $sth->execute +    or warn "Error executing $statement: ". $sth->errstr; +} + +$dbh->commit or die $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-reply user\n";  +} + + diff --git a/bin/fs-setup b/bin/fs-setup index 45332d85c..7c716d35e 100755 --- a/bin/fs-setup +++ b/bin/fs-setup @@ -1,60 +1,64 @@  #!/usr/bin/perl -Tw  # -# create database and necessary tables, etc.  DBI version. -# -# ivan@sisd.com 97-nov-8,9 -# -# agent_type and type_pkgs added. -# (index need to be declared, & primary keys shoudln't have mysql syntax) -# ivan@sisd.com 97-nov-13 -# -# pulled modified version back out of register.cgi ivan@sisd.com 98-feb-21 -# -# removed extraneous sample data ivan@sisd.com 98-mar-23 -# -# gained the big hash from dbdef.pm, dbdef.pm usage rewrite ivan@sisd.com -# 98-apr-19 - 98-may-11 plus -# -# finished up ivan@sisd.com 98-jun-1 -# -# part_svc fields are all forced NULL, not the opposite -# hmm: also are forced varchar($char_d) as fixed '0' for things like -# uid is Not Good.  will this break anything else? -# ivan@sisd.com 98-jun-29 -# -# ss is 11 chars ivan@sisd.com 98-jul-20 -# -# setup of arbitrary radius fields ivan@sisd.com 98-aug-9 -# -# ouch, removed index on company name that wasn't supposed to be there -# ivan@sisd.com 98-sep-4 -# -# fix radius attributes ivan@sisd.com 98-sep-27 +# $Id: fs-setup,v 1.77 2002-02-12 05:58:42 ivan Exp $  #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.19; +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; +use FS::raddb; +use FS::part_bill_event; + +die "Not running uid freeside!" unless checkeuid(); + +my %attrib2db = +  map { lc($FS::raddb::attrib{$_}) => $_ } keys %FS::raddb::attrib; + +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;  ### -print "\nEnter the maximum username length: "; -my($username_len)=&getvalue; +#print "\nEnter the maximum username length: "; +#my($username_len)=&getvalue; +my $username_len = 32; #usernamemax config file  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 User-Name, check attribute Password and +reply attribute Framed-IP-Address for each user.  You can specify additional +check and reply attributes (or you can add them later with the +fs-radius-add-check and fs-radius-add-reply programs). + +First enter any additional RADIUS check attributes you need to track for each  +user, separated by whitespace.  END -my @attributes = map { s/\-/_/g; $_; } split(" ",&getvalue); +my @check_attributes = map { $attrib2db{lc($_)} or die "unknown attribute $_"; } +                         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 { $attrib2db{lc($_)} or die "unknown attribute $_"; } +                   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>); @@ -62,19 +66,20 @@ sub getvalue {    $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) = ( 'text', 'NULL', ''  );  +my @money_type = ( 'decimal',   '', '10,2' );  ###  # create a dbdef object from the old data structure @@ -83,30 +88,35 @@ 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) ); +my $cust_main = $dbdef->table('cust_main'); +unless ($ship) { #remove ship_ from cust_main +  $cust_main->delcolumn($_) foreach ( grep /^ship_/, $cust_main->columns ); +} else { #add indices on ship_last and ship_company +  push @{$cust_main->index->lol_ref}, ( ['ship_last'], ['ship_company'] )  +} +  #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,82 +124,147 @@ foreach $attribute (@attributes) {    ));  } -#make part_svc table (but now as object) - -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)) { -  my($table)=$dbdef->table($_); -  my($col); -  foreach $col ( $table->columns ) { -    next if $col =~ /^svcnum$/; -    $part_svc->addcolumn( new FS::dbdef_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 ( -      $table->name. '__'. $table->column($col)->name . "_flag", -      'char', -      'NULL', -      1, -    )); -  } +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'); +# +##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_domain svc_forward svc_www)) { +#  my($table)=$dbdef->table($_); +#  my($col); +#  foreach $col ( $table->columns ) { +#    next if $col =~ /^svcnum$/; +#    $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 DBIx::DBSchema::Column ( +#      $table->name. '__'. $table->column($col)->name . "_flag", +#      'char', +#      'NULL', +#      1, +#    )); +#  } +#} +  #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)=create FS::cust_main_county({ +  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)=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; +  die $error if $error; +} + +#billing events +foreach my $aref (  +  [ 'COMP', 'Comp invoice', '$cust_bill->comp();', 30, 'comp' ], +  [ 'CARD', 'Batch card', '$cust_bill->batch_card();', 40, 'batch-card' ], +  [ 'BILL', 'Send invoice', '$cust_bill->send();', 50, 'send' ], +) { + +  my $part_bill_event = new FS::part_bill_event({ +    'payby' => $aref->[0], +    'event' => $aref->[1], +    'eventcode' => $aref->[2], +    'seconds' => 0, +    'weight' => $aref->[3], +    'plan' => $aref->[4], +  }); +  my($error); +  $error=$part_bill_event->insert; +  die $error if $error; + +} + +  $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 +281,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,14 +315,43 @@ sub tables_hash_hack {          'custnum',   'int',  '', '',          '_date',     @date_type,          'charged',   @money_type, -        'owed',      @money_type,          'printed',   'int',  '', '', +        'closed',    'char', 'NULL', 1,        ],        'primary_key' => 'invnum',        'unique' => [ [] ],        'index' => [ ['custnum'] ],      }, +    'cust_bill_event' => { +      'columns' => [ +        'eventnum',    'int',  '', '', +        'invnum',   'int',  '', '', +        'eventpart',   'int',  '', '', +        '_date',     @date_type, +      ], +      'primary_key' => 'eventnum', +      'unique' => [ [ 'eventpart', 'invnum' ] ], +      'index' => [ ['invnum'] ], +    }, + +    'part_bill_event' => { +      'columns' => [ +        'eventpart',    'int',  '', '', +        'payby',       'char',  '', 4, +        'event',       'varchar',           '',     $char_d, +        'eventcode',    @perl_type, +        'seconds',     'int', 'NULL', '', +        'weight',      'int', '', '', +        'plan',       'varchar', 'NULL', $char_d, +        'plandata',   'text', 'NULL', '', +        'disabled',     'char', 'NULL', 1, +      ], +      'primary_key' => 'eventpart', +      'unique' => [ [] ], +      'index' => [ ['payby'] ], +    }, +      'cust_bill_pkg' => {        'columns' => [          'pkgnum',  'int', '', '', @@ -268,20 +372,35 @@ sub tables_hash_hack {          'custnum',  'int', '', '',          '_date',    @date_type,          'amount',   @money_type, -        'credited', @money_type,          'otaker',   'varchar', '', 8, -        'reason',   'varchar', '', 255, +        'reason',   'text', 'NULL', '', +        'closed',    'char', 'NULL', 1,        ],        'primary_key' => 'crednum',        'unique' => [ [] ],        'index' => [ ['custnum'] ],      }, +    'cust_credit_bill' => { +      'columns' => [ +        'creditbillnum', 'int', '', '', +        'crednum',  'int', '', '', +        'invnum',  'int', '', '', +        '_date',    @date_type, +        'amount',   @money_type, +      ], +      'primary_key' => 'creditbillnum', +      'unique' => [ [] ], +      'index' => [ ['crednum'], ['invnum'] ], +    }, +      'cust_main' => {        '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,33 +408,62 @@ 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, +        'payinfo',  'varchar', 'NULL', $char_d, +        #'paydate',  @date_type, +        'paydate',  'varchar', 'NULL', 10,          'payname',  'varchar', 'NULL', $char_d,          'tax',      'char', 'NULL', 1,          'otaker',   'varchar', '',     8,          'refnum',   'int',  '',     '', +        'referral_custnum', 'int',  'NULL', '', +        'comments', 'text', 'NULL', '',        ],        'primary_key' => 'custnum',        'unique' => [ [] ],        #'index' => [ ['last'], ['company'] ], -      'index' => [ ['last'], ], +      'index' => [ ['last'], [ 'company' ], [ 'referral_custnum' ] ],      }, -    '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', @@ -327,22 +475,38 @@ sub tables_hash_hack {      'cust_pay' => {        'columns' => [          'paynum',   'int',    '',   '', -        'invnum',   'int',    '',   '', +        #now cust_bill_pay #'invnum',   'int',    '',   '', +        'custnum',  'int',    '',   '',          'paid',     @money_type,          '_date',    @date_type,          'payby',    'char',   '',     4, # CARD/BILL/COMP, should be index into                                           # payment type table.          'payinfo',  'varchar',   'NULL', 16,  #see cust_main above          'paybatch', 'varchar',   'NULL', $char_d, #for auditing purposes. +        'closed',    'char', 'NULL', 1,        ],        'primary_key' => 'paynum',        'unique' => [ [] ], -      'index' => [ ['invnum'] ], +      'index' => [ [ 'custnum' ], [ 'paybatch' ] ], +    }, + +    'cust_bill_pay' => { +      'columns' => [ +        'billpaynum', 'int',     '',   '', +        'invnum',  'int',     '',   '', +        'paynum',  'int',     '',   '', +        'amount',  @money_type, +        '_date',   @date_type +      ], +      'primary_key' => 'billpaynum', +      'unique' => [ [] ], +      'index' => [ [ 'paynum' ], [ 'invnum' ] ],      },      'cust_pay_batch' => { #what's this used for again?  list of customers                            #in current CARD batch? (necessarily CARD?)        'columns' => [ +        'paybatchnum',   'int',    '',   '',          'invnum',   'int',    '',   '',          'custnum',   'int',    '',   '',          'last',     'varchar', '',     $char_d, @@ -350,16 +514,17 @@ 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,        ], -      'primary_key' => '', +      'primary_key' => 'paybatchnum',        'unique' => [ [] ],        'index' => [ ['invnum'], ['custnum'] ],      }, @@ -375,6 +540,7 @@ sub tables_hash_hack {          'susp',      @date_type,          'cancel',    @date_type,          'expire',    @date_type, +        'manual_flag', 'char', 'NULL', 1,        ],        'primary_key' => 'pkgnum',        'unique' => [ [] ], @@ -384,7 +550,8 @@ sub tables_hash_hack {      'cust_refund' => {        'columns' => [          'refundnum',    'int',    '',   '', -        'crednum',      'int',    '',   '', +        #now cust_credit_refund #'crednum',      'int',    '',   '', +        'custnum',  'int',    '',   '',          '_date',        @date_type,          'refund',       @money_type,          'otaker',       'varchar',   '',   8, @@ -392,16 +559,32 @@ sub tables_hash_hack {          'payby',        'char',   '',     4, # CARD/BILL/COMP, should be index                                               # into payment type table.          'payinfo',      'varchar',   'NULL', 16,  #see cust_main above +        'paybatch',     'varchar',   'NULL', $char_d, +        'closed',    'char', 'NULL', 1,        ],        'primary_key' => 'refundnum',        'unique' => [ [] ], -      'index' => [ ['crednum'] ], +      'index' => [ [] ],      }, +    'cust_credit_refund' => { +      'columns' => [ +        'creditrefundnum', 'int',     '',   '', +        'crednum',  'int',     '',   '', +        'refundnum',  'int',     '',   '', +        'amount',  @money_type, +        '_date',   @date_type +      ], +      'primary_key' => 'creditrefundnum', +      'unique' => [ [] ], +      'index' => [ [ 'crednum', 'refundnum' ] ], +    }, + +      'cust_svc' => {        'columns' => [          'svcnum',    'int',    '',   '', -        'pkgnum',    'int',    '',   '', +        'pkgnum',    'int',    'NULL',   '',          'svcpart',   'int',    '',   '',        ],        'primary_key' => 'svcnum', @@ -415,14 +598,29 @@ 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, +        'setuptax',  'char', 'NULL', 1, +        'recurtax',  'char', 'NULL', 1, +        'plan',       'varchar', 'NULL', $char_d, +        'plandata',   'text', 'NULL', '', +        'disabled',   'char', 'NULL', 1,        ],        'primary_key' => 'pkgpart',        'unique' => [ [] ],        'index' => [ [] ],      }, +#    'part_title' => { +#      'columns' => [ +#        'titlenum',   'int',    '',   '', +#        'title',      'varchar',   '',   $char_d, +#      ], +#      'primary_key' => 'titlenum', +#      'unique' => [ [] ], +#      'index' => [ [] ], +#    }, +      'pkg_svc' => {        'columns' => [          'pkgpart',    'int',    '',   '', @@ -449,57 +647,87 @@ sub tables_hash_hack {          'svcpart',    'int',    '',   '',          'svc',        'varchar',   '',   $char_d,          'svcdb',      'varchar',   '',   $char_d, +        'disabled',   'char',  'NULL',   1,        ],        'primary_key' => 'svcpart',        'unique' => [ [] ],        'index' => [ [] ],      }, +    'part_svc_column' => { +      'columns' => [ +        'columnnum',   'int',         '', '', +        'svcpart',     'int',         '', '', +        'columnname',  'varchar',     '', 64, +        'columnvalue', 'varchar', 'NULL', $char_d, +        'columnflag',  'char',    'NULL', 1,  +      ], +      'primary_key' => 'columnnum', +      'unique' => [ [ 'svcpart', 'columnname' ] ], +      'index' => [ [ 'svcpart' ] ], +    }, +      #(this should be renamed to part_pop)      'svc_acct_pop' => {        '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' => [ [] ], -      'index' => [ [] ], +      'index' => [ [ 'state' ] ], +    }, + +    'part_pop_local' => { +      'columns' => [ +        'localnum',  'int',     '',     '', +        'popnum',    'int',     '',     '', +        'city',      'varchar', 'NULL', $char_d, +        'state',     'char',    'NULL', 2, +        'npa',       'char',    '',     3, +        'nxx',       'char',    '',     3, +      ], +      'primary_key' => 'popnum', +      'unique' => [ [] ], +      'index' => [ [ 'npa', 'nxx' ] ],      },      'svc_acct' => {        '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'] ], +      'unique' => [ [ 'username', 'domsvc' ] ], +      'index' => [ ['username'], ['domsvc'] ],      }, -    'svc_acct_sm' => { -      'columns' => [ -        'svcnum',    'int',    '',   '', -        'domsvc',    'int',    '',   '', -        'domuid',    'bigint', '',   '', -        'domuser',   'varchar',   '',   $char_d, -      ], -      'primary_key' => 'svcnum', -      'unique' => [ [] ], -      'index' => [ ['domsvc'], ['domuid'] ],  -    }, +#    'svc_acct_sm' => { +#      'columns' => [ +#        'svcnum',    'int',    '',   '', +#        'domsvc',    'int',    '',   '', +#        'domuid',    'int', '',   '', +#        'domuser',   'varchar',   '',   $char_d, +#      ], +#      'primary_key' => 'svcnum', +#      'unique' => [ [] ], +#      'index' => [ ['domsvc'], ['domuid'] ],  +#    },      #'svc_charge' => {      #  'columns' => [ @@ -515,12 +743,50 @@ sub tables_hash_hack {        'columns' => [          'svcnum',    'int',    '',   '',          'domain',    'varchar',    '',   $char_d, +        'catchall',  'int', 'NULL',    '',        ],        '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,104 @@ 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' ] ], +    }, + +    'queue' => { +      'columns' => [ +        'jobnum', 'int', '', '', +        'job', 'text', '', '', +        '_date', 'int', '', '', +        'status', 'varchar', '', $char_d, +      ], +      'primary_key' => 'jobnum', +      'unique'      => [], +      'index'       => [], +    }, + +    'queue_arg' => { +      'columns' => [ +        'argnum', 'int', '', '', +        'jobnum', 'int', '', '', +        'arg', 'text', 'NULL', '', +      ], +      'primary_key' => 'argnum', +      'unique'      => [], +      'index'       => [ [ 'jobnum' ] ], +    }, + +    'part_export' => { +      'columns' => [ +        'exportnum', 'int', '', '', +        'svcpart',   'int', '', '', +        'machine', 'varchar', '', $char_d, +        'exporttype', 'varchar', '', $char_d, +        'nodomain',     'char', 'NULL', 1, +      ], +      'primary_key' => 'exportnum', +      'unique'      => [], +      'index'       => [ [ 'machine' ], [ 'exporttype' ] ], +    }, + +    'part_export_option' => { +      'columns' => [ +        'optionnum', 'int', '', '', +        'exportnum', 'int', '', '', +        'option', 'varchar', '', $char_d, +        'optionvalue', 'text', 'NULL', '', +      ], +      'primary_key' => 'optionnum', +      'unique'      => [], +      'index'       => [ [ 'exportnum' ], [ 'option' ] ], +    }, +    );    %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/generate-raddb b/bin/generate-raddb new file mode 100755 index 000000000..1d0053a2b --- /dev/null +++ b/bin/generate-raddb @@ -0,0 +1,37 @@ +#!/usr/bin/perl + +# usage: generate-raddb radius-server/raddb/dictionary* >raddb.pm +#  i.e.: generate-raddb ~/src/freeradius-0.2/raddb/dictionary* >FS/raddb.pm + +print <<END; +package FS::raddb; +use vars qw(%attrib); + +%attrib = ( +END + +while (<>) { +  next if /^(#|\s*$|\$INCLUDE\s+)/; +  next if /^(VALUE|VENDOR|BEGIN\-VENDOR|END\-VENDOR)\s+/; +  /^(ATTRIBUTE|ATTRIB_NMC)\s+([\w\-]+)\s+/ or die $_; +  $attrib = $2; +  $dbname = lc($2); +  $dbname =~ s/\-/_/g; +  $hash{$dbname} = $attrib; +  #print "$2\n"; +} + +foreach ( keys %hash ) { +#  print "$_\n" if length($_)>24; +#  print substr($_,0,24),"\n" if length($_)>24;  +#  $max = length($_) if length($_)>$max; +#everything >24 is still unique, at least with freeradius comprehensive dataset +  print "  '". substr($_,0,24). "' => '$hash{$_}',\n"; +} + +print <<END; +); + +1; +END + diff --git a/bin/generate-tests b/bin/generate-tests new file mode 100755 index 000000000..73fd29ecb --- /dev/null +++ b/bin/generate-tests @@ -0,0 +1,21 @@ +#!/usr/bin/perl +@files = glob('FS/*.pm'); +foreach (@files) { +#  warn $_; +  chomp; +  s/^FS\///; +  $f=$_; +  $f=~s/pm$/t/; +  $m=$_; +  $m=~s/\.pm$//; +  open(TEST,">t/$f"); +  print "t/$f\n"; +  print TEST +             'BEGIN { $| = 1; print "1..1\n" }'. "\n". +             'END {print "not ok 1\n" unless $loaded;}'. "\n". +             "use FS::$m;\n". +             '$loaded=1;'. "\n". +             'print "ok 1\n";'. "\n" +             ; +  close TEST; +} 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,54 @@  #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"; -  my $name = $1; -  print "$name\n";  -  system "pod2text $file >$catman/$name.txt";  -#  system "pod2html --podpath=$site_perl $file >$html/$name.html"; +#make some useless links +foreach my $file ( +  glob("$site_perl/bin/freeside-*"), +) { +  next if $file =~ /\.pod$/; +  #symlink $file, "$file.pod"; # or die "link $file to $file.pod: $!"; +  system("cp $file $file.pod"); +} + +foreach my $file ( +  glob("$site_perl/*.pm"), +  glob("$site_perl/*/*.pm"), +  glob("$site_perl/*/*/*.pm"), +  glob("$site_perl/bin/*.pod"), +  glob("./fs_sesmon/FS-SessionClient/*.pm"), +  glob("./fs_signup/FS-SignupClient/*.pm"), +  glob("./fs_selfadmin/FS-MailAdminServer/*.pm"), +) { +  next if $file =~ /^blib\//; +  #$file =~ /\/([\w\-]+)\.pm$/ or die "oops file $file"; +  my $name; +  if ( $file =~ /fs_\w+\/FS\-\w+\/(.*)\.pm$/ ) { +    $name = "FS/$1"; +  } elsif ( $file =~ /$site_perl\/(.*)\.(pm|pod)$/ ) { +    $name = $1; +  } else { +    die "oops file $file"; +  } +  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:.:./bin --norecurse --htmlroot=$htmlroot $file >$html/$name.html"; +  #system "pod2html --podroot=$site_perl --htmlroot=$htmlroot $file >$html/$name.html";  #  system "pod2html $file >$html/$name.html";  } + +#remove the useless links +unlink glob("$site_perl/bin/*.pod"); + diff --git a/bin/svc_acct.export b/bin/svc_acct.export index 3f65a08ba..cee63bcd5 100755 --- a/bin/svc_acct.export +++ b/bin/svc_acct.export @@ -1,108 +1,110 @@ -#!/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.32 2002-02-15 20:21:56 jeff Exp $  # -# ivan@voicenet.com late august/september 96 -# (the password encryption bits were from melody) -# -# 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 -# -# 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 +# 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 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; -} +warn "using depriciated textradiusprepend file" if $textradiusprepend; + + +my $radiusprepend = +  $conf->exists('radiusprepend') +    ? join("\n", $conf->config('radiusprepend')) +    : ''; + +my @vpopmailmachines = $conf->config('vpopmailmachines') +  if $conf->exists('vpopmailmachines'); +my $vpopmailrestart = ''; +$vpopmailrestart = $conf->config('vpopmailrestart') +  if $conf->exists('vpopmailrestart'); + +my ($machine, $vpopdir, $vpopuid, $vpopgid) = split (/\s+/, $vpopmailmachines[0]) if $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 +112,426 @@ 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'; +print USERS "$radiusprepend\n"; + +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" if $vpopmailmachines[0]; + +  (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->getfield('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 \"\" " . $svc_acct->email . "\n" +      if $vpopmailmachines[0]; +  }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" +      if $vpopmailmachines[0]; +  } -    ### -    # 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 ) +    if ( ( length($password) <= 12 ) +         && ( $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 ($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; +    } elsif ($userpolicy =~ /^append domain$/) { +      $username=$svc_acct->username . $svc_domain->domain; +    } elsif ($userpolicy =~ /^append \@domain$/) { +      $username=$svc_acct->username . '@'. $svc_domain->domain; +    } else { +      die "Unknown policy in username_policy\n"; +    } -  if ( $svc_acct->slipip ne '' ) { +    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 ACP_* FILES HERE -    print ACP_PASSWD join(":", +    # FORMAT OF THE VPASSWD FILE HERE +    print VPASSWD join(":",        $svc_acct->username,        $cpassword, -      "0", -      "0", -      "", -      "", -      "", +      '1', +      '0', +      $svc_acct->username, +      "$vpopdir/domains/" . $svc_domain->domain ."/" . $svc_acct->username, +      'NOQUOTA',      ), "\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->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;      } +   +        if ( $ip && $ip ne '0e0' ) { +          my $sth = $icradius_dbh->prepare( +            "INSERT INTO radreply (id, UserName, Attribute, Value) VALUES ( ". +            join(", ", map { $icradius_dbh->quote( $_ ) } ( +              '', +              $username, +              'Framed-IP-Address', +              $ip, +            ) ). " )" +          ); +          $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 +539,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,14 +569,16 @@ 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; ". -      "mv /etc/master.passwd.new /etc/master.passwd; ". +      #"mv /etc/master.passwd.new /etc/master.passwd; ". +      "pwd_mkdb /etc/master.passwd.new; ".      " )"    )      == 0 or die "ssh error: $!"; @@ -307,10 +586,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 +601,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 +616,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 +627,102 @@ 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}; + +  ssh("root\@$machine", +    "( ". +      $vpopmailrestart . +    " )" +  ) +    == 0 or die "ssh error: $!"; + + +} + +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..eb94e1c37 100755 --- a/bin/svc_acct.import +++ b/bin/svc_acct.import @@ -1,31 +1,22 @@  #!/usr/bin/perl -Tw -# -# ivan@sisd.com 98-mar-9 -# -# changed 'password' field to '_password' because PgSQL 6.3 reserves this word -#	bmccane@maxbaud.net  98-Apr-3 -# -# generalized svcparts (still needs radius import) ivan@sisd.com 98-mar-23 -# -# radius import, now an interactive script.  still needs erpcd import? -# ivan@sisd.com 98-jun-24 -# -# arbitrary radius attributes ivan@sisd.com 98-aug-9 -# -# don't import /var/spool/freeside/conf/shells!  ivan@sisd.com 98-aug-13 +# $Id: svc_acct.import,v 1.17 2001-08-19 10:25:44 ivan Exp $  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; + +my $user = shift or die &usage; +adminsuidsetup $user; -adminsuidsetup; +push @FS::svc_acct::shells, qw(/bin/sync /sbin/shuddown /bin/halt); #others? -#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 +24,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 +51,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 +63,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 +109,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 +125,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 +143,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 +181,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 +215,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 +230,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..b668405f5 100755 --- a/bin/svc_acct_sm.import +++ b/bin/svc_acct_sm.import @@ -1,30 +1,22 @@  #!/usr/bin/perl -Tw  # -# ivan@sisd.com 98-mar-9 -# -# generalized svcparts ivan@sisd.com 98-mar-23 - -# You really need to enable ssh into a shell machine as this needs to rename -# .qmail-extension files. -# -# now an interactive script ivan@sisd.com 98-jun-30 -# -# 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 +# $Id: svc_acct_sm.import,v 1.10 2001-08-21 02:43:18 ivan Exp $  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 +30,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 +64,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 +82,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 +97,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 +125,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 +187,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 +198,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 +218,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 +229,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 +254,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..10fe5b584 --- /dev/null +++ b/bin/svc_domain.import @@ -0,0 +1,92 @@ +#!/usr/bin/perl -w +# +# $Id: svc_domain.import,v 1.3 2001-11-05 12:07:10 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!"; +while (<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"; +} +  | 
