diff options
author | rhatto <rhatto> | 2005-06-23 01:21:41 +0000 |
---|---|---|
committer | rhatto <rhatto> | 2005-06-23 01:21:41 +0000 |
commit | 3d49948fce1260171c9e7b4ef805f01885c370af (patch) | |
tree | 3eb88c507c48f7629c4c56779f1bd8357bc32d3e | |
download | firma-3d49948fce1260171c9e7b4ef805f01885c370af.tar.gz firma-3d49948fce1260171c9e7b4ef805f01885c370af.tar.bz2 |
firma devel release
-rwxr-xr-x | firma | 280 |
1 files changed, 280 insertions, 0 deletions
@@ -0,0 +1,280 @@ +#!/bin/bash +# +# firma v0.3: encrypted mailing list manager +# feedback: rhatto@riseup.net luis@riseup.net | GPL +# +# list configuration is passed thru the config file, +# where you put PARAMETER=value (whithout spaces) +# +# MAIL= path for mail program +# GPG= path for gnupg binary +# LISTNAME= list email +# LISTADMIN= list administrator email addresses (space separated) +# GPGDIR= gpg dir for the lists' keyring +# PASSWD= passwd for the lists' keyring +# + +FIRMA_LIST_PATH=/usr/local/etc/lists +VERSION=0.3 + +# todo: +# errase all vars before quit the game +# unset MESSAGE +# unset GPG_MESSAGE +# umask .... + +function usage { + echo usage: $0 firma \<option\> \<config-file\> + echo -c: create a new list using config-file + echo -p: process a message + echo -r: admin and user requests (mail only) + echo -a: admin commands +} + +function check_config { + # check configuration file parameters + if [ ! -f $GPG -o ! -x $GPG ]; then + echo -e "\n$1: GPG binary ($GPG) could not be found.\n" + exit 1 + elif [ ! -f $MAIL -o ! -x $MAIL ]; then + echo -e "\n$1: Mail program ($MAIL) could not be found.\n" + exit 1 + elif [ ! -d $GPGDIR -o ! -f $GPGDIR/pubring.gpg -o ! -f $GPGDIR/secring.gpg ]; then + echo -e "\n$1: GPG home directory ($GPGDIR) or the GPG keyrings could not be found.\n" + exit 1 + elif [ -z "$(cat $CONFIG | grep -o ^PASSWD=\'[^\']*\'$)" -o \ + -z "$(echo -n $PASSWD)" -o \ + "$(echo -n $PASSWD | wc -m)" -lt "25" -o \ + -z "$(echo -n $PASSWD | grep -o [[:lower:][:upper:]])" -o \ + -z "$(echo -n $PASSWD | grep -o [[:digit:]])" -o \ + "$(echo -n $PASSWD | grep -o [[:punct:]] | wc -l)" -lt "5" ]; then + echo -e "\n$CONFIG: PASSWD is empty or does not meet the minimum complexity requirements." + echo "$1: Please set a new passphrase for the list's private key. Make it at least" + echo "$1: 25 characters long (using a combination of letters, numbers and at least" + echo "$1: 5 special characters) and enclose it in 'single quotes'. The passphrase" + echo -e "$CONFIG: itself, though, cannot contain any single quote.\n" + exit 1 + elif [ -z "$($GPGLIST | grep ^pub | cut -d : -f 10 | grep -i \<$LISTNAME\>$)" ]; then + echo -e "\n$CONFIG: GPG key for list \"$LISTNAME\" could not be found." + echo -e "$CONFIG: Note that this parameter expects an email address.\n" + exit 1 + else + for ADMIN in $LISTADMIN; do { + if [ -z "$($GPGLIST | grep ^pub | cut -d : -f 10 | grep -i \<$ADMIN\>$)" ]; then + echo -e "\n$CONFIG: GPG key for list administrator \"$ADMIN\" could not be found." + echo -e "$CONFIG: Note that this parameter expects one or more space separated email addresses.\n" + exit 1 + fi; } + done + fi +} + +function GPGSTDERR { + # discard $GPGDECRYPT STDOUT and get its STDERR instead, for signature checking + echo -e "$PASSWD\n${GPG_MESSAGE[@]}" | sed -e 's/^ //' | ($GPGDECRYPT --status-fd 2 1> /dev/null) 2>&1 ; +} + +function SUBSCRIBERS { + # get list susbscriber's addresses + $GPGLIST | sed -ne "/$LISTNAME/Id" -e '/pub/p' | cut -d : -f 10 | grep -o '<[^<>]*>$' | sed -e 's/[<>]//g' ; +} + +function get_message { + n=0; + while read STDIN; do + MESSAGE[$n]="$STDIN\n" + ((++n)) + done +} + +function get_gpg_message { + signal=0; x=0; + for ((count=0;count<=n;count++)); do + if [[ $signal == "0" ]] && [[ "$(echo "${MESSAGE[$count]}" | grep -v -e "-----BEGIN PGP MESSAGE-----")" == "" ]]; then + GPG_MESSAGE[$x]=${MESSAGE[$count]}; ((++x)) + signal=1 + elif [[ $signal == "1" ]]; then + GPG_MESSAGE[$x]=${MESSAGE[$count]} + ((++x)) + if [[ "$(echo "${MESSAGE[$count]}" | grep -v -e "-----END PGP MESSAGE-----")" == "" ]]; then + signal=0 + fi + fi + done +} + +function get_headers { + # get the message headers and the sender's email address + FROM=$(echo -e "${MESSAGE[@]}" | grep -m 1 "From:" | cut -d : -f 2- | sed -e 's/^ //') + FROMADD=$(if [ -z "$(echo $FROM | grep '>$')" ] ; then echo $FROM ; else echo $FROM | grep -o '<[^<>]*>$' | sed -e 's/[<>]// +g' ; fi) + DATE=$(echo -e "${MESSAGE[@]}" | grep -m 1 "Date:") + SUBJECT=$(echo -e "${MESSAGE[@]}" | grep -m 1 "Subject:" | cut -d : -f 2- | sed -e 's/^ //') +} + +function message_list { +# compose and send a message to the list +# $1: subscriber email +# sorry no identation :P +echo "$PASSWD +Message from: $FROM +Subject: $SUBJECT +$DATE + +$(GPGSTDERR | grep -F 'gpg: Signature made') +$(GPGSTDERR | grep -F 'gpg: Good signature from') + +$(echo -e "$PASSWD\n${GPG_MESSAGE[@]}" | $GPGDECRYPT 2> /dev/null)" | sed -e 's/=20$//' | $GPGENCRYPT $1 | $MAIL -r $LISTNAME $1 +} + +function message_list_error { +# compose and send an error message +# sorry no identation :P +echo "$PASSWD +Message from: $FROM +Subject: [BAD SIGNATURE] $SUBJECT +$DATE + +$(GPGSTDERR | grep -F 'gpg: Signature made') +$(GPGSTDERR | grep -F 'gpg: BAD signature from') + +$(echo -e "$PASSWD\n${GPG_MESSAGE[@]}" | $GPGDECRYPT 2> /dev/null)" | sed -e 's/=20$//' | $GPGENCRYPT $1 | $MAIL -r $LISTNAME $1 +} + +function message_list_return { +# send a bouce message +# $1: sender email (usually $FROMADD) +# sorry no identation :P +echo " +Message from: $FROM +Subject: [RETURNED MAIL] $SUBJECT +$DATE + + [ It was not possible to process this message. Either or both + the message was not encrypted and/or signed, or you are not + subscribed to this list. Contact the list administrator if + you have any questions. ] + + -- + firma v$VERSION" | $MAIL -r $LISTNAME $1 +} + +function process_message { + # process a message sent to the list + + get_message + get_headers + get_gpg_message + + # if signature is Good, encrypt and send it for each list subscriber + # todo: declare a function to decrypt, re-encrypt and send the list messages + if (GPGSTDERR | grep -Fq GOODSIG); then + + for EMAIL in $(SUBSCRIBERS); do + message_list $EMAIL + done + + # else, if signature is BAD, email it back to the list admins and to sender + elif (GPGSTDERR | grep -Fq BADSIG) ; then + + for EMAIL in $(echo $LISTADMIN $FROMADD); do + message_list_error $EMAIL + done + + # else, probably either the message was not signed or the sender is not subscribed to the list + # email the message back to sender including a note about this + # todo: parse STDERR to find out why the signature couldn't be checked and send more specific errors back to sender + else + message_list_return $FROMADD + fi + +} + +function newlist { + # create a list if it doesnt already exist + if [ ! -d "$CONFIG_PATH" ]; then + echo creating folder $CONFIG_PATH... + mkdir "$CONFIG_PATH" # || (echo "error creating $CONFIG_PATH: installation aborted"; exit 1) + echo "creating list config file and will ask some questions." + + GPGDIR="$CONFIG_PATH" + + read -p "path to nail command (eg, /usr/bin/nail): " MAIL + read -p "path to gpg binary (eg, /usr/bin/gpg): " GPG + + # if [ ! -x $GPG ]; then + + read -p "list keyring folder (defaults to $GPGDIR): " GPGDIR + + # todo: please no utf-8 (see DETAILS) + read -p "list email (eg, firma@domain.tld): " LISTNAME + read -p "list admins emails (space delimited)" LISTADMIN + read -p "password for list keyring (use a huge one): " PASSWD + + # todo: key specs (size, expiry date...) + + echo "creating your config..." + touch $CONFIG + chown root.root $CONFIG + chmod 600 $CONFIG + if [ -f $CONFIG ]; then + echo -e "MAIL=$MAIL\nGPG=$GPG\nGPGDIR=$GPGDIR\nLISTNAME=$LISTNAME\nLISTADMIN=$LISTADMIN\nPASSWD=$PASSWD" > $CONFIG + echo "now generating your keyring..." + # re-eval GPGCOMMAND + # todo: GPGFLAGS depende de GPGDIR + GPGCOMMAND="$GPG $GPGFLAGS" + $GPGCOMMAND --gen-key + + fi + else + echo error creating $CONFIG_FILE: list already exists + exit 1 + fi +} + +# main - +# command line checking +if [ -z $2 ]; then + usage; exit 1 +else + CONFIG_FILE="$2" + CONFIG_PATH="$FIRMA_LIST_PATH/$2" + CONFIG="$CONFIG_PATH/$2.conf" +fi + +# if the configuration file exists, disable "sourcepath" and evaluate the parameters +if [ -f $CONFIG ] && [[ $1 != "-c" ]]; then + shopt -u sourcepath && source $CONFIG +else + echo -e "\nConfiguration file \"$CONFIG\" could not be found.\n" + exit 1 +fi + +declare -a MESSAGE +declare -a GPG_MESSAGE +declare n +export LANG=en_US + +# declare GPG variables +GPGFLAGS="--quiet --homedir $GPGDIR --batch --no-tty --no-use-agent --no-permission-warning" +GPGCOMMAND="$GPG $GPGFLAGS" +GPGLIST="$GPGCOMMAND --list-keys --with-colons" +GPGDECRYPT="$GPGCOMMAND --passphrase-fd 0 --decrypt" +GPGENCRYPT="$GPGCOMMAND --passphrase-fd 0 --always-trust --encrypt --sign --armor --recipient" + +# then check the config +check_config + +# command line parsing +if [[ $1 == "-c" ]]; then + newlist +elif [[ $1 == "-p" ]]; then + process_message +elif [[ $1 == "-a" ]]; then + list_admin +elif [[ $1 == "-r" ]]; then + list_request +else + usage; exit 1 +fi + |