andrejpodzimek

Simple IMAP client (STARTTLS + cram-sha256) with Bash and OpenSSL

Dec 11th, 2022 (edited)
177
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 2.84 KB | None | 0 0
  1. #!/bin/bash
  2. set -euo pipefail
  3.  
  4. ################################################################################
  5. ## Fill this in!                                                              ##
  6. ################################################################################
  7. declare -r server='your.server.name'            # server to connect to
  8. declare -ri port='143'                          # IMAP with STARTTLS == 143
  9. declare -r username='someone@your.server.name'  # some servers use only someone
  10. declare -r password='your.clear.text.password'  # used for authentication
  11. declare -r hash='sha256'                        # md5, sha1, sha256
  12. ################################################################################
  13.  
  14. # This is taken from here: https://www.atmail.com/blog/advanced-imap/
  15. respond_to_challenge() {
  16.   local digest _
  17.   read _ digest < <(openssl base64 -d <<< "$1" |
  18.                     openssl dgst "-${hash}" -hmac "$password")
  19.   printf '%s %s' "$username" "$digest" | openssl base64 -A
  20.   echo
  21. }
  22.  
  23. tmpdir=$(mktemp -d)
  24. declare -r tmpdir
  25. declare -a pids
  26. trap 'rm -Rf "$tmpdir"; ((${#pids[@]})) && kill -9 "${pids[@]/#/-}" || :;' EXIT
  27.  
  28. declare -r input="${tmpdir}/imap_server_input"
  29. declare -r output="${tmpdir}/imap_server_output"
  30. declare -r value_fifo="${tmpdir}/value_fifo"
  31. mkfifo "$input" "$output" "$value_fifo"
  32.  
  33. # Start the OpenSSL client to connect to the IMAP server.
  34. openssl s_client -starttls imap -crlf -connect "${server}:$((port))" \
  35.     <"$input" >"$output" 2>/dev/null&
  36. pids+=("$!")
  37.  
  38. # Start the IMAP server input writer.
  39. {
  40.   echo "1 authenticate cram-${hash}"
  41.   respond_to_challenge "$(< "$value_fifo")"
  42.   [[ "$(< "$value_fifo")" == 'OK' ]]
  43.   echo '2 list "" "*"'
  44.   [[ "$(< "$value_fifo")" == 'OK' ]]
  45.   echo '3 select INBOX'
  46.   [[ "$(< "$value_fifo")" == 'OK' ]]
  47.   echo '4 status INBOX (MESSAGES)'
  48.   [[ "$(< "$value_fifo")" == 'OK' ]]
  49.   echo '5 logout'
  50.   [[ "$(< "$value_fifo")" == 'OK' ]]
  51. } | tee "$input" &
  52. pids+=("$!")
  53.  
  54. declare -r color_default=$'\033[00m'
  55. declare -r color_yellow=$'\033[01;33m'
  56.  
  57. # Start the IMAP server output reader.
  58. {
  59.   expected_prefixes=('+' '1' '2' '3' '4' '5')
  60.   output() { :; }
  61.   for expected in "${expected_prefixes[@]}"; do
  62.     prefix=
  63.     while read prefix value rest; do
  64.       prefix="${prefix%$'\r'}"
  65.       value="${value%$'\r'}"
  66.       rest="${rest%$'\r'}"
  67.       [[ "$prefix" != "$expected" ]] || break
  68.       output "$prefix" "$value" "$rest"
  69.     done
  70.     [[ "$prefix" == "$expected" ]]
  71.     output() {
  72.       printf "${color_yellow}%s %s %s${color_default}\n" "$1" "$2" "$3"
  73.     }
  74.     output "$prefix" "$value" "$rest"
  75.     printf '%s' "$value" > "$value_fifo"
  76.   done
  77.   cat >/dev/null
  78. } <"$output" &
  79. pids+=("$!")
  80.  
  81. declare -i errors=0 idx
  82. for idx in "${!pids[@]}"; do
  83.   pid="${pids[idx]}"
  84.   unset 'pids[idx]'
  85.   wait -n "$pid" || ((++errors))
  86. done
  87. ((! errors))
  88.  
Add Comment
Please, Sign In to add comment