aboutsummaryrefslogtreecommitdiff
path: root/misc/poc/firma-0.2.3
blob: 286411536c524fa7ca8b574c349bdeb1f6a8b984 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#!/bin/bash
#
# firma v0.2.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
# TMP= where you want the temp files
# LISTNAME= list email
# LISTADMIN= list administrator email addresses (space separated)
# GPGDIR= gpg dir for the lists' keyring
# PASSWD= passwd for the lists' keyring
#

VERSION=0.2.3

function usage {
  echo usage: $0 firma \<option\> \<config-file\>
  echo -c: create a new list using config-file
  echo -p: process a message 
  echo -a: admin commands
}

function check_config {
  # check configuration file parameters
  # todo: check if $TMP directory/files exist
  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 $PASSWD | ($GPGDECRYPT --status-fd 2 $TMP.gpg 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 process_message {
  # process a message sent to the list

  # create the temporary files and restrict their permissions
  rm -f $TMP $TMP.gpg
  touch $TMP && chmod 600 $TMP
  touch $TMP.gpg && chmod 600 $TMP.gpg
  
  # todo: use an array
  while read STDIN; do
    echo $STDIN >> $TMP
  done
  
  # get the message headers and the sender's email address
  FROM=$(grep -m 1 ^From: $TMP | 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=$(grep -m 1 ^Date: $TMP)
  SUBJECT=$(grep -m 1 ^Subject: $TMP | cut -d : -f 2- | sed -e 's/^ //')
  
  # get the encrypted message
  sed -ne '/-----BEGIN PGP MESSAGE-----/,/-----END PGP MESSAGE-----/p' $TMP >> $TMP.gpg
  
  # 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 
  
      echo "$PASSWD
    Message from: $FROM
    Subject: $SUBJECT
    $DATE
  
    $(GPGSTDERR | grep -F 'gpg: Signature made')
    $(GPGSTDERR | grep -F 'gpg: Good signature from')
  
  $(echo $PASSWD | $GPGDECRYPT $TMP.gpg 2> /dev/null)" | sed -e 's/=20$//' | $GPGENCRYPT $EMAIL | $MAIL -r $LISTNAME $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
  
      echo "$PASSWD
    Message from: $FROM
    Subject: [BAD SIGNATURE] $SUBJECT
    $DATE
  
    $(GPGSTDERR | grep -F 'gpg: Signature made')
    $(GPGSTDERR | grep -F 'gpg: BAD signature from')
  
  $(echo $PASSWD | $GPGDECRYPT $TMP.gpg 2> /dev/null)" | sed -e 's/=20$//' | $GPGENCRYPT $EMAIL | $MAIL -r $LISTNAME $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
  
      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 $FROMADD
  
  fi
   
  rm -f $TMP $TMP.gpg
  
}

# main -
# command line checking
if [ -z $2 ]; then
  usage; exit 1
else
  CONFIG=$2
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 GPG variables
GPGCOMMAND="$GPG --quiet --homedir $GPGDIR --batch --no-tty --no-use-agent --no-permission-warning"
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
  admin_task
else
  usage; exit 1
fi