summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjeff <jeff>2001-08-08 17:45:36 +0000
committerjeff <jeff>2001-08-08 17:45:36 +0000
commit71d824b3ad4daa313fbb420b9dea3c32bde66c1e (patch)
tree68bf56ff26528b344d17e234447d03344df53568
parent339da5e73898ade0fcd1e67e55fc17d334fb7a3c (diff)
initial vpopmail supportfreeside_vpopmail_support-branch
-rw-r--r--FS/FS/svc_acct.pm12
-rw-r--r--FS/FS/svc_domain.pm5
-rw-r--r--FS/FS/svc_forward.pm255
-rwxr-xr-xbin/fs-migrate-svc_acct_sm239
-rwxr-xr-xbin/fs-setup33
-rwxr-xr-xbin/svc_acct.export647
-rwxr-xr-xbin/svc_acct_sm.export254
-rw-r--r--htdocs/docs/config.html2
-rw-r--r--htdocs/docs/upgrade8.html52
9 files changed, 1030 insertions, 469 deletions
diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm
index 0e0c885..68869c1 100644
--- a/FS/FS/svc_acct.pm
+++ b/FS/FS/svc_acct.pm
@@ -82,6 +82,10 @@ FS::svc_acct - Object methods for svc_acct records
%hash = $record->radius;
+ %hash = $record->radius_reply;
+
+ %hash = $record->radius_check;
+
=head1 DESCRIPTION
An FS::svc_acct object represents an account. FS::svc_acct inherits from
@@ -113,6 +117,8 @@ FS::svc_Common. The following fields are currently supported:
=item radius_I<Radius_Attribute> - I<Radius-Attribute>
+=item domsvc - service number of svc_domain with which to associate
+
=back
=head1 METHODS
@@ -169,7 +175,9 @@ sub insert {
return $error if $error;
return "Username ". $self->username. " in use"
- if qsearchs( 'svc_acct', { 'username' => $self->username } );
+ if qsearchs( 'svc_acct', { 'username' => $self->username,
+ 'domsvc' => $self->domsvc,
+ } );
my $part_svc = qsearchs( 'part_svc', { 'svcpart' => $self->svcpart } );
return "Unknown svcpart" unless $part_svc;
@@ -542,7 +550,7 @@ sub radius_check {
=head1 VERSION
-$Id: svc_acct.pm,v 1.17 2001-06-03 12:36:10 ivan Exp $
+$Id: svc_acct.pm,v 1.17.2.1 2001-08-08 17:45:34 jeff Exp $
=head1 BUGS
diff --git a/FS/FS/svc_domain.pm b/FS/FS/svc_domain.pm
index 01aa21a..d74049b 100644
--- a/FS/FS/svc_domain.pm
+++ b/FS/FS/svc_domain.pm
@@ -336,6 +336,9 @@ sub check {
$recref->{action} =~ /^(M|N)$/ or return "Illegal action";
$recref->{action} = $1;
+ my $svc_acct = qsearchs( 'svc_acct', { 'svcnum' => $recref->{catchall} } );
+ return "Unknown catchall" unless $svc_acct || ! $recref->{catchall};
+
$self->ut_textn('purpose');
}
@@ -478,7 +481,7 @@ sub submit_internic {
=head1 VERSION
-$Id: svc_domain.pm,v 1.12 2001-06-03 17:22:52 ivan Exp $
+$Id: svc_domain.pm,v 1.12.2.1 2001-08-08 17:45:35 jeff Exp $
=head1 BUGS
diff --git a/FS/FS/svc_forward.pm b/FS/FS/svc_forward.pm
new file mode 100644
index 0000000..5e496b1
--- /dev/null
+++ b/FS/FS/svc_forward.pm
@@ -0,0 +1,255 @@
+package FS::svc_forward;
+
+use strict;
+use vars qw( @ISA $nossh_hack $conf $shellmachine @qmailmachines @vpopmailmachines);
+use FS::Record qw( fields qsearch qsearchs );
+use FS::svc_Common;
+use FS::cust_svc;
+use Net::SSH qw(ssh);
+use FS::Conf;
+use FS::svc_acct;
+use FS::svc_domain;
+
+@ISA = qw( FS::svc_Common );
+
+#ask FS::UID to run this stuff for us later
+$FS::UID::callback{'FS::svc_forward'} = sub {
+ $conf = new FS::Conf;
+ $shellmachine = $conf->exists('qmailmachines')
+ ? $conf->config('shellmachine')
+ : '';
+ if ( $conf->exists('vpopmailmachines') ) {
+ @vpopmailmachines = $conf->config('vpopmailmachines');
+ }
+};
+
+=head1 NAME
+
+FS::svc_forward - Object methods for svc_forward records
+
+=head1 SYNOPSIS
+
+ use FS::svc_forward;
+
+ $record = new FS::svc_forward \%hash;
+ $record = new FS::svc_forward { 'column' => 'value' };
+
+ $error = $record->insert;
+
+ $error = $new_record->replace($old_record);
+
+ $error = $record->delete;
+
+ $error = $record->check;
+
+ $error = $record->suspend;
+
+ $error = $record->unsuspend;
+
+ $error = $record->cancel;
+
+=head1 DESCRIPTION
+
+An FS::svc_forward object represents a mail forwarding alias. FS::svc_forward
+inherits from FS::Record. The following fields are currently supported:
+
+=over 4
+
+=item svcnum - primary key (assigned automatcially for new accounts)
+
+=item srcsvc - svcnum of the source of the forward (see L<FS::svc_acct>)
+
+=item dstsvc - svcnum of the destination of the forward (see L<FS::svc_acct>)
+
+=item dst - foreign destination (email address) - forward not local to freeside
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new mail forwarding alias. To add the mail forwarding alias to the
+database, see L<"insert">.
+
+=cut
+
+sub table { 'svc_forward'; }
+
+=item insert
+
+Adds this mail forwarding alias to the database. If there is an error, returns
+the error, otherwise returns false.
+
+The additional fields pkgnum and svcpart (see L<FS::cust_svc>) should be
+defined. An FS::cust_svc record will be created and inserted.
+
+If the configuration values (see L<FS::Conf>) vpopmailmachines exist, then
+the command:
+
+ [ -d /home/vpopmail/$vdomain/$source ] || {
+ echo "$destination" >> /home/vpopmail/$vdomain/$source/.$qmail
+ chown $vpopuid:$vpopgid /home/vpopmail/$vdomain/$source/.$qmail
+ }
+
+is executed on each vpopmailmachine via ssh (see L<dot-qmail/"EXTENSION ADDRESSES">).
+This behaviour can be surpressed by setting $FS::svc_forward::nossh_hack true.
+
+=cut
+
+sub insert {
+ my $self = shift;
+ my $error;
+
+ local $SIG{HUP} = 'IGNORE';
+ local $SIG{INT} = 'IGNORE';
+ local $SIG{QUIT} = 'IGNORE';
+ local $SIG{TERM} = 'IGNORE';
+ local $SIG{TSTP} = 'IGNORE';
+ local $SIG{PIPE} = 'IGNORE';
+
+ $error=$self->check;
+ return $error if $error;
+
+ $error = $self->SUPER::insert;
+ return $error if $error;
+
+ my $svc_acct = qsearchs( 'svc_acct', { 'svcnum' => $self->srcsvc } );
+ my $svc_domain = qsearchs( 'svc_domain', { 'svcnum' => $svc_acct->domsvc } );
+ my $source = $svc_acct->username . $svc_domain->domain;
+ my $destination;
+ if ($self->dstdvc) {
+ my $svc_acct = qsearchs( 'svc_acct', { 'svcnum' => $self->dstsvc } );
+ my $svc_domain = qsearchs( 'svc_domain', { 'svcnum' => $svc_acct->domsvc } );
+ $destination = $svc_acct->username . $svc_domain->domain;
+ } else {
+ $destination = $self->dst;
+ }
+
+ my $vdomain = $svc_acct->domain;
+
+ foreach my $vpopmailmachine ( @vpopmailmachines ) {
+ my ($machine, $vpopdir, $vpopuid, $vpopgid) = split (/\s+/, $vpopmailmachine);
+
+ ssh("root\@$machine","[ -d $vpopdir/$vdomain/$source ] || { echo $destination >> $vpopdir/$vdomain/$source/.qmail; chown $vpopuid:$vpopgid $vpopdir/$vdomain/$source/.qmail; }")
+ if ( ! $nossh_hack && $machine);
+ }
+
+ ''; #no error
+
+}
+
+=item delete
+
+Deletes this mail forwarding alias from the database. If there is an error,
+returns the error, otherwise returns false.
+
+The corresponding FS::cust_svc record will be deleted as well.
+
+=item replace OLD_RECORD
+
+Replaces OLD_RECORD with this one in the database. If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+sub replace {
+ my ( $new, $old ) = ( shift, shift );
+ my $error;
+
+ $new->SUPER::replace($old);
+
+}
+
+=item suspend
+
+Just returns false (no error) for now.
+
+Called by the suspend method of FS::cust_pkg (see L<FS::cust_pkg>).
+
+=item unsuspend
+
+Just returns false (no error) for now.
+
+Called by the unsuspend method of FS::cust_pkg (see L<FS::cust_pkg>).
+
+=item cancel
+
+Just returns false (no error) for now.
+
+Called by the cancel method of FS::cust_pkg (see L<FS::cust_pkg>).
+
+=item check
+
+Checks all fields to make sure this is a valid mail forwarding alias. If there
+is an error, returns the error, otherwise returns false. Called by the insert
+and replace methods.
+
+Sets any fixed values; see L<FS::part_svc>.
+
+=cut
+
+sub check {
+ my $self = shift;
+ my $error;
+
+ my $x = $self->setfixed;
+ return $x unless ref($x);
+ my $part_svc = $x;
+
+ my($recref) = $self->hashref;
+
+ $recref->{srcsvc} =~ /^(\d+)$/ or return "Illegal srcsvc";
+ $recref->{srcsvc} = $1;
+ my($svc_acct);
+ return "Unknown srcsvc" unless
+ $svc_acct=qsearchs('svc_acct',{'svcnum'=> $recref->{srcsvc} } );
+
+ return "Illegal use of dstsvc and dst" if
+ ($recref->{dstsvc} && $recref->{dst});
+
+ return "Illegal use of dstsvc and dst" if
+ (! $recref->{dstsvc} && ! $recref->{dst});
+
+ $recref->{dstsvc} =~ /^(\d+)$/ or return "Illegal dstsvc";
+ $recref->{dstsvc} = $1;
+
+ if ($recref->{dstsvc}) {
+ my($svc_acct);
+ return "Unknown dstsvc" unless
+ my $svc_domain=qsearchs('svc_acct',{'svcnum'=> $recref->{dstsvc} } );
+ }
+
+ if ($recref->{dst}) {
+ $recref->{dst} =~ /^(\w\.\-]+)\@(([\w\.\-]+\.)+\w+)$/
+ or return "Illegal dst";
+ $recref->{dst} = $1;
+ }
+
+ ''; #no error
+}
+
+=back
+
+=head1 VERSION
+
+$Id: svc_forward.pm,v 1.1.2.1 2001-08-08 17:45:35 jeff Exp $
+
+=head1 BUGS
+
+The remote commands should be configurable.
+
+The $recref stuff in sub check should be cleaned up.
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::Conf>, L<FS::cust_svc>, L<FS::part_svc>, L<FS::cust_pkg>,
+L<FS::svc_acct>, L<FS::svc_domain>, L<Net::SSH>, L<ssh>, L<dot-qmail>,
+schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/bin/fs-migrate-svc_acct_sm b/bin/fs-migrate-svc_acct_sm
new file mode 100755
index 0000000..c121471
--- /dev/null
+++ b/bin/fs-migrate-svc_acct_sm
@@ -0,0 +1,239 @@
+#!/usr/bin/perl -Tw
+#
+# $Id: fs-migrate-svc_acct_sm,v 1.1.2.1 2001-08-08 17:45:35 jeff Exp $
+#
+# jeff@cmh.net 01-Jul-20
+#
+# $Log: fs-migrate-svc_acct_sm,v $
+# Revision 1.1.2.1 2001-08-08 17:45:35 jeff
+# initial vpopmail support
+#
+#
+#
+# Initial vpopmail changes
+#
+
+#to delay loading dbdef until we're ready
+#BEGIN { $FS::Record::setup_hack = 1; }
+
+use strict;
+use Term::Query qw(query);
+#use DBI;
+#use DBIx::DBSchema;
+#use DBIx::DBSchema::Table;
+#use DBIx::DBSchema::Column;
+#use DBIx::DBSchema::ColGroup::Unique;
+#use DBIx::DBSchema::ColGroup::Index;
+use FS::Conf;
+use FS::UID qw(adminsuidsetup datasrc checkeuid getsecrets);
+use FS::Record qw(qsearch qsearchs);
+use FS::svc_domain;
+use FS::svc_forward;
+use vars qw( $conf $old_default_domain %part_domain_svc %part_acct_svc %part_forward_svc $svc_acct $svc_acct_sm $error);
+
+die "Not running uid freeside!" unless checkeuid();
+
+my $user = shift or die &usage;
+getsecrets($user);
+
+$conf = new FS::Conf;
+$old_default_domain = $conf->config('domain');
+
+#needs to match FS::Record
+#my($dbdef_file) = "/usr/local/etc/freeside/dbdef.". datasrc;
+
+###
+# This section would be the appropriate place to manipulate
+# the schema & tables.
+###
+
+## we need to add the domsvc to svc_acct
+## we must add a svc_forward record....
+## I am thinking that the fields svcnum (int), destsvc (int), and
+## dest (varchar (80)) are appropriate, with destsvc/dest an either/or
+## much in the spirit of cust_main_invoice
+
+###
+# massage the data
+###
+
+my($dbh)=adminsuidsetup $user;
+
+$|=1;
+
+$FS::svc_acct::nossh_hack = 1;
+$FS::svc_forward::nossh_hack = 1;
+$FS::svc_domain::whois_hack = 1;
+
+%part_domain_svc=map { $_->svcpart, $_ } qsearch('part_svc',{'svcdb'=>'svc_domain'});
+%part_acct_svc=map { $_->svcpart, $_ } qsearch('part_svc',{'svcdb'=>'svc_acct'});
+%part_forward_svc=map { $_->svcpart, $_ } qsearch('part_svc',{'svcdb'=>'svc_forward'});
+
+die "No services with svcdb svc_domain!\n" unless %part_domain_svc;
+die "No services with svcdb svc_acct!\n" unless %part_acct_svc;
+die "No services with svcdb svc_forward!\n" unless %part_forward_svc;
+
+my($svc_domain) = qsearchs('svc_domain', { 'domain' => $old_default_domain });
+if (! $svc_domain || $svc_domain->domain != $old_default_domain) {
+ print <<EOF;
+
+Your database currently does not contain a svc_domain record for the
+domain $old_default_domain. Would you like me to add one for you?
+EOF
+
+ my($response)=scalar(<STDIN>);
+ chop $response;
+ if ($response =~ /^[yY]/) {
+ print "\n\n", &menu_domain_svc, "\n", <<END;
+I need to create new domain accounts. Which service shall I use for that?
+END
+ my($domain_svcpart)=&getdomainpart;
+
+ $svc_domain = new FS::svc_domain {
+ 'domain' => $old_default_domain,
+ 'svcpart' => $domain_svcpart,
+ 'action' => 'M',
+ };
+# $error=$svc_domain->insert && die "Error adding domain $old_default_domain: $error";
+ $error=$svc_domain->insert;
+ die "Error adding domain $old_default_domain: $error" if $error;
+ }else{
+ print <<EOF;
+
+ This program cannot function properly until a svc_domain record matching
+your conf_dir/domain file exists.
+EOF
+
+ exit 1;
+ }
+}
+
+print "\n\n", &menu_acct_svc, "\n", <<END;
+I may need to create some new pop accounts and set up forwarding to them
+for some users. Which service shall I use for that?
+END
+my($pop_svcpart)=&getacctpart;
+
+print "\n\n", &menu_forward_svc, "\n", <<END;
+I may need to create some new forwarding for some users. Which service
+shall I use for that?
+END
+my($forward_svcpart)=&getforwardpart;
+
+sub menu_domain_svc {
+ ( join "\n", map "$_: ".$part_domain_svc{$_}->svc, sort keys %part_domain_svc ). "\n";
+}
+sub menu_acct_svc {
+ ( join "\n", map "$_: ".$part_acct_svc{$_}->svc, sort keys %part_acct_svc ). "\n";
+}
+sub menu_forward_svc {
+ ( join "\n", map "$_: ".$part_forward_svc{$_}->svc, sort keys %part_forward_svc ). "\n";
+}
+sub getdomainpart {
+ $^W=0; # Term::Query isn't -w-safe
+ my $return = query "Enter part number:", 'irk', [ keys %part_domain_svc ];
+ $^W=1;
+ $return;
+}
+sub getacctpart {
+ $^W=0; # Term::Query isn't -w-safe
+ my $return = query "Enter part number:", 'irk', [ keys %part_acct_svc ];
+ $^W=1;
+ $return;
+}
+sub getforwardpart {
+ $^W=0; # Term::Query isn't -w-safe
+ my $return = query "Enter part number:", 'irk', [ keys %part_forward_svc ];
+ $^W=1;
+ $return;
+}
+
+
+#migrate data
+
+my(@svc_accts) = qsearch('svc_acct', {});
+foreach $svc_acct (@svc_accts) {
+ my(@svc_acct_sms) = qsearch('svc_acct_sm', {
+ domuid => $svc_acct->getfield('uid'),
+ }
+ );
+
+ # Ok.. we've got the svc_acct record, and an array of svc_acct_sm's
+ # What do we do from here?
+
+ # The intuitive:
+ # plop the svc_acct into the 'default domain'
+ # and then represent the svc_acct_sm's with svc_forwards
+ # they can be gussied up manually, later
+ #
+ # Perhaps better:
+ # when no svc_acct_sm exists, place svc_acct in 'default domain'
+ # when one svc_acct_sm exists, place svc_acct in corresponding
+ # domain & possibly create a svc_forward in 'default domain'
+ # when multiple svc_acct_sm's exists (in different domains) we'd
+ # better use the 'intuitive' approach.
+ #
+ # Specific way:
+ # as 'perhaps better,' but we may be able to guess which domain
+ # is correct by comparing the svcnum of domains to the username
+ # of the svc_acct
+ #
+
+ # The intuitive way:
+
+ my $def_acct = new FS::svc_acct ( { $svc_acct->hash } );
+ $def_acct->setfield('domsvc' => $svc_domain->getfield('svcnum'));
+ $error = $def_acct->replace($svc_acct);
+ die "Error replacing svc_acct for " . $def_acct->username . " : $error" if $error;
+
+ foreach $svc_acct_sm (@svc_acct_sms) {
+
+ my($domrec)=qsearchs('svc_domain', {
+ svcnum => $svc_acct_sm->getfield('domsvc'),
+ }) || die "svc_acct_sm references invalid domsvc $svc_acct_sm->getfield('domsvc')\n";
+
+ if ($svc_acct_sm->getfield('domuser') =~ /^\*$/) {
+
+ my($newdom) = new FS::svc_domain ( { $domrec->hash } );
+ $newdom->setfield('catchall', $svc_acct->svcnum);
+ $newdom->setfield('action', "M");
+ $error = $newdom->replace($domrec);
+ die "Error replacing svc_domain for (anything)@" . $domrec->domain . " : $error" if $error;
+
+ } else {
+
+ my($newacct) = new FS::svc_acct {
+ 'svcpart' => $pop_svcpart,
+ 'username' => $svc_acct_sm->getfield('domuser'),
+ 'domsvc' => $svc_acct_sm->getfield('domsvc'),
+ 'dir' => '/dev/null',
+ };
+ $error = $newacct->insert;
+ die "Error adding svc_acct for " . $newacct->username . " : $error" if $error;
+
+ my($newforward) = new FS::svc_forward {
+ 'svcpart' => $forward_svcpart,
+ 'srcsvc' => $newacct->getfield('svcnum'),
+ 'dstsvc' => $def_acct->getfield('svcnum'),
+ };
+ $error = $newforward->insert;
+ die "Error adding svc_forward for " . $newacct->username ." : $error" if $error;
+ }
+
+ $error = $svc_acct_sm->delete;
+ die "Error deleting svc_acct_sm for " . $svc_acct_sm->domuser ." : $error" if $error;
+
+ };
+
+};
+
+
+$dbh->commit or die $dbh->errstr;
+$dbh->disconnect or die $dbh->errstr;
+
+print "svc_acct_sm records sucessfully migrated\n";
+
+sub usage {
+ die "Usage:\n fs-migrate-svc_acct_sm user\n";
+}
+
diff --git a/bin/fs-setup b/bin/fs-setup
index c1e87c8..f355438 100755
--- a/bin/fs-setup
+++ b/bin/fs-setup
@@ -1,6 +1,6 @@
#!/usr/bin/perl -Tw
#
-# $Id: fs-setup,v 1.37 2001-06-03 14:16:11 ivan Exp $
+# $Id: fs-setup,v 1.37.2.1 2001-08-08 17:45:35 jeff Exp $
#
# ivan@sisd.com 97-nov-8,9
#
@@ -32,7 +32,18 @@
# fix radius attributes ivan@sisd.com 98-sep-27
#
# $Log: fs-setup,v $
-# Revision 1.37 2001-06-03 14:16:11 ivan
+# Revision 1.37.2.1 2001-08-08 17:45:35 jeff
+# initial vpopmail support
+#
+# Revision 1.2 2001/08/07 22:05:42 jeff
+#
+#
+# Initial vpopmail changes
+#
+# Revision 1.1.1.1 2001/07/17 18:08:43 jeff
+# Import of Freeside 1.3.1 pre
+#
+# Revision 1.37 2001/06/03 14:16:11 ivan
# allow empty refund reasons
#
# Revision 1.36 2001/04/15 12:56:31 ivan
@@ -244,7 +255,7 @@ 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)) {
+foreach (qw(svc_acct svc_acct_sm svc_domain svc_forward svc_www)) {
my($table)=$dbdef->table($_);
my($col);
foreach $col ( $table->columns ) {
@@ -665,10 +676,11 @@ sub tables_hash_hack {
'quota', 'varchar', 'NULL', $char_d,
'slipip', 'varchar', 'NULL', 15, #four TINYINTs, bah.
'seconds', 'int', 'NULL', '', #uhhhh
+ 'domsvc', 'int', '', '',
],
'primary_key' => 'svcnum',
'unique' => [ [] ],
- 'index' => [ ['username'] ],
+ 'index' => [ ['username'], ['domsvc'] ],
},
'svc_acct_sm' => {
@@ -697,6 +709,7 @@ sub tables_hash_hack {
'columns' => [
'svcnum', 'int', '', '',
'domain', 'varchar', '', $char_d,
+ 'catchall', 'int', '', '',
],
'primary_key' => 'svcnum',
'unique' => [ ['domain'] ],
@@ -717,6 +730,18 @@ sub tables_hash_hack {
'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', '', '',
diff --git a/bin/svc_acct.export b/bin/svc_acct.export
index 822f70a..f62cd58 100755
--- a/bin/svc_acct.export
+++ b/bin/svc_acct.export
@@ -1,96 +1,46 @@
#!/usr/bin/perl -w
#
-# $Id: svc_acct.export,v 1.20 2001-06-20 08:33:42 ivan Exp $
+# $Id: svc_acct.export,v 1.20.2.1 2001-08-08 17:45:36 jeff Exp $
#
-# Create and export password files: passwd, passwd.adjunct, shadow,
-# acp_passwd, acp_userinfo, acp_dialup, users
+# 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.
#
-# 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.20 2001-06-20 08:33:42 ivan
-# > Use of uninitialized value in concatenation (.) at svc_acct.export line
-# > 276.
-#
-# 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.20.2.1 2001-08-08 17:45:36 jeff
+# initial vpopmail support
#
-# 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
+# Initial vpopmail changes
#
-# 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 Archive::Tar;
use Fcntl qw(:flock);
+use File::Path;
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::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');
@@ -127,6 +77,29 @@ my $textradiusprepend =
? $conf->config('textradiusprepend')
: '';
+my @vpopmailmachines = $conf->config('vpopmailmachines')
+ if $conf->exists('vpopmailmachines');
+
+my ($machine, $vpopdir, $vpopuid, $vpopgid) = split (/\s+/, $vpopmailmachines[0]);
+
+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') if $conf->exists('domain');
+
+
+
+
my(@saltset)= ( 'a'..'z' , 'A'..'Z' , '0'..'9' , '.' , '/' );
require 5.004; #srand(time|$$);
@@ -139,42 +112,81 @@ 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",
;
+rmtree"$spooldir/domains", 0, 1;
+mkdir "$spooldir/domains", 0700;
+
if ( $icradiusmachines ) {
my $sth = $icradius_dbh->prepare("DELETE FROM radcheck");
$sth->execute or die "Can't reset radcheck table: ". $sth->errstr;
@@ -184,167 +196,320 @@ if ( $icradiusmachines ) {
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';
+my %usernames; ## this hack helps keep the passwd files sane
+my @sendmail;
+
+my $svc_domain;
+foreach $svc_domain (sort {$a->domain cmp $b->domain} @svc_domain) {
+
+ my($domain)=$svc_domain->domain;
+ print RCPTHOSTS "$domain\n.$domain\n";
+ print VPOPRCPTHOSTS "$domain\n";
+ print SENDMAIL_CW "$domain\n";
+
+ ###
+ # FORMAT OF THE ASSIGN/USERS FILE HERE
+ print ASSIGN join(":",
+ "+" . $domain . "-",
+ $domain,
+ $vpopuid,
+ $vpopgid,
+ $vpopdir . "/domains/" . $domain,
+ "-",
+ "",
+ "",
+ ), "\n";
+
+ (mkdir "$spooldir/domains/" . $domain, 0700)
+ or die "Can't create $spooldir/domains/" . $domain .": $!";
+
+ ( open(QMAILDEFAULT,">$spooldir/domains/" . $domain . "/.qmail-default")
+ and flock(QMAILDEFAULT,LOCK_EX|LOCK_NB)
+ ) or die "Can't open $spooldir/domains/" . $domain . "/.qmail-default: $!";
+
+ ( open(VPASSWD,">$spooldir/domains/" . $domain . "/vpasswd")
+ and flock(VPASSWD,LOCK_EX|LOCK_NB)
+ ) or die "Can't open $spooldir/domains/" . $domain . "/vpasswd: $!";
+
+ my ($svc_acct);
+
+ if ($svc_domain->catchall) {
+ $svc_acct = qsearchs('svc_acct', {'svcnum' => $svc_domain->catchall});
+ die "Cannot find catchall account for domain $domain\n" unless $svc_acct;
+
+ my $username = $svc_acct->username;
+ push @sendmail, "\@$domain\t$username\n";
+ print VIRTUALDOMAINS "$domain:$username-$domain\n",
+ ".$domain:$username-$domain\n",
+ ;
###
- # FORMAT OF FreeBSD MASTER PASSWD FILE HERE
- print MASTER join(":",
- $svc_acct->username, # User name
- $cpassword, # Encrypted password
- $svc_acct->uid, # User ID
- $svc_acct->gid, # Group ID
- "", # Login Class
- "0", # Password Change Time
- "0", # Password Expiration Time
- $svc_acct->finger, # Users name
- $svc_acct->dir, # Users home directory
- $svc_acct->shell, # shell
- ), "\n" ;
+ # FORMAT OF THE .QMAIL-DEFAULT FILE HERE
+ print QMAILDEFAULT "| $vpopdir/bin/vdelivermail \"\" $username\@$domain\n";
+ }else{
###
- # FORMAT OF THE PASSWD FILE HERE
- print PASSWD join(":",
- $svc_acct->username,
- 'x', # "##". $svc_acct->$username,
- $svc_acct->uid,
- $svc_acct->gid,
- $svc_acct->finger,
- $svc_acct->dir,
- $svc_acct->shell,
- ), "\n";
-
- ###
- # FORMAT OF THE SHADOW FILE HERE
- print SHADOW join(":",
- $svc_acct->username,
- $cpassword,
- '',
- '',
- '',
- '',
- '',
- '',
- '',
- ), "\n";
-
+ # FORMAT OF THE .QMAIL-DEFAULT FILE HERE
+ print QMAILDEFAULT "| $vpopdir/bin/vdelivermail \"\" bounce-no-mailbox\n";
}
- if ( $svc_acct->slipip ne '' ) {
+ print VPOPVIRTUALDOMAINS "$domain:$domain\n";
+
+ foreach $svc_acct (qsearch('svc_acct', {'domsvc' => $svc_domain->svcnum})) {
+ my($password)=$svc_acct->getfield('_password');
+ my($cpassword,$rpassword);
+ if ( ( length($password) <= 8 )
+ && ( $password ne '*' )
+ && ( $password ne '' )
+ ) {
+ $cpassword=crypt($password,
+ $saltset[int(rand(64))].$saltset[int(rand(64))]
+ );
+ $rpassword=$password;
+ } else {
+ $cpassword=$password;
+ $rpassword='UNIX';
+ }
- ###
- # 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 $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;
+ } else {
+ die "Unknown policy in username_policy\n";
}
- my %radreply = $svc_acct->radius_reply;
- my %radcheck = $svc_acct->radius_check;
+ 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";
+ }
- my $radcheck = join ", ", map { qq($_ = "$radcheck{$_}") } keys %radcheck;
- $radcheck .= ", " if $radcheck;
+ ###
+ # FORMAT OF THE VPASSWD FILE HERE
+ print VPASSWD join(":",
+ $svc_acct->username,
+ $cpassword,
+ '1',
+ '0',
+ $svc_acct->username,
+ "$vpopdir/domains/" . $svc_domain->domain ."/" . $svc_acct->username,
+ 'NOQUOTA',
+ ), "\n";
- ###
- # 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 ) {
+ if ( $svc_acct->slipip ne '' ) {
- 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;
+ ###
+ # 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);
+ }
- foreach my $attribute ( keys %radcheck ) {
+ ###
+ # 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,
- $attribute,
- $radcheck{$attribute},
+ $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; }
}
-
- 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;
+ }
+
+ ###
+ # 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;
@@ -352,19 +517,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) {
+my($ashellmachine);
+foreach $ashellmachine (@shellmachines) {
my $scp = new Net::SCP;
- $scp->scp("$spooldir/passwd","root\@$shellmachine:/etc/passwd.new")
+ $scp->scp("$spooldir/passwd","root\@$ashellmachine:/etc/passwd.new")
or die "scp error: ". $scp->{errstr};
- $scp->scp("$spooldir/shadow","root\@$shellmachine:/etc/shadow.new")
+ $scp->scp("$spooldir/shadow","root\@$ashellmachine:/etc/shadow.new")
or die "scp error: ". $scp->{errstr};
- ssh("root\@$shellmachine",
+ ssh("root\@$ashellmachine",
"( ".
"mv /etc/passwd.new /etc/passwd; ".
"mv /etc/shadow.new /etc/shadow; ".
@@ -453,6 +625,65 @@ foreach my $icradiusmachine ( @icradiusmachines ) {
close WRITER;
}
+my @args = ("/bin/tar", "c", "--force-local", "-C", "$spooldir", "-f", "$spooldir/vpoptarball", "domains");
+
+system {$args[0]} @args;
+
+my($vpopmailmachine);
+foreach $vpopmailmachine (@vpopmailmachines) {
+ my ($machine, $vpopdir, $vpopuid, $vpopgid) = split (/\s+/, $vpopmailmachine);
+ my $scp = new Net::SCP;
+ $scp->scp("$spooldir/vpoptarball","root\@$machine:vpoptarball")
+ or die "scp error: ". $scp->{errstr};
+ ssh("root\@$machine",
+ "( ".
+ "tar xf vpoptarball; ".
+ "chown -R $vpopuid:$vpopgid domains; ".
+ "tar cf vpoptarball domains; ".
+ "cd $vpopdir; ".
+ "tar xf ~/vpoptarball; ".
+ " )"
+ )
+ == 0 or die "ssh error: $!";
+
+ $scp->scp("$spooldir/assign","root\@$machine:/var/qmail/users/assign")
+ or die "scp error: ". $scp->{errstr};
+ $scp->scp("$spooldir/vpopvirtualdomains","root\@$machine:/var/qmail/control/virtualdomains")
+ or die "scp error: ". $scp->{errstr};
+ $scp->scp("$spooldir/vpoprcpthosts","root\@$machine:/var/qmail/control/rcpthosts")
+ or die "scp error: ". $scp->{errstr};
+}
+
+my($sendmailmachine);
+foreach $sendmailmachine (@sendmailmachines) {
+ my $scp = new Net::SCP;
+ $scp->scp("$spooldir/sendmail.cw","root\@$sendmailmachine:$sendmailconfigpath/sendmail.cw.new")
+ or die "scp error: ". $scp->{errstr};
+ $scp->scp("$spooldir/virtusertable","root\@$sendmailmachine:$sendmailconfigpath/virtusertable.new")
+ or die "scp error: ". $scp->{errstr};
+ ssh("root\@$sendmailmachine",
+ "( ".
+ "mv $sendmailconfigpath/sendmail.cw.new $sendmailconfigpath/sendmail.cw; ".
+ "mv $sendmailconfigpath/virtusertable.new $sendmailconfigpath/virtusertable; ".
+ $sendmailrestart.
+ " )"
+ )
+ == 0 or die "ssh error: $!";
+}
+
+my($qmailmachine);
+foreach $qmailmachine (@qmailmachines) {
+ my $scp = new Net::SCP;
+ $scp->scp("$spooldir/recipientmap","root\@$qmailmachine:/var/qmail/control/recipientmap")
+ or die "scp error: ". $scp->{errstr};
+ $scp->scp("$spooldir/virtualdomains","root\@$qmailmachine:/var/qmail/control/virtualdomains")
+ or die "scp error: ". $scp->{errstr};
+ $scp->scp("$spooldir/rcpthosts","root\@$qmailmachine:/var/qmail/control/rcpthosts")
+ or die "scp error: ". $scp->{errstr};
+ #ssh("root\@$qmailmachine","/etc/init.d/qmail restart")
+ # == 0 or die "ssh error: $!";
+}
+
unlink $spoollock;
flock(EXPORT,LOCK_UN);
close EXPORT;
diff --git a/bin/svc_acct_sm.export b/bin/svc_acct_sm.export
deleted file mode 100755
index d7a7840..0000000
--- a/bin/svc_acct_sm.export
+++ /dev/null
@@ -1,254 +0,0 @@
-#!/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/htdocs/docs/config.html b/htdocs/docs/config.html
index 49be720..cdd4dbd 100644
--- a/htdocs/docs/config.html
+++ b/htdocs/docs/config.html
@@ -101,6 +101,8 @@ All further configuration files and directories are located in
<li><a name="usernamemax">usernamemax</a> - Maximum username length (default is the size of the SQL column, probably specified when fs-setup was run)
<li><a name="usernamemax">username-letter</a> - The existance of this file will turn on the requirement that usernames contain at least one letter.
<li><a name="usernamemax">username-letterfirst</a> - The existance of this file will turn on the requirement that usernames start with a letter.
+ <li><a name="username_policy">username_policy</a> - This file controls the mechanism for preventing duplicate usernames in passwd/radius files exported from svc_accts. This should be one of 'prepend domsvc' 'append domsvc' or 'append domain'
+ <li><a name="vpopmailmachines">vpopmailmachines</a> - Your vpopmail pop toasters, one per line. Each line is of the form "machinename vpopdir vpopuid vpopgid". Eg: poptoaster.domain.tld /home/vpopmail 508 508 Note: vpopuid and vpopgid are values taken from the vpopmail machine's /etc/passwd
</ul>
</body>
diff --git a/htdocs/docs/upgrade8.html b/htdocs/docs/upgrade8.html
new file mode 100644
index 0000000..3798922
--- /dev/null
+++ b/htdocs/docs/upgrade8.html
@@ -0,0 +1,52 @@
+<head>
+ <title>Upgrading to 1.3.2</title>
+</head>
+<body>
+<h1>Upgrading to 1.3.2 from 1.3.1</h1>
+<ul>
+ <li>If migrating from 1.0.0, see these <a href="upgrade.html">instructions</a> first.
+ <li>If migrating from less than 1.1.4, see these <a href="upgrade2.html">instructions</a> first.
+ <li>If migrating from less than 1.2.0, see these <a href="upgrade3.html">instructions</a> first.
+ <li>If migrating from less than 1.2.2, see these <a href="upgrade4.html">instructions</a> first.
+ <li>If migrating from less than 1.2.3, see these <a href="upgrade5.html">instructions</a> first.
+ <li>If migrating from less than 1.3.0, see these <a href="upgrade6.html">instructions</a> first.
+ <li>If migrating from less than 1.3.1, see these <a href="upgrade7.html">instructions</a> first.
+ <li>Back up your data and current Freeside installation.
+ <li>Apply the following changes to your database:
+<pre>
+CREATE TABLE svc_forward (
+ svcnum int NOT NULL,
+ srcsvc int NOT NULL,
+ dstsvc int NOT NULL,
+ dst varchar(80),
+ PRIMARY KEY (svcnum)
+);
+ALTER TABLE svc_acct ADD domsvc integer NOT NULL;
+ALTER TABLE svc_domain ADD catchall integer;
+ALTER TABLE part_svc ADD svc_acct__domsvc integer NULL;
+ALTER TABLE part_svc ADD svc_acct__domsvc_flag char(1) NULL;
+ALTER TABLE part_svc ADD svc_domain__catchall integer NULL;
+ALTER TABLE part_svc ADD svc_domain__catchall_flag char(1) NULL;
+ALTER TABLE part_svc ADD svc_forward__srcsvc integer NULL;
+ALTER TABLE part_svc ADD svc_forward__srcsvc_flag char(1) NULL;
+ALTER TABLE part_svc ADD svc_forward__dstsvc integer NULL;
+ALTER TABLE part_svc ADD svc_forward__dstsvc_flag char(1) NULL;
+ALTER TABLE part_svc ADD svc_forward__dst integer NULL;
+ALTER TABLE part_svc ADD svc_forward__dst_flag char(1) NULL;
+
+</pre>
+ <li>Copy or symlink htdocs to the new copy.
+ <li>Remove the symlink or directory <i>(your_site_perl_directory)</i>/FS.
+ <li>Change to the FS directory in the new tarball, and build and install the
+ Perl modules:
+ <pre>
+$ cd FS/
+$ perl Makefile.PL
+$ make
+$ su
+# make install</pre>
+ <li>Run bin/dbdef-create.
+ <li>create a service based on svc_forward
+ <li>Run bin/fs-migrate-svc_acct_sm
+ <li>create the conf.dbsrc/user_policy as appropriate for your site
+</body>