Subversion Repositories general

Compare Revisions

No changes between revisions

Ignore whitespace Rev 1220 → Rev 1221

/hostadmiral/trunk/backend/delete_mailbox.sh
18,7 → 18,7
 
### config ################################################
 
ROOT=/var/spool/mail
. `dirname $0`/scripts.conf
 
### validate params #######################################
 
/hostadmiral/trunk/backend/move_domain.sh
0,0 → 1,55
#!/bin/sh
 
#
# HostAdmiral backend. Executed with ROOT privileges
#
# The script moves specified old domain dir to new one
#
# Params:
# old_domain (e.g. example.com)
# new_domain (e.g. domain.net)
#
# Return:
# 0 - nothing done, all OK
# 2 - dir moved
# 3 - wrong params
# 4 - some error
# 5 - error from system
#
 
### config ################################################
 
. `dirname $0`/scripts.conf
 
### validate params #######################################
 
if [ -z "$2" -o -n "$3" ] ; then echo "Wrong params 1"; exit 3; fi
 
OLD="/$1/"
echo "$OLD" | awk '$0 ~ "//" || $0 ~ "/\\./" || $0 ~ "/\\.\\./" || $0 !~ "^/(([a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)\\.)*([a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)/$" {exit 1} {exit 0}'
if [ $? -ne 0 ]; then
echo "Wrong params 2"; exit 3
fi
 
NEW="/$2/"
echo "$NEW" | awk '$0 ~ "//" || $0 ~ "/\\./" || $0 ~ "/\\.\\./" || $0 !~ "^/(([a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)\\.)*([a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)/$" {exit 1} {exit 0}'
if [ $? -ne 0 ]; then
echo "Wrong params 3"; exit 3
fi
 
### work ##################################################
 
if [ -d "${ROOT}${NEW}" ] ; then
# the new maildir exists already - error
exit 4;
else
# the new maildir doesn't exist and the old one doesn't exist - do nothing
if [ ! -d "${ROOT}${OLD}" ] ; then
exit 0;
fi
 
# the new maildir doesn't exist the old one exists - move it
mv "${ROOT}${OLD}" "${ROOT}${NEW}" || { echo "Cannot move maildir"; exit 5; }
exit 2;
fi
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/hostadmiral/trunk/backend/move_mailbox.sh
25,8 → 25,7
 
### config ################################################
 
ROOT=/var/spool/mail
DEFAULT_OWNER=202
. `dirname $0`/scripts.conf
 
### validate params #######################################
 
/hostadmiral/trunk/backend/scripts.conf.sample
0,0 → 1,9
#
# HostAdmiral backend. Executed with ROOT privileges
#
# configuration for *.sh scripts
#
 
ROOT=/var/spool/mail
DEFAULT_OWNER=202
 
/hostadmiral/trunk/backend/backend.pl
1,9 → 1,11
#!/usr/bin/perl -w
 
#
# Sample backend for HostAdmiral
# (copyleft) Anatoli Klassen
#
###################################################################################################
# #
# Sample backend for HostAdmiral #
# (copyleft) Anatoli Klassen #
# #
###################################################################################################
 
#
# Design:
31,8 → 33,6
 
# FIXME secure to show wrong (m.b. hacked) strings in logs and socket answers?
# FIXME double check validate_* functions
# FIXME by delete and rename domain - should the frontend send us an event for each mailbox
# (alias, destination etc) in the domain or should we do it at once?
 
use strict;
use vars;
42,7 → 42,7
use Time::HiRes qw( gettimeofday tv_interval );
use File::Basename qw( dirname );
 
# == configuration =============================
#=== configuration ================================================================================
 
my $base_dir = dirname($0);
 
58,7 → 58,7
my $config_name = "$base_dir/backend.conf";
require $config_name; # read the config
 
# == constants =================================
#=== constants ====================================================================================
 
# protocol description
my $protocol_ver_maj = '1';
96,7 → 96,7
my $code_script_error = 506;
my $code_panic = 600;
 
# == internal global variables =================
#=== internal global variables ====================================================================
 
my %handlers;
my $database_connection;
103,7 → 103,7
my $database_in_use = 0;
my $database_in_transaction = 0;
 
# == functions =================================
#=== functions ====================================================================================
 
sub handle_request
{
186,7 → 186,7
# rollback transaction if it's still open
if($database_in_transaction) {
eval {
log_warn("Rollback transaction");
log_error("Rollback transaction");
db_rollback_transaction();
};
if($@) {
202,8 → 202,10
}
}
 
### request handlers ######################################
### request handlers ##############################################################################
 
#-- user handlers ---------------------------------------------------------------------------------
 
sub handle_user_create
{
my $request = shift @_;
225,6 → 227,8
set_request_code($request, $code_ignored, "Not interesting in users");
}
 
#-- system user handlers --------------------------------------------------------------------------
 
sub handle_system_user_create
{
my $request = shift @_;
246,6 → 250,8
set_request_code($request, $code_ignored, "Not interesting in system users");
}
 
#-- domain handlers -------------------------------------------------------------------------------
 
sub save_domain
{
my $request = shift @_;
257,16 → 263,60
{ domain => $oldName },
{ domain => $name, comment => $comment, transport => 'virtual:' } );
# FIXME: transport => 'procmail:'? then restart mail system by transport change too
return 'error' if($res_action eq 'error');
# update users and aliases tables
if($name ne $oldName) {
my $dbh = db_begin($request);
return 'error' unless($dbh);
 
eval {
$dbh->do("update users set domain=?, login=concat(name,'\@',?),"
. " maildir=concat(?,'/',name,'/'), mailid=concat(id,'\@',?)"
. " where domain=?",
undef, $name, $name, $name, $name, $oldName);
};
if($@) {
return 'error' unless(db_end($request));
set_request_code($request, $code_db_inconsistent, "Cannot update users");
return 'error';
}
 
eval {
$dbh->do("update aliases set domain=?, alias=concat(name,'\@',?) where domain=?",
undef, $name, $name, $oldName);
};
if($@) {
return 'error' unless(db_end($request));
set_request_code($request, $code_db_inconsistent, "Cannot update aliases");
return 'error';
}
 
eval {
$dbh->do("update aliases set rcpt_domain=?, rcpt=concat(rcpt_name,'\@',?)"
. " where rcpt_domain=?",
undef, $name, $name, $oldName);
};
if($@) {
return 'error' unless(db_end($request));
set_request_code($request, $code_db_inconsistent, "Cannot update aliases");
return 'error';
}
 
return 'error' unless(db_end($request));
}
 
# restart postfix
if($res_action eq 'insert' || ($res_action eq 'update' && $name ne $oldName)) {
return 'error' unless(restart_mail_system());
}
# move domain dir
if($oldName ne $name) {
my $call_res = call_external_script($request, 'delete_domain.sh', [ $oldName ]);
log_debug("delete_domain.sh: $call_res");
my $call_res = call_external_script($request, 'move_domain.sh', [ $oldName, $name ]);
log_debug("move_domain.sh: $call_res");
if($call_res >= 3) {
set_request_code($request, $code_script_error, "Cannot delete domain dir");
set_request_code($request, $code_script_error, "Cannot move domain dir");
return 'error';
}
}
375,6 → 425,8
db_commit_transaction($request);
}
 
#-- mailbox handlers ------------------------------------------------------------------------------
 
sub update_mailbox_mailid
{
my $request = shift @_;
391,9 → 443,14
 
# create alias loop
my $res_action3 = save_to_db($request, 'aliases',
{ alias => "$id\@$domain", rcpt => "$id\@$domain" },
{ alias => "$id\@$domain", rcpt => "$id\@$domain",
comment => "loop for $login\@$domain" } );
{ alias => "$id\@$domain", rcpt => "$id\@$domain" },
{ name => $id,
domain => $domain,
alias => "$id\@$domain",
rcpt_name => $id,
rcpt_domain => $domain,
rcpt => "$id\@$domain",
comment => "loop for $login\@$domain" } );
return 0 if($res_action3 eq 'error');
 
return 1;
415,7 → 472,9
my $id;
my $res_action = save_to_db($request, 'users',
{ login => "$oldLogin\@$oldDomain" },
{ login => "$login\@$domain",
{ name => $login,
domain => $domain,
login => "$login\@$domain",
password => $password,
maildir => "$domain/$login/",
expired => $expired,
426,6 → 485,53
# set mailid for the new record
return 'error' unless(update_mailbox_mailid($request, $id, $login, $domain));
 
# update aliases table
if($domain ne $oldDomain || $login ne $oldLogin) {
my $dbh = db_begin($request);
return 'error' unless($dbh);
 
# find id
eval {
my $select_sth = $dbh->prepare("select id from users where login=?");
$select_sth->execute("$login\@$domain");
$id = $select_sth->fetchrow_array();
};
if(!$id || $@) {
return 'error' unless(db_end($request));
set_request_code($request, $code_db_inconsistent, "Cannot find id");
return;
}
 
# aliases
if($domain ne $oldDomain) {
eval {
$dbh->do("update aliases set rcpt_domain=?, rcpt=concat(rcpt_name,'\@',?)"
. " where rcpt_name=? and rcpt_domain=?",
undef, $domain, $domain, $id, $oldDomain);
};
if($@) {
return 'error' unless(db_end($request));
set_request_code($request, $code_db_inconsistent, "Cannot update aliases");
return 'error';
}
}
 
# the loop
eval {
$dbh->do("update aliases set domain=?, alias=?, rcpt_domain=?, rcpt=?, comment=?"
. " where alias=?",
undef, $domain, "$id\@$domain", $domain, "$id\@$domain",
"loop for $login\@$domain", "$id\@$oldDomain");
};
if($@) {
return 'error' unless(db_end($request));
set_request_code($request, $code_db_inconsistent, "Cannot update loop");
return 'error';
}
 
return 'error' unless(db_end($request));
}
 
# update disk
my $call_res = call_external_script($request, 'move_mailbox.sh',
[ (defined($systemUser) ? $systemUser : ''), "$oldDomain/$oldLogin", "$domain/$login" ]);
553,7 → 659,7
{ login => "$params{'login'}\@$params{'domain'}" } );
return if($res_action eq 'error');
 
my $res_action2 = delete_from_db($request, 'aliases', { alias => $mail_id } );
my $res_action2 = delete_from_db($request, 'aliases', { rcpt => $mail_id } );
return if($res_action2 eq 'error');
 
# delete from disk - last one, because disk has no transactions
577,6 → 683,8
db_commit_transaction($request);
}
 
#-- mail aliases handlers -------------------------------------------------------------------------
 
sub save_mail_alias_dest
{
my $request = shift @_;
619,9 → 727,16
# save
foreach my $rcpt (@$rcpts) {
log_debug("save $rcpt");
my ($rcpt_name, $rcpt_domain) = ($rcpt =~ /^(.*)\@(.*)$/);
my $res_action = save_to_db($request, 'aliases',
undef,
{ alias => "$address\@$domain", rcpt => $rcpt, comment => $comment } );
{ name => $address,
domain => $domain,
alias => "$address\@$domain",
rcpt_name => $rcpt_name,
rcpt_domain => $rcpt_domain,
rcpt => $rcpt,
comment => $comment } );
return 0 if($res_action eq 'error');
}
 
759,7 → 874,7
db_commit_transaction($request);
}
 
### validators ############################################
### validators ####################################################################################
 
sub validate_boolean
{
813,7 → 928,7
return ($_ eq '' || $_ >= 1000) ? 1 : 0; # additional security check
}
 
### request parsing #######################################
### request parsing ###############################################################################
 
sub decode_param
{
882,7 → 997,7
return %values;
}
 
### hanlders help functions ###############################
### hanlders help functions #######################################################################
 
sub restart_mail_system
{
916,7 → 1031,8
return 7;
}
elsif($res & 127) {
set_request_code($request, $code_exec_error, "Script died with signal " . ($res & 127));
set_request_code($request, $code_exec_error,
"Script died with signal " . ($res & 127));
return 7;
}
else {
924,7 → 1040,7
}
}
 
### db functions ##########################################
### db functions ##################################################################################
 
sub db_connect
{
1203,7 → 1319,7
return $res_action;
}
 
### logging and response formers ##########################
### logging and response formers ##################################################################
 
sub strip_request_password
{
1275,7 → 1391,7
print shift @_, ":\t", shift @_, "\n";
}
 
### main functions ########################################
### main functions ################################################################################
 
sub init
{
/hostadmiral/trunk/backend/delete_domain.sh
17,7 → 17,7
 
### config ################################################
 
ROOT=/var/spool/mail
. `dirname $0`/scripts.conf
 
### validate params #######################################
 
/hostadmiral/trunk/backend/restart_mail_system.sh
15,6 → 15,10
# 5 - error from system
#
 
### config ################################################
 
. `dirname $0`/scripts.conf
 
### work ##################################################
 
/usr/local/sbin/postfix reload
/hostadmiral/trunk/backend
Property changes:
Modified: svn:ignore
backend.conf
+scripts.conf
/hostadmiral/trunk/src/ak/hostadmiral/core/model/SystemUserManager.java
31,6 → 31,7
throws ModelException
{
UserManager.getInstance().addBeforeDeleteListener(this);
UserManager.getInstance().addDeletingListener(this);
}
 
public SystemUser create(User editor)
/hostadmiral/trunk/src/ak/hostadmiral/core/model/MailboxManager.java
36,8 → 36,11
throws ModelException
{
UserManager.getInstance().addBeforeDeleteListener(this);
UserManager.getInstance().addDeletingListener(this);
SystemUserManager.getInstance().addBeforeDeleteListener(this);
SystemUserManager.getInstance().addDeletingListener(this);
InetDomainManager.getInstance().addBeforeDeleteListener(this);
InetDomainManager.getInstance().addDeletingListener(this);
}
 
public Mailbox create(User editor)
303,6 → 306,7
Collection mailboxes = store.listMailboxesForSystemUser(user);
 
for(Iterator i = mailboxes.iterator(); i.hasNext(); ) {
// FIXME do not delete, just reset system user (?)
delete(editor, (Mailbox)i.next());
}
}
/hostadmiral/trunk/src/ak/hostadmiral/core/model/store/hibernate/MailAliasHibernate.java
14,6 → 14,7
import ak.hostadmiral.util.hibernate.HibernateUtil;
import ak.hostadmiral.core.model.User;
import ak.hostadmiral.core.model.InetDomain;
import ak.hostadmiral.core.model.Mailbox;
import ak.hostadmiral.core.model.MailAlias;
import ak.hostadmiral.core.model.MailAliasManager;
import ak.hostadmiral.core.model.store.MailAliasStore;
209,7 → 210,7
{
throw new ModelStoreException(ex);
}
}
}
 
public Collection listMailAliasesForDomain(InetDomain domain)
throws ModelStoreException
223,8 → 224,23
{
throw new ModelStoreException(ex);
}
}
}
 
public Collection listMailAliasesForMailbox(Mailbox mailbox)
throws ModelStoreException
{
try {
return HibernateUtil.currentSession().find(
"select a from MailAlias a left join fetch a.owner"
+ " left join fetch a.destinations as dest where dest.mailbox = ?",
mailbox, Hibernate.entity(Mailbox.class) );
}
catch(HibernateException ex)
{
throw new ModelStoreException(ex);
}
}
 
protected static Map sortKeys = new HashMap();
protected static Map sortKeysSql = new HashMap();
private static boolean sortKeysInitialized = false;
/hostadmiral/trunk/src/ak/hostadmiral/core/model/store/MailAliasStore.java
5,6 → 5,7
import ak.hostadmiral.util.ModelStoreException;
import ak.hostadmiral.core.model.User;
import ak.hostadmiral.core.model.InetDomain;
import ak.hostadmiral.core.model.Mailbox;
import ak.hostadmiral.core.model.MailAlias;
 
public interface MailAliasStore
40,4 → 41,7
 
public Collection listMailAliasesForDomain(InetDomain domain)
throws ModelStoreException;
 
public Collection listMailAliasesForMailbox(Mailbox mailbox)
throws ModelStoreException;
}
/hostadmiral/trunk/src/ak/hostadmiral/core/model/MailAliasManager.java
18,7 → 18,8
UserBeforeDeleteListener,
UserDeletingListener,
InetDomainBeforeDeleteListener,
InetDomainDeletingListener
InetDomainDeletingListener,
MailboxDeletingListener
{
private MailAliasStore store;
 
33,6 → 34,11
throws ModelException
{
UserManager.getInstance().addBeforeDeleteListener(this);
UserManager.getInstance().addDeletingListener(this);
InetDomainManager.getInstance().addBeforeDeleteListener(this);
InetDomainManager.getInstance().addDeletingListener(this);
// FIXME register for mailbox before delete event? or silently delete destinations?
MailboxManager.getInstance().addDeletingListener(this);
}
 
public MailAlias create(User editor)
85,6 → 91,8
public void save(User editor, MailAlias mailAlias)
throws ModelException
{
// FIXME: how the onwer can save new destinations if he has no right to save the alias?
 
// security check
if(!mailAlias.editableBy(editor))
throw new ModelSecurityException();
309,6 → 317,28
return cascade;
}
 
public void mailboxDeleting(User editor, Mailbox mailbox)
throws ModelException
{
Collection mailAliases = store.listMailAliasesForMailbox(mailbox);
 
for(Iterator i = mailAliases.iterator(); i.hasNext(); ) {
MailAlias mailAlias = (MailAlias)i.next();
System.out.println("mailboxDeleting: " + mailAlias);
 
// FIXME is it possible that editor has right to delete mailbox
// but has no right to change alias?
if(mailAlias.mayChangeDestinations(editor)) {
for(Iterator j = mailAlias.getDestinations(editor).iterator(); j.hasNext(); ) {
MailAliasDestination dest = (MailAliasDestination)j.next();
if(mailbox == dest.getMailbox()) j.remove();
}
 
save(editor, mailAlias);
}
}
}
 
public static final Integer SORT_ADDRESS = new Integer(1);
public static final Integer SORT_DOMAIN = new Integer(2);
 
/hostadmiral/trunk/src/ak/hostadmiral/core/model/MailAliasDestination.java
135,7 → 135,7
+ (alias == null ? "_none_" : alias.getAddress() + "@"
+ (alias.getDomain() == null ? "_none_" : alias.getDomain().getName()))
+ "] mailbox=[" + (mailbox == null ? "_none_" : mailbox.getLogin() + "@"
+ (mailbox.getDomain() == null ? "_none_" : mailbox.getDomain().getName())) + "]"
+ (mailbox.getDomain() == null ? "_none_" : mailbox.getDomain().getName()))
+ "] email=[" + (email == null ? "_none_" : email) + "]";
}
}