summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rw-r--r--scripts/Makefile64
-rw-r--r--scripts/TARGETS5
-rw-r--r--scripts/it-pam=d1
-rw-r--r--scripts/it-recipients=d1
-rw-r--r--scripts/it-scan=d1
-rw-r--r--scripts/it-x509=d2
-rw-r--r--scripts/it=d4
-rw-r--r--scripts/ksh-auto.sh2
-rw-r--r--scripts/ldap-pam.pl149
-rw-r--r--scripts/mkdkimkey.sh213
-rw-r--r--scripts/multiple-queues.sh112
-rw-r--r--scripts/perl-auto.sh2
-rw-r--r--scripts/qmail-alias2recipients.sh4
-rw-r--r--scripts/qmail-queue-scan.sh144
-rw-r--r--scripts/warn-auto.sh2
-rw-r--r--scripts/x509fingerprint.sh10
16 files changed, 716 insertions, 0 deletions
diff --git a/scripts/Makefile b/scripts/Makefile
new file mode 100644
index 0000000..26ed772
--- /dev/null
+++ b/scripts/Makefile
@@ -0,0 +1,64 @@
+# Don't edit Makefile! Use conf-* for configuration.
+
+SHELL=/bin/sh
+
+default: it-scan it-recipients \
+it-x509 it-pam
+
+clean: \
+TARGETS
+ rm -f `cat TARGETS`
+
+it-pam: \
+ldap-pam
+
+it-recipients: \
+qmail-alias2recipients
+
+it-scan: \
+qmail-queue-scan
+
+it-x509: \
+x509fingerprint mkdkimkey
+
+ldap-pam: \
+perl-auto.sh ldap-pam.pl ../conf-home
+ cat perl-auto.sh ldap-pam.pl \
+ | sed s}PERL}"`which perl`"}g \
+ | sed s}HOME}"`head -1 ../conf-home`"}g \
+ > ldap-pam
+ chmod 755 ldap-pam
+
+mkdkimkey: \
+warn-auto.sh mkdkimkey.sh ../conf-home
+ cat warn-auto.sh mkdkimkey.sh \
+ | sed s}HOME}"`head -1 ../conf-home`"}g \
+ > mkdkimkey
+ chmod 755 mkdkimkey
+
+qmail-alias2recipients: \
+warn-auto.sh qmail-alias2recipients.sh ../conf-home
+ cat warn-auto.sh qmail-alias2recipients.sh \
+ | sed s}HOME}"`head -1 ../conf-home`"}g \
+ > qmail-alias2recipients
+ chmod 755 qmail-alias2recipients
+
+qmail-mrtg-queue: \
+warn-auto.sh qmail-mrtg-queue.sh ../conf-home
+ cat warn-auto.sh qmail-mrtg-queue.sh \
+ | sed s}HOME}"`head -1 ../conf-home`"}g \
+ > qmail-mrtg-queue
+ chmod 755 qmail-mrtg-queue
+
+qmail-queue-scan: \
+warn-auto.sh qmail-queue-scan.sh ../conf-home
+ cat warn-auto.sh qmail-queue-scan.sh \
+ | sed s}HOME}"`head -1 ../conf-home`"}g \
+ > qmail-queue-scan
+ chmod 755 qmail-queue-scan
+
+x509fingerprint: \
+warn-auto.sh x509fingerprint.sh
+ cat warn-auto.sh x509fingerprint.sh \
+ > x509fingerprint
+ chmod 755 x509fingerprint
diff --git a/scripts/TARGETS b/scripts/TARGETS
new file mode 100644
index 0000000..909572d
--- /dev/null
+++ b/scripts/TARGETS
@@ -0,0 +1,5 @@
+ldap-pam
+mkdkimkey
+qmail-alias2recipients
+qmail-queue-scan
+x509fingerprint
diff --git a/scripts/it-pam=d b/scripts/it-pam=d
new file mode 100644
index 0000000..a3b6f9e
--- /dev/null
+++ b/scripts/it-pam=d
@@ -0,0 +1 @@
+ldap-pam
diff --git a/scripts/it-recipients=d b/scripts/it-recipients=d
new file mode 100644
index 0000000..7de3576
--- /dev/null
+++ b/scripts/it-recipients=d
@@ -0,0 +1 @@
+qmail-alias2recipients
diff --git a/scripts/it-scan=d b/scripts/it-scan=d
new file mode 100644
index 0000000..456c4b3
--- /dev/null
+++ b/scripts/it-scan=d
@@ -0,0 +1 @@
+qmail-queue-scan
diff --git a/scripts/it-x509=d b/scripts/it-x509=d
new file mode 100644
index 0000000..a91ec38
--- /dev/null
+++ b/scripts/it-x509=d
@@ -0,0 +1,2 @@
+x509fingerprint
+mkdkimkey
diff --git a/scripts/it=d b/scripts/it=d
new file mode 100644
index 0000000..ba3e272
--- /dev/null
+++ b/scripts/it=d
@@ -0,0 +1,4 @@
+it-pam
+it-recipients
+it-x509
+it-scan
diff --git a/scripts/ksh-auto.sh b/scripts/ksh-auto.sh
new file mode 100644
index 0000000..f62c82a
--- /dev/null
+++ b/scripts/ksh-auto.sh
@@ -0,0 +1,2 @@
+#!KSH
+# WARNING: This file was auto-generated. Do not edit!
diff --git a/scripts/ldap-pam.pl b/scripts/ldap-pam.pl
new file mode 100644
index 0000000..675a2c9
--- /dev/null
+++ b/scripts/ldap-pam.pl
@@ -0,0 +1,149 @@
+#
+# checkpassword compatible LDAP pam for ADDRESSS (version 0.9.2)
+#
+# Usage: ldpap-pam -h:host:port -d:DN -w:password -b:base -s:scope -c:certificate -l(ogging) -ll
+#
+# Warning: This PERL code might not work on all versions of PERL !
+#
+# Some code taken from:
+# ldap_verify.pl by Ted Fines, Jan. 2005. version 0.1
+#
+# Customization:
+# Default search attribute is 'Mail'.
+#
+# Requires:
+# 'Net::LDAP' on http://www.cpan.org
+#
+# History:
+# 0.9.2 Fixed bug evalulation reference mailname (tx. Sven)
+#
+#---------------------------------------------------------------------
+use Net::LDAP;
+use IO::Handle;
+use warnings;
+use strict;
+#
+## Verbose output
+#
+my $ME='ldap-pam';
+my $LOGGING=0;
+#
+my @INPUT;
+my $LDAPHOST='localhost';
+my $LDAPPORT='default';
+my $LDAPUSR='';
+my $LDAPPWD='';
+my $LDAPBASE='';
+my $LDAPCERT='';
+my $TIMEOUT='30';
+#
+my $LDAPSCOPE='sub';
+my $ATTRIBUTE='mail';
+my $PROTOCOL_LEN=512;
+#
+## Check Arguments
+#
+if ( $#ARGV == -1) {
+ print STDERR "[Usage] ldpap-pam -h:host:port -t:timeout -d:DN -w:password -b:base -s:scope -c:certificate -l[l](ogging)\n";
+ print STDERR "[Defaults] Host:$LDAPHOST - Port:$LDAPPORT - DN:anonymous - Scope:$LDAPSCOPE - Attribute:$ATTRIBUTE - Timeout:$TIMEOUT \n";
+ exit 111;
+}
+
+while ( $#ARGV >= 0 ) {
+ $_=$ARGV[0];
+ s/^-h// && do { @INPUT = split(/:/,$_); $LDAPHOST=$INPUT[1];
+ if ( $INPUT[2] ) { $LDAPPORT=$INPUT[2]; } };
+ s/^-t// && do { @INPUT = split(/:/,$_); $TIMEOUT=$INPUT[1]; };
+ s/^-d// && do { @INPUT = split(/:/,$_); $LDAPUSR=$INPUT[1]; };
+ s/^-w// && do { @INPUT = split(/:/,$_); $LDAPPWD=$INPUT[1]; };
+ s/^-b// && do { @INPUT = split(/:/,$_); $LDAPBASE=$INPUT[1]; };
+ s/^-s// && do { @INPUT = split(/:/,$_); $LDAPSCOPE=$INPUT[1]; };
+ s/^-c// && do { @INPUT = split(/:/,$_); $LDAPCERT=$INPUT[1]; };
+ s/^-ll// && do { $LOGGING = 2; };
+ s/^-l// && do { $LOGGING = 1; };
+ shift;
+}
+#
+##
+my $ldap;
+my $mesg;
+my $rawinput;
+my $verifyaddr;
+my $verifyresult;
+#
+my $num_params = 1;
+my $input_descriptor = 3;
+#
+# These codes from DJB's checkpassword page.
+#
+my ($verify_ok,$verify_none,$resp_misused,$resp_tempfailure) = (0,1,2,111);
+#
+my $fhin = new IO::Handle;
+my $fherr = new IO::Handle;
+$fhin->fdopen($input_descriptor,"r");
+$fherr->fdopen(fileno(STDERR),"w");
+
+if (($fhin->opened) && ($fherr->opened)) {
+ $fhin->read($rawinput,$PROTOCOL_LEN);
+ my @checkfields = split(/\0/,$rawinput);
+ if (scalar(@checkfields) != $num_params) {
+ if ($LOGGING) { print STDERR "$ME [Error] Wrong format of input address specified.\n"; }
+ exit $resp_misused;
+ }
+ $verifyaddr = $checkfields[0];
+ #
+ # This section is the 'bottom line' so to speak, where the yea or nay is given.
+ #
+ $verifyresult = &ldap_mail($verifyaddr);
+ if ($verifyresult == $verify_ok) {
+ if ($LOGGING) { print STDERR "$ME [Info] Address '$verifyaddr' verified at LDAP Server '$LDAPHOST'.\n"; }
+ } elsif ($verifyresult == $verify_none) {
+ if ($LOGGING) { print STDERR "$ME [Info] Could not verify address '$verifyaddr' at LDAP Server '$LDAPHOST'.\n"; }
+ }
+ exit $verifyresult;
+}
+print STDERR "$ME [Error] Could not connect to LDAP Server '$LDAPHOST:$LDAPPORT'.\n";
+exit $resp_tempfailure;
+
+sub ldap_mail {
+ (my $mailaddr) = @_;
+
+ if ( $LDAPCERT ne "" && $LDAPUSR ne "" && $LDAPPWD ne "" ) {
+ if ( $LDAPPORT eq "default" ) { $LDAPPORT='636'; }
+ $ldap = Net::LDAPS->new($LDAPHOST, port => $LDAPPORT, timeout => $TIMEOUT) or &mydie();
+ $mesg = $ldap->bind($LDAPUSR, password => $LDAPPWD, version => 3, verify => require, cafile => $LDAPCERT);
+ } elsif ( $LDAPUSR ne "" && $LDAPPWD ne "" ) {
+ if ( $LDAPPORT eq "default" ) { $LDAPPORT='389'; }
+ $ldap = Net::LDAP->new($LDAPHOST, port => $LDAPPORT, timeout => $TIMEOUT) or &mydie();
+ $mesg = $ldap->bind($LDAPUSR, password => $LDAPPWD, version => 3);
+ } else {
+ if ( $LDAPPORT eq "default" ) { $LDAPPORT='389'; }
+ $ldap = Net::LDAP->new($LDAPHOST, port => $LDAPPORT, timeout => $TIMEOUT) or &mydie();
+ $mesg = $ldap->bind(version => 3);
+ }
+ if ( $mesg->code ) { &mydie($mesg->code) };
+
+ $mesg = $ldap->search (base => $LDAPBASE, scope => $LDAPSCOPE, filter => "$ATTRIBUTE=$mailaddr");
+ $mesg->code && &mydie($mesg);
+ $ldap->unbind;
+
+ my $href= $mesg->as_struct;
+ my @mailnames = keys %$href;
+ foreach (@mailnames) {
+ my $DN = $_;
+ my $valref = $$href{$_};
+ my $mailname = @$valref{$ATTRIBUTE};
+ if ( $LOGGING == 2 ) { print STDERR "$ME [Debug] Returned DN '$DN' with '@$mailname' for address '$mailaddr' at LDAP Server '$LDAPHOST'.\n"; }
+ if ( "lc($mailaddr)" eq "lc((@$mailname)[0])" ) { return $verify_ok; }
+ }
+ return $verify_none;
+}
+
+sub mydie {
+ if (scalar(@_) > 0) {
+ print STDERR "$ME [Error] Strange message received from LDAP Server '$LDAPHOST:$LDAPPORT': '$mesg->code', '$mesg->error_name', '$mesg->error->text'.\n";
+ } else {
+ print STDERR "$ME [Error] Could not connect to LDAP Server '$LDAPHOST:$LDAPPORT'.\n";
+ }
+ exit $resp_tempfailure;
+}
diff --git a/scripts/mkdkimkey.sh b/scripts/mkdkimkey.sh
new file mode 100644
index 0000000..5714173
--- /dev/null
+++ b/scripts/mkdkimkey.sh
@@ -0,0 +1,213 @@
+#********************************************************************************
+# Create/Handle domainkeys for openqmail/eQmail/(net)qmail and derivatives #
+# #
+# Author: Kai Peter (parts taken from Joerg Backschues), ©2014 #
+# Version: 0.32 -> 0.46 #
+# Licence: This program is Copyright(C) ©2015 Kai Peter. It can be copied and #
+# modified according to the GNU GENERAL PUBLIC LICENSE (GPL) Version 2 #
+# or a later version. This software comes without any warranty. #
+# #
+# Description: Creation of domain keys and DNS TXT records for bind #
+# #
+# Addendum for s/qmail: #
+# #
+# a) This version is modified for s/qmail (etc/dkimkey -> ssl/domainkeys) #
+# b) RSA and Ed25519 private/public keys are considered (-> RFC 8463) #
+# c) tinydns supports DKIM records while just providing the public key; #
+# beware of the 'selector'; it is set to 'default' #
+# d) Unlike previous versions, the new private key is *not* automatically #
+# linked to a file named 'default'; but rather to #
+# rsa|ed25519.private_<selector> -> <selector> #
+# e) The ed25519 public key is stripped from the ASN1 header information #
+# This base64 encoded key is available as 'ed25519.basekey_<Selector> #
+# f) RSA and Ed25519 private keys may share the same <Selector> name. #
+# If identical, the Ed25519 private key is linked as '<Selector>_' #
+# to be picked up automatically by qmail-dksign for simultaneous signing. #
+# #
+# Changelog: #
+# #
+# 0.46 Fix for RSA DKIM TXT file generation, compactified TXT data. #
+#********************************************************************************
+DKDIR="HOME/ssl/domainkeys"
+USR="qmailq"
+GRP="sqmail"
+MODULUS=2048
+CURVE=0
+VERBOSE=0
+SELECTOR="default"
+DOMAIN=""
+ASN1="MCowBQYDK2VwAyEA"
+PRINT=0
+
+OPENSSL=$(which openssl 2>/dev/null)
+if [ $? -ne 0 ] ; then
+ echo "Couldn't find openssl! Aborting!" ; exit 0 ;
+fi
+
+showHelp() {
+echo "Usage: $(basename $0) [-hpc] [-s selector] [-m modulus] domain"
+echo
+echo "-h (show this help and exit)"
+echo "-v (verbose output)"
+echo "-p (print TXT record for domain)"
+echo "-s <selector> (set the selector)"
+echo "-m <N> (set RSA modulo size; default: 2048 bits)"
+echo "-c (generate Ed25519 keys)"
+echo ""
+echo "RSA key generation:"
+echo "=================="
+echo ""
+echo " mkdkimkey -s rsa-selector domain"
+echo ""
+echo "Ed25519 key generation:"
+echo "======================"
+echo ""
+echo " mkdkimkey -c -s ed-selector domain"
+echo ""
+echo "Key activation:"
+echo "=============="
+echo " The created private key 'rsa|ed25519.private_<selector>'"
+echo " is automatically symlinked to '<selector>'."
+echo " If included in 'control/dkimdomains', this file name"
+echo " is picked up by qmail-dksign for signing outgoing mails."
+echo " The default name for '<selector>' is 'default'."
+echo " This is implicitely assumed if no particular '<selector>' is given."
+echo ""
+exit 1 ;
+}
+
+readInit() {
+
+FLAG=""
+PARAMS="vhpcs:m:"
+
+if [ $# -gt 0 ]; then
+ while getopts ${PARAMS} FLAG
+ do
+ case ${FLAG} in
+ v) VERBOSE=1;;
+ p) PRINT=1;;
+ s) SELECTOR=${OPTARG};;
+ m) MODULUS=${OPTARG};;
+ c) CURVE=1;;
+ h) showHelp;;
+ *) showHelp;;
+ esac
+ done
+ shift $((OPTIND-1))
+fi
+
+# Validate the input a bit ...
+DOMAIN=$1 ; if [ "x${DOMAIN}" = "x" ] ; then showHelp ; fi
+# Only one argument is allowed ($1) and have to follow any other options
+if [ $2 ] ; then echo "Syntax ERROR!;" showHelp ; fi
+
+# Create main DKIM directory for keys if required
+
+if [ ! -d ${DKDIR} ] ; then mkdir -p ${DKDIR} ; fi
+}
+
+showTXT() {
+# backslashes MUST NOT be used in TXT records to quote semicolons !
+
+cd ${DKDIR}/${DOMAIN}
+
+echo "Domain's public key in '${DKDIR}/${DOMAIN}' used for TXT DNS record:"
+
+echo -n "${SELECTOR}._domainkey.${DOMAIN}. IN TXT "
+if [ -f rsa.public_${SELECTOR} ]; then
+ key=`grep -v -e '^-' rsa.public_${SELECTOR} | tr -d '\n'`
+ echo "\"v=DKIM1;k=rsa;t=y;p=${key}\""
+elif [ -f ed25519.public_${SELECTOR} ]; then
+ key=`grep -v -e '^-' ed25519.public_${SELECTOR} | tr -d '\n'`
+ basekey=${key#${ASN1}}
+ if [ `echo -n ${basekey} | wc -c | awk '{print $1}'` -eq 44 ]; then
+ echo "\"v=DKIM1;k=ed25519;t=y;p=${basekey}\""
+ echo ${basekey} > ed25519.basekey_${SELECTOR}
+ else
+ (errString="error generating Ed25519 public key" && showError; echo ${key}; echo ${basekey}; exit 1)
+ fi
+fi
+echo -n "You need to publish this TXT record in the DNS before activating [rsa|ed25519].private_${SELECTOR} -> ${SELECTOR} for signing."
+
+echo ; exit 0;
+}
+
+showError() {
+ echo "Domainkey for domain '${DOMAIN}' with selector '${SELECTOR}' [${errString}]!";
+}
+
+###############################################################################
+# Main
+###############################################################################
+
+# Read input args; create dirs, do some validation
+
+readInit ${@}
+
+if [ ${PRINT} -eq 1 ]; then showTXT; fi
+
+# Do some tests for existing keys
+
+if [ ${VERBOSE} -eq 1 ] ; then
+ if [ ${CURVE} -eq 0 ] ; then
+ test -f ${DKDIR}/${DOMAIN}/rsa.private_${SELECTOR} && \
+ (errString="already exists" && showError)
+ else
+ test -f ${DKDIR}/${DOMAIN}/ed25519.private_${SELECTOR} && \
+ (errString="already exists" && showError)
+ fi
+fi
+
+# Create a directory for domain and populate it with new keys
+# Existing old keys are safed as 'previous'
+
+mkdir -p ${DKDIR}/${DOMAIN}
+cd ${DKDIR}/${DOMAIN}
+
+if [ ${CURVE} -eq 0 ] ; then
+ if [ -f rsa.public_${SELECTOR} ]; then
+ cp rsa.public_${SELECTOR} rsa.public_${SELECTOR}.previous
+ cp rsa.private_${SELECTOR} rsa.private_${SELECTOR}.previous
+ fi
+ ${OPENSSL} genrsa -out rsa.private_${SELECTOR} ${MODULUS}
+ ${OPENSSL} rsa -in rsa.private_${SELECTOR} \
+ -out rsa.public_${SELECTOR} -pubout -outform PEM
+ ln -sf rsa.private_${SELECTOR} ${SELECTOR}
+else
+ if [ -f ed25519.public_${SELECTOR} ]; then
+ cp ed25519.public_${SELECTOR} ed25519.public_${SELECTOR}.previous
+ cp ed25519.private_${SELECTOR} ed25519.private_${SELECTOR}.previous
+ fi
+ ${OPENSSL} genpkey -algorithm Ed25519 \
+ -out ed25519.private_${SELECTOR}
+ ${OPENSSL} pkey -in ed25519.private_${SELECTOR} \
+ -out ed25519.public_${SELECTOR} -pubout
+ if [ -f ${SELECTOR} ]; then
+ ln -sf ed25519.private_${SELECTOR} "${SELECTOR}_"
+ else
+ ln -sf ed25519.private_${SELECTOR} ${SELECTOR}
+ fi
+fi
+
+# Set permissions
+
+chmod 0711 ${DKDIR}
+chmod 0700 ${DKDIR}/${DOMAIN}
+chmod 0600 ${DKDIR}/${DOMAIN}/*
+chown -R ${USR}:${GRP} ${DKDIR}
+
+# Do some tests
+
+if [ ${CURVE} -eq 0 ] ; then
+ test -f rsa.public_${SELECTOR} || \
+ (errString="does not exist" && showError)
+else
+ test -f ed25519.public_${SELECTOR} || \
+ (errString="does not exist" && showError)
+fi
+
+# Done
+
+[ "$?" = 0 ] && showTXT
+exit 0
diff --git a/scripts/multiple-queues.sh b/scripts/multiple-queues.sh
new file mode 100644
index 0000000..d6239d7
--- /dev/null
+++ b/scripts/multiple-queues.sh
@@ -0,0 +1,112 @@
+#!/bin/sh
+#set -o xtrace
+
+SQMAIL=HOME
+QMAIL_LOGS="/var/log"
+SVC_HOME="/service"
+
+SKELETON_SOURCE="${SQMAL}/source"
+SKELETON_ME="mail.example.com"
+SKELETON_CONCURRENCYREMOTE="120"
+SKELETON_QUEUELIFETIME="1440"
+SKELETON_PORT="1000"
+
+SKELETON_DIR="${SQMAL}/skeleton"
+SKELETON_QMAIL_SEND="start_run"
+SKELETON_QMAIL_LOGS="log_start_run"
+SKELETON_QMAIL_SMTP="smtpd_run"
+SKELETON_SMTP_LOGS="log_smtpd_run"
+SKELETON_QMAIL_QMTPD="qmtpd_run"
+SKELETON_QMAIL_LOGS="log_qmtpd_run"
+
+if [[ -f conf-qmq ]]; then
+ MYINSTANCES=$(grep -v "^#" conf-qmq | cut -d"#" -f1)
+ echo "The follwing qmail instances are defined:"
+ echo ""
+ grep -v "^#" conf-qmq
+ echo ""
+ echo "--> Use '$0 build' to setup the instances."
+ echo "--> Use '$0 conf' to deploy the instances."
+ echo "--> Use '$0 all' to setup and deploy the instances."
+ echo ""
+ echo "Note (1): qmail will be installed at '${SQMAL}'."
+ echo "Note (2): qmail-logs will be installed at '${QMAIL_LOGS}/qmail-send-INSTANCEID' ...."
+ echo "Note (3): 'service' base directory is '${SVC_HOME}'."
+ echo "Note (4): 'qmail-send' will be initially touched 'down' at every instance."
+ echo "Note (5): Initial configuration is: 'queuelifetime=${SKELETON_QUEUELIFETIME}', concurrencyremote=${SKELETON_CONCURRENCYREMOTE}'."
+ echo "Note (6): Communication from the primary qmail instance to the secondaries is bsed on 'QMTP'.
+ echo ""
+ echo "Enter 'ctl-c' to abort; or continue installation."
+else
+ echo "Configuration file 'conf-qmq' not available."
+ exit 1
+fi
+
+set -A INSTANCES ${MYINSTANCES}
+
+if [[ "$1" = "build" || "$1" = "all" ]]; then
+ for MAPPING in ${INSTANCES[@]}
+ do
+ INSTANCE=$(echo "${MAPPING}" | awk -F: '{print $1}')
+ NAME=$(echo "${MAPPING}" | awk -F: '{print $2}')
+ if [[ "x${NAME}" != "x" ]]; then
+ mkdir ${SQMAL}-${INSTANCE}
+ mkdir ${QMAL_LOGS}/qmail-${INSTANCE}
+ chown qmaill ${QMAL_LOGS}/qmail-${INSTANCE}
+ mkdir ${QMAL_LOGS}/qmtp-${INSTANCE}
+ chown qmaill ${QMAL_LOGS}/qmtp-${INSTANCE}
+ cd ${QMAIL_SOURCE}
+ echo "${SQMAL}-${INSTANCE}" > conf-qmail
+ make
+ make setup check
+ echo "${SKELETON_ME}" > ${SQMAL}-${INSTANCE}/control/me
+ echo "${SKELETON_CONCURRENCYREMOTE}" > ${SQMAL}-${INSTANCE}/control/concurrencyremote
+ echo "${SKELETON_QUEUELIFETIME}" > ${SQMAL}-${INSTANCE}/control/queuelifetime
+ fi
+ done
+elif [[ "$1" == "conf" || "$1" == "all" ]]; then
+ for MAPPING in ${INSTANCES[@]}
+ do
+ INSTANCE=$(echo "${MAPPING}" | awk -F: '{print $1}')
+ NAME=$(echo "${MAPPING}" | awk -F: '{print $2}')
+ if [[ "x${NAME}" != "x" ]]; then
+ integer PORT=$((${SKELETON_PORT}+${INSTANCE}))
+ echo "Selecting ${PORT} for instance ${INSTANCE} ..."
+#
+## qmail-send/qmail-start
+#
+ mkdir -p ${SQMAL}-${INSTANCE}/svc/qmail-${INSTANCE}-start/log
+ touch ${SQMAL}-${INSTANCE}/svc/qmail-${INSTANCE}-start/down
+
+ sed s/INSTANCE/${INSTANCE}/g ${SKELETON_DIR}/${SKELETON_QMAIL_LOGS} > \
+ ${SQMAL}-${INSTANCE}/svc/qmail-${INSTANCE}-start/log/run
+ chmod +x ${SQMAL}-${INSTANCE}/svc/qmail-${INSTANCE}-start/log/run
+
+ sed s/INSTANCE/${INSTANCE}/g ${SKELETON_DIR}/${SKELETON_QMAIL_SEND} > \
+ ${SQMAL}-${INSTANCE}/svc/qmail-${INSTANCE}-start/run
+ chmod +x ${SQMAL}-${INSTANCE}/svc/qmail-${INSTANCE}-start/run
+ ln -s ${SQMAL}-${INSTANCE}/svc/qmail-${INSTANCE}-start ${SVC_HOME}/qmail-${INSTANCE}-start
+#
+## qmail-qmtpd
+#
+ mkdir -p ${SQMAL}-${INSTANCE}/svc/qmail-${INSTANCE}-qmtpd/log
+
+ sed s/INSTANCE/${INSTANCE}/g ${SKELETON_DIR}/ ${SKELETON_QMTPD_LOGS} > \
+ ${SQMAL}-${INSTANCE}/svc/qmail-${INSTANCE}-qmtpd/log/run
+ chmod +x ${SQMAL}-${INSTANCE}/svc/qmail-${INSTANCE}-qmtpd/log/run
+
+ sed s/INSTANCE/${INSTANCE}/g ${SKELETON_DIR}/ ${SKELETON_QMAIL_QMTPD} | \
+ sed s/PORT/${PORT}/g > ${SQMAL}-${INSTANCE}/svc/qmail-${INSTANCE}-qmtpd/run
+ chmod +x ${SQMAL}-${INSTANCE}/svc/qmail-${INSTANCE}-qmtpd/run
+#
+## link to /svc
+#
+ ln -s ${SQMAL}-${INSTANCE}/svc/qmail-${INSTANCE}-qmtpd ${SVC_HOME}/qmail-${INSTANCE}-qmtpd
+ ln -s ${SQMAL}-${INSTANCE}/svc/qmail-${INSTANCE}-start ${SVC_HOME}/qmail-${INSTANCE}-start
+ fi
+ done
+else
+ echo "Please provide either 'build' and 'conf' for individual steps; or 'all' for all-inclusive."
+fi
+
+exit 0
diff --git a/scripts/perl-auto.sh b/scripts/perl-auto.sh
new file mode 100644
index 0000000..738ec79
--- /dev/null
+++ b/scripts/perl-auto.sh
@@ -0,0 +1,2 @@
+#!PERL
+# WARNING: This file was auto-generated. Do not edit!
diff --git a/scripts/qmail-alias2recipients.sh b/scripts/qmail-alias2recipients.sh
new file mode 100644
index 0000000..60398d3
--- /dev/null
+++ b/scripts/qmail-alias2recipients.sh
@@ -0,0 +1,4 @@
+# Tx. Warren Odom (28 Apr 2005)
+
+cd HOME/alias
+ls -l .qmail-* | grep -v .qmail-default | tr -s " " | awk '{print $9}' | sed s/^\.qmail-// | awk '{print $2"@localhost"}' | sort -u >> HOME/users/recipients
diff --git a/scripts/qmail-queue-scan.sh b/scripts/qmail-queue-scan.sh
new file mode 100644
index 0000000..3ab29fb
--- /dev/null
+++ b/scripts/qmail-queue-scan.sh
@@ -0,0 +1,144 @@
+#
+# Notes:
+# chmod 1755 qmail-queue.scan; chown qmailq:qmail qmail-queue.scan
+# SQMAIL/tmp has to exist prior with owner qmaill:qmail
+#
+# Usage:
+# Generate: control/spamdomains
+# Input: recipient-domain:spam-threshold
+# Sample: example.com:8
+# allspams:0
+# #testdomain:11 # entries with leading '#' are disregarded
+#
+# Caution:
+# This script is a sample. Depending on your anti-virus and/or anti-spam
+# software, some heavy tweaking is required.
+#
+#
+# Dependencies:
+# Korn shell
+# DJB's MESS822 package (or not)
+#
+# Environment variables used:
+#
+# $MAILFROM -- set by qmail-smtpd
+# $RCPTTO -- set by qmail-smtpd
+#
+# Virus scanner:
+# The AV scanner returns '0' if ok -- or '1'/'2' if virus -- anything else = error
+#
+# Spam scanner:
+# SpamAssassin > 3.0 (spamc/spamd)
+#
+# Output:
+# RC=0; if ok
+# RC=32; if virus
+# RC=33; if spam
+# RC=81; if error
+#
+# Performance:
+# Put SQMAIL/tmp on a RAMDISK
+#
+# License:
+# Public Domain
+#
+# Author:
+# Dr. Erwin Hoffmann - FEHCom
+#
+# Version:
+# 0.9.7
+#
+#------------------------------------------------------------------------------------------------
+SQMAIL=HOME
+#
+alias -x SCANNER='/usr/local/bin/clamdscan'
+#alias -x SCANNER='/etc/iscan/vscan'
+alias -x SPAMMER='/usr/bin/spamc'
+alias -x 822FIELD='/usr/local/bin/822field'
+# alias -x 822FIELD='/usr/bin/grep'
+#
+VERBOSE=0
+#
+SCANNERARGS="--no-summary"
+SPAMMERARGS=""
+#
+## No code change necessary from here
+#
+typeset SPAM
+integer SPAMC=0
+integer SPAMTHRESHOLD=-1
+integer SPAMTH
+typeset SPAMDOMAINS
+
+ID="${RANDOM}$$"
+MESSAGE="${SQMAIL}/tmp/msg.${ID}"
+export DTLINE="spam-queue"
+#
+[[ ! -d ${SQMAIL}/tmp ]] && exit 53
+cat > ${MESSAGE} || exit 53
+#
+## Virus scanning
+#
+if [[ "x${QHPSI}" = "x" ]]; then
+ VIRUS=$(SCANNER ${SCANNERARGS} ${MESSAGE})
+ VRC=$?
+ [[ ${VERBOSE} -gt 0 ]] && print -u2 "AV Scanner info [`SCANNER` -V]: ${VIRUS}"
+
+# VIRUS=$(echo "${VIRUS}" | grep -e "\*\*") ## for TrendMicro only
+ case ${VRC} in
+ (0) RC=0;;
+ (1|2) exec 1>&2; echo "Infected email not delivered (${VIRUS})"; RC=32;;
+ (*) exec 1>&2; echo "`SCANNER -V` internal error (${VRC})"; RC=81;;
+ esac
+fi
+#
+## Check Spamlevel for each domain
+#
+if [[ -f ${SQMAIL}/control/spamdomains && ${RC} -eq 0 ]]; then
+ SPAMDOMAINS=$(grep -v "^#" ${SQMAIL}/control/spamdomains)
+ for LINE in ${SPAMDOMAINS}
+ do
+ DOMAIN=${LINE%:*}
+ SPAMTH=${LINE#*:*}
+ [[ $(echo "${RCPTTO}" | grep -ci "${DOMAIN}") -gt 0 ]] && SPAMTHRESHOLD=${SPAMTH}
+ done
+
+ [[ ${VERBOSE} -gt 0 ]] && print -u2 "Rcptdomain: ${RCPTTO#*@} -- Threshold: ${SPAMTHRESHOLD}"
+
+ if [[ ${SPAMTHRESHOLD} -ge 0 ]]; then
+#
+## Spam recognition -- the following codes is only useful for SpamAssassins spamc version 3.x
+#
+ SPAM=$(SPAMMER ${SPAMMERARGS} < ${MESSAGE} > ${MESSAGE}_$$ && mv ${MESSAGE}_$$ ${MESSAGE} || exit 53)
+ SPAM=$(822FIELD "X-Spam-Level" < ${MESSAGE} | head -n 1)
+ SPAM=${SPAM# }
+
+ [[ ${VERBOSE} -gt 0 ]] && print -u2 echo "[$(echo `SPAMMER -V` | tr -d '\n')]: ${SPAMTHRESHOLD}"
+
+ if [[ "x${SPAM}" != "x" ]]; then
+ if [[ $(echo "${SPAM}" | grep -c "X-Spam-Level") -gt 0 ]]; then
+ SPAMC=$(echo "${SPAM##X-Spam-Level:}" tr -d ' ' | tr -d '\n' | wc -c)
+ fi
+ else
+ SPAMC=$(echo "${SPAM}" | awk -F"/" '{print $1}' | awk -F"." '{print $1}')
+ fi
+ [[ ${VERBOSE} -gt 0 ]] && print -u2 "Spam: ${SPAM} - Spamc: ${SPAMC}"
+#
+## Spam rejection
+#
+ if [[ ${SPAMC} -gt 0 && ${SPAMC} -gt ${SPAMTHRESHOLD} ]]; then
+#
+# If you enable one of the next lines, the sender receives a rejection, while the email is let thru
+#
+# ${SQMAIL}/bin/forward ${MAILFROM} "${RCPTTO}" < ${MESSAGE}
+# ${SQMAIL}/bin/forward ${MAILFROM} "${DELIVERTO}" < ${MESSAGE}
+ export SPAMSCORE="${SPAMC}"
+ RC=33
+ fi
+ fi
+fi
+
+[[ ${RC} -eq 0 ]] && ${SQMAIL}/bin/qmail-queue < ${MESSAGE}
+
+rm ${MESSAGE}
+exit ${RC}
diff --git a/scripts/warn-auto.sh b/scripts/warn-auto.sh
new file mode 100644
index 0000000..36d2313
--- /dev/null
+++ b/scripts/warn-auto.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+# WARNING: This file was auto-generated. Do not edit!
diff --git a/scripts/x509fingerprint.sh b/scripts/x509fingerprint.sh
new file mode 100644
index 0000000..5550150
--- /dev/null
+++ b/scripts/x509fingerprint.sh
@@ -0,0 +1,10 @@
+
+cert=$1
+[ -f "$cert" ] || (echo "$0: Provide path to certificate as argument."; exit 2;)
+
+openssl x509 -sha1 -in $cert -noout -fingerprint | tr -d ':'
+openssl x509 -sha224 -in $cert -noout -fingerprint | tr -d ':'
+openssl x509 -sha256 -in $cert -noout -fingerprint | tr -d ':'
+openssl x509 -sha512 -in $cert -noout -fingerprint | tr -d ':'
+
+exit $?