]> gitweb.fluxo.info Git - firma.git/commitdiff
firma devel release
authorrhatto <rhatto>
Thu, 23 Jun 2005 01:21:41 +0000 (01:21 +0000)
committerrhatto <rhatto>
Thu, 23 Jun 2005 01:21:41 +0000 (01:21 +0000)
firma [new file with mode: 0755]

diff --git a/firma b/firma
new file mode 100755 (executable)
index 0000000..126f998
--- /dev/null
+++ b/firma
@@ -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