commit 63ed8f2480c7e42f04a1a9edd4d6a2287074c9ad
parent b89665a20ce042d69e3834750e5b654eef7cbc90
Author: Jaromil <jaromil@dyne.org>
Date:   Sun, 22 Mar 2015 23:38:01 +0100
remember fingerprint of known smtp servers
Diffstat:
4 files changed, 70 insertions(+), 25 deletions(-)
diff --git a/src/jaro b/src/jaro
@@ -63,6 +63,7 @@ fi
 WORKDIR=${JAROWORKDIR:-$WORKDIR}
 
 # load our zuper extension
+zkv=1
 source $WORKDIR/zlibs/zuper
 
 
@@ -130,6 +131,9 @@ vars+=(name login imap imap_port smtp smtp_port protocol password auth accountop
 typeset -ah folders exclude
 vars+=(host port type)
 
+# global for server fingerprints
+vars+=(fingerprint)
+
 # global variables for addressbook
 vars+=(hostname addressbook addressbook_tmp)
 
@@ -826,5 +830,5 @@ main() {
 
 check_bin
 main $@
-endgame NOERRORS
-#return $exitcode
+# endgame NOERRORS
+# return $exitcode
diff --git a/src/zlibs/email b/src/zlibs/email
@@ -263,6 +263,10 @@ fetch() {
 ################################################
 # read an email from stdin and send it via msmtp 
 smtp_send() {
+    fn smtp-send
+    req=(account)
+    ckreq
+
     read_account ${account}
     { test  $? != 0 } && {
         error "Invalid account: $account"
@@ -279,6 +283,42 @@ smtp_send() {
     host=$smtp
     port=$smtp_port
 
+    # load known fingerprints
+    typeset -A smtp_fingerprints
+    [[ -s $MAILDIRS/smtp_fingerprints.zkv ]] && {
+        zkv.load $MAILDIRS/smtp_fingerprints.zkv }
+    known_fingerprint=${smtp_fingerprints[$smtp:$port]}
+    # get the server's fingerprint
+    print QUIT \
+        | openssl s_client -starttls smtp \
+        -connect $smtp:$smtp_port \
+        -showcerts 2>/dev/null \
+        | openssl x509 -fingerprint -md5 -noout \
+        | awk -F '=' '/Fingerprint/ {print $2}' | sysread fingerprint
+    fingerprint=$(print $fingerprint | trim)
+    # force printing fingerprint to stderr
+    oldquiet=$QUIET
+    QUIET=0
+    act "known  fingerprint: $known_fingerprint"
+    act "server fingerprint: $fingerprint"
+    [[ "$known_fingerprint" = "$fingerprint" ]] || {
+        warning "fingerprint difference detected"
+        # not the same?
+        if [[ "$known_fingerprint" = "" ]]; then
+            # never knew before, save it
+            act "$smtp:$port new fingerprint acknowledged"
+            smtp_fingerprints[$smtp:$port]="$fingerprint"
+        else
+            error "Server fingerprint mismatch!"
+            warning "The known one was different, this may be a man in the middle!"
+            warning "To override and forget the old one, edit $MAILDIRS/smtp_fingerprints.zkv"
+            return 1
+        fi
+    }
+    QUIET=$oldquiet
+
+    zkv.save smtp_fingerprints $MAILDIRS/smtp_fingerprints.zkv
+    
     ask_password
     [[ $? = 0 ]] || {
         error "Error retrieving password for $login on $smtp"
diff --git a/src/zlibs/helpers b/src/zlibs/helpers
@@ -353,7 +353,7 @@ human_size() {
 
 
 # TODO: save fingeprints of servers and check connections
-fingerprint() {
+get-smtp-fingerprint() {
 # dyne.org one:
 # tls_fingerprint 6A:D4:DF:E4:20:32:F9:66:94:35:0C:33:9D:74:96:5C
 
@@ -370,7 +370,7 @@ fingerprint() {
         -connect $smtp:$smtp_port \
         -showcerts 2>/dev/null \
         | openssl x509 -fingerprint -md5 -noout \
-        | awk -F '=' '/^MD5 Fingerprint/ {print $2}'
+        | awk -F '=' '/Fingerprint/ {print $2}' | sysread fingerprint
 
 }
 
diff --git a/src/zlibs/zuper b/src/zlibs/zuper
@@ -24,11 +24,15 @@
 ##########################
 typeset -aU vars
 typeset -aU arrs
-vars=(debug quiet ztmpfile)
-arrs=()
+vars=(DEBUG QUIET ztmpfile)
+arrs=(req freq)
 
-debug=${debug:-0}
-quiet=${quiet:-0}
+# reset list of destructors
+destruens=()
+
+# global execution flags
+DEBUG=${DEBUG:-0}
+QUIET=${QUIET:-0}
 
 vars+=(zuper_version)
 zuper_version=0.1
@@ -93,48 +97,39 @@ function _msg() {
 function _message say act() {
     local notice="message"
     [[ "$1" = "-n" ]] && shift && notice="inline"
-    [[ $quiet = 1 ]] || _msg "$notice" $@
+    [[ $QUIET = 1 ]] || _msg "$notice" $@
     return 0
 }
 
 function _verbose xxx func() {
-    [[ $debug = 1 ]] && _msg verbose $@
+    [[ $DEBUG = 1 ]] && _msg verbose $@
     return 0
 }
 
 function _success yes notice() {
-    [[ $quiet = 1 ]] || _msg success $@
+    [[ $QUIET = 1 ]] || _msg success $@
     return 0
 }
 
 function _warning no warn warning() {
-    [[ $quiet = 1 ]] || _msg warning $@
+    [[ $QUIET = 1 ]] || _msg warning $@
     return 0
 }
 
 function _failure fatal die error() {
     #    typeset -i exitcode=${exitv:-1}
-    [[ $quiet = 1 ]] || _msg failure $@
+    [[ $QUIET = 1 ]] || _msg failure $@
     return 1
 }
 
 function _print() {
-    [[ $quiet = 1 ]] || _msg print $@
+    [[ $QUIET = 1 ]] || _msg print $@
     return 0
 }
 
 
-
 fn() {
-    local msg="$1"
-    command -v gettext 1>/dev/null 2>/dev/null \
-        && msg="$(gettext -s "$1")"
-    for i in $(seq 2 ${#}); do
-        msg=${(S)msg//::$(($i - 1))*::/$*[$i]}
-    done
-    
-    fun="$msg"
-    func "$fun"
+    fun="$@"
     req=()
     freq=()
 }
@@ -181,7 +176,10 @@ zdump() {
     done
 }
 
-
+# handy wrappers for throw/catch execution of blocks where we need the
+# program to exit on any error (non-zero) returned by any function
+throw() { function TRAPZERR() { zerr; return 1 } }
+catch() { function TRAPZERR() { } }
 
 ##########################
 # Endgame handling
@@ -215,6 +213,9 @@ endgame() {
     return 0
 }
 
+# Register endgame() to be called at exit.
+# unlike TRAPEXIT, the zshexit() hook is not called when functions exit.
+zshexit() { endgame EXIT; return $? }
 
 ##########################
 # Temp file handling