From bef09f6e3375fef7a5e26146d38f8acc7390f033 Mon Sep 17 00:00:00 2001 From: Matthew Saunders Brown Date: Wed, 10 Feb 2021 16:16:23 -0800 Subject: [PATCH] initial commit --- LICENSE | 19 +++ README.md | 1 + bin/roundcubemail-settings-export.php | 92 +++++++++++++++ bin/roundcubemail-settings-import.php | 160 ++++++++++++++++++++++++++ bin/vmail-aliases-add.sh | 106 +++++++++++++++++ bin/vmail-aliases-del.sh | 92 +++++++++++++++ bin/vmail-aliases-get.sh | 98 ++++++++++++++++ bin/vmail-deploy.sh | 27 +++++ bin/vmail-dkim-add.sh | 36 ++++++ bin/vmail-dkim-del.sh | 29 +++++ bin/vmail-domains-add.sh | 122 ++++++++++++++++++++ bin/vmail-domains-del.sh | 115 ++++++++++++++++++ bin/vmail-domains-get.sh | 81 +++++++++++++ bin/vmail-domains-mod.sh | 98 ++++++++++++++++ bin/vmail-installer.sh | 3 + bin/vmail-mboxes-add.sh | 135 ++++++++++++++++++++++ bin/vmail-mboxes-get.sh | 102 ++++++++++++++++ bin/vmail-purge.sh | 31 +++++ bin/vmail-secure.sh | 34 ++++++ bin/webmail-disable.sh | 24 ++++ bin/webmail-enable.sh | 30 +++++ etc/vmail-db-info.conf | 6 + etc/vmail.conf | 20 ++++ libexec/vmail-quota-warning.sh | 12 ++ 24 files changed, 1473 insertions(+) create mode 100644 LICENSE create mode 100644 README.md create mode 100755 bin/roundcubemail-settings-export.php create mode 100755 bin/roundcubemail-settings-import.php create mode 100755 bin/vmail-aliases-add.sh create mode 100755 bin/vmail-aliases-del.sh create mode 100755 bin/vmail-aliases-get.sh create mode 100755 bin/vmail-deploy.sh create mode 100755 bin/vmail-dkim-add.sh create mode 100755 bin/vmail-dkim-del.sh create mode 100755 bin/vmail-domains-add.sh create mode 100755 bin/vmail-domains-del.sh create mode 100755 bin/vmail-domains-get.sh create mode 100755 bin/vmail-domains-mod.sh create mode 100755 bin/vmail-installer.sh create mode 100755 bin/vmail-mboxes-add.sh create mode 100755 bin/vmail-mboxes-get.sh create mode 100755 bin/vmail-purge.sh create mode 100755 bin/vmail-secure.sh create mode 100755 bin/webmail-disable.sh create mode 100755 bin/webmail-enable.sh create mode 100644 etc/vmail-db-info.conf create mode 100644 etc/vmail.conf create mode 100644 libexec/vmail-quota-warning.sh diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..156bfd4 --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +MIT License Copyright (c) 2021 Matthew Saunders Brown + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..6aed005 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# vmail-stack diff --git a/bin/roundcubemail-settings-export.php b/bin/roundcubemail-settings-export.php new file mode 100755 index 0000000..7ce73c5 --- /dev/null +++ b/bin/roundcubemail-settings-export.php @@ -0,0 +1,92 @@ +#!/usr/bin/php +$vusers) { + if (is_null($vusers)) { + $vusers = 'NULL'; + } + $roundcubemail["$virtualhost"]["users"][$user_id][$kusers] = $vusers; + } + + /* identities */ + $dbQuery_identities = "SELECT * FROM `rc_identities` WHERE `user_id` = '$user_id'"; + $dbResult_identities = mysqli_query($dbLink, $dbQuery_identities); + while ($row_identities = mysqli_fetch_assoc($dbResult_identities)) { + + $identity_id=$row_identities['identity_id']; + unset($row_identities['identity_id']); + foreach($row_identities as $kidentities=>$videntities) { + if (is_null($videntities)) { + $videntities = 'NULL'; + } + $roundcubemail["$virtualhost"]["users"][$user_id]['identities'][$identity_id][$kidentities] = $videntities; + } + + } + + /* contacts */ + $dbQuery_contacts = "SELECT * FROM `rc_contacts` WHERE `user_id` = '$user_id'"; + $dbResult_contacts = mysqli_query($dbLink, $dbQuery_contacts); + while ($row_contacts = mysqli_fetch_assoc($dbResult_contacts)) { + + $contact_id=$row_contacts['contact_id']; + unset($row_contacts['contact_id']); + foreach($row_contacts as $kcontacts=>$vcontacts) { + if (is_null($vcontacts)) { + $vcontacts = 'NULL'; + } + $roundcubemail["$virtualhost"]["users"][$user_id]['contacts'][$contact_id][$kcontacts] = $vcontacts; + } + + } + + /* contactgroups */ + $dbQuery_contactgroups = "SELECT * FROM `rc_contactgroups` WHERE `user_id` = '$user_id'"; + $dbResult_contactgroups = mysqli_query($dbLink, $dbQuery_contactgroups); + while ($row_contactgroups = mysqli_fetch_assoc($dbResult_contactgroups)) { + + $contactgroup_id=$row_contactgroups['contactgroup_id']; + unset($row_contactgroups['contactgroup_id']); + foreach($row_contactgroups as $kcontactgroups=>$vcontactgroups) { + if (is_null($vcontactgroups)) { + $vcontactgroups = 'NULL'; + } + $roundcubemail["$virtualhost"]["users"][$user_id]['contactgroups'][$contactgroup_id][$kcontactgroups] = $vcontactgroups; + } + + /* contactgroupmembers */ + $dbQuery_contactgroupmembers = "SELECT * FROM `rc_contactgroupmembers` WHERE `contactgroup_id` = '$contactgroup_id'"; + $dbResult_contactgroupmembers = mysqli_query($dbLink, $dbQuery_contactgroupmembers); + while ($row_contactgroupmembers = mysqli_fetch_assoc($dbResult_contactgroupmembers)) { + $roundcubemail["$virtualhost"]["users"][$user_id]['contactgroups'][$contactgroup_id]['contactgroupmembers'][] = $row_contactgroupmembers; + } + } + +} + +file_put_contents("/var/www/$virtualhost/roundcubemail", serialize($roundcubemail)); diff --git a/bin/roundcubemail-settings-import.php b/bin/roundcubemail-settings-import.php new file mode 100755 index 0000000..6cf906f --- /dev/null +++ b/bin/roundcubemail-settings-import.php @@ -0,0 +1,160 @@ +#!/usr/bin/php +$users_array) { + foreach ($users_array['users'] as $user_id => $user_array) { + $username = $user_array['username']; + $dbQuery = "SELECT user_id FROM rc_users WHERE username LIKE '$username'"; + $dbResult = mysqli_query($dbLink, $dbQuery); + $dbAffectedRows = mysqli_affected_rows($dbLink); + + if ($dbAffectedRows == 0) { + echo "adding $username\n"; + + $dbQuery = "INSERT INTO rc_users SET"; + foreach ($user_array as $kusers=>$vusers) { + if (!is_array($vusers)) { + if ($vusers == 'NULL') { + $dbQuery .= " `$kusers` = $vusers,"; + } else { + $vusers = mysqli_escape_string($dbLink, $vusers); + $dbQuery .= " `$kusers` = '$vusers',"; + } + } + } + $dbQuery = rtrim($dbQuery, ","); + $dbResult = mysqli_query($dbLink, $dbQuery); + $dbAffectedRows = mysqli_affected_rows($dbLink); + if ($dbAffectedRows != '1') { + echo "ERROR: $dbResult = $dbAffectedRows\n"; + } + $user_id_new = mysqli_insert_id($dbLink); + + /* identities */ + if (!empty($users_array['users'][$user_id]['identities'])) { + foreach ($users_array['users'][$user_id]['identities'] as $identity_id => $identity_array) { + $identity_array['user_id'] = $user_id_new; + $dbQuery = "INSERT INTO rc_identities SET"; + foreach ($identity_array as $kidentities=>$videntities) { + if (!is_array($videntities)) { + if ($videntities == 'NULL') { + $dbQuery .= " `$kidentities` = $videntities,"; + } else { + $videntities = mysqli_escape_string($dbLink, $videntities); + $dbQuery .= " `$kidentities` = '$videntities',"; + } + } + } + $dbQuery = rtrim($dbQuery, ","); + $dbResult = mysqli_query($dbLink, $dbQuery); + $dbAffectedRows = mysqli_affected_rows($dbLink); + if ($dbAffectedRows != '1') { + echo "ERROR: $dbResult = $dbAffectedRows\n"; + } + $identity_id_new = mysqli_insert_id($dbLink); + } + } + + /* contacts */ + if (!empty($users_array['users'][$user_id]['contacts'])) { + foreach ($users_array['users'][$user_id]['contacts'] as $contacts_id => $contacts_array) { + $contacts_array['user_id'] = $user_id_new; + $dbQuery = "INSERT INTO rc_contacts SET"; + foreach ($contacts_array as $kcontacts=>$vcontacts) { + if (!is_array($vcontacts)) { + if ($vcontacts == 'NULL') { + $dbQuery .= " `$kidentities` = $vcontacts,"; + } else { + $vcontacts = mysqli_escape_string($dbLink, $vcontacts); + $dbQuery .= " `$kcontacts` = '$vcontacts',"; + } + } + } + $dbQuery = rtrim($dbQuery, ","); + $dbResult = mysqli_query($dbLink, $dbQuery); + $dbAffectedRows = mysqli_affected_rows($dbLink); + if ($dbAffectedRows != '1') { + echo "ERROR: $dbResult = $dbAffectedRows\n"; + } + $contact_id_new = mysqli_insert_id($dbLink); + $contact_id_array_map[$contacts_id] = $contact_id_new; + } + } + + /* contactgroups */ + if (!empty($users_array['users'][$user_id]['contactgroups'])) { + foreach ($users_array['users'][$user_id]['contactgroups'] as $contactgroups_id => $contactgroups_array) { + $contactgroups_array['user_id'] = $user_id_new; + $dbQuery = "INSERT INTO rc_contactgroups SET"; + foreach ($contactgroups_array as $kcontactgroups=>$vcontactgroups) { + if (!is_array($vcontactgroups)) { + if ($vcontactgroups == 'NULL') { + $dbQuery .= " `$kidentities` = $vcontactgroups,"; + } else { + $vcontactgroups = mysqli_escape_string($dbLink, $vcontactgroups); + $dbQuery .= " `$kcontactgroups` = \"$vcontactgroups\","; + } + } + } + $dbQuery = rtrim($dbQuery, ","); + $dbResult = mysqli_query($dbLink, $dbQuery); + $dbAffectedRows = mysqli_affected_rows($dbLink); + if ($dbAffectedRows != '1') { + echo "ERROR: $dbResult = $dbAffectedRows\n"; + } + $contactgoup_id_new = mysqli_insert_id($dbLink); + + /* contactgroupmembers */ + if (!empty($users_array['users'][$user_id]['contactgroups'][$contactgroups_id]['contactgroupmembers'])) { + foreach ($users_array['users'][$user_id]['contactgroups'][$contactgroups_id]['contactgroupmembers'] as $contactgroupmembers_id => $contactgroupmembers_array) { + $contactgroupmembers_array['contactgroup_id'] = $contactgoup_id_new; + $contactgroupmembers_array['contact_id'] = $contact_id_array_map[$contactgroupmembers_array['contact_id']]; + $dbQuery = "INSERT INTO rc_contactgroupmembers SET"; + foreach ($contactgroupmembers_array as $kcontactgroupmembers=>$vcontactgroupmembers) { + if (!is_array($vcontactgroupmembers)) { + $vcontactgroupmembers = mysqli_escape_string($dbLink, $vcontactgroupmembers); + $dbQuery .= " `$kcontactgroupmembers` = \"$vcontactgroupmembers\","; + } + } + $dbQuery = rtrim($dbQuery, ","); + $dbResult = mysqli_query($dbLink, $dbQuery); + $dbAffectedRows = mysqli_affected_rows($dbLink); + if ($dbAffectedRows != '1') { + echo "ERROR: $dbResult = $dbAffectedRows\n"; + } + } + } + + } + } + + } else { + echo "$username already exists, skipping\n"; + } + + } +} diff --git a/bin/vmail-aliases-add.sh b/bin/vmail-aliases-add.sh new file mode 100755 index 0000000..163dc39 --- /dev/null +++ b/bin/vmail-aliases-add.sh @@ -0,0 +1,106 @@ +#!/bin/bash +# +# vmail-stack +# https://git.stack-source.com/msb/vmail-stack +# MIT License Copyright (c) 2021 Matthew Saunders Brown + +# load config +source /usr/local/etc/vmail.conf + +help() +{ + thisfilename=$(basename -- "$0") + echo "$thisfilename" + echo "Add email alias to vmail system" + echo "" + echo "usage: $thisfilename email alias [OPTIONS]" + echo "" + echo " -h Print this help." + echo "" + echo " 'email' should be the full address 'alias' just the local part (username)." + echo " .e.g to have info@example.com delivered (aliased) to joe@example.com do:" + echo " $thisfilename joe@example.com info" + exit +} + +# set any options that were passed +while getopts "h" opt; do + case "${opt}" in + h ) + help + exit;; + \? ) + echo "Invalid option: $OPTARG" 1>&2 + exit;; + : ) + echo "Invalid option: $OPTARG requires an argument" 1>&2 + exit;; + esac +done + +# check for and set alias & email address & split in to local part & domain +if [ -n "$2" ]; then + if [ $1 == "-h" ] || [ $2 == "-h" ]; then + help + else + email=$1 + shift + alias=$1 + shift + if [[ $email =~ "@" ]] ; then + mbox=${email%@*} + domain=${email##*@} + if [ -z $mbox ] ; then + echo "ERROR: No local part in $email." + exit + elif [ -z $domain ] ; then + echo "ERROR: No domain in $email." + exit + elif [[ ! $domain =~ ^(([a-zA-Z](-?[a-zA-Z0-9])*)\.)+[a-zA-Z]{2,}$ ]] ; then + echo "ERROR: $domain is not a valid domain name." + exit + fi + else + echo "ERROR: $email is not a valid email." + exit + fi + fi +else + help +fi + +# get domain_id (and thus check if domain already exists) +domain_id=`mysql --defaults-extra-file=/usr/local/etc/vmail.conf -s -r -N -e "SELECT id from vm_domains WHERE domain='$domain';"` +if [ -z $domain_id ] ; then + echo "ERROR: Domain $domain does not exist." + exit +fi + +# get mbox id, which also verfies that email address exists +mbox_id=`mysql --defaults-extra-file=/usr/local/etc/vmail.conf -s -r -N -e "SELECT id FROM vm_mboxes WHERE domain_id='$domain_id' AND mbox='$mbox';"` +# rowcount=`mysql --defaults-extra-file=/usr/local/etc/vmail.conf -s -r -N -e "SELECT COUNT(*) FROM vm_mboxes WHERE domain_id='$domain_id' AND mbox='$mbox';"` +if [ -z $mbox_id ] ; then + # mbox does not exist, can't create alias + echo "ERROR: Address to Alias To ($email) does not exist." + exit +elif [ "$mbox_id" -gt '1' ] ; then + # verified mbox, check for existing alias + existing_alias=`mysql --defaults-extra-file=/usr/local/etc/vmail.conf -s -r -N -e "SELECT vm_mboxes.mbox FROM vm_mboxes, vm_aliases WHERE vm_aliases.alias='$alias' AND vm_aliases.mbox_id=vm_mboxes.id AND vm_mboxes.domain_id='$domain_id';"` + if [ -z $existing_alias ]; then + # existing alias does not exist, add new one now + dbcmd="mysql --defaults-extra-file=/usr/local/etc/vmail.conf -e 'INSERT INTO vm_aliases SET vm_aliases.alias=\"$alias\", vm_aliases.mbox_id=\"$mbox_id\";'" + echo $dbcmd + else + if [ "$existing_alias" == "$mbox" ]; then + echo "ERROR: Alias for $alias To $email already exists." + exit + else + echo "ERROR: Alias for $alias already points to another address ($existing_alias@$domain). To update delete that alias first, then add a new one." + exit + fi + fi +else + # db query error + echo "ERROR: System error querying vmail database." + exit 1 +fi diff --git a/bin/vmail-aliases-del.sh b/bin/vmail-aliases-del.sh new file mode 100755 index 0000000..1712881 --- /dev/null +++ b/bin/vmail-aliases-del.sh @@ -0,0 +1,92 @@ +#!/bin/bash +# +# vmail-stack +# https://git.stack-source.com/msb/vmail-stack +# MIT License Copyright (c) 2021 Matthew Saunders Brown + +# load config +source /usr/local/etc/vmail.conf + +help() +{ + thisfilename=$(basename -- "$0") + echo "$thisfilename" + echo "Delete email alias from vmail database." + echo "" + echo "usage: $thisfilename alias" + echo "" + echo " -h Print this help." + echo "" + echo " Enter alias in full email address format." + exit +} + +dbcmd="mysql --defaults-extra-file=$MYSQL_CONNECTION_INFO_FILE" +dbcmdopts="-e" +dbquery="SELECT vm_aliases.alias, vm_mboxes.mbox, vm_domains.domain FROM vm_aliases, vm_mboxes, vm_domains WHERE vm_aliases.mbox_id = vm_mboxes.id AND vm_mboxes.domain_id = vm_domains.id" + +# check for and set alias search term(s) +if [ -n "$1" ]; then + if [ $1 == "-h" ]; then + help + elif [[ ! $1 =~ ^- ]] ; then + searchterm=$1 + shift + if [[ $searchterm =~ "@" ]] ; then + alias=${searchterm%@*} + domain=${searchterm##*@} + if ! vmail::validate_domain $domain; then + echo "ERROR: $searchterm is not a valid email address." + exit + fi + elif vmail::validate_domain $searchterm; then + domain=$searchterm + else + echo "ERROR: $searchterm is not a valid search term." + help + fi + fi +fi + +# set any options that were passed +while getopts "achs" opt; do + case "${opt}" in + a ) + aliassearch=true + ;; + c ) + cvs="| sed 's/\t/,/g'" + ;; + h ) + help + exit;; + s ) + dbcmdopts="-s -N $dbcmdopts" + ;; + \? ) + echo "Invalid option: $OPTARG" 1>&2 + exit;; + esac +done + +# build query +if [ -n "$domain" ]; then + # add specific domain + dbquery="$dbquery AND vm_domains.domain='$domain'" + if [ -n "$localpart" ]; then + # search for specific alias or mbox + if [ -n "$aliassearch" ]; then + # search for specific alias address + dbquery="$dbquery AND vm_aliases.alias='$localpart'" + else + # search for all aliases for specific email address + dbquery="$dbquery AND vm_mboxes.mbox='$localpart'" + fi + fi +fi + +# set order by +dbquery="$dbquery ORDER BY vm_domains.domain, vm_mboxes.mbox, vm_aliases.alias;"; + +# execute mysql query +eval $dbcmd $dbcmdopts "\"$dbquery\"" $cvs diff --git a/bin/vmail-aliases-get.sh b/bin/vmail-aliases-get.sh new file mode 100755 index 0000000..7753028 --- /dev/null +++ b/bin/vmail-aliases-get.sh @@ -0,0 +1,98 @@ +#!/bin/bash +# +# vmail-stack +# https://git.stack-source.com/msb/vmail-stack +# MIT License Copyright (c) 2021 Matthew Saunders Brown + +# load config +source /usr/local/etc/vmail.conf + +help() +{ + thisfilename=$(basename -- "$0") + echo "$thisfilename" + echo "Get email alias data from vmail database." + echo "" + echo "usage: $thisfilename [email|alias|domain] [OPTIONS]" + echo "" + echo " -a Return info for specific alias." + echo " -c Output in cvs format." + echo " -h Print this help." + echo " -s Be more silent - use tabs instead of tables for output, do not display column headers." + echo "" + echo " Search term is optional. If nothing specified all aliases for all email acccounts for all domains will be returned." + echo " Enter email address to get all aliases that route to that email address." + echo " Enter alias (in full email address format) with the -a option to get address that alias delivers to." + echo " Enter domain name to get all aliases for all email addresses under that domain." + exit +} + +dbcmd="mysql --defaults-extra-file=$MYSQL_CONNECTION_INFO_FILE" +dbcmdopts="-e" +dbquery="SELECT vm_aliases.alias, vm_mboxes.mbox, vm_domains.domain FROM vm_aliases, vm_mboxes, vm_domains WHERE vm_aliases.mbox_id = vm_mboxes.id AND vm_mboxes.domain_id = vm_domains.id" + +# check for and set alias search term(s) +if [ -n "$1" ]; then + if [ $1 == "-h" ]; then + help + elif [[ ! $1 =~ ^- ]] ; then + searchterm=$1 + shift + if [[ $searchterm =~ "@" ]] ; then + localpart=${searchterm%@*} + domain=${searchterm##*@} + if ! vmail::validate_domain $domain; then + echo "ERROR: $searchterm is not a valid email address." + exit + fi + elif vmail::validate_domain $searchterm; then + domain=$searchterm + else + echo "ERROR: $searchterm is not a valid search term." + help + fi + fi +fi + +# set any options that were passed +while getopts "achs" opt; do + case "${opt}" in + a ) + aliassearch=true + ;; + c ) + cvs="| sed 's/\t/,/g'" + ;; + h ) + help + exit;; + s ) + dbcmdopts="-s -N $dbcmdopts" + ;; + \? ) + echo "Invalid option: $OPTARG" 1>&2 + exit;; + esac +done + +# build query +if [ -n "$domain" ]; then + # add specific domain + dbquery="$dbquery AND vm_domains.domain='$domain'" + if [ -n "$localpart" ]; then + # search for specific alias or mbox + if [ -n "$aliassearch" ]; then + # search for specific alias address + dbquery="$dbquery AND vm_aliases.alias='$localpart'" + else + # search for all aliases for specific email address + dbquery="$dbquery AND vm_mboxes.mbox='$localpart'" + fi + fi +fi + +# set order by +dbquery="$dbquery ORDER BY vm_domains.domain, vm_mboxes.mbox, vm_aliases.alias;"; + +# execute mysql query +eval $dbcmd $dbcmdopts "\"$dbquery\"" $cvs diff --git a/bin/vmail-deploy.sh b/bin/vmail-deploy.sh new file mode 100755 index 0000000..dc22a00 --- /dev/null +++ b/bin/vmail-deploy.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# +# vmail-stack +# https://git.stack-source.com/msb/vmail-stack +# MIT License Copyright (c) 2021 Matthew Saunders Brown + +# load config +source /usr/local/etc/vmail.conf + +# check for and set virtualhost +if [ -n "$1" ]; then + virtualhost=$1 +else + echo "virtualhost not set" + exit 1 +fi + +vmail.sh create domain +dkim create + check if stack-dns nameservers + add dkim record + add dmarc record + vmail-secure.sh + esle + notify dkim & dmar + + diff --git a/bin/vmail-dkim-add.sh b/bin/vmail-dkim-add.sh new file mode 100755 index 0000000..347d2e3 --- /dev/null +++ b/bin/vmail-dkim-add.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# +# vmail-stack +# https://git.stack-source.com/msb/vmail-stack +# MIT License Copyright (c) 2021 Matthew Saunders Brown + +# load config +source /usr/local/etc/vmail.conf + +# check for and set virtualhost +if [ -n "$1" ]; then + virtualhost=$1 +else + echo "virtualhost not set" + exit 1 +fi + +# check for existing dkim +if [ -f /etc/ssl/dkim/$virtualhost.dkim ]; then + echo "dkim for $virtualhost already exists" + exit 1 +fi + +cd /etc/ssl/dkim +date +%Y%m%d > $virtualhost.selector +openssl genrsa -out $virtualhost.pem 2048 +openssl rsa -in $virtualhost.pem -out $virtualhost.pub -pubout +tail -n +2 $virtualhost.pub |head -n -1|tr -d '\n' > $virtualhost.dkim +echo `cat $virtualhost.selector`._domainkey.$virtualhost. 3600 IN TXT \""k=rsa; p=`cat $virtualhost.dkim`"\" > $virtualhost.dns +chown Debian-exim:ssl-cert $virtualhost.* + +echo +echo create this dns record: +echo +cat $virtualhost.dns +echo diff --git a/bin/vmail-dkim-del.sh b/bin/vmail-dkim-del.sh new file mode 100755 index 0000000..ae69798 --- /dev/null +++ b/bin/vmail-dkim-del.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# +# vmail-stack +# https://git.stack-source.com/msb/vmail-stack +# MIT License Copyright (c) 2021 Matthew Saunders Brown + +# load config +source /usr/local/etc/vmail.conf + +# check for and set virtualhost +if [ -n "$1" ]; then + virtualhost=$1 +else + echo "virtualhost not set" + exit 1 +fi + +# check for existing dkim +if [ ! -f /etc/ssl/dkim/$virtualhost.dkim ]; then + echo "dkim for $virtualhost does not exist" + exit 1 +fi + +echo delete this dkim dns record +echo +cat /etc/ssl/dkim/$virtualhost.dns +echo + +rm /etc/ssl/dkim/$virtualhost.* diff --git a/bin/vmail-domains-add.sh b/bin/vmail-domains-add.sh new file mode 100755 index 0000000..aa30f5c --- /dev/null +++ b/bin/vmail-domains-add.sh @@ -0,0 +1,122 @@ +#!/bin/bash +# +# vmail-stack +# https://git.stack-source.com/msb/vmail-stack +# MIT License Copyright (c) 2021 Matthew Saunders Brown + +# load config +source /usr/local/etc/vmail.conf + +help() +{ + thisfilename=$(basename -- "$0") + echo "$thisfilename" + echo "Add domain to vmail system" + echo "" + echo "usage: $thisfilename domain [OPTIONS]" + echo "" + echo " -h Print this help." + echo " -l LIMIT Maximum number of mailboxes for this domain." + echo " -q QUOTA Default mailbox quota in GB." + echo " -s STATUS 1 for enabled, 0 for disabled." + echo "" + echo " Defaults for are all OPTIONS are configured in database." + echo " NULL for LIMIT or QUOTA means no limit." + exit +} + +# check for and set domain +if [ -n "$1" ]; then + if [ $1 == "-h" ]; then + help + elif vmail::validate_domain $1; then + domain=$1 + shift + else + echo "ERROR: Invalid domain name: $1" + exit 1 + fi +else + help +fi + +# set any options that were passed +while getopts "hl:q:s:" opt; do + case "${opt}" in + h ) + help + exit;; + l ) + limit=${OPTARG} + ;; + q ) + quota=${OPTARG} + ;; + s ) + status=${OPTARG} + ;; + \? ) + echo "Invalid option: $OPTARG" 1>&2 + exit;; + : ) + echo "Invalid option: $OPTARG requires an argument" 1>&2 + exit;; + esac +done + +# check if vmail domain dir exits +if [ -d $VMAIL_DIR/$domain ]; then + echo "ERROR: Directory $VMAIL_DIR/$domain already exists." + exit 1 +fi + +# check if domain exists in vmail database +rowcount=`mysql --defaults-extra-file=$MYSQL_CONNECTION_INFO_FILE -s -r -N -e "SELECT COUNT(*) from vm_domains WHERE domain='$domain';"` +if [ "$rowcount" -eq '0' ] ; then + # looks good, build SQL + cmd="mysql --defaults-extra-file=$MYSQL_CONNECTION_INFO_FILE -e \"INSERT INTO vm_domains SET domain='$domain'\"" + if [ ! -z "$status" ] ; then + if [ "$status" == 0 ] || [ "$status" == 1 ]; then + cmd="$cmd, status='$status'" + else + echo "ERROR: status (-s) must be 1 or 0" + exit 1 + fi + fi + if [ ! -z "$limit" ] ; then + if [[ "$limit" == "NULL" ]]; then + cmd="$cmd, mbox_limit=NULL" + elif [[ "$limit" =~ ^[0-9]+$ ]]; then + cmd="$cmd, mbox_limit='$limit'" + else + echo "ERROR: limit (-l) must numeric or NULL" + exit 1 + fi + fi + if [ ! -z "$quota" ] ; then + if [[ "$quota" == "NULL" ]]; then + cmd="$cmd, mbox_quota_default=NULL" + elif [[ "$quota" =~ ^[0-9]+$ ]]; then + cmd="$cmd, mbox_quota_default='$quota'" + else + echo "ERROR: quota (-q) must numeric or NULL" + exit 1 + fi + fi + cmd="$cmd;" + # add domain to vmail database + echo $cmd + # create vmail directory for domain + if [ ! -d "$VMAIL_DIR" ] ; then + echo "install -o vmail -g vmail -m 750 -d $VMAIL_DIR" + fi + if [ ! -d "$VMAIL_DIR/$domain" ] ; then + echo "install -o vmail -g vmail -m 750 -d $VMAIL_DIR/$domain" + fi +elif [ "$rowcount" -eq '1' ] ; then + echo "ERROR: $domain already exists in vmail database." + exit 1 +else + echo "ERROR: System error querying vmail database" + exit 1 +fi diff --git a/bin/vmail-domains-del.sh b/bin/vmail-domains-del.sh new file mode 100755 index 0000000..28aafff --- /dev/null +++ b/bin/vmail-domains-del.sh @@ -0,0 +1,115 @@ +#!/bin/bash +# +# vmail-stack +# https://git.stack-source.com/msb/vmail-stack +# MIT License Copyright (c) 2021 Matthew Saunders Brown + +# load config +source /usr/local/etc/vmail.conf + +help() +{ + thisfilename=$(basename -- "$0") + echo "$thisfilename" + echo "Delete domain and all associated email accounts from the vmail system." + echo "" + echo "usage: $thisfilename domain [OPTIONS]" + echo "" + echo " -h Print this help." + exit +} + +# check for and set domain +if [ -n "$1" ]; then + if vmail::validate_domain $1; then + domain=$1 + shift + else + echo "ERROR: Invalid domain name: $1" + exit 1 + fi +else + help +fi + +# set any options that were passed +while getopts "h" opt; do + case "${opt}" in + h ) + help + exit;; + \? ) + echo "Invalid option: $OPTARG" 1>&2 + ;; + : ) + echo "Invalid option: $OPTARG requires an argument" 1>&2 + ;; + esac +done + + + +# check if domain exists in vmail database +rowcount=`mysql --defaults-extra-file=$MYSQL_CONNECTION_INFO_FILE -s -r -N -e "SELECT COUNT(*) from vm_domains WHERE domain='$domain';"` +if [ "$rowcount" -eq '0' ] ; then + # looks good, build SQL + cmd="mysql --defaults-extra-file=$MYSQL_CONNECTION_INFO_FILE -e \"INSERT INTO vm_domains SET domain='$domain'\"" + if [ ! -z "$status" ] ; then + if [ "$status" == 0 ] || [ "$status" == 1 ]; then + cmd="$cmd, status='$status'" + else + echo "ERROR: status (-s) must be 1 or 0" + exit 1 + fi + fi + if [ ! -z "$limit" ] ; then + if [[ "$limit" == "NULL" ]]; then + cmd="$cmd, mbox_limit=NULL" + elif [[ "$limit" =~ ^[0-9]+$ ]]; then + cmd="$cmd, mbox_limit='$limit'" + else + echo "ERROR: limit (-l) must numeric or NULL" + exit 1 + fi + fi + if [ ! -z "$quota" ] ; then + if [[ "$quota" == "NULL" ]]; then + cmd="$cmd, mbox_quota_default=NULL" + elif [[ "$quota" =~ ^[0-9]+$ ]]; then + cmd="$cmd, mbox_quota_default='$quota'" + else + echo "ERROR: quota (-q) must numeric or NULL" + exit 1 + fi + fi + cmd="$cmd;" + # add domain to vmail database + echo $cmd +elif [ "$rowcount" -eq '1' ] ; then + echo "ERROR: $domain already exists in vmail database." + exit 1 +else + echo "ERROR: System error querying vmail database" + exit 1 +fi + +# delete confirmed +echo "mysql --defaults-extra-file=$MYSQL_CONNECTION_INFO_FILE -e \"DELETE FROM vm_aliases WHERE mbox_id='$mboxes_id';\"" +echo "mysql --defaults-extra-file=$MYSQL_CONNECTION_INFO_FILE -e \"DELETE FROM vm_autoresponders WHERE mbox_id='$mboxes_id';\"" +echo "mysql --defaults-extra-file=$MYSQL_CONNECTION_INFO_FILE -e \"DELETE FROM vm_filters WHERE mbox_id='$mboxes_id';\"" +echo "mysql --defaults-extra-file=$MYSQL_CONNECTION_INFO_FILE -e \"DELETE FROM vm_forwards WHERE domain_id='$domain_id' AND local_part='$mbox';\"" +echo "mysql --defaults-extra-file=$MYSQL_CONNECTION_INFO_FILE -e \"DELETE FROM vm_greylisting WHERE recipient='$mbox@$domain';\"" +echo "mysql --defaults-extra-file=$MYSQL_CONNECTION_INFO_FILE -e \"DELETE FROM vmail.sa_userpref WHERE username='$mbox@$domain';\"" +# delete from rc_* tables +echo "mysql --defaults-extra-file=$MYSQL_CONNECTION_INFO_FILE -e \"DELETE FROM vm_mboxes WHERE id='$mboxes_id';\"" +if [ -d "$VMAIL_DIR/$domain/$mbox" ] ; then + echo "rm -r $VMAIL_DIR/$domain/$mbox" +fi + +# delete from roundcube too + +# check if vmail domain dir exits +if [ -d $VMAIL_DIR/$domain ]; then + echo "ERROR: Directory $VMAIL_DIR/$domain already exists." + exit 1 +fi diff --git a/bin/vmail-domains-get.sh b/bin/vmail-domains-get.sh new file mode 100755 index 0000000..0519cf3 --- /dev/null +++ b/bin/vmail-domains-get.sh @@ -0,0 +1,81 @@ +#!/bin/bash +# +# vmail-stack +# https://git.stack-source.com/msb/vmail-stack +# MIT License Copyright (c) 2021 Matthew Saunders Brown + +# load config +source /usr/local/etc/vmail.conf + +help() +{ + thisfilename=$(basename -- "$0") + echo "$thisfilename" + echo "Get domain data from vmail database." + echo "" + echo "usage: $thisfilename [domain] [OPTIONS]" + echo "" + echo " -c Output in cvs format." + echo " -h Print this help." + echo " -s Be more silent - use tabs instead of tables for output, do not display column headers." + echo " -w Wildcard search when searching for specific domain." + echo "" + echo " Domain is optional. If not specified all domains will be queried." + echo " By default domain search is for an exact matchs." + echo " Specify -w to turn them in to wildcard search. e.g:" + echo " $thisfilename stack -w # search for all domains that contain 'stack'." + exit +} + +dbcmd="mysql --defaults-extra-file=$MYSQL_CONNECTION_INFO_FILE" +dbcmdopts="-e" +dbquery="SELECT * from vm_domains" + +# check for and set domain +if [ -n "$1" ]; then + if [ $1 == "-h" ]; then + help + elif [[ ! $1 =~ ^- ]] ; then + domain=$1 + shift +# query="SELECT * from vm_domains WHERE domain LIKE '%$domain%';" + fi +fi + +# set any options that were passed +while getopts "chsw" opt; do + case "${opt}" in + c ) + cvs="| sed 's/\t/,/g'" + ;; + h ) + help + exit;; + s ) + dbcmdopts="-s -N $dbcmdopts" + ;; + w ) + wildcardsearch=true + ;; + \? ) + echo "Invalid option: $OPTARG" 1>&2 + exit;; + esac +done + +# build query +if [ -n "$domain" ]; then + if [ -n "$wildcardsearch" ]; then + dbquery="$dbquery WHERE domain LIKE '%$domain%'" + else + if vmail::validate_domain $domain; then + dbquery="$dbquery WHERE domain='$domain'" + else + echo "ERROR: Invalid domain name: $domain" + exit 1 + fi + fi +fi + +# execute mysql query +eval $dbcmd $dbcmdopts "\"$dbquery;\"" $cvs diff --git a/bin/vmail-domains-mod.sh b/bin/vmail-domains-mod.sh new file mode 100755 index 0000000..401006c --- /dev/null +++ b/bin/vmail-domains-mod.sh @@ -0,0 +1,98 @@ +#!/bin/bash +# +# vmail-stack +# https://git.stack-source.com/msb/vmail-stack +# MIT License Copyright (c) 2021 Matthew Saunders Brown + +# load config +source /usr/local/etc/vmail.conf + +help() +{ + thisfilename=$(basename -- "$0") + echo "$thisfilename" + echo "Get domain data from vmail database." + echo "" + echo "usage: $thisfilename [domain] [OPTIONS]" + echo "" + echo " -e Exact match instead of wildcard search." + echo " -c Output in cvs format." + echo " -h Print this help." + echo " -s Be more silent - use tabs instead of tables for output, do not display column headers." + echo "" + echo " Domain can either be a FQDN or a search term." + echo " e.g. to search for all .org domains enter .org as the domain." + echo " Use the -e option to disable wildcard search and require exact match of FQDN." + exit +} + +# set any options that were passed +while getopts ":s:l:q:" opt; do + case "${opt}" in + s ) + status=${OPTARG} + ;; + l ) + limit=${OPTARG} + ;; + q ) + quota=${OPTARG} + ;; + \? ) + echo "Invalid option: $OPTARG" 1>&2 + ;; + : ) + echo "Invalid option: $OPTARG requires an argument" 1>&2 + ;; + esac +done + +# check if vmail domain dir exits +if [ -d /var/vmail/$domain ]; then + echo "ERROR: Directory /var/vmail/$domain already exists." + exit 1 +fi + +# check if domain exists in vmail database +rowcount=`mysql --defaults-extra-file=$MYSQL_CONNECTION_INFO_FILE -s -r -N -e "SELECT COUNT(*) from vm_domains WHERE domain='$domain';"` +if [ "$rowcount" -eq '0' ] ; then + # looks good, build SQL + cmd="mysql --defaults-extra-file=$MYSQL_CONNECTION_INFO_FILE -e \"INSERT INTO vm_domains SET domain='$domain'\"" + if [ ! -z "$status" ] ; then + if [ "$status" == 0 ] || [ "$status" == 1 ]; then + cmd="$cmd, status='$status'" + else + echo "ERROR: status (-s) must be 1 or 0" + exit 1 + fi + fi + if [ ! -z "$limit" ] ; then + if [[ "$limit" == "NULL" ]]; then + cmd="$cmd, mbox_limit=NULL" + elif [[ "$limit" =~ ^[0-9]+$ ]]; then + cmd="$cmd, mbox_limit='$limit'" + else + echo "ERROR: limit (-l) must numeric or NULL" + exit 1 + fi + fi + if [ ! -z "$quota" ] ; then + if [[ "$quota" == "NULL" ]]; then + cmd="$cmd, mbox_quota_default=NULL" + elif [[ "$quota" =~ ^[0-9]+$ ]]; then + cmd="$cmd, mbox_quota_default='$quota'" + else + echo "ERROR: quota (-q) must numeric or NULL" + exit 1 + fi + fi + cmd="$cmd;" + # add domain to vmail database + echo $cmd +elif [ "$rowcount" -eq '1' ] ; then + echo "ERROR: $domain already exists in vmail database." + exit 1 +else + echo "ERROR: System error querying vmail database" + exit 1 +fi diff --git a/bin/vmail-installer.sh b/bin/vmail-installer.sh new file mode 100755 index 0000000..e0d6b81 --- /dev/null +++ b/bin/vmail-installer.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +echo 'installing vmail-stack now!' diff --git a/bin/vmail-mboxes-add.sh b/bin/vmail-mboxes-add.sh new file mode 100755 index 0000000..6425b88 --- /dev/null +++ b/bin/vmail-mboxes-add.sh @@ -0,0 +1,135 @@ +#!/bin/bash +# +# vmail-stack +# https://git.stack-source.com/msb/vmail-stack +# MIT License Copyright (c) 2021 Matthew Saunders Brown + +# load config +source /usr/local/etc/vmail.conf + +help() +{ + thisfilename=$(basename -- "$0") + echo "$thisfilename" + echo "Add email account to vmail system" + echo "" + echo "usage: $thisfilename email password [OPTIONS]" + echo "" + echo " -h Print this help." + echo " -q QUOTA Set mailbox quota in GB, otherwise default for this domain is used. NULL means no limit." + echo " -s STATUS 1 for enabled, 0 for disabled." + exit +} + +# check for and set email address, local part & domain, password +if [ -n "$2" ]; then + if [ $1 == "-h" ] || [ $2 == "-h" ]; then + help + else + email=$1 + shift + passwd=$1 + shift + if [[ $email =~ "@" ]] ; then + mbox=${email%@*} + domain=${email##*@} + if [ -z $mbox ] ; then + echo "ERROR: No local part in $email." + exit + elif [ -z $domain ] ; then + echo "ERROR: No domain in $email." + exit + elif ! vmail::validate_domain $domain; then + echo "ERROR: $domain is not a valid domain name." + exit + fi + else + echo "ERROR: $email is not a valid email." + exit + fi + fi +else + help +fi + +# set any options that were passed +while getopts "hq:s:" opt; do + case "${opt}" in + h ) + help + exit;; + q ) + quota=${OPTARG} + ;; + s ) + status=${OPTARG} + ;; + \? ) + echo "Invalid option: $OPTARG" 1>&2 + exit;; + : ) + echo "Invalid option: $OPTARG requires an argument" 1>&2 + exit;; + esac +done + +# get domain_id (and thus check if domain already exists) +domain_id=`mysql --defaults-extra-file=$MYSQL_CONNECTION_INFO_FILE -s -r -N -e "SELECT id from vm_domains WHERE domain='$domain';"` +if [ -z $domain_id ] ; then + echo "ERROR: Domain $domain does not exist." + exit +fi + +# make sure mbox doesn't already exist +rowcount=`mysql --defaults-extra-file=$MYSQL_CONNECTION_INFO_FILE -s -r -N -e "SELECT COUNT(*) FROM vm_mboxes WHERE domain_id='$domain_id' AND mbox='$mbox';"` +if [ "$rowcount" -eq '0' ] ; then + # mbox does not exist, build SQL + # first encrypt password + passwd=`doveadm pw -s sha512-crypt -p "$passwd"|sed 's|^{SHA512-CRYPT}||'` + dbcmd="mysql --defaults-extra-file=$MYSQL_CONNECTION_INFO_FILE -e 'INSERT INTO vm_mboxes SET domain_id=\"$domain_id\", mbox=\"$mbox\", passwd=\"$passwd\"" + if [ -n "$status" ] ; then + if [ "$status" == 0 ] || [ "$status" == 1 ]; then + dbcmd="$dbcmd, status=\"$status\"" + else + echo "ERROR: status (-s) must be 1 or 0" + exit + fi + fi + if [ -z "$quota" ] ; then + # get mbox_quota_default from domains table + quota=`mysql --defaults-extra-file=$MYSQL_CONNECTION_INFO_FILE -s -r -N -e "SELECT mbox_quota_default from vm_domains WHERE domain='$domain';"` + fi + if [[ "$quota" == "NULL" ]]; then + dbcmd="$dbcmd, quota=NULL" + elif [[ "$quota" =~ ^[0-9]+$ ]]; then + dbcmd="$dbcmd, quota=\"$quota\"" + else + echo "ERROR: quota (-q) must numeric or NULL" + exit 1 + fi + dbcmd="$dbcmd;'" +elif [ "$rowcount" -eq '1' ] ; then + echo "ERROR: $email already exists in vmail database." + exit +else + echo "ERROR: System error querying vmail database." + exit 1 +fi + +# add mbox +# evail $dbcmd +echo $dbcmd + +# create all required vmail dirs +if [ ! -d "/var/vmail/$domain" ] ; then + echo "install -o vmail -g vmail -m 750 -d /var/vmail/$domain" +fi +if [ ! -d "/var/vmail/$domain/$mbox" ] ; then + echo "install -o vmail -g vmail -m 750 -d /var/vmail/$domain/$mbox" +fi +if [ ! -d "/var/vmail/$domain/$mbox/Maildir" ] ; then + echo "install -o vmail -g vmail -m 750 -d /var/vmail/$domain/$mbox/Maildir" +fi +if [ ! -d "/var/vmail/$domain/$mbox/Maildir/cur" ] ; then + echo "install -o vmail -g vmail -m 750 -d /var/vmail/$domain/$mbox/Maildir/cur" +fi diff --git a/bin/vmail-mboxes-get.sh b/bin/vmail-mboxes-get.sh new file mode 100755 index 0000000..1f3b533 --- /dev/null +++ b/bin/vmail-mboxes-get.sh @@ -0,0 +1,102 @@ +#!/bin/bash +# +# vmail-stack +# https://git.stack-source.com/msb/vmail-stack +# MIT License Copyright (c) 2021 Matthew Saunders Brown + +# load config +source /usr/local/etc/vmail.conf + +help() +{ + thisfilename=$(basename -- "$0") + echo "$thisfilename" + echo "Get email account data from vmail database." + echo "" + echo "usage: $thisfilename [username|domain|fullemail] [OPTIONS]" + echo "" + echo " -c Output in cvs format." + echo " -h Print this help." + echo " -s Be more silent - use tabs instead of tables for output, do not display column headers." + echo " -w Wildcard search when searching for username." + echo "" + echo " Search term is optional. If nothing specified all email acccounts for all domains will be returned." + echo " By default username searches are for exact matchs." + echo " Specify -w to turn them in to a wildcard search. Examples:" + echo " $thisfilename joe@example.com # search for specific email address 'joe@example.com'." + echo " $thisfilename joe # search for username 'joe' in all domains." + echo " $thisfilename joe -w # search for usernames containing 'joe' in all domains." + echo " $thisfilename example.com # search for all usernames in the 'example.com' domain." + exit +} + +dbcmd="mysql --defaults-extra-file=$MYSQL_CONNECTION_INFO_FILE" +dbcmdopts="-e" +dbquery="SELECT vm_mboxes.mbox, vm_domains.domain, vm_mboxes.status, vm_mboxes.quota FROM vm_domains, vm_mboxes WHERE vm_domains.id=vm_mboxes.domain_id" + +# check for and set email search term(s) +if [ -n "$1" ]; then + if [ $1 == "-h" ]; then + help + elif [[ ! $1 =~ ^- ]] ; then + searchterm=$1 + shift + if [[ $searchterm =~ "@" ]] ; then + mbox=${searchterm%@*} + domain=${searchterm##*@} + elif vmail::validate_domain $searchterm; then + domain=$searchterm + else + mbox=$searchterm + fi + fi +fi + +# set any options that were passed +while getopts "chsw" opt; do + case "${opt}" in + c ) + cvs="| sed 's/\t/,/g'" + ;; + h ) + help + exit;; + s ) + dbcmdopts="-s -N $dbcmdopts" + ;; + w ) + wildcardsearch=true + ;; + \? ) + echo "Invalid option: $OPTARG" 1>&2 + exit;; + esac +done + +# build query +if [ -n "$mbox" ] && [ -n "$domain" ]; then + # search for specific email address + dbquery="$dbquery AND vm_domains.domain='$domain' AND vm_mboxes.mbox='$mbox'" +elif [ -n "$mbox" ] && [ -z "$domain" ]; then + # search all domains for username + if [ -n "$wildcardsearch" ]; then + # wildcard search + dbquery="$dbquery AND vm_mboxes.mbox LIKE '%$mbox%'" + else + # exact match + dbquery="$dbquery AND vm_mboxes.mbox='$mbox'" + fi +elif [ -z "$mbox" ] && [ -n "$domain" ]; then + # get all usernames for domain + dbquery="$dbquery AND vm_domains.domain='$domain'" +# elif [ -z "$mbox" ] && [ -z "$domain" ]; then +# echo "ERROR: No username or domain specified." +# help +# uncomment above 3 lines to force search term, otherwise all email addresses for all domains will be returned +fi + +# set order by +dbquery="$dbquery ORDER BY vm_domains.domain, vm_mboxes.mbox;"; + +# execute mysql query +eval $dbcmd $dbcmdopts "\"$dbquery\"" $cvs diff --git a/bin/vmail-purge.sh b/bin/vmail-purge.sh new file mode 100755 index 0000000..4524bc0 --- /dev/null +++ b/bin/vmail-purge.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# +# vmail-stack +# https://git.stack-source.com/msb/vmail-stack +# MIT License Copyright (c) 2021 Matthew Saunders Brown + +# load config +source /usr/local/etc/vmail.conf + +accounts=(`find $VMAIL_DIR/*/ -mindepth 1 -maxdepth 1 -type d`); +dirs=('.Junk' '.Trash'); +subdirs=('new' 'cur'); + +for account in "${accounts[@]}"; do + + for dir in "${dirs[@]}"; do + + for subdir in "${subdirs[@]}"; do + + if [[ -d "$account/Maildir/$dir/$subdir" ]]; then + + /usr/bin/find $account/Maildir/$dir/$subdir -type f -mtime +30 -exec rm -f {} + + + fi + + done + + done + +done + diff --git a/bin/vmail-secure.sh b/bin/vmail-secure.sh new file mode 100755 index 0000000..655a6b1 --- /dev/null +++ b/bin/vmail-secure.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# +# vmail-stack +# https://git.stack-source.com/msb/vmail-stack +# MIT License Copyright (c) 2021 Matthew Saunders Brown + +# load config +source /opt/stack/include/config.inc + +# check for and set virtualhost +if [ -n "$1" ]; then + virtualhost=$1 +else + echo "virtualhost not set" + exit 1 +fi + +check that IP points here + install le cert + create dovecot conf + vhost-enable + + +dkim +_dmarc.example.com 3600 TXT "v=DMARC1; p=reject;" +letsencrypt-certonly.sh +vmail.sh create domain +vhost VHostMAIL +dovecot/sites.d/ + + +# enable webmail vhost & restart apache +webmail-enable.sh $virtualhost + diff --git a/bin/webmail-disable.sh b/bin/webmail-disable.sh new file mode 100755 index 0000000..6cd6337 --- /dev/null +++ b/bin/webmail-disable.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# +# vmail-stack +# https://git.stack-source.com/msb/vmail-stack +# MIT License Copyright (c) 2021 Matthew Saunders Brown + +# load config +source /opt/stack/include/config.inc + +# check for and set virtualhost +if [ -n "$1" ]; then + virtualhost=$1 +else + echo "virtualhost not set" + exit 1 +fi + +if [ -h "/etc/apache2/sites-enabled/mail.$virtualhost.conf" ]; then + /usr/sbin/a2dissite --quiet mail.$virtualhost + /usr/bin/systemctl --quiet reload apache2 +fi +if [ -f "/etc/apache2/sites-available/mail.$virtualhost.conf" ]; then + rm /etc/apache2/sites-available/mail.$virtualhost.conf +fi diff --git a/bin/webmail-enable.sh b/bin/webmail-enable.sh new file mode 100755 index 0000000..4497f48 --- /dev/null +++ b/bin/webmail-enable.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# +# vmail-stack +# https://git.stack-source.com/msb/vmail-stack +# MIT License Copyright (c) 2021 Matthew Saunders Brown + +# load config +source /opt/stack/include/config.inc + +# check for and set virtualhost +if [ -n "$1" ]; then + virtualhost=$1 +else + echo "virtualhost not set" + exit 1 +fi + +if [ ! -f /etc/ssl/letsencrypt/mail.$virtualhost.pem ]; then + echo "Let's Encrypt cert for mail.$virtualhost does not exist, create that first:" + exit 1 +fi + +# enable webmail vhost & restart apache +if [ ! -f "/etc/apache2/sites-available/mail.$virtualhost.conf" ]; then + echo "Use VHostMAIL $virtualhost" > /etc/apache2/sites-available/mail.$virtualhost.conf +fi +if [ ! -h "/etc/apache2/sites-enabled/mail.$virtualhost.conf" ]; then + /usr/sbin/a2ensite --quiet mail.$virtualhost + /usr/bin/systemctl --quiet is-active apache2 && systemctl --quiet reload apache2 +fi diff --git a/etc/vmail-db-info.conf b/etc/vmail-db-info.conf new file mode 100644 index 0000000..b6eff35 --- /dev/null +++ b/etc/vmail-db-info.conf @@ -0,0 +1,6 @@ +[client] +host = localhost +database = vmail +user = vmail +password = passwd +socket = /var/run/mysqld/mysqld.sock diff --git a/etc/vmail.conf b/etc/vmail.conf new file mode 100644 index 0000000..14abfaa --- /dev/null +++ b/etc/vmail.conf @@ -0,0 +1,20 @@ +# vmail configs + +# constants + +readonly MYSQL_CONNECTION_INFO_FILE=/usr/local/etc/vmail-db-info.conf +readonly VMAIL_DIR=/var/vmail +readonly VMAIL_DB=vmail + +# functions + +# crude but good enough domain name format validation +function vmail::validate_domain () { + local my_domain=$1 + if [[ $my_domain =~ ^(([a-zA-Z](-?[a-zA-Z0-9])*)\.)+[a-zA-Z]{2,}$ ]] ; then + return 0 + else + return 1 + fi +} + diff --git a/libexec/vmail-quota-warning.sh b/libexec/vmail-quota-warning.sh new file mode 100644 index 0000000..f630aa1 --- /dev/null +++ b/libexec/vmail-quota-warning.sh @@ -0,0 +1,12 @@ +#!/bin/bash +PERCENT=$1 +USER=$2 +DOMAIN=${USER##*@} + +if [ "$PERCENT" -eq '95' ] ; then + MSG="Your mailbox is now $PERCENT% full. Please delete some messages immediately to avoid email service interruptions." +else + MSG="Your mailbox is now $PERCENT% full. Please delete some messages to avoid exceeding your quota." +fi + +echo "$MSG" | mail -s "Email quota warning" $USER -aFrom:postmaster@$DOMAIN