freedombone-sec 26KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951
  1. #!/bin/bash
  2. #
  3. # .---. . .
  4. # | | |
  5. # |--- .--. .-. .-. .-.| .-. .--.--. |.-. .-. .--. .-.
  6. # | | (.-' (.-' ( | ( )| | | | )( )| | (.-'
  7. # ' ' --' --' -' - -' ' ' -' -' -' ' - --'
  8. #
  9. # Freedom in the Cloud
  10. #
  11. # Alters the security settings
  12. #
  13. # License
  14. # =======
  15. #
  16. # Copyright (C) 2015-2016 Bob Mottram <bob@robotics.uk.to>
  17. #
  18. # This program is free software: you can redistribute it and/or modify
  19. # it under the terms of the GNU Affero General Public License as published by
  20. # the Free Software Foundation, either version 3 of the License, or
  21. # (at your option) any later version.
  22. #
  23. # This program is distributed in the hope that it will be useful,
  24. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  25. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  26. # GNU Affero General Public License for more details.
  27. #
  28. # You should have received a copy of the GNU Affero General Public License
  29. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  30. PROJECT_NAME='freedombone'
  31. export TEXTDOMAIN=${PROJECT_NAME}-sec
  32. export TEXTDOMAINDIR="/usr/share/locale"
  33. CONFIGURATION_FILE=/root/${PROJECT_NAME}.cfg
  34. COMPLETION_FILE=$HOME/${PROJECT_NAME}-completed.txt
  35. SSL_PROTOCOLS=
  36. SSL_CIPHERS=
  37. SSH_CIPHERS=
  38. SSH_MACS=
  39. SSH_KEX=
  40. SSH_HOST_KEY_ALGORITHMS=
  41. SSH_PASSWORDS=
  42. XMPP_CIPHERS=
  43. XMPP_ECC_CURVE=
  44. WEBSITES_DIRECTORY='/etc/nginx/sites-available'
  45. DOVECOT_CIPHERS='/etc/dovecot/conf.d/10-ssl.conf'
  46. SSH_CONFIG='/etc/ssh/sshd_config'
  47. XMPP_CONFIG='/etc/prosody/conf.avail/xmpp.cfg.lua'
  48. MINIMUM_LENGTH=6
  49. IMPORT_FILE=
  50. EXPORT_FILE=
  51. CURRENT_DIR=$(pwd)
  52. REGENERATE_SSH_HOST_KEYS="no"
  53. REGENERATE_DH_KEYS="no"
  54. DH_KEYLENGTH=2048
  55. LETSENCRYPT_SERVER='https://acme-v01.api.letsencrypt.org/directory'
  56. MY_USERNAME=
  57. if grep -q "MY_USERNAME" $CONFIGURATION_FILE; then
  58. MY_USERNAME=$(grep "MY_USERNAME" $CONFIGURATION_FILE | awk -F '=' '{print $2}')
  59. fi
  60. function get_protocols_from_website {
  61. if [ ! -f $WEBSITES_DIRECTORY/$1 ]; then
  62. return
  63. fi
  64. SSL_PROTOCOLS=$(cat $WEBSITES_DIRECTORY/$1 | grep 'ssl_protocols ' | awk -F "ssl_protocols " '{print $2}' | awk -F ';' '{print $1}')
  65. }
  66. function get_ciphers_from_website {
  67. if [ ! -f $WEBSITES_DIRECTORY/$1 ]; then
  68. return
  69. fi
  70. SSL_CIPHERS=$(cat $WEBSITES_DIRECTORY/$1 | grep 'ssl_ciphers ' | awk -F "ssl_ciphers " '{print $2}' | awk -F "'" '{print $2}')
  71. }
  72. function get_website_settings {
  73. if [ ! -d $WEBSITES_DIRECTORY ]; then
  74. return
  75. fi
  76. cd $WEBSITES_DIRECTORY
  77. for file in `dir -d *` ; do
  78. get_protocols_from_website $file
  79. if [ ${#SSL_PROTOCOLS} -gt $MINIMUM_LENGTH ]; then
  80. get_ciphers_from_website $file
  81. if [ ${#SSL_CIPHERS} -gt $MINIMUM_LENGTH ]; then
  82. break
  83. else
  84. SSL_PROTOCOLS=""
  85. fi
  86. fi
  87. done
  88. }
  89. function get_imap_settings {
  90. if [ ! -f $DOVECOT_CIPHERS ]; then
  91. return
  92. fi
  93. # clear commented out cipher list
  94. sed -i "s|#ssl_cipher_list.*||g" $DOVECOT_CIPHERS
  95. if [ $SSL_CIPHERS ]; then
  96. return
  97. fi
  98. if [ ${#SSL_CIPHERS} -gt $MINIMUM_LENGTH ]; then
  99. return
  100. fi
  101. SSL_CIPHERS=$(cat $DOVECOT_CIPHERS | grep 'ssl_cipher_list' | awk -F '=' '{print $2}' | awk -F "'" '{print $2}')
  102. }
  103. function get_xmpp_settings {
  104. if [ ! -f $XMPP_CONFIG ]; then
  105. return
  106. fi
  107. XMPP_CIPHERS=$(cat $XMPP_CONFIG | grep 'ciphers ' | awk -F '=' '{print $2}' | awk -F '"' '{print $2}')
  108. XMPP_ECC_CURVE=$(cat $XMPP_CONFIG | grep 'curve ' | awk -F '=' '{print $2}' | awk -F '"' '{print $2}')
  109. }
  110. function get_ssh_settings {
  111. if [ -f $SSH_CONFIG ]; then
  112. SSH_CIPHERS=$(cat $SSH_CONFIG | grep 'Ciphers ' | awk -F 'Ciphers ' '{print $2}')
  113. SSH_MACS=$(cat $SSH_CONFIG | grep 'MACs ' | awk -F 'MACs ' '{print $2}')
  114. SSH_KEX=$(cat $SSH_CONFIG | grep 'KexAlgorithms ' | awk -F 'KexAlgorithms ' '{print $2}')
  115. SSH_PASSWORDS=$(cat $SSH_CONFIG | grep 'PasswordAuthentication ' | awk -F 'PasswordAuthentication ' '{print $2}')
  116. fi
  117. if [ -f /etc/ssh/ssh_config ]; then
  118. SSH_HOST_KEY_ALGORITHMS=$(cat /etc/ssh/ssh_config | grep 'HostKeyAlgorithms ' | awk -F 'HostKeyAlgorithms ' '{print $2}')
  119. if [ ! $SSH_CIPHERS ]; then
  120. SSH_CIPHERS=$(cat /etc/ssh/ssh_config | grep 'Ciphers ' | awk -F 'Ciphers ' '{print $2}')
  121. fi
  122. if [ ! $SSH_MACS ]; then
  123. SSH_MACS=$(cat /etc/ssh/ssh_config | grep 'MACs ' | awk -F 'MACs ' '{print $2}')
  124. fi
  125. fi
  126. }
  127. function change_website_settings {
  128. if [ ! "$SSL_PROTOCOLS" ]; then
  129. return
  130. fi
  131. if [ ! $SSL_CIPHERS ]; then
  132. return
  133. fi
  134. if [ ${#SSL_PROTOCOLS} -lt $MINIMUM_LENGTH ]; then
  135. return
  136. fi
  137. if [ ${#SSL_CIPHERS} -lt $MINIMUM_LENGTH ]; then
  138. return
  139. fi
  140. if [ ! -d $WEBSITES_DIRECTORY ]; then
  141. return
  142. fi
  143. cd $WEBSITES_DIRECTORY
  144. for file in `dir -d *` ; do
  145. sed -i "s|ssl_protocols .*|ssl_protocols $SSL_PROTOCOLS;|g" $WEBSITES_DIRECTORY/$file
  146. sed -i "s|ssl_ciphers .*|ssl_ciphers '$SSL_CIPHERS';|g" $WEBSITES_DIRECTORY/$file
  147. done
  148. systemctl restart nginx
  149. echo $'Web security settings changed'
  150. }
  151. function change_imap_settings {
  152. if [ ! -f $DOVECOT_CIPHERS ]; then
  153. return
  154. fi
  155. if [ ! $SSL_CIPHERS ]; then
  156. return
  157. fi
  158. if [ ${#SSL_CIPHERS} -lt $MINIMUM_LENGTH ]; then
  159. return
  160. fi
  161. sed -i "s|ssl_cipher_list.*|ssl_cipher_list = '$SSL_CIPHERS'|g" $DOVECOT_CIPHERS
  162. sed -i "s|ssl_protocols.*|ssl_protocols = '$SSL_PROTOCOLS'|g" $DOVECOT_CIPHERS
  163. systemctl restart dovecot
  164. echo $'imap security settings changed'
  165. }
  166. function change_ssh_settings {
  167. if [ -f /etc/ssh/ssh_config ]; then
  168. if [ $SSH_HOST_KEY_ALGORITHMS ]; then
  169. sed -i "s|HostKeyAlgorithms .*|HostKeyAlgorithms $SSH_HOST_KEY_ALGORITHMS|g" /etc/ssh/ssh_config
  170. echo $'ssh client security settings changed'
  171. fi
  172. fi
  173. if [ -f $SSH_CONFIG ]; then
  174. if [ ! $SSH_CIPHERS ]; then
  175. return
  176. fi
  177. if [ ! $SSH_MACS ]; then
  178. return
  179. fi
  180. if [ ! $SSH_KEX ]; then
  181. return
  182. fi
  183. if [ ! $SSH_PASSWORDS ]; then
  184. return
  185. fi
  186. sed -i "s|Ciphers .*|Ciphers $SSH_CIPHERS|g" $SSH_CONFIG
  187. sed -i "s|MACs .*|MACs $SSH_MACS|g" $SSH_CONFIG
  188. sed -i "s|KexAlgorithms .*|KexAlgorithms $SSH_KEX|g" $SSH_CONFIG
  189. sed -i "s|PasswordAuthentication .*|PasswordAuthentication $SSH_PASSWORDS|g" $SSH_CONFIG
  190. systemctl restart ssh
  191. echo $'ssh server security settings changed'
  192. fi
  193. }
  194. function change_xmpp_settings {
  195. if [ ! -f $XMPP_CONFIG ]; then
  196. return
  197. fi
  198. if [ ! $XMPP_CIPHERS ]; then
  199. return
  200. fi
  201. if [ ! $XMPP_ECC_CURVE ]; then
  202. return
  203. fi
  204. sed -i "s|ciphers =.*|ciphers = \"$XMPP_CIPHERS\";|g" $XMPP_CONFIG
  205. sed -i "s|curve =.*|curve = \"$XMPP_ECC_CURVE\";|g" $XMPP_CONFIG
  206. systemctl restart prosody
  207. echo $'xmpp security settings changed'
  208. }
  209. function interactive_setup {
  210. if [ $SSL_CIPHERS ]; then
  211. data=$(tempfile 2>/dev/null)
  212. trap "rm -f $data" 0 1 2 5 15
  213. dialog --backtitle $"Freedombone Security Configuration" \
  214. --form $"\nWeb/IMAP Ciphers:" 10 95 2 \
  215. $"Protocols:" 1 1 "$SSL_PROTOCOLS" 1 15 90 90 \
  216. $"Ciphers:" 2 1 "$SSL_CIPHERS" 2 15 90 512 \
  217. 2> $data
  218. sel=$?
  219. case $sel in
  220. 1) SSL_PROTOCOLS=$(cat $data | sed -n 1p)
  221. SSL_CIPHERS=$(cat $data | sed -n 2p)
  222. ;;
  223. 255) exit 0;;
  224. esac
  225. fi
  226. data=$(tempfile 2>/dev/null)
  227. trap "rm -f $data" 0 1 2 5 15
  228. if [ $SSH_HOST_KEY_ALGORITHMS ]; then
  229. dialog --backtitle $"Freedombone Security Configuration" \
  230. --form $"\nSecure Shell Ciphers:" 13 95 4 \
  231. $"Ciphers:" 1 1 "$SSH_CIPHERS" 1 15 90 512 \
  232. $"MACs:" 2 1 "$SSH_MACS" 2 15 90 512 \
  233. $"KEX:" 3 1 "$SSH_KEX" 3 15 90 512 \
  234. $"Host key algorithms:" 4 1 "$SSH_HOST_KEY_ALGORITHMS" 4 15 90 512 \
  235. 2> $data
  236. sel=$?
  237. case $sel in
  238. 1) SSH_CIPHERS=$(cat $data | sed -n 1p)
  239. SSH_MACS=$(cat $data | sed -n 2p)
  240. SSH_KEX=$(cat $data | sed -n 3p)
  241. SSH_HOST_KEY_ALGORITHMS=$(cat $data | sed -n 4p)
  242. ;;
  243. 255) exit 0;;
  244. esac
  245. else
  246. dialog --backtitle $"Freedombone Security Configuration" \
  247. --form $"\nSecure Shell Ciphers:" 11 95 3 \
  248. $"Ciphers:" 1 1 "$SSH_CIPHERS" 1 15 90 512 \
  249. $"MACs:" 2 1 "$SSH_MACS" 2 15 90 512 \
  250. $"KEX:" 3 1 "$SSH_KEX" 3 15 90 512 \
  251. 2> $data
  252. sel=$?
  253. case $sel in
  254. 1) SSH_CIPHERS=$(cat $data | sed -n 1p)
  255. SSH_MACS=$(cat $data | sed -n 2p)
  256. SSH_KEX=$(cat $data | sed -n 3p)
  257. ;;
  258. 255) exit 0;;
  259. esac
  260. fi
  261. if [[ $SSH_PASSWORDS == "yes" ]]; then
  262. dialog --title $"SSH Passwords" \
  263. --backtitle $"Freedombone Security Configuration" \
  264. --yesno $"\nAllow SSH login using passwords?" 7 60
  265. else
  266. dialog --title $"SSH Passwords" \
  267. --backtitle $"Freedombone Security Configuration" \
  268. --defaultno \
  269. --yesno $"\nAllow SSH login using passwords?" 7 60
  270. fi
  271. sel=$?
  272. case $sel in
  273. 0) SSH_PASSWORDS="yes";;
  274. 1) SSH_PASSWORDS="no";;
  275. 255) exit 0;;
  276. esac
  277. if [ $XMPP_CIPHERS ]; then
  278. data=$(tempfile 2>/dev/null)
  279. trap "rm -f $data" 0 1 2 5 15
  280. dialog --backtitle $"Freedombone Security Configuration" \
  281. --form $"\nXMPP Ciphers:" 10 95 2 \
  282. $"Ciphers:" 1 1 "$XMPP_CIPHERS" 1 15 90 512 \
  283. $"ECC Curve:" 2 1 "$XMPP_ECC_CURVE" 2 15 50 50 \
  284. 2> $data
  285. sel=$?
  286. case $sel in
  287. 1) XMPP_CIPHERS=$(cat $data | sed -n 1p)
  288. XMPP_ECC_CURVE=$(cat $data | sed -n 2p)
  289. ;;
  290. 255) exit 0;;
  291. esac
  292. fi
  293. dialog --title $"Final Confirmation" \
  294. --backtitle $"Freedombone Security Configuration" \
  295. --defaultno \
  296. --yesno $"\nPlease confirm that you wish your security settings to be changed?\n\nWARNING: any mistakes made in the security settings could compromise your system, so be extra careful when answering 'yes'." 12 60
  297. sel=$?
  298. case $sel in
  299. 1) clear
  300. echo $'Exiting without changing security settings'
  301. exit 0;;
  302. 255) clear
  303. echo $'Exiting without changing security settings'
  304. exit 0;;
  305. esac
  306. clear
  307. }
  308. function regenerate_ssh_host_keys {
  309. if [[ $REGENERATE_SSH_HOST_KEYS == "yes" ]]; then
  310. rm -f /etc/ssh/ssh_host_*
  311. dpkg-reconfigure openssh-server
  312. echo $'ssh host keys regenerated'
  313. # remove small moduli
  314. awk '$5 > 2000' /etc/ssh/moduli > ~/moduli
  315. mv ~/moduli /etc/ssh/moduli
  316. echo $'ssh small moduli removed'
  317. # update monkeysphere
  318. DEFAULT_DOMAIN_NAME=
  319. if grep -q "DEFAULT_DOMAIN_NAME" $CONFIGURATION_FILE; then
  320. DEFAULT_DOMAIN_NAME=$(grep "DEFAULT_DOMAIN_NAME" $CONFIGURATION_FILE | awk -F '=' '{print $2}')
  321. fi
  322. monkeysphere-host import-key /etc/ssh/ssh_host_rsa_key ssh://$DEFAULT_DOMAIN_NAME
  323. SSH_ONION_HOSTNAME=$(cat ${COMPLETION_FILE} | grep 'ssh onion domain' | awk -F ':' '{print $2}')
  324. monkeysphere-host import-key /etc/ssh/ssh_host_rsa_key ssh://$SSH_ONION_HOSTNAME
  325. monkeysphere-host publish-key --all
  326. echo $'updated monkeysphere ssh host key'
  327. systemctl restart ssh
  328. fi
  329. }
  330. function regenerate_dh_keys {
  331. if [[ $REGENERATE_DH_KEYS == "yes" ]]; then
  332. if [ ! -d /etc/ssl/mycerts ]; then
  333. echo $'No dhparam certificates were found'
  334. return
  335. fi
  336. data=$(tempfile 2>/dev/null)
  337. trap "rm -f $data" 0 1 2 5 15
  338. dialog --backtitle "Freedombone Security Configuration" \
  339. --title "Diffie-Hellman key length" \
  340. --radiolist "The smaller length is better suited to low power embedded systems:" 12 40 3 \
  341. 1 "2048 bits" off \
  342. 2 "3072 bits" on \
  343. 3 "4096 bits" off 2> $data
  344. sel=$?
  345. case $sel in
  346. 1) exit 1;;
  347. 255) exit 1;;
  348. esac
  349. case $(cat $data) in
  350. 1) DH_KEYLENGTH=2048;;
  351. 2) DH_KEYLENGTH=3072;;
  352. 3) DH_KEYLENGTH=4096;;
  353. esac
  354. ${PROJECT_NAME}-dhparam --recalc yes -l ${DH_KEYLENGTH}
  355. fi
  356. }
  357. function renew_startssl {
  358. renew_domain=
  359. data=$(tempfile 2>/dev/null)
  360. trap "rm -f $data" 0 1 2 5 15
  361. dialog --title $"Renew a StartSSL certificate" \
  362. --backtitle $"Freedombone Security Settings" \
  363. --inputbox $"Enter the domain name" 8 60 2>$data
  364. sel=$?
  365. case $sel in
  366. 0)
  367. renew_domain=$(<$data)
  368. ;;
  369. esac
  370. if [ ! $renew_domain ]; then
  371. return
  372. fi
  373. if [[ $renew_domain == "http"* ]]; then
  374. dialog --title $"Renew a StartSSL certificate" \
  375. --msgbox $"Don't include the https://" 6 40
  376. return
  377. fi
  378. if [ ! -f /etc/ssl/certs/${renew_domain}.dhparam ]; then
  379. dialog --title $"Renew a StartSSL certificate" \
  380. --msgbox $"An existing certificate for $renew_domain was not found" 6 40
  381. return
  382. fi
  383. if [[ $renew_domain != *"."* ]]; then
  384. dialog --title $"Renew a StartSSL certificate" \
  385. --msgbox $"Invalid domain name: $renew_domain" 6 40
  386. return
  387. fi
  388. ${PROJECT_NAME}-renew-cert -h $renew_domain -p startssl
  389. exit 0
  390. }
  391. function renew_letsencrypt {
  392. renew_domain=
  393. data=$(tempfile 2>/dev/null)
  394. trap "rm -f $data" 0 1 2 5 15
  395. dialog --title $"Renew a Let's Encrypt certificate" \
  396. --backtitle $"Freedombone Security Settings" \
  397. --inputbox $"Enter the domain name" 8 60 2>$data
  398. sel=$?
  399. case $sel in
  400. 0)
  401. renew_domain=$(<$data)
  402. ;;
  403. esac
  404. if [ ! $renew_domain ]; then
  405. return
  406. fi
  407. if [[ $renew_domain == "http"* ]]; then
  408. dialog --title $"Renew a Let's Encrypt certificate" \
  409. --msgbox $"Don't include the https://" 6 40
  410. return
  411. fi
  412. if [ ! -f /etc/ssl/certs/${renew_domain}.dhparam ]; then
  413. dialog --title $"Renew a Let's Encrypt certificate" \
  414. --msgbox $"An existing certificate for $renew_domain was not found" 6 40
  415. return
  416. fi
  417. if [[ $renew_domain != *"."* ]]; then
  418. dialog --title $"Renew a Let's Encrypt certificate" \
  419. --msgbox $"Invalid domain name: $renew_domain" 6 40
  420. return
  421. fi
  422. ${PROJECT_NAME}-renew-cert -h $renew_domain -p 'letsencrypt'
  423. exit 0
  424. }
  425. function create_letsencrypt {
  426. new_domain=
  427. data=$(tempfile 2>/dev/null)
  428. trap "rm -f $data" 0 1 2 5 15
  429. dialog --title $"Create a new Let's Encrypt certificate" \
  430. --backtitle $"Freedombone Security Settings" \
  431. --inputbox $"Enter the domain name" 8 60 2>$data
  432. sel=$?
  433. case $sel in
  434. 0)
  435. new_domain=$(<$data)
  436. ;;
  437. esac
  438. if [ ! $new_domain ]; then
  439. return
  440. fi
  441. if [[ $new_domain == "http"* ]]; then
  442. dialog --title $"Create a new Let's Encrypt certificate" \
  443. --msgbox $"Don't include the https://" 6 40
  444. return
  445. fi
  446. if [[ $new_domain != *"."* ]]; then
  447. dialog --title $"Create a new Let's Encrypt certificate" \
  448. --msgbox $"Invalid domain name: $new_domain" 6 40
  449. return
  450. fi
  451. if [ ! -d /var/www/${new_domain} ]; then
  452. dialog --title $"Create a new Let's Encrypt certificate" \
  453. --msgbox $'Domain not found within /var/www' 6 40
  454. return
  455. fi
  456. ${PROJECT_NAME}-addcert -e $new_domain -s $LETSENCRYPT_SERVER --dhkey $DH_KEYLENGTH
  457. exit 0
  458. }
  459. function update_ciphersuite {
  460. project_filename=/usr/local/bin/${PROJECT_NAME}
  461. if [ ! -f $project_filename ]; then
  462. project_filename=/usr/bin/${PROJECT_NAME}
  463. fi
  464. RECOMMENDED_SSL_CIPHERS=$(cat $project_filename | grep 'SSL_CIPHERS=' | head -n 1 | awk -F '=' '{print $2}' | awk -F '"' '{print $2}')
  465. if [ ! "$RECOMMENDED_SSL_CIPHERS" ]; then
  466. return
  467. fi
  468. if [ ${#RECOMMENDED_SSL_CIPHERS} -lt 5 ]; then
  469. return
  470. fi
  471. RECOMMENDED_SSL_PROTOCOLS=$(cat $project_filename | grep 'SSL_PROTOCOLS=' | head -n 1 | awk -F '=' '{print $2}' | awk -F '"' '{print $2}')
  472. if [ ! "$RECOMMENDED_SSL_PROTOCOLS" ]; then
  473. return
  474. fi
  475. if [ ${#RECOMMENDED_SSL_PROTOCOLS} -lt 5 ]; then
  476. return
  477. fi
  478. RECOMMENDED_SSH_CIPHERS=$(cat $project_filename | grep 'SSH_CIPHERS=' | head -n 1 | awk -F '=' '{print $2}' | awk -F '"' '{print $2}')
  479. if [ ! "$RECOMMENDED_SSH_CIPHERS" ]; then
  480. return
  481. fi
  482. if [ ${#RECOMMENDED_SSH_CIPHERS} -lt 5 ]; then
  483. return
  484. fi
  485. RECOMMENDED_SSH_MACS=$(cat $project_filename | grep 'SSH_MACS=' | head -n 1 | awk -F '=' '{print $2}' | awk -F '"' '{print $2}')
  486. if [ ! "$RECOMMENDED_SSH_MACS" ]; then
  487. return
  488. fi
  489. if [ ${#RECOMMENDED_SSH_MACS} -lt 5 ]; then
  490. return
  491. fi
  492. RECOMMENDED_SSH_KEX=$(cat $project_filename | grep 'SSH_KEX=' | head -n 1 | awk -F '=' '{print $2}' | awk -F '"' '{print $2}')
  493. if [ ! "$RECOMMENDED_SSH_KEX" ]; then
  494. return
  495. fi
  496. if [ ${#RECOMMENDED_SSH_KEX} -lt 5 ]; then
  497. return
  498. fi
  499. cd $WEBSITES_DIRECTORY
  500. for file in `dir -d *` ; do
  501. sed -i "s|ssl_protocols .*|ssl_protocols $RECOMMENDED_SSL_PROTOCOLS;|g" $WEBSITES_DIRECTORY/$file
  502. sed -i "s|ssl_ciphers .*|ssl_ciphers '$RECOMMENDED_SSL_CIPHERS';|g" $WEBSITES_DIRECTORY/$file
  503. done
  504. systemctl restart nginx
  505. sed -i "s|Ciphers .*|Ciphers $RECOMMENDED_SSH_CIPHERS|g" $SSH_CONFIG
  506. sed -i "s|MACs .*|MACs $RECOMMENDED_SSH_MACS|g" $SSH_CONFIG
  507. sed -i "s|KexAlgorithms .*|KexAlgorithms $RECOMMENDED_SSH_KEX|g" $SSH_CONFIG
  508. systemctl restart ssh
  509. dialog --title $"Update ciphersuite" \
  510. --msgbox $"The ciphersuite has been updated to recommended versions" 6 40
  511. exit 0
  512. }
  513. function gpg_pubkey_from_email {
  514. key_owner_username=$1
  515. key_email_address=$2
  516. key_id=
  517. if [[ $key_owner_username != "root" ]]; then
  518. key_id=$(su -c "gpg --list-keys $key_email_address | grep 'pub '" - $key_owner_username | awk -F ' ' '{print $2}' | awk -F '/' '{print $2}')
  519. else
  520. key_id=$(gpg --list-keys $key_email_address | grep 'pub ' | awk -F ' ' '{print $2}' | awk -F '/' '{print $2}')
  521. fi
  522. echo $key_id
  523. }
  524. function enable_monkeysphere {
  525. monkey=
  526. dialog --title $"GPG based authentication" \
  527. --backtitle $"Freedombone Security Configuration" \
  528. --defaultno \
  529. --yesno $"\nEnable GPG based authentication with monkeysphere ?" 7 60
  530. sel=$?
  531. case $sel in
  532. 0) monkey='yes';;
  533. 255) exit 0;;
  534. esac
  535. if [ $monkey ]; then
  536. if [ ! -f /home/$MY_USERNAME/.monkeysphere/authorized_user_ids ]; then
  537. dialog --title $"GPG based authentication" \
  538. --msgbox $"$MY_USERNAME does not currently have any ids within ~/.monkeysphere/authorized_user_ids" 6 40
  539. exit 0
  540. fi
  541. MY_GPG_PUBLIC_KEY_ID=$(gpg_pubkey_from_email "$MY_USERNAME" "$MY_USERNAME@$HOSTNAME")
  542. if [ ${#MY_GPG_PUBLIC_KEY_ID} -lt 4 ]; then
  543. echo $'monkeysphere unable to get GPG key ID for user $MY_USERNAME'
  544. exit 52825
  545. fi
  546. sed -i 's|#AuthorizedKeysFile|AuthorizedKeysFile|g' /etc/ssh/sshd_config
  547. sed -i 's|AuthorizedKeysFile.*|AuthorizedKeysFile /var/lib/monkeysphere/authorized_keys/%u|g' /etc/ssh/sshd_config
  548. monkeysphere-authentication update-users
  549. # The admin user is the identity certifier
  550. fpr=$(gpg --with-colons --fingerprint $MY_GPG_PUBLIC_KEY_ID | grep fpr | head -n 1 | awk -F ':' '{print $10}')
  551. monkeysphere-authentication add-identity-certifier $fpr
  552. monkeysphere-host publish-key --all
  553. else
  554. sed -i 's|#AuthorizedKeysFile|AuthorizedKeysFile|g' /etc/ssh/sshd_config
  555. sed -i 's|AuthorizedKeysFile.*|AuthorizedKeysFile %h/.ssh/authorized_keys|g' /etc/ssh/sshd_config
  556. fi
  557. systemctl restart ssh
  558. if [ $monkey ]; then
  559. dialog --title $"GPG based authentication" \
  560. --msgbox $"GPG based authentication was enabled" 6 40
  561. else
  562. dialog --title $"GPG based authentication" \
  563. --msgbox $"GPG based authentication was disabled" 6 40
  564. fi
  565. exit 0
  566. }
  567. function housekeeping {
  568. cmd=(dialog --separate-output \
  569. --backtitle "Freedombone Security Configuration" \
  570. --title "Housekeeping options" \
  571. --checklist "If you don't need to do any of these things then just press Enter:" 17 76 17)
  572. options=(1 "Regenerate ssh host keys" off
  573. 2 "Regenerate Diffie-Hellman keys" off
  574. 3 "Renew a StartSSL certificate" off
  575. 4 "Update cipersuite" off
  576. 5 "Create a new Let's Encrypt certificate" off
  577. 6 "Renew Let's Encrypt certificate" off
  578. 7 "Enable GPG based authentication (monkeysphere)" off)
  579. choices=$("${cmd[@]}" "${options[@]}" 2>&1 >/dev/tty)
  580. clear
  581. for choice in $choices
  582. do
  583. case $choice in
  584. 1)
  585. REGENERATE_SSH_HOST_KEYS="yes"
  586. ;;
  587. 2)
  588. REGENERATE_DH_KEYS="yes"
  589. ;;
  590. 3)
  591. renew_startssl
  592. ;;
  593. 4)
  594. update_ciphersuite
  595. ;;
  596. 5)
  597. create_letsencrypt
  598. ;;
  599. 6)
  600. renew_letsencrypt
  601. ;;
  602. 7)
  603. enable_monkeysphere
  604. ;;
  605. esac
  606. done
  607. }
  608. function import_settings {
  609. cd $CURRENT_DIR
  610. if [ ! $IMPORT_FILE ]; then
  611. return
  612. fi
  613. if [ ! -f $IMPORT_FILE ]; then
  614. echo $"Import file $IMPORT_FILE not found"
  615. exit 6393
  616. fi
  617. if grep -q "SSL_PROTOCOLS" $IMPORT_FILE; then
  618. TEMP_VALUE=$(grep "SSL_PROTOCOLS" $IMPORT_FILE | awk -F '=' '{print $2}')
  619. if [ ${#TEMP_VALUE} -gt $MINIMUM_LENGTH ]; then
  620. SSL_PROTOCOLS=$TEMP_VALUE
  621. fi
  622. fi
  623. if grep -q "SSL_CIPHERS" $IMPORT_FILE; then
  624. TEMP_VALUE=$(grep "SSL_CIPHERS" $IMPORT_FILE | awk -F '=' '{print $2}')
  625. if [ ${#TEMP_VALUE} -gt $MINIMUM_LENGTH ]; then
  626. SSL_CIPHERS=$TEMP_VALUE
  627. fi
  628. fi
  629. if grep -q "SSH_CIPHERS" $IMPORT_FILE; then
  630. TEMP_VALUE=$(grep "SSH_CIPHERS" $IMPORT_FILE | awk -F '=' '{print $2}')
  631. if [ ${#TEMP_VALUE} -gt $MINIMUM_LENGTH ]; then
  632. SSH_CIPHERS=$TEMP_VALUE
  633. fi
  634. fi
  635. if grep -q "SSH_MACS" $IMPORT_FILE; then
  636. TEMP_VALUE=$(grep "SSH_MACS" $IMPORT_FILE | awk -F '=' '{print $2}')
  637. if [ ${#TEMP_VALUE} -gt $MINIMUM_LENGTH ]; then
  638. SSH_MACS=$TEMP_VALUE
  639. fi
  640. fi
  641. if grep -q "SSH_KEX" $IMPORT_FILE; then
  642. TEMP_VALUE=$(grep "SSH_KEX" $IMPORT_FILE | awk -F '=' '{print $2}')
  643. if [ ${#TEMP_VALUE} -gt $MINIMUM_LENGTH ]; then
  644. SSH_KEX=$TEMP_VALUE
  645. fi
  646. fi
  647. if grep -q "SSH_HOST_KEY_ALGORITHMS" $IMPORT_FILE; then
  648. TEMP_VALUE=$(grep "SSH_HOST_KEY_ALGORITHMS" $IMPORT_FILE | awk -F '=' '{print $2}')
  649. if [ ${#TEMP_VALUE} -gt $MINIMUM_LENGTH ]; then
  650. SSH_HOST_KEY_ALGORITHMS=$TEMP_VALUE
  651. fi
  652. fi
  653. if grep -q "SSH_PASSWORDS" $IMPORT_FILE; then
  654. TEMP_VALUE=$(grep "SSH_PASSWORDS" $IMPORT_FILE | awk -F '=' '{print $2}')
  655. if [[ $TEMP_VALUE == "yes" || $TEMP_VALUE == "no" ]]; then
  656. SSH_PASSWORDS=$TEMP_VALUE
  657. fi
  658. fi
  659. if grep -q "XMPP_CIPHERS" $IMPORT_FILE; then
  660. TEMP_VALUE=$(grep "XMPP_CIPHERS" $IMPORT_FILE | awk -F '=' '{print $2}')
  661. if [ ${#TEMP_VALUE} -gt $MINIMUM_LENGTH ]; then
  662. XMPP_CIPHERS=$TEMP_VALUE
  663. fi
  664. fi
  665. if grep -q "XMPP_ECC_CURVE" $IMPORT_FILE; then
  666. TEMP_VALUE=$(grep "XMPP_ECC_CURVE" $IMPORT_FILE | awk -F '=' '{print $2}')
  667. if [ ${#TEMP_VALUE} -gt 3 ]; then
  668. XMPP_ECC_CURVE=$TEMP_VALUE
  669. fi
  670. fi
  671. }
  672. function export_settings {
  673. if [ ! $EXPORT_FILE ]; then
  674. return
  675. fi
  676. cd $CURRENT_DIR
  677. if [ ! -f $EXPORT_FILE ]; then
  678. if [ "$SSL_PROTOCOLS" ]; then
  679. echo "SSL_PROTOCOLS=$SSL_PROTOCOLS" >> $EXPORT_FILE
  680. fi
  681. if [ $SSL_CIPHERS ]; then
  682. echo "SSL_CIPHERS=$SSL_CIPHERS" >> $EXPORT_FILE
  683. fi
  684. if [ $SSH_CIPHERS ]; then
  685. echo "SSH_CIPHERS=$SSH_CIPHERS" >> $EXPORT_FILE
  686. fi
  687. if [ $SSH_MACS ]; then
  688. echo "SSH_MACS=$SSH_MACS" >> $EXPORT_FILE
  689. fi
  690. if [ $SSH_KEX ]; then
  691. echo "SSH_KEX=$SSH_KEX" >> $EXPORT_FILE
  692. fi
  693. if [ $SSH_HOST_KEY_ALGORITHMS ]; then
  694. echo "SSH_HOST_KEY_ALGORITHMS=$SSH_HOST_KEY_ALGORITHMS" >> $EXPORT_FILE
  695. fi
  696. if [ $SSH_PASSWORDS ]; then
  697. echo "SSH_PASSWORDS=$SSH_PASSWORDS" >> $EXPORT_FILE
  698. fi
  699. if [ $XMPP_CIPHERS ]; then
  700. echo "XMPP_CIPHERS=$XMPP_CIPHERS" >> $EXPORT_FILE
  701. fi
  702. if [ $XMPP_ECC_CURVE ]; then
  703. echo "XMPP_ECC_CURVE=$XMPP_ECC_CURVE" >> $EXPORT_FILE
  704. fi
  705. echo "Security settings exported to $EXPORT_FILE"
  706. exit 0
  707. fi
  708. if [ "$SSL_PROTOCOLS" ]; then
  709. if grep -q "SSL_PROTOCOLS" $EXPORT_FILE; then
  710. sed -i "s|SSL_PROTOCOLS=.*|SSL_PROTOCOLS=$SSL_PROTOCOLS|g" $EXPORT_FILE
  711. else
  712. echo "SSL_PROTOCOLS=$SSL_PROTOCOLS" >> $EXPORT_FILE
  713. fi
  714. fi
  715. if [ $SSL_CIPHERS ]; then
  716. if grep -q "SSL_CIPHERS" $EXPORT_FILE; then
  717. sed -i "s|SSL_CIPHERS=.*|SSL_CIPHERS=$SSL_CIPHERS|g" $EXPORT_FILE
  718. else
  719. echo "SSL_CIPHERS=$SSL_CIPHERS" >> $EXPORT_FILE
  720. fi
  721. fi
  722. if [ $SSH_CIPHERS ]; then
  723. if grep -q "SSH_CIPHERS" $EXPORT_FILE; then
  724. sed -i "s|SSH_CIPHERS=.*|SSH_CIPHERS=$SSH_CIPHERS|g" $EXPORT_FILE
  725. else
  726. echo "SSH_CIPHERS=$SSH_CIPHERS" >> $EXPORT_FILE
  727. fi
  728. fi
  729. if [ $SSH_MACS ]; then
  730. if grep -q "SSH_MACS" $EXPORT_FILE; then
  731. sed -i "s|SSH_MACS=.*|SSH_MACS=$SSH_MACS|g" $EXPORT_FILE
  732. else
  733. echo "SSH_MACS=$SSH_MACS" >> $EXPORT_FILE
  734. fi
  735. fi
  736. if [ $SSH_KEX ]; then
  737. if grep -q "SSH_KEX" $EXPORT_FILE; then
  738. sed -i "s|SSH_KEX=.*|SSH_KEX=$SSH_KEX|g" $EXPORT_FILE
  739. else
  740. echo "SSH_KEX=$SSH_KEX" >> $EXPORT_FILE
  741. fi
  742. fi
  743. if [ $SSH_HOST_KEY_ALGORITHMS ]; then
  744. if grep -q "SSH_HOST_KEY_ALGORITHMS" $EXPORT_FILE; then
  745. sed -i "s|SSH_HOST_KEY_ALGORITHMS=.*|SSH_HOST_KEY_ALGORITHMS=$SSH_HOST_KEY_ALGORITHMS|g" $EXPORT_FILE
  746. else
  747. echo "SSH_HOST_KEY_ALGORITHMS=$SSH_HOST_KEY_ALGORITHMS" >> $EXPORT_FILE
  748. fi
  749. fi
  750. if [ $SSH_PASSWORDS ]; then
  751. if grep -q "SSH_PASSWORDS" $EXPORT_FILE; then
  752. sed -i "s|SSH_PASSWORDS=.*|SSH_PASSWORDS=$SSH_PASSWORDS|g" $EXPORT_FILE
  753. else
  754. echo "SSH_PASSWORDS=$SSH_PASSWORDS" >> $EXPORT_FILE
  755. fi
  756. fi
  757. if [ $XMPP_CIPHERS ]; then
  758. if grep -q "XMPP_CIPHERS" $EXPORT_FILE; then
  759. sed -i "s|XMPP_CIPHERS=.*|XMPP_CIPHERS=$XMPP_CIPHERS|g" $EXPORT_FILE
  760. else
  761. echo "XMPP_CIPHERS=$XMPP_CIPHERS" >> $EXPORT_FILE
  762. fi
  763. fi
  764. if [ $XMPP_ECC_CURVE ]; then
  765. if grep -q "XMPP_ECC_CURVE" $EXPORT_FILE; then
  766. sed -i "s|XMPP_ECC_CURVE=.*|XMPP_ECC_CURVE=$XMPP_ECC_CURVE|g" $EXPORT_FILE
  767. else
  768. echo "XMPP_ECC_CURVE=$XMPP_ECC_CURVE" >> $EXPORT_FILE
  769. fi
  770. fi
  771. echo $"Security settings exported to $EXPORT_FILE"
  772. exit 0
  773. }
  774. function refresh_gpg_keys {
  775. for d in /home/*/ ; do
  776. USERNAME=$(echo "$d" | awk -F '/' '{print $3}')
  777. if [[ $USERNAME != "git" && $USERNAME != "mirrors" && $USERNAME != "sync" ]]; then
  778. su -c 'gpg --refresh-keys' - $USERNAME
  779. fi
  780. done
  781. exit 0
  782. }
  783. function register_website {
  784. domain="$1"
  785. if [[ ${domain} == *".local" ]]; then
  786. echo $"Can't register local domains"
  787. exit 82438
  788. fi
  789. if [ ! -f /etc/ssl/private/${domain}.key ]; then
  790. echo $"No SSL/TLS private key found for ${domain}"
  791. exit 62852
  792. fi
  793. if [ ! -f /etc/nginx/sites-available/${domain} ]; then
  794. echo $"No virtual host found for ${domain}"
  795. exit 25625
  796. fi
  797. monkeysphere-host import-key /etc/ssl/private/${domain}.key https://${domain}
  798. monkeysphere-host publish-key
  799. exit 0
  800. }
  801. function show_help {
  802. echo ''
  803. echo "${PROJECT_NAME}-sec"
  804. echo ''
  805. echo $'Alters the security settings'
  806. echo ''
  807. echo ''
  808. echo $' -h --help Show help'
  809. echo $' -e --export Export security settings to a file'
  810. echo $' -i --import Import security settings from a file'
  811. echo $' -r --refresh Refresh GPG keys for all users'
  812. echo $' --register [domain] Register a https domain with monkeysphere'
  813. echo ''
  814. exit 0
  815. }
  816. # Get the commandline options
  817. while [[ $# > 1 ]]
  818. do
  819. key="$1"
  820. case $key in
  821. -h|--help)
  822. show_help
  823. ;;
  824. # Export settings
  825. -e|--export)
  826. shift
  827. EXPORT_FILE="$1"
  828. ;;
  829. # Export settings
  830. -i|--import)
  831. shift
  832. IMPORT_FILE="$1"
  833. ;;
  834. # Refresh GPG keys
  835. -r|--refresh)
  836. shift
  837. refresh_gpg_keys
  838. ;;
  839. # register a website
  840. --register|--reg|--site)
  841. shift
  842. register_website "$1"
  843. ;;
  844. *)
  845. # unknown option
  846. ;;
  847. esac
  848. shift
  849. done
  850. housekeeping
  851. get_website_settings
  852. get_imap_settings
  853. get_ssh_settings
  854. get_xmpp_settings
  855. import_settings
  856. export_settings
  857. interactive_setup
  858. change_website_settings
  859. change_imap_settings
  860. change_ssh_settings
  861. change_xmpp_settings
  862. regenerate_ssh_host_keys
  863. regenerate_dh_keys
  864. exit 0