diff options
Diffstat (limited to 'bin')
-rw-r--r-- | bin/backup-freeside | 6 | ||||
-rwxr-xr-x | bin/dbdef-create | 37 | ||||
-rwxr-xr-x | bin/freeside-session-kill | 100 | ||||
-rwxr-xr-x | bin/fs-radius-add-check | 52 | ||||
-rwxr-xr-x | bin/fs-radius-add-reply | 52 | ||||
-rwxr-xr-x | bin/fs-setup | 799 | ||||
-rwxr-xr-x | bin/generate-prepay | 35 | ||||
-rwxr-xr-x | bin/pod2x | 29 | ||||
-rwxr-xr-x | bin/svc_acct.export | 458 | ||||
-rwxr-xr-x | bin/svc_acct.import | 289 | ||||
-rwxr-xr-x | bin/svc_acct_sm.export | 254 | ||||
-rwxr-xr-x | bin/svc_acct_sm.import | 301 | ||||
-rw-r--r-- | bin/svc_domain.import | 92 |
13 files changed, 2504 insertions, 0 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/dbdef-create b/bin/dbdef-create new file mode 100755 index 000000000..902f7f145 --- /dev/null +++ b/bin/dbdef-create @@ -0,0 +1,37 @@ +#!/usr/bin/perl -Tw +# +# $Id: dbdef-create,v 1.3 2001-04-15 12:56:31 ivan Exp $ +# +# create dbdef file for existing mySQL database (needs SHOW|DESCRIBE command +# not in Pg) based on fs-setup +# +# ivan@sisd.com 98-jun-2 +# +# $Log: dbdef-create,v $ +# Revision 1.3 2001-04-15 12:56:31 ivan +# s/dbdef/DBIx::DBSchema/ +# +# Revision 1.2 1998/11/19 11:17:44 ivan +# adminsuidsetup requires argument +# + +use strict; +use DBI; +use DBIx::DBSchema; +use FS::UID qw(adminsuidsetup datasrc driver_name); + +my $user = shift or die &usage; + +my($dbh)=adminsuidsetup $user; + +#needs to match FS::Record +my($dbdef_file) = "/usr/local/etc/freeside/dbdef.". datasrc; + +my $dbdef = new_native DBIx::DBSchema $dbh; + +#important +$dbdef->save($dbdef_file); + +sub usage { + die "Usage:\n dbdef-create user\n"; +} diff --git a/bin/freeside-session-kill b/bin/freeside-session-kill new file mode 100755 index 000000000..9f11abd5b --- /dev/null +++ b/bin/freeside-session-kill @@ -0,0 +1,100 @@ +#!/usr/bin/perl -w + +use strict; +use vars qw($conf); +use Fcntl qw(:flock); +use FS::UID qw(adminsuidsetup datasrc dbh); +use FS::Record qw(dbdef qsearch fields); +use FS::session; +use FS::svc_acct; + +my $user = shift or die &usage; +adminsuidsetup $user; + +my $sessionlock = "/usr/local/etc/freeside/session-kill.lock.". datasrc; + +open(LOCK,"+>>$sessionlock") or die "Can't open $sessionlock: $!"; +select(LOCK); $|=1; select(STDOUT); +unless ( flock(LOCK,LOCK_EX|LOCK_NB) ) { + seek(LOCK,0,0); + my($pid)=<LOCK>; + chop($pid); + #no reason to start loct of blocking processes + die "Is another session kill process running under pid $pid?\n"; +} +seek(LOCK,0,0); +print LOCK $$,"\n"; + +$FS::UID::AutoCommit = 0; + +my $now = time; + +#uhhhhh + +use DBIx::DBSchema; +use DBIx::DBSchema::Table; #down this path lies madness +use DBIx::DBSchema::Column; + +my $dbdef = dbdef or die; +#warn $dbdef; +#warn $dbdef->{'tables'}; +#warn keys %{$dbdef->{'tables'}}; +my $session_table = $dbdef->table('session') or die; +my $svc_acct_table = $dbdef->table('svc_acct') or die; + +my $session_svc_acct = new DBIx::DBSchema::Table ( 'session,svc_acct', '', '', '', + map( DBIx::DBSchema::Column->new( "session.$_", + $session_table->column($_)->type, + $session_table->column($_)->null, + $session_table->column($_)->length, + ), $session_table->columns() ), + map( DBIx::DBSchema::Column->new( "svc_acct.$_", + $svc_acct_table->column($_)->type, + $svc_acct_table->column($_)->null, + $svc_acct_table->column($_)->length, + ), $svc_acct_table->columns ), +# map("svc_acct.$_", $svc_acct_table->columns), +); + +$dbdef->addtable($session_svc_acct); #madness, i tell you + +$FS::Record::DEBUG = 1; +my @session = qsearch('session,svc_acct', {}, '', ' WHERE '. join(' AND ', + 'svc_acct.svcnum = session.svcnum', + '( session.logout IS NULL OR session.logout = 0 )', + "( $now - session.login ) >= svc_acct.seconds" +). " FOR UPDATE" ); + +my $dbh = dbh; + +foreach my $join ( @session ) { + + my $session = new FS::session ( { + map { $_ => $join->{'Hash'}{"session.$_"} } fields('session') + } ); #see no evil + + my $svc_acct = new FS::svc_acct ( { + map { $_ => $join->{'Hash'}{"svc_acct.$_"} } fields('svc_acct') + } ); + + #false laziness w/ fs_session_server + my $nsession = new FS::session ( { $session->hash } ); + my $error = $nsession->replace($session); + if ( $error ) { + $dbh->rollback; + die $error; + } + my $time = $nsession->logout - $nsession->login; + my $new_svc_acct = new FS::svc_acct ( { $svc_acct->hash } ); + my $seconds = $new_svc_acct->seconds; + $seconds -= $time; + $seconds = 0 if $seconds < 0; + $new_svc_acct->seconds( $seconds ); + $error = $new_svc_acct->replace( $svc_acct ); + warn "can't debit time from ". $svc_acct->username. ": $error\n"; #don't want to rollback, though + #ssenizal eslaf + +} + +$dbh->commit or die $dbh->errstr; + diff --git a/bin/fs-radius-add-check b/bin/fs-radius-add-check new file mode 100755 index 000000000..92523eb95 --- /dev/null +++ b/bin/fs-radius-add-check @@ -0,0 +1,52 @@ +#!/usr/bin/perl -Tw + +# quick'n'dirty hack of fs-setup to add radius attributes + +use strict; +use DBI; +use FS::UID qw(adminsuidsetup checkeuid getsecrets); +die "Not running uid freeside!" unless checkeuid(); + +my $user = shift or die &usage; +getsecrets($user); + +my $dbh = adminsuidsetup $user; + +### + +print "\n\n", <<END, ":"; +Enter the additional RADIUS check attributes you need to track for +each user, separated by whitespace. +END +my @attributes = map { s/\-/_/g; $_; } split(" ",&getvalue); + +sub getvalue { + my($x)=scalar(<STDIN>); + chop $x; + $x; +} + +### + +my($char_d) = 80; #default maxlength for text fields + +### + +foreach my $attribute ( @attributes ) { + foreach my $statement ( + "ALTER TABLE svc_acct ADD rc_$attribute varchar($char_d) NULL", + "ALTER TABLE part_svc ADD svc_acct__rc_$attribute varchar($char_d) NULL;", + "ALTER TABLE part_svc ADD svc_acct__rc_${attribute}_flag char(1) NULL;", + ) { + $dbh->do( $statement ) or warn "Error executing $statement: ". $dbh->errstr; } +} + +$dbh->disconnect or die $dbh->errstr; + +print "\n\n", "Now you must run dbdef-create.\n\n"; + +sub usage { + die "Usage:\n fs-radius-add user\n"; +} + + diff --git a/bin/fs-radius-add-reply b/bin/fs-radius-add-reply new file mode 100755 index 000000000..7938feac6 --- /dev/null +++ b/bin/fs-radius-add-reply @@ -0,0 +1,52 @@ +#!/usr/bin/perl -Tw + +# quick'n'dirty hack of fs-setup to add radius attributes + +use strict; +use DBI; +use FS::UID qw(adminsuidsetup checkeuid getsecrets); +die "Not running uid freeside!" unless checkeuid(); + +my $user = shift or die &usage; +getsecrets($user); + +my $dbh = adminsuidsetup $user; + +### + +print "\n\n", <<END, ":"; +Enter the additional RADIUS reply attributes you need to track for +each user, separated by whitespace. +END +my @attributes = map { s/\-/_/g; $_; } split(" ",&getvalue); + +sub getvalue { + my($x)=scalar(<STDIN>); + chop $x; + $x; +} + +### + +my($char_d) = 80; #default maxlength for text fields + +### + +foreach my $attribute ( @attributes ) { + foreach my $statement ( + "ALTER TABLE svc_acct ADD radius_$attribute varchar($char_d) NULL", + "ALTER TABLE part_svc ADD svc_acct__radius_$attribute varchar($char_d) NULL;", + "ALTER TABLE part_svc ADD svc_acct__radius_${attribute}_flag char(1) NULL;", + ) { + $dbh->do( $statement ) or warn "Error executing $statement: ". $dbh->errstr; } +} + +$dbh->disconnect or die $dbh->errstr; + +print "\n\n", "Now you must run dbdef-create.\n\n"; + +sub usage { + die "Usage:\n fs-radius-add user\n"; +} + + diff --git a/bin/fs-setup b/bin/fs-setup new file mode 100755 index 000000000..c1e87c8d6 --- /dev/null +++ b/bin/fs-setup @@ -0,0 +1,799 @@ +#!/usr/bin/perl -Tw +# +# $Id: fs-setup,v 1.37 2001-06-03 14:16:11 ivan Exp $ +# +# 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 +# +# $Log: fs-setup,v $ +# Revision 1.37 2001-06-03 14:16:11 ivan +# allow empty refund reasons +# +# Revision 1.36 2001/04/15 12:56:31 ivan +# s/dbdef/DBIx::DBSchema/ +# +# Revision 1.35 2001/04/15 09:36:43 ivan +# http://www.sisd.com/freeside/list-archive/msg01450.html +# +# Revision 1.34 2001/04/09 23:05:16 ivan +# Transactions Part I!!! +# +# Revision 1.33 2001/02/03 14:03:50 ivan +# time-based prepaid cards, session monitor. woop! +# +# Revision 1.32 2000/12/04 00:13:02 ivan +# fix nas.last type +# +# Revision 1.31 2000/12/01 18:34:53 ivan +# another tyop +# +# Revision 1.30 2000/12/01 18:33:32 ivan +# tyop +# +# Revision 1.29 2000/11/07 15:00:37 ivan +# session monitor +# +# Revision 1.28 2000/10/30 10:47:26 ivan +# nas.last can't be defined NULL if indexed +# +# Revision 1.26 2000/07/06 08:57:27 ivan +# support for radius check attributes (except importing). poorly documented. +# +# Revision 1.25 2000/06/29 12:00:49 ivan +# support for pre-encrypted md5 passwords. +# +# Revision 1.24 2000/03/02 07:44:07 ivan +# typo forgot closing ' +# +# Revision 1.23 2000/02/03 05:16:52 ivan +# beginning of DNS and Apache support +# +# Revision 1.22 2000/01/31 05:22:23 ivan +# prepaid "internet cards" +# +# Revision 1.21 2000/01/30 06:03:26 ivan +# postgres 6.5 finally supports decimal(10,2) +# +# Revision 1.20 2000/01/28 22:53:33 ivan +# track full phone number +# +# Revision 1.19 1999/07/29 08:50:35 ivan +# wrong type for cust_pay_batch.exp +# +# Revision 1.18 1999/04/15 22:46:30 ivan +# TT isn't a state! +# +# Revision 1.17 1999/04/14 07:58:39 ivan +# export getsecrets from FS::UID instead of calling it explicitly +# +# Revision 1.16 1999/02/28 19:44:16 ivan +# constructors s/create/new/ pointed out by "Bao C. Ha" <bao@hacom.net> +# +# Revision 1.15 1999/02/27 21:06:21 ivan +# cust_main.paydate should be varchar(10), not @date_type ; problem reported +# by Ben Leibig <leibig@colorado.edu> +# +# Revision 1.14 1999/02/07 09:59:14 ivan +# more mod_perl fixes, and bugfixes Peter Wemm sent via email +# +# Revision 1.13 1999/02/04 06:09:23 ivan +# add AU provences +# +# Revision 1.12 1999/02/03 10:42:27 ivan +# *** empty log message *** +# +# Revision 1.11 1999/01/17 03:11:52 ivan +# remove preliminary completehost changes +# +# Revision 1.10 1998/12/16 06:05:38 ivan +# add table cust_main_invoice +# +# Revision 1.9 1998/12/15 04:36:29 ivan +# s/croak/die/; #oops +# +# Revision 1.8 1998/12/15 04:33:27 ivan +# dies if it isn't running as the freeside user +# +# Revision 1.7 1998/11/18 09:01:31 ivan +# i18n! i18n! +# +# Revision 1.6 1998/11/15 13:18:02 ivan +# remove debugging +# +# Revision 1.5 1998/11/15 09:43:03 ivan +# update for new config file syntax, new adminsuidsetup +# +# Revision 1.4 1998/10/22 15:51:23 ivan +# also varchar with no length specified - postgresql fix broke mysql. +# +# Revision 1.3 1998/10/22 15:46:28 ivan +# now smallint is illegal, so remove that too. +# + +#to delay loading dbdef until we're ready +BEGIN { $FS::Record::setup_hack = 1; } + +use strict; +use DBI; +use DBIx::DBSchema; +use DBIx::DBSchema::Table; +use DBIx::DBSchema::Column; +use DBIx::DBSchema::ColGroup::Unique; +use DBIx::DBSchema::ColGroup::Index; +use FS::UID qw(adminsuidsetup datasrc checkeuid getsecrets); +use FS::Record; +use FS::cust_main_county; + +die "Not running uid freeside!" unless checkeuid(); + +my $user = shift or die &usage; +getsecrets($user); + +#needs to match FS::Record +my($dbdef_file) = "/usr/local/etc/freeside/dbdef.". datasrc; + +### + +print "\nEnter the maximum username length: "; +my($username_len)=&getvalue; + +print "\n\n", <<END, ":"; +Freeside tracks the RADIUS attributes User-Name, check attribute Password and +reply attribute Framed-IP-Address for each user. You can specify additional +check and reply attributes. First enter any additional RADIUS check attributes +you need to track for each user, separated by whitespace. +END +my @check_attributes = map { s/\-/_/g; $_; } split(" ",&getvalue); + +print "\n\n", <<END, ":"; +Now enter any additional reply attributes you need to track for each user, +separated by whitespace. +END +my @attributes = map { s/\-/_/g; $_; } split(" ",&getvalue); + +sub getvalue { + my($x)=scalar(<STDIN>); + chop $x; + $x; +} + +### + +my($char_d) = 80; #default maxlength for text fields + +#my(@date_type) = ( 'timestamp', '', '' ); +my(@date_type) = ( 'int', 'NULL', '' ); +my(@perl_type) = ( 'varchar', 'NULL', 255 ); +my @money_type = ( 'decimal', '', '10,2' ); + +### +# create a dbdef object from the old data structure +### + +my(%tables)=&tables_hash_hack; + +#turn it into objects +my($dbdef) = new DBIx::DBSchema ( map { + my(@columns); + while (@{$tables{$_}{'columns'}}) { + my($name,$type,$null,$length)=splice @{$tables{$_}{'columns'}}, 0, 4; + push @columns, new DBIx::DBSchema::Column ( $name,$type,$null,$length ); + } + DBIx::DBSchema::Table->new( + $_, + $tables{$_}{'primary_key'}, + DBIx::DBSchema::ColGroup::Unique->new($tables{$_}{'unique'}), + DBIx::DBSchema::ColGroup::Index->new($tables{$_}{'index'}), + @columns, + ); +} (keys %tables) ); + +#add radius attributes to svc_acct + +my($svc_acct)=$dbdef->table('svc_acct'); + +my($attribute); +foreach $attribute (@attributes) { + $svc_acct->addcolumn ( new DBIx::DBSchema::Column ( + 'radius_'. $attribute, + 'varchar', + 'NULL', + $char_d, + )); +} + +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_acct_sm svc_domain 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($dbdef_file); + +### +# create 'em +### + +my($dbh)=adminsuidsetup $user; + +#create tables +$|=1; + +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 UT VT VI VA WA WV WI WY AE AA AP +) ) { + my($cust_main_county)=new FS::cust_main_county({ + 'state' => $_, + 'tax' => 0, + 'country' => 'US', + }); + my($error); + $error=$cust_main_county->insert; + die $error if $error; +} + +#AU "offical" state codes ala mark.williamson@ebbs.com.au (Mark Williamson) +foreach ( qw( +VIC NSW NT QLD TAS ACT WA SA +) ) { + my($cust_main_county)=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; +} + +$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. +### +sub tables_hash_hack { + + #note that s/(date|change)/_$1/; to avoid keyword conflict. + #put a kludge in FS::Record to catch this or? (pry need some date-handling + #stuff anyway also) + + my(%tables)=( #yech.} + + 'agent' => { + 'columns' => [ + 'agentnum', 'int', '', '', + 'agent', 'varchar', '', $char_d, + 'typenum', 'int', '', '', + 'freq', 'int', 'NULL', '', + 'prog', @perl_type, + ], + 'primary_key' => 'agentnum', + 'unique' => [ [] ], + 'index' => [ ['typenum'] ], + }, + + 'agent_type' => { + 'columns' => [ + 'typenum', 'int', '', '', + 'atype', 'varchar', '', $char_d, + ], + 'primary_key' => 'typenum', + 'unique' => [ [] ], + 'index' => [ [] ], + }, + + 'type_pkgs' => { + 'columns' => [ + 'typenum', 'int', '', '', + 'pkgpart', 'int', '', '', + ], + 'primary_key' => '', + 'unique' => [ ['typenum', 'pkgpart'] ], + 'index' => [ ['typenum'] ], + }, + + 'cust_bill' => { + 'columns' => [ + 'invnum', 'int', '', '', + 'custnum', 'int', '', '', + '_date', @date_type, + 'charged', @money_type, + 'printed', 'int', '', '', + ], + 'primary_key' => 'invnum', + 'unique' => [ [] ], + 'index' => [ ['custnum'] ], + }, + + 'cust_bill_pkg' => { + 'columns' => [ + 'pkgnum', 'int', '', '', + 'invnum', 'int', '', '', + 'setup', @money_type, + 'recur', @money_type, + 'sdate', @date_type, + 'edate', @date_type, + ], + 'primary_key' => '', + 'unique' => [ ['pkgnum', 'invnum'] ], + 'index' => [ ['invnum'] ], + }, + + 'cust_credit' => { + 'columns' => [ + 'crednum', 'int', '', '', + 'custnum', 'int', '', '', + '_date', @date_type, + 'amount', @money_type, + 'otaker', 'varchar', '', 8, + 'reason', 'varchar', 'NULL', 255, + ], + 'primary_key' => 'crednum', + 'unique' => [ [] ], + 'index' => [ ['custnum'] ], + }, + + '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, + 'address1', 'varchar', '', $char_d, + 'address2', 'varchar', 'NULL', $char_d, + 'city', 'varchar', '', $char_d, + 'county', 'varchar', 'NULL', $char_d, + 'state', 'varchar', 'NULL', $char_d, + 'zip', 'varchar', '', 10, + 'country', 'char', '', 2, + 'daytime', 'varchar', 'NULL', 20, + 'night', 'varchar', 'NULL', 20, + 'fax', 'varchar', 'NULL', 12, + 'payby', 'char', '', 4, + 'payinfo', 'varchar', 'NULL', 16, + #'paydate', @date_type, + 'paydate', 'varchar', 'NULL', 10, + 'payname', 'varchar', 'NULL', $char_d, + 'tax', 'char', 'NULL', 1, + 'otaker', 'varchar', '', 8, + 'refnum', 'int', '', '', + ], + 'primary_key' => 'custnum', + 'unique' => [ [] ], + #'index' => [ ['last'], ['company'] ], + 'index' => [ ['last'], ], + }, + + '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', 'varchar', 'NULL', $char_d, + 'county', 'varchar', 'NULL', $char_d, + 'country', 'char', '', 2, + 'tax', 'real', '', '', #tax % + ], + 'primary_key' => 'taxnum', + 'unique' => [ [] ], + # 'unique' => [ ['taxnum'], ['state', 'county'] ], + 'index' => [ [] ], + }, + + 'cust_pay' => { + 'columns' => [ + 'paynum', 'int', '', '', + 'invnum', '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. + ], + 'primary_key' => 'paynum', + 'unique' => [ [] ], + 'index' => [ ['invnum'] ], + }, + + 'cust_pay_batch' => { #what's this used for again? list of customers + #in current CARD batch? (necessarily CARD?) + 'columns' => [ + 'invnum', 'int', '', '', + 'custnum', 'int', '', '', + 'last', 'varchar', '', $char_d, + 'first', 'varchar', '', $char_d, + 'address1', 'varchar', '', $char_d, + 'address2', 'varchar', 'NULL', $char_d, + 'city', 'varchar', '', $char_d, + 'state', 'varchar', '', $char_d, + 'zip', 'varchar', '', 10, + 'country', 'char', '', 2, + 'trancode', 'int', '', '', + 'cardnum', 'varchar', '', 16, + #'exp', @date_type, + 'exp', 'varchar', '', 11, + 'payname', 'varchar', 'NULL', $char_d, + 'amount', @money_type, + ], + 'primary_key' => '', + 'unique' => [ [] ], + 'index' => [ ['invnum'], ['custnum'] ], + }, + + 'cust_pkg' => { + 'columns' => [ + 'pkgnum', 'int', '', '', + 'custnum', 'int', '', '', + 'pkgpart', 'int', '', '', + 'otaker', 'varchar', '', 8, + 'setup', @date_type, + 'bill', @date_type, + 'susp', @date_type, + 'cancel', @date_type, + 'expire', @date_type, + ], + 'primary_key' => 'pkgnum', + 'unique' => [ [] ], + 'index' => [ ['custnum'] ], + }, + + 'cust_refund' => { + 'columns' => [ + 'refundnum', 'int', '', '', + 'crednum', 'int', '', '', + '_date', @date_type, + 'refund', @money_type, + 'otaker', 'varchar', '', 8, + 'reason', 'varchar', '', $char_d, + 'payby', 'char', '', 4, # CARD/BILL/COMP, should be index + # into payment type table. + 'payinfo', 'varchar', 'NULL', 16, #see cust_main above + ], + 'primary_key' => 'refundnum', + 'unique' => [ [] ], + 'index' => [ ['crednum'] ], + }, + + 'cust_svc' => { + 'columns' => [ + 'svcnum', 'int', '', '', + 'pkgnum', 'int', 'NULL', '', + 'svcpart', 'int', '', '', + ], + 'primary_key' => 'svcnum', + 'unique' => [ [] ], + 'index' => [ ['svcnum'], ['pkgnum'], ['svcpart'] ], + }, + + 'part_pkg' => { + 'columns' => [ + 'pkgpart', 'int', '', '', + 'pkg', 'varchar', '', $char_d, + 'comment', 'varchar', '', $char_d, + 'setup', @perl_type, + 'freq', 'int', '', '', #billing frequency (months) + 'recur', @perl_type, + ], + 'primary_key' => 'pkgpart', + 'unique' => [ [] ], + 'index' => [ [] ], + }, + +# 'part_title' => { +# 'columns' => [ +# 'titlenum', 'int', '', '', +# 'title', 'varchar', '', $char_d, +# ], +# 'primary_key' => 'titlenum', +# 'unique' => [ [] ], +# 'index' => [ [] ], +# }, + + 'pkg_svc' => { + 'columns' => [ + 'pkgpart', 'int', '', '', + 'svcpart', 'int', '', '', + 'quantity', 'int', '', '', + ], + 'primary_key' => '', + 'unique' => [ ['pkgpart', 'svcpart'] ], + 'index' => [ ['pkgpart'] ], + }, + + 'part_referral' => { + 'columns' => [ + 'refnum', 'int', '', '', + 'referral', 'varchar', '', $char_d, + ], + 'primary_key' => 'refnum', + 'unique' => [ [] ], + 'index' => [ [] ], + }, + + 'part_svc' => { + 'columns' => [ + 'svcpart', 'int', '', '', + 'svc', 'varchar', '', $char_d, + 'svcdb', 'varchar', '', $char_d, + ], + 'primary_key' => 'svcpart', + 'unique' => [ [] ], + 'index' => [ [] ], + }, + + #(this should be renamed to part_pop) + 'svc_acct_pop' => { + 'columns' => [ + 'popnum', 'int', '', '', + 'city', 'varchar', '', $char_d, + 'state', 'varchar', '', $char_d, + 'ac', 'char', '', 3, + 'exch', 'char', '', 3, + 'loc', 'char', 'NULL', 4, #NULL for legacy purposes + ], + 'primary_key' => 'popnum', + 'unique' => [ [] ], + 'index' => [ [] ], + }, + + 'svc_acct' => { + 'columns' => [ + 'svcnum', 'int', '', '', + 'username', 'varchar', '', $username_len, #unique (& remove dup code) + '_password', 'varchar', '', 50, #13 for encryped pw's plus ' *SUSPENDED* (mp5 passwords can be 34) + 'popnum', 'int', '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 + ], + 'primary_key' => 'svcnum', + 'unique' => [ [] ], + 'index' => [ ['username'] ], + }, + + 'svc_acct_sm' => { + 'columns' => [ + 'svcnum', 'int', '', '', + 'domsvc', 'int', '', '', + 'domuid', 'int', '', '', + 'domuser', 'varchar', '', $char_d, + ], + 'primary_key' => 'svcnum', + 'unique' => [ [] ], + 'index' => [ ['domsvc'], ['domuid'] ], + }, + + #'svc_charge' => { + # 'columns' => [ + # 'svcnum', 'int', '', '', + # 'amount', @money_type, + # ], + # 'primary_key' => 'svcnum', + # 'unique' => [ [] ], + # 'index' => [ [] ], + #}, + + 'svc_domain' => { + 'columns' => [ + 'svcnum', 'int', '', '', + 'domain', 'varchar', '', $char_d, + ], + '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_www' => { + 'columns' => [ + 'svcnum', 'int', '', '', + 'recnum', 'int', '', '', + 'usersvc', 'int', '', '', + ], + 'primary_key' => 'svcnum', + 'unique' => [ [] ], + 'index' => [ [] ], + }, + + #'svc_wo' => { + # 'columns' => [ + # 'svcnum', 'int', '', '', + # 'svcnum', 'int', '', '', + # 'svcnum', 'int', '', '', + # 'worker', 'varchar', '', $char_d, + # '_date', @date_type, + # ], + # 'primary_key' => 'svcnum', + # 'unique' => [ [] ], + # 'index' => [ [] ], + #}, + + 'prepay_credit' => { + 'columns' => [ + 'prepaynum', 'int', '', '', + 'identifier', 'varchar', '', $char_d, + 'amount', @money_type, + 'seconds', 'int', 'NULL', '', + ], + 'primary_key' => 'prepaynum', + 'unique' => [ ['identifier'] ], + 'index' => [ [] ], + }, + + 'port' => { + 'columns' => [ + 'portnum', 'int', '', '', + 'ip', 'varchar', 'NULL', 15, + 'nasport', 'int', 'NULL', '', + 'nasnum', 'int', '', '', + ], + 'primary_key' => 'portnum', + 'unique' => [], + 'index' => [], + }, + + 'nas' => { + 'columns' => [ + 'nasnum', 'int', '', '', + 'nas', 'varchar', '', $char_d, + 'nasip', 'varchar', '', 15, + 'nasfqdn', 'varchar', '', $char_d, + 'last', 'int', '', '', + ], + 'primary_key' => 'nasnum', + 'unique' => [ [ 'nas' ], [ 'nasip' ] ], + 'index' => [ [ 'last' ] ], + }, + + 'session' => { + 'columns' => [ + 'sessionnum', 'int', '', '', + 'portnum', 'int', '', '', + 'svcnum', 'int', '', '', + 'login', @date_type, + 'logout', @date_type, + ], + 'primary_key' => 'sessionnum', + 'unique' => [], + 'index' => [ [ 'portnum' ] ], + }, + + ); + + %tables; + +} + diff --git a/bin/generate-prepay b/bin/generate-prepay new file mode 100755 index 000000000..cb4ba7fc6 --- /dev/null +++ b/bin/generate-prepay @@ -0,0 +1,35 @@ +#!/usr/bin/perl -w + +use strict; +use FS::UID qw(adminsuidsetup); +use FS::prepay_credit; + +require 5.004; #srand(time|$$); + +my $user = shift or die &usage; +&adminsuidsetup( $user ); + +my $amount = shift or die &usage; + +my $seconds = shift or die &usage; + +my $num_digits = shift or die &usage; + +my $num_entries = shift or die &usage; + +for ( 1 .. $num_entries ) { + my $identifier = join( '', map int(rand(10)), ( 1 .. $num_digits ) ); + my $prepay_credit = new FS::prepay_credit { + 'identifier' => $identifier, + 'amount' => $amount, + 'seconds' => $seconds, + }; + my $error = $prepay_credit->insert; + die $error if $error; + print "$identifier\n"; +} + +sub usage { + die "Usage:\n\n generate-prepay user amount seconds num_digits num_entries"; +} + diff --git a/bin/pod2x b/bin/pod2x new file mode 100755 index 000000000..2c10a30d0 --- /dev/null +++ b/bin/pod2x @@ -0,0 +1,29 @@ +#!/usr/bin/perl + +#use Pod::Text; +#$Pod::Text::termcap=1; + +my $site_perl = "./FS"; +#my $catman = "./catman"; +#my $catman = "./htdocs/docs/man"; +my $html = "./htdocs/docs/man"; + +$|=1; + +die "Can't find $site_perl and $catman" + unless [ -d $site_perl ] && [ -d $catman ] && [ -d $html ]; + +foreach my $file ( + glob("$site_perl/*.pm"), + glob("$site_perl/*/*.pm"), + glob("$site_perl/*/*/*.pm") +) { + #$file =~ /\/([\w\-]+)\.pm$/ or die "oops file $file"; + $file =~ /$site_perl\/(.*)\.pm$/ or die "oops file $file"; + my $name = $1; + print "$name\n"; + my $htmlroot = join('/', map '..',1..(scalar($file =~ tr/\///)-2)) || '.'; +# system "pod2text $file >$catman/$name.txt"; + system "pod2html --podroot=$site_perl --podpath=./FS:./FS/UI:. --norecurse --htmlroot=$htmlroot $file >$html/$name.html"; +# system "pod2html $file >$html/$name.html"; +} diff --git a/bin/svc_acct.export b/bin/svc_acct.export new file mode 100755 index 000000000..1c3ffa243 --- /dev/null +++ b/bin/svc_acct.export @@ -0,0 +1,458 @@ +#!/usr/bin/perl -w +# +# $Id: svc_acct.export,v 1.19 2001-05-08 10:44:17 ivan Exp $ +# +# Create and export password files: passwd, passwd.adjunct, shadow, +# acp_passwd, acp_userinfo, acp_dialup, users +# +# 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 +# +# $Log: svc_acct.export,v $ +# Revision 1.19 2001-05-08 10:44:17 ivan +# fix for OO Net::SCP +# +# Revision 1.18 2001/04/22 01:56:15 ivan +# get rid of FS::SSH.pm (became Net::SSH and Net::SCP on CPAN) +# +# Revision 1.17 2001/02/21 23:48:19 ivan +# add icradius_secrets config file to export to a non-Freeside MySQL database for +# ICRADIUS +# +# Revision 1.16 2000/07/06 13:23:29 ivan +# tyop +# +# Revision 1.15 2000/07/06 08:57:28 ivan +# support for radius check attributes (except importing). poorly documented. +# +# Revision 1.14 2000/06/29 15:01:25 ivan +# another silly typo in svc_acct.export +# +# Revision 1.13 2000/06/28 12:37:28 ivan +# add support for config option textradiusprepend +# +# Revision 1.12 2000/06/15 14:07:02 ivan +# added ICRADIUS radreply table support, courtesy of Kenny Elliott +# +# Revision 1.11 2000/03/06 16:00:39 ivan +# sync up with working versoin +# +# Revision 1.2 1998/12/10 07:23:15 ivan +# use FS::Conf, need user (for datasrc) +# + +use strict; +use vars qw($conf); +use Fcntl qw(:flock); +use IO::Handle; +use DBI; +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 fields); +use FS::svc_acct; + +my $user = shift or die &usage; +adminsuidsetup $user; + +$conf = new FS::Conf; + +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 $textradiusprepend = $conf->config('textradiusprepend'); + +my(@saltset)= ( 'a'..'z' , 'A'..'Z' , '0'..'9' , '.' , '/' ); +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); +unless ( flock(EXPORT,LOCK_EX|LOCK_NB) ) { + seek(EXPORT,0,0); + my($pid)=<EXPORT>; + chop($pid); + #no reason to start loct 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',{}); + +( open(MASTER,">$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) +) or die "Can't open $spooldir/shadow: $!"; +( 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) +) or die "Can't open $spooldir/acp_dialup: $!"; +( open (USERS,">$spooldir/users") + and flock(USERS,LOCK_EX|LOCK_NB) +) or die "Can't open $spooldir/users: $!"; + +chmod 0644, "$spooldir/passwd", + "$spooldir/acp_dialup", +; +chmod 0600, "$spooldir/master.passwd", + "$spooldir/acp_passwd", + "$spooldir/shadow", + "$spooldir/users", +; + +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; +} + +setpriority(0,0,10); + +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 ( $svc_acct->uid =~ /^(\d+)$/ ) { + + die "Non-root user ". $svc_acct->username. " has 0 UID!" + if $svc_acct->uid == 0 && $svc_acct->username ne 'root'; + + ### + # 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 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 SHADOW FILE HERE + print SHADOW join(":", + $svc_acct->username, + $cpassword, + '', + '', + '', + '', + '', + '', + '', + ), "\n"; + + } + + if ( $svc_acct->slipip ne '' ) { + + ### + # FORMAT OF THE ACP_* FILES HERE + print ACP_PASSWD join(":", + $svc_acct->username, + $cpassword, + "0", + "0", + "", + "", + "", + ), "\n"; + + my($ip)=$svc_acct->slipip; + + unless ( $ip eq '0.0.0.0' || $svc_acct->slipip eq '0e0' ) { + print ACP_DIALUP $svc_acct->username, "\t*\t", $svc_acct->slipip, "\n"; + } + + 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 + $svc_acct->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( $_ ) } ( + '', + $svc_acct->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( $_ ) } ( + '', + $svc_acct->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( $_ ) } ( + '', + $svc_acct->username, + $attribute, + $radreply{$attribute}, + ) ). " )" + ); + $sth->execute or die "Can't insert into radreply table: ". $sth->errstr; + } + + } + + } + +} + +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); + +close MASTER; +close PASSWD; +close SHADOW; +close ACP_DIALUP; +close ACP_PASSWD; +close USERS; + +### +# export stuff +# + +my($shellmachine); +foreach $shellmachine (@shellmachines) { + my $scp = new Net::SCP; + $scp->scp("$spooldir/passwd","root\@$shellmachine:/etc/passwd.new") + or die "scp error: ". $scp->{errstr}; + $scp->scp("$spooldir/shadow","root\@$shellmachine:/etc/shadow.new") + or die "scp error: ". $scp->{errstr}; + ssh("root\@$shellmachine", + "( ". + "mv /etc/passwd.new /etc/passwd; ". + "mv /etc/shadow.new /etc/shadow; ". + " )" + ) + == 0 or die "ssh error: $!"; +} + +my($bsdshellmachine); +foreach $bsdshellmachine (@bsdshellmachines) { + 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; ". + " )" + ) + == 0 or die "ssh error: $!"; +} + +my($nismachine); +foreach $nismachine (@nismachines) { + 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; ". + " )" + ) + == 0 or die "ssh error: $!"; +} + +my($erpcdmachine); +foreach $erpcdmachine (@erpcdmachines) { + 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\'". + " )" + ) + == 0 or die "ssh error: $!"; +} + +my($radiusmachine); +foreach $radiusmachine (@radiusmachines) { + my $scp = new Net::SCP; + $scp->scp("$spooldir/users","root\@$radiusmachine:/etc/raddb/users") + or die "scp error: ". $scp->{errstr}; + ssh("root\@$radiusmachine", + "( ". + "builddbm". + " )" + ) + == 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; +} + +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 new file mode 100755 index 000000000..2e51a8b2c --- /dev/null +++ b/bin/svc_acct.import @@ -0,0 +1,289 @@ +#!/usr/bin/perl -Tw +# +# $Id: svc_acct.import,v 1.14 2001-05-07 15:24:15 ivan Exp $ +# +# 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 +# +# $Log: svc_acct.import,v $ +# Revision 1.14 2001-05-07 15:24:15 ivan +# s/!/*/ +# +# Revision 1.13 2001/05/05 08:51:16 ivan +# http://www.sisd.com/freeside/list-archive/msg01915.html +# +# Revision 1.12 2001/04/22 01:56:15 ivan +# get rid of FS::SSH.pm (became Net::SSH and Net::SCP on CPAN) +# +# Revision 1.11 2000/06/29 12:27:01 ivan +# s/password/_password/ for PostgreSQL wasn't done in the import. +# +# Revision 1.10 2000/06/28 12:32:30 ivan +# allow RADIUS lines with "Auth-Type = Local" too +# +# Revision 1.8 2000/02/03 05:16:52 ivan +# beginning of DNS and Apache support +# +# Revision 1.7 1999/07/08 02:32:26 ivan +# import fix, noticed by Ben Leibig and Joel Griffiths +# +# Revision 1.6 1999/07/08 01:49:00 ivan +# updates to avoid -w warnings from Joel Griffiths <griff@aver-computer.com> +# +# Revision 1.5 1999/03/25 08:42:19 ivan +# import stuff uses Term::Query and spits out (some kinds of) nonsensical input +# +# Revision 1.4 1999/03/24 00:43:38 ivan +# die if no relevant services +# +# Revision 1.3 1998/12/10 07:23:16 ivan +# use FS::Conf, need user (for datasrc) +# +# Revision 1.2 1998/10/13 12:07:51 ivan +# Assigns password from the shadow file for RADIUS password "UNIX" +# + +use strict; +use vars qw(%part_svc); +use Date::Parse; +use 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; + +my($spooldir)="/usr/local/etc/freeside/export.". datasrc; + +$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). +END +my($ppp_svcpart)=&getpart; + +print "\n\n", &menu_svc, "\n", <<END; +Some accounts have entries in passwd and users, but with Port-Limit 2 (or +more). +END +my($isdn_svcpart)=&getpart; + +print "\n\n", &menu_svc, "\n", <<END; +Some accounts might have entries in users only (Port-Limit 1) +END +my($oppp_svcpart)=&getpart; + +print "\n\n", &menu_svc, "\n", <<END; +Some accounts might have entries in users only (Port-Limit >= 2) +END +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 +my($pop_shell)=&getvalue("Enter that shell:"); +my($popmail_svcpart)=&getpart; + +print "\n\n", &menu_svc, "\n", <<END; +Everything else in passwd is a shell account. +END +my($shell_svcpart)=&getpart; + +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 +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 +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 +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 { + $^W=0; # Term::Query isn't -w-safe + my $return = query "Enter part number:", 'irk', [ keys %part_svc ]; + $^W=1; + $return; +} +sub getvalue { + my $prompt = shift; + $^W=0; # Term::Query isn't -w-safe + my $return = query $prompt, ''; + $^W=1; + $return; +} + +print "\n\n"; + +### + +open(PASSWD,"<$spooldir/passwd.import"); +open(SHADOW,"<$spooldir/shadow.import"); +open(USERS,"<$spooldir/users.import"); + +my(%upassword,%ip,%allparam); +my(%param,$username); +while (<USERS>) { + chop; + next if /^\s*$/; + next if /^\s*#/; + if ( /^\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),$3,$5); + $password = '' if $password eq 'UNIX'; + $upassword{$username}=$password; + undef %param; + } else { + die "2Unexpected line in users.import: $_"; + } + while (<USERS>) { + chop; + if ( /^\s*$/ ) { + 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*$/ ) { + my($attribute,$value)=($1,$2); + $attribute =~ s/\-/_/g; + $param{'radius_'.$attribute}=$value; + } else { + die "3Unexpected line in users.import: $_"; + } + } +} +#? incase there isn't a terminating blank line ? +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; +} + +while (<PASSWD>) { + chop; + my($username,$x,$uid,$gid,$finger,$dir,$shell)=split(/:/); + my($password)=$upassword{$username} || $password{$username}; + + my($maxb)=${$allparam{$username}}{'radius_Port_Limit'}; + my($svcpart); + if ( exists $upassword{$username} ) { + if ( $maxb >= 2 ) { + $svcpart = $isdn_svcpart + } elsif ( ! $maxb || $maxb == 1 ) { + $svcpart = $ppp_svcpart + } else { + die "Illegal Port-Limit in users ($username)!\n"; + } + } elsif ( $shell eq $pop_shell ) { + $svcpart = $popmail_svcpart; + } else { + $svcpart = $shell_svcpart; + } + + 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); + $error=$svc_acct->insert; + die $error if $error; + + delete $allparam{$username}; + delete $upassword{$username}; +} + +#my($username); +foreach $username ( keys %upassword ) { + my($password)=$upassword{$username}; + + my($maxb)=${$allparam{$username}}{'radius_Port_Limit'} || 0; + my($svcpart); + if ( $maxb == 2 ) { + $svcpart = $oisdn_svcpart + } elsif ( ! $maxb || $maxb == 1 ) { + $svcpart = $oppp_svcpart + } else { + die "Illegal Port-Limit in users!\n"; + } + + my($svc_acct) = new FS::svc_acct ({ + 'svcpart' => $svcpart, + 'username' => $username, + '_password' => $password, + 'slipip' => $ip{$username}, + %{$allparam{$username}}, + }); + my($error); + $error=$svc_acct->insert; + die $error, if $error; + + delete $allparam{$username}; + 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 new file mode 100755 index 000000000..d7a7840f1 --- /dev/null +++ b/bin/svc_acct_sm.export @@ -0,0 +1,254 @@ +#!/usr/bin/perl -Tw +# +# $Id: svc_acct_sm.export,v 1.10 2001-05-08 10:44:17 ivan Exp $ +# +# Create and export config files for sendmail, qmail +# +# (used to) 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 +# +# $Log: svc_acct_sm.export,v $ +# Revision 1.10 2001-05-08 10:44:17 ivan +# fix for OO Net::SCP +# +# Revision 1.9 2001/04/22 01:56:15 ivan +# get rid of FS::SSH.pm (became Net::SSH and Net::SCP on CPAN) +# +# Revision 1.8 2000/07/06 03:37:24 ivan +# don't error out on invalid svc_acct_sm.domuid's that can't be matched in +# svc_acct.uid - just warn. +# +# Revision 1.7 2000/07/03 09:13:10 ivan +# get rid of double sendmailrestart invocation; no need for multiple sessions +# +# Revision 1.6 2000/07/03 09:09:14 ivan +# typo +# +# Revision 1.5 2000/07/03 09:03:14 ivan +# added sendmailrestart and sendmailconfigpath config files +# +# Revision 1.4 2000/06/29 14:02:29 ivan +# add sendmailrestart configuration file +# +# Revision 1.3 2000/06/12 08:37:56 ivan +# sendmail fix from Jeff Finucane +# +# Revision 1.2 1998/12/10 07:23:17 ivan +# use FS::Conf, need user (for datasrc) +# + +use strict; +use vars qw($conf); +use Fcntl qw(:flock); +use Net::SSH qw(ssh); +use Net::SCP qw(scp); +use FS::UID qw(adminsuidsetup datasrc); +use FS::Record qw(qsearch qsearchs); +use FS::svc_acct; +use FS::svc_acct_sm; +use FS::svc_domain; + +my $user = shift or die &usage; +adminsuidsetup $user; + +$conf = new FS::Conf; + +my($shellmachine, @qmailmachines); +if ( $conf->exists('qmailmachines') ) { + $shellmachine = $conf->config('shellmachine'); + @qmailmachines = $conf->config('qmailmachines'); +} + +my(@sendmailmachines, $sendmailconfigpath, $sendmailrestart); +if ( $conf->exists('sendmailmachines') ) { + @sendmailmachines = $conf->config('sendmailmachines'); + $sendmailconfigpath = $conf->config('sendmailconfigpath') || '/etc'; + $sendmailrestart = $conf->config('sendmailrestart'); +} + +my $mydomain = $conf->config('domain'); + +my $spooldir = "/usr/local/etc/freeside/export.". datasrc; +my $spoollock = "/usr/local/etc/freeside/svc_acct_sm.export.lock.". datasrc; + +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"; + +( 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}); + unless ( $svc_acct ) { + warn "WARNING: couldn't find svc_acct.uid $domuid (svc_acct_sm.svcnum ". + $svc_acct_sm->svcnum. ") - corruped database?\n"; + next; + } + 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) { + 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_sm.import b/bin/svc_acct_sm.import new file mode 100755 index 000000000..723fb029f --- /dev/null +++ b/bin/svc_acct_sm.import @@ -0,0 +1,301 @@ +#!/usr/bin/perl -Tw +# +# $Id: svc_acct_sm.import,v 1.9 2001-04-22 01:56:15 ivan Exp $ +# +# ivan@sisd.com 98-mar-9 +# +# generalized svcparts ivan@sisd.com 98-mar-23 + +# 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 +# +# $Log: svc_acct_sm.import,v $ +# Revision 1.9 2001-04-22 01:56:15 ivan +# get rid of FS::SSH.pm (became Net::SSH and Net::SCP on CPAN) +# +# Revision 1.8 2000/12/03 15:14:00 ivan +# bugfixes from Jeff Finucane <jeff@cmh.net>, thanks! +# +# Revision 1.7 2000/06/29 10:51:52 ivan +# oops, silly mistake +# +# Revision 1.6 2000/06/29 10:48:25 ivan +# make svc_acct_sm skip blank lines in sendmail import +# +# Revision 1.5 2000/02/03 05:16:52 ivan +# beginning of DNS and Apache support +# +# Revision 1.4 1999/03/25 08:42:20 ivan +# import stuff uses Term::Query and spits out (some kinds of) nonsensical input +# +# Revision 1.3 1999/03/24 00:51:55 ivan +# die if no relevant services... cvspain +# +# Revision 1.2 1998/12/10 07:23:18 ivan +# use FS::Conf, need user (for datasrc) +# + +use strict; +use vars qw(%d_part_svc %m_part_svc); +use 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; + +my $user = shift or die &usage; +adminsuidsetup $user; + +my($spooldir)="/usr/local/etc/freeside/export.". datasrc; + +my(%mta) = ( + 1 => "qmail", + 2 => "sendmail", +); + +### + +%d_part_svc = + map { $_->svcpart, $_ } qsearch('part_svc',{'svcdb'=>'svc_domain'}); +%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\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\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"; +$^W=0; #Term::Query isn't -w-safe +my $mta = query ":", 'irk', [ keys %mta ]; +$^W=1; + +if ( $mta{$mta} eq "qmail" ) { + + print "\n\n", <<END; +Enter the location and name of your qmail control directory, for example +"mail.isp.com:/var/qmail/control" +END + my($control)=&getvalue(":"); + iscp("root\@$control/rcpthosts","$spooldir/rcpthosts.import"); +# iscp("root\@$control/recipientmap","$spooldir/recipientmap.import"); + iscp("root\@$control/virtualdomains","$spooldir/virtualdomains.import"); + +# print "\n\n", <<END; +#Enter the name of the machine with your user .qmail files, for example +#"mail.isp.com" +#END +# print ":"; +# my($shellmachine)=&getvalue; + +} elsif ( $mta{$mta} eq "sendmail" ) { + + print "\n\n", <<END; +Enter the location and name of your sendmail virtual user table, for example +"mail.isp.com:/etc/virtusertable" +END + 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 + my($sendmail_cw)=&getvalue(":"); + iscp("root\@$sendmail_cw","$spooldir/sendmail.cw.import"); + +} else { + die "Unknown MTA!\n"; +} + +sub getvalue { + my $prompt = shift; + $^W=0; #Term::Query isn't -w-safe + my $data = query $prompt, ''; + $^W=1; + $data; +} + +print "\n\n"; + +### + +$FS::svc_domain::whois_hack=1; +$FS::svc_acct_sm::nossh_hack=1; + +if ( $mta{$mta} eq "qmail" ) { + open(RCPTHOSTS,"<$spooldir/rcpthosts.import") + or die "Can't open $spooldir/rcpthosts.import: $!"; +} elsif ( $mta{$mta} eq "sendmail" ) { + open(RCPTHOSTS,"<$spooldir/sendmail.cw.import") + or die "Can't open $spooldir/sendmail.cw.import: $!"; +} else { + die "Unknown MTA!\n"; +} + +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 = new FS::svc_domain ({ + 'domain' => $domain, + 'svcpart' => $domain_svcpart, + 'action' => 'N', + }); + my $error = $svc_domain->insert; + #warn $error if $error; + die $error if $error; + } + $svcnum{$domain}=$svc_domain->svcnum; +} +close RCPTHOSTS; + +#these two loops have enough similar parts they should probably be merged +if ( $mta{$mta} eq "qmail" ) { + + open(VD_FIX,">$spooldir/virtualdomains.FIX"); + print VD_FIX "#!/usr/bin/perl\n"; + + open(VIRTUALDOMAINS,"<$spooldir/virtualdomains.import") + or die "Can't open $spooldir/virtualdomains.import: $!"; + while (<VIRTUALDOMAINS>) { + next if /^#/; + /^\.?([\w\-\.]+):(\w+)(\-([\w\-\.]+))?$/ + #or do { warn "Strange virtualdomains line: $_"; next; }; + or die "Strange virtualdomains line: $_"; + my($domain,$username,$dash_ext,$extension)=($1,$2,$3,$4); + $dash_ext ||= ''; + $extension ||= ''; + my($svc_acct)=qsearchs('svc_acct',{'username'=>$username}); + unless ( $svc_acct ) { + #warn "Unknown user $username in virtualdomains; skipping\n"; + #die "Unknown user $username in virtualdomains; skipping\n"; + next; + } + if ( $domain ne $extension ) { + #warn "virtualdomains line $domain:$username$dash_ext changed to $domain:$username-$domain\n"; + my($dir)=$svc_acct->dir; + my($qdomain)=$domain; + $qdomain =~ s/\./:/g; #see manpage for 'dot-qmail': EXTENSION ADDRESSES + #example to move .qmail files for virtual domains to their new location + #dry run + #issh("root\@$shellmachine",'perl -e \'foreach $a (<'. $dir. '/.qmail'. $dash_ext. '-*>) { $old=$a; $a =~ s/\\.qmail'. $dash_ext. '\\-/\\.qmail\\-'. $qdomain. '\\-/; print " $old -> $a\n"; }\''); + #the real thing + #issh("root\@$shellmachine",'perl -e \'foreach $a (<'. $dir. '/.qmail'. $dash_ext. '-*>) { $old=$a; $a =~ s/\\.qmail'. $dash_ext. '\\-/\\.qmail\\-'. $qdomain. '\\-/; rename $old, $a; }\''); + print VD_FIX <<END; +foreach \$file (<$dir/.qmail$dash_ext-*>) { + \$old = \$file; + \$file =~ s/\.qmail$dash_ext\-/\.qmail\-$qdomain\-/; + rename \$old, \$file; +} +END + } + + unless ( exists $svcnum{$domain} ) { + my($svc_domain) = new FS::svc_domain ({ + 'domain' => $domain, + 'svcpart' => $domain_svcpart, + 'action' => 'N', + }); + my $error = $svc_domain->insert; + #warn $error if $error; + die $error if $error; + $svcnum{$domain}=$svc_domain->svcnum; + } + + my($svc_acct_sm)=new FS::svc_acct_sm ({ + 'domsvc' => $svcnum{$domain}, + 'domuid' => $svc_acct->uid, + 'domuser' => '*', + 'svcpart' => $mailalias_svcpart, + }); + my($error)=''; + $error=$svc_acct_sm->insert; + #warn $error if $error; + die $error, ", domain $domain" if $error; + } + close VIRTUALDOMAINS; + close VD_FIX; + +} elsif ( $mta{$mta} eq "sendmail" ) { + + open(VIRTUSERTABLE,"<$spooldir/virtusertable.import") + or die "Can't open $spooldir/virtusertable.import: $!"; + while (<VIRTUSERTABLE>) { + next if /^#/; #comments? + 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); + my($svc_acct)=qsearchs('svc_acct',{'username'=>$username}); + unless ( $svc_acct ) { + #warn "Unknown user $username in virtusertable"; + die "Unknown user $username in virtusertable"; + next; + } + my($svc_acct_sm)=new FS::svc_acct_sm ({ + 'domsvc' => $svcnum{$domain}, + 'domuid' => $svc_acct->uid, + 'domuser' => $domuser || '*', + 'svcpart' => $mailalias_svcpart, + }); + my($error)=''; + $error=$svc_acct_sm->insert; + #warn $error if $error; + die $error if $error; + } + close VIRTUSERTABLE; + +} else { + die "Unknown MTA!\n"; +} + +#open(RECIPIENTMAP,"<$spooldir/recipientmap.import"); +#close RECIPIENTMAP; + +print "\n\n", <<END if $mta{$mta} eq "qmail"; +Don\'t forget to run $spooldir/virtualdomains.FIX before using +$spooldir/virtualdomains ! +END + +# + +sub usage { + die "Usage:\n\n svc_acct_sm.import user\n"; +} + diff --git a/bin/svc_domain.import b/bin/svc_domain.import new file mode 100644 index 000000000..3d3be9da5 --- /dev/null +++ b/bin/svc_domain.import @@ -0,0 +1,92 @@ +#!/usr/bin/perl -w +# +# $Id: svc_domain.import,v 1.2 2001-04-22 01:56:15 ivan Exp $ + +use strict; +use vars qw( %d_part_svc ); +use Term::Query qw(query); +use Net::SCP qw(iscp); +use FS::UID qw(adminsuidsetup datasrc); +#use FS::Record qw(qsearch qsearchs); +#use FS::svc_acct_sm; +use FS::svc_domain; +use FS::domain_record; +#use FS::svc_acct; +#use FS::part_svc; + +my $user = shift or die &usage; +adminsuidsetup $user; + +my($spooldir)="/usr/local/etc/freeside/export.". datasrc; + +%d_part_svc = + map { $_->svcpart, $_ } qsearch('part_svc',{'svcdb'=>'svc_domain'}); + +print "\n\n", + ( join "\n", map "$_: ".$d_part_svc{$_}->svc, sort keys %d_part_svc ), + "\n\n"; +$^W=0; #Term::Query isn't -w-safe +my $domain_svcpart = + query "Enter part number for domains: ", 'irk', [ keys %d_part_svc ]; +$^W=1; + + print "\n\n", <<END; +Enter the location and name of your primary named.conf file, for example +"ns.isp.com:/var/named/named.conf" +END + my($named_conf)=&getvalue(":"); + iscp("root\@$named_conf","$spooldir/named.conf.import"); + +my $named_machine = (split(/:/, $named_conf))[0]; + +print "\n\n"; + +## + +$FS::svc_domain::whois_hack=1; + +open(NAMED_CONF,"<$spooldir/named.conf.import") + or die "Can't open $spooldir/named.conf.import: $!"; + +while (<NAMED_CONF>) { + next unless /^\s*options/; +} +my $directory; +while (<NAMED_CONF>) { + last if /^\s*directory\s+\"([\/\w+]+)\";/; +} +$directory = $1 or die "can't locate directory in named.conf!"; +whlie (<NAMED_CONF>) { + next unless /^\s*zone\s+\"([\w\.\-]+)\"\s+\{/; + my $zone = $1; + while (<NAMED_CONF>) { + my $type; + if ( /^\s*type\s+(master|slave)\s*\;/ ) { + $type = $1; + } + if ( /^\s*file\s+\"([\w\.\-]+)\"\s*\;/ && $type eq 'master' ) { + + # + # (add svc_domain) + my $file = $1; + iscp("root\@$named_machine:$directory/$file","$spooldir/$file.import"); + open(ZONE,"<$spooldir/$file.import") + or die "Can't open $spooldir/$file.import: $!"; + while (<ZONE>) { + # (add domain_record) + } + + # + + } + + last if /^\s*\}\s*\;/; + } +} + +## + +sub usage { + die "Usage:\n\n svc_domain.import user\n"; +} + |