diff options
-rwxr-xr-x | GUIDELINES | 3 | ||||
-rwxr-xr-x | firma | 257 |
2 files changed, 181 insertions, 79 deletions
@@ -54,5 +54,6 @@ In the future this procedure will be automatic. expect fold uniq - mimencode + tac + sha1sum @@ -190,6 +190,15 @@ WARNING: $LIST_NAME: Removing this address from LIST_ADMIN." LIST_REQUEST_ADDRESS="`echo $LIST_ADDRESS | cut -d @ -f 1`-request@`echo $LIST_ADDRESS | cut -d @ -f 2`" fi + if [ "$REPLAY_PROTECTION" == "yes" ]; then + if [ -z "$REPLAY_COUNT" ]; then + REPLAY_COUNT="10" + fi + if [ -z "$REPLAY_FILE" ]; then + REPLAY_FILE="$REPLAY_DEFAULT_FILE" + fi + fi + SetDeliveryRandomization return $return_code @@ -701,100 +710,113 @@ function ProcessMessage { # check if the message was encrypted if GetGpgMessage; then - # if it was, parse gpg decrypt STDERR to decide what to do next - ParseGpgDecryptStderr - - # if the message was encrypted with the list's public key and if the - #+message signature is valid, send message to list subscribers - if AllowMessageProcessing; then - - # check if the list has valid subscribers - - GetSenderAddress - GetMessageHeadersAndBody - EditListMessageHeaders - DecryptGpgMessage - - if [ "$MODE" == "list-message" ]; then - if GetSubscribersList; then - ReEncryptAndSendListMessage - else - return_code=1 + # look for replay attacks + if ReplayProtectionCheck; then + + # if it was, parse gpg decrypt STDERR to decide what to do next + ParseGpgDecryptStderr + + # if the message was encrypted with the list's public key and if the + #+message signature is valid, send message to list subscribers + if AllowMessageProcessing; then + + # check if the list has valid subscribers + + GetSenderAddress + GetMessageHeadersAndBody + EditListMessageHeaders + DecryptGpgMessage + + if [ "$MODE" == "list-message" ]; then + if GetSubscribersList; then + ReEncryptAndSendListMessage + else + return_code=1 + fi + elif [ "$MODE" == "admin-non-interactive" ]; then + EmailListAdministration fi - elif [ "$MODE" == "admin-non-interactive" ]; then - EmailListAdministration - fi - - # else, if the message was correctly encrypted but its signature is invalid, - #+send a warning about this to the list administrator(s) and to sender - elif [ "$ENCRYPTED_TO_LIST" == "1" ] && [ "$BAD_SIGNATURE" == "1" ] && [ "$REQUIRE_SIGNATURE" == "yes" ]; then - - GetSenderAddress - - if [[ -n $(echo $LIST_ADMIN) || -n "$SENDER_ADDRESS" ]]; then - ComposeAndSendWarningMessage - fi - - # else, a bounce should be sent - else - - # if bounce processing is enabled, continue - if [[ "$SILENTLY_DISCARD_INVALID_MESSAGES" != 1 ]]; then - + + # else, if the message was correctly encrypted but its signature is invalid, + #+send a warning about this to the list administrator(s) and to sender + elif [ "$ENCRYPTED_TO_LIST" == "1" ] && [ "$BAD_SIGNATURE" == "1" ] && [ "$REQUIRE_SIGNATURE" == "yes" ]; then + GetSenderAddress - if [[ -n "$SENDER_ADDRESS" ]]; then - - # if the message was encrypted with the list's public key - if [[ $ENCRYPTED_TO_LIST == 1 ]]; then - - # then, if signature can't be checked, then probably the sender is not subscribed to the list - # send a bounce, if possible - if [ "$SIGNATURE_CHECKING_FAILED" == "1" ] && [ "$REQUIRE_SIGNATURE" == "yes" ]; then - - # this is the body of the message to be sent, so no indentation here - MESSAGE_BODY="\ + + if [[ -n $(echo $LIST_ADMIN) || -n "$SENDER_ADDRESS" ]]; then + ComposeAndSendWarningMessage + fi + + # else, a bounce should be sent + else + + # if bounce processing is enabled, continue + if [[ "$SILENTLY_DISCARD_INVALID_MESSAGES" != 1 ]]; then + + GetSenderAddress + if [[ -n "$SENDER_ADDRESS" ]]; then + + # if the message was encrypted with the list's public key + if [[ $ENCRYPTED_TO_LIST == 1 ]]; then + + # then, if signature can't be checked, then probably the sender is not subscribed to the list + # send a bounce, if possible + if [ "$SIGNATURE_CHECKING_FAILED" == "1" ] && [ "$REQUIRE_SIGNATURE" == "yes" ]; then + + # this is the body of the message to be sent, so no indentation here + MESSAGE_BODY="\ It was not possible to process this message. Your email address is not subscribed to this list. Contact the list administrator if you have any questions." - ComposeAndSendBounceMessage - - # or, if message can be decrypted but its signature can't be checked, then message wasn't signed - # send a bounce, if possible - elif [[ $MESSAGE_DECRYPTION_OKAY == 1 ]]; then - - # this is the body of the message to be sent, so no indentation here - MESSAGE_BODY="\ + ComposeAndSendBounceMessage + + # or, if message can be decrypted but its signature can't be checked, then message wasn't signed + # send a bounce, if possible + elif [[ $MESSAGE_DECRYPTION_OKAY == 1 ]]; then + + # this is the body of the message to be sent, so no indentation here + MESSAGE_BODY="\ It was not possible to process this message. Message was not signed. Contact the list administrator if you have any questions." - ComposeAndSendBounceMessage - - elif [ "$SIGNATURE_MADE_BY_SENDER" != "1" ] && [ "$REQUIRE_SIGNATURE" == "yes" ]; then - - # this is the body of the message to be sent, so no indentation here - MESSAGE_BODY="\ + ComposeAndSendBounceMessage + + elif [ "$SIGNATURE_MADE_BY_SENDER" != "1" ] && [ "$REQUIRE_SIGNATURE" == "yes" ]; then + + # this is the body of the message to be sent, so no indentation here + MESSAGE_BODY="\ It was not possible to process this message. Message was not sent by the person who signed it." - - ComposeAndSendBounceMessage - - fi - - # else, message wasn't encrypted with the list's public key - # send a bounce, if possible - else - - # this is the body of the message to be sent, so no indentation here - MESSAGE_BODY="\ + + ComposeAndSendBounceMessage + + fi + + # else, message wasn't encrypted with the list's public key + # send a bounce, if possible + else + + # this is the body of the message to be sent, so no indentation here + MESSAGE_BODY="\ It was not possible to process this message. Message was not encrypted with the list's public key. Contact the list administrator if you have any questions." - ComposeAndSendBounceMessage + ComposeAndSendBounceMessage + fi fi fi fi + else + # the anti-replay mechanism detected a repeated message + MESSAGE_BODY="\ + It was not possible to process this message. This list + is configured to discarded replayed messages as an attack + protection measue. It looks like that your message was + already sent to the list and then it was discarded. + Contact the list administrator if you have any questions." + ComposeAndSendBounceMessage fi - + # else, message wasn't encrypted at all # send a bounce, if possible else @@ -1044,6 +1066,9 @@ EOF # fix permissions chown -R $FIRMA_USER.$FIRMA_GROUP $LIST_HOMEDIR + + echo "Your list was created. No check its configuration at $LIST_CONFIG_FILE." + echo "To see a list of optional config parameters, type firma --help config." fi else echo "Cannot create list $LIST_HOMEDIR: Installation aborted" @@ -2053,6 +2078,19 @@ function SourceListConfig { \t of messages or if you're going to have a lot of encrypted mailing lists, all randomizing \t its delivery." || \ DELIVERY_RANDOMIZATION="`EvalConfigParameter $LIST_CONFIG_FILE DELIVERY_RANDOMIZATION`" + + [ "$1" == "help" ] && echo -e "\tREPLAY_PROTECTION= when set to \"yes\", stores sha1sums of the last REPLAY_COUNT +\t received messages; then, if some message with an already stored sha1sum, then its bounced back +\t to the sender and considered as an attempt of replay attack." || \ + REPLAY_PROTECTION="`EvalConfigParameter $LIST_CONFIG_FILE REPLAY_PROTECTION`" + + [ "$1" == "help" ] && echo -e "\tREPLAY_COUNT= number of messages to store sha1sums; defaults to 10 and only used +\t when REPLAY_PROTECTION is set to \"yes\"." || \ + REPLAY_COUNT="`EvalConfigParameter $LIST_CONFIG_FILE REPLAY_COUNT`" + + [ "$1" == "help" ] && echo -e "\tREPLAY_FILE= file to store sha1sums of messages; only used when REPLAY_PROTECTION +\t is set to \"yes\"; defaults to $REPLAY_DEFAULT_FILE" || \ + REPLAY_FILE="`EvalConfigParameter $LIST_CONFIG_FILE REPLAY_FILE`" } @@ -2111,12 +2149,71 @@ function DeliveryRandomization { fi } + +function ReplayProtectionFlush { + #------------------------------------------------------------- + # flushes the replay database file + # + # parameter(s): none + # depends on function(s): none + # returns: 0 + #------------------------------------------------------------- + + if [ "$REPLAY_PROTECTION" == "yes" ]; then + if [ -f "$REPLAY_FILE" ]; then + if [ "`wc -l $REPLAY_FILE | awk '{ print $1 }'`" -gt "$REPLAY_COUNT" ]; then + tac $REPLAY_FILE | head -n $REPLAY_COUNT | tac > $REPLAY_FILE + fi + else + touch $REPLAY_FILE + chown $FIRMA_USER.$FIRMA_GROUP $REPLAY_FILE + chmod 600 $REPLAY_FILE + fi + fi + + return 0 +} + + +function ReplayProtectionCheck { + #------------------------------------------------------------- + # check if message was already received and stores it + #+in the database + # + # parameter(s): GetGpgMessage, ReplayProtectionFlush + # depends on function(s): none + # returns: 0 if message's sha1sum is not in replay database + # 1 if message's sha1sum is in the database + #------------------------------------------------------------- + + local sha1 + + if [ "$REPLAY_PROTECTION" == "yes" ]; then + ReplayProtectionFlush + sha1="`echo $GPG_MESSAGE | sha1sum | awk '{ print $1 }'`" + if grep -q "^$sha1$" $REPLAY_FILE; then + touch $REPLAY_FILE.tmp + chown $FIRMA_USER.$FIRMA_GROUP $REPLAY_FILE.tmp + chmod 600 $REPLAY_FILE.tmp + cat $REPLAY_FILE | sed -e "/^$sha1$/d" > $REPLAY_FILE.tmp + mv $REPLAY_FILE.tmp $REPLAY_FILE + return 1 + else + return 0 + fi + echo $sha1 >> $REPLAY_FILE + else + return 0 + fi +} + #------------------------------------------------------------- # main() #------------------------------------------------------------- # path to firma.conf and firma version FIRMA_CONFIG_FILE="/usr/local/etc/firma.conf" +REPLAY_DEFAULT_FILE="/var/log/firma/replay.db" VERSION="0.3" # set environmental variables and options @@ -2153,7 +2250,11 @@ GLOBAL_VARS=" MODE REQUIRE_SIGNATURE SIGNATURE_MADE_BY_SENDER - DELIVERY_RANDOMIZATION" + DELIVERY_RANDOMIZATION + REPLAY_FILE + REPLAY_DEFAULT_FILE + REPLAY_PROTECTION + REPLAY_COUNT" FUNCTIONS=" Usage |