freedombone-sec 50KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621
  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-2018 Bob Mottram <bob@freedombone.net>
  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=$HOME/${PROJECT_NAME}.cfg
  34. COMPLETION_FILE=$HOME/${PROJECT_NAME}-completed.txt
  35. UTILS_FILES="/usr/share/${PROJECT_NAME}/utils/${PROJECT_NAME}-utils-*"
  36. for f in $UTILS_FILES
  37. do
  38. source "$f"
  39. done
  40. SSL_PROTOCOLS=
  41. SSL_CIPHERS=
  42. SSH_CIPHERS=
  43. SSH_MACS=
  44. SSH_KEX=
  45. SSH_HOST_KEY_ALGORITHMS=
  46. SSH_PASSWORDS=
  47. XMPP_CIPHERS=
  48. XMPP_ECC_CURVE=
  49. WEBSITES_DIRECTORY='/etc/nginx/sites-available'
  50. DOVECOT_CIPHERS='/etc/dovecot/conf.d/10-ssl.conf'
  51. SSH_CONFIG='/etc/ssh/sshd_config'
  52. XMPP_CONFIG='/etc/prosody/conf.avail/xmpp.cfg.lua'
  53. MINIMUM_LENGTH=6
  54. IMPORT_FILE=
  55. EXPORT_FILE=
  56. CURRENT_DIR=$(pwd)
  57. DH_KEYLENGTH=2048
  58. LETSENCRYPT_SERVER='https://acme-v01.api.letsencrypt.org/directory'
  59. MY_USERNAME=
  60. function ping_enable_disable {
  61. ping_str=$"\\nDo you want to enable other systems to ping this machine?\\n\\nPing may be useful for diagnostic purposes, but for added security you may not want to enable it."
  62. enable_ping="no"
  63. dialog --title $"Enable Ping / ICMP" \
  64. --backtitle $"Freedombone Control Panel" \
  65. --defaultno \
  66. --yesno "$ping_str" 10 60
  67. sel=$?
  68. case $sel in
  69. 0) enable_ping="yes";;
  70. 255) return;;
  71. esac
  72. if [[ $enable_ping == "yes" ]]; then
  73. iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
  74. iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT
  75. echo "0" > /proc/sys/net/ipv4/icmp_echo_ignore_all
  76. else
  77. iptables -D INPUT -p icmp --icmp-type echo-request -j ACCEPT
  78. iptables -D OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT
  79. echo "1" > /proc/sys/net/ipv4/icmp_echo_ignore_all
  80. fi
  81. }
  82. function any_key_verify {
  83. echo ''
  84. read -n1 -rsp $"Press any key to continue or C to check a hash..." key
  85. if [[ "$key" != 'c' && "$key" != 'C' ]]; then
  86. return
  87. fi
  88. data=$(mktemp 2>/dev/null)
  89. dialog --title $"Check tripwire hash" \
  90. --backtitle $"Freedombone Control Panel" \
  91. --inputbox $"Paste your tripwire hash below and it will be checked against the current database" 12 60 2>"$data"
  92. sel=$?
  93. case $sel in
  94. 0)
  95. GIVEN_HASH=$(<"$data")
  96. if [ ${#GIVEN_HASH} -gt 8 ]; then
  97. if [[ "$GIVEN_HASH" == *' '* ]]; then
  98. dialog --title $"Check tripwire" \
  99. --msgbox $"\\nThe hash should not contain any spaces" 10 40
  100. else
  101. DBHASH=$(sha512sum "/var/lib/tripwire/${HOSTNAME}.twd" | awk -F ' ' '{print $1}')
  102. if [[ "$DBHASH" == "$GIVEN_HASH" ]]; then
  103. dialog --title $"Check tripwire" \
  104. --msgbox $"\\nSuccess\\n\\nThe hash you gave matches the current tripwire database" 10 40
  105. else
  106. dialog --title $"Check tripwire" \
  107. --msgbox $"\\nFailed\\n\\nThe hash you gave does not match the current tripwire database. This might be because you reset the tripwire, or there could have been an unauthorised modification of the system" 12 50
  108. fi
  109. fi
  110. fi
  111. ;;
  112. esac
  113. rm -f "$data"
  114. }
  115. function show_tripwire_verification_code {
  116. if [ ! -f "/var/lib/tripwire/${HOSTNAME}.twd" ]; then
  117. return
  118. fi
  119. clear
  120. echo ''
  121. echo $'Tripwire Verification Code'
  122. echo ''
  123. DBHASH=$(sha512sum "/var/lib/tripwire/${HOSTNAME}.twd")
  124. echo -n "$DBHASH" | qrencode -t UTF8
  125. echo ''
  126. echo "$DBHASH"
  127. echo ''
  128. }
  129. function reset_tripwire {
  130. if [ ! -f /usr/bin/reset-tripwire ]; then
  131. echo $'Missing /usr/bin/reset-tripwire'
  132. any_key
  133. return
  134. fi
  135. if [ ! -f "/etc/tripwire/${HOSTNAME}-local.key" ]; then
  136. if [ -f "/etc/tripwire/${PROJECT_NAME}-local.key" ]; then
  137. # shellcheck disable=SC2086
  138. mv /etc/tripwire/${PROJECT_NAME}-local.key /etc/tripwire/${HOSTNAME}-local.key
  139. # shellcheck disable=SC2086
  140. mv /etc/tripwire/${PROJECT_NAME}-site.key /etc/tripwire/${HOSTNAME}-site.key
  141. else
  142. echo $'Error: missing local key'
  143. any_key
  144. return
  145. fi
  146. fi
  147. clear
  148. echo $'Turing off logging...'
  149. "${PROJECT_NAME}-logging" off
  150. echo $'Locking down permissions...'
  151. lockdown_permissions
  152. echo $'Creating configuration...'
  153. echo '
  154. ' | twadmin --create-cfgfile -S "/etc/tripwire/${HOSTNAME}-site.key" /etc/tripwire/twcfg.txt
  155. echo $'Resetting policy...'
  156. echo '
  157. ' | twadmin --create-polfile -S "/etc/tripwire/${HOSTNAME}-site.key" /etc/tripwire/twpol.txt
  158. echo $'Creating tripwire database'
  159. echo '
  160. ' | tripwire --init --cfgfile /etc/tripwire/tw.cfg --polfile /etc/tripwire/tw.pol --dbfile "/var/lib/tripwire/${HOSTNAME}.twd"
  161. echo $'Resetting the Tripwire...'
  162. echo ''
  163. echo '
  164. ' | reset-tripwire
  165. echo ''
  166. # Sometimes nginx fails to restart if matrix is installed
  167. # Restart matrix first
  168. if [ -d /etc/matrix ]; then
  169. systemctl restart matrix
  170. systemctl restart nginx
  171. fi
  172. if [ -f "/var/lib/tripwire/${HOSTNAME}.twd" ]; then
  173. show_tripwire_verification_code
  174. echo $'Tripwire is now reset. Take a note of the above hash, or record'
  175. echo $'the QR code using a mobile device. This will enable you to independently'
  176. echo $'verify the integrity of the tripwire.'
  177. else
  178. echo $'ERROR: tripwire database was not created'
  179. fi
  180. any_key
  181. }
  182. function passwords_show_apps {
  183. SELECTED_APP=
  184. i=0
  185. W=()
  186. name=()
  187. # shellcheck disable=SC2068
  188. for a in ${APPS_AVAILABLE[@]}
  189. do
  190. if grep -q "change_password_" "/usr/share/${PROJECT_NAME}/apps/${PROJECT_NAME}-app-${a}"; then
  191. i=$((i+1))
  192. W+=("$i" "$a")
  193. name+=("$a")
  194. fi
  195. done
  196. i=$((i+1))
  197. W+=("$i" "mariadb")
  198. name+=("mariadb")
  199. # shellcheck disable=SC2068
  200. selected_app_index=$(dialog --backtitle $"Freedombone Control Panel" --title $"User $SELECTED_USERNAME: Select App" --menu $"Select one of the following:" 24 40 17 ${W[@]} 3>&2 2>&1 1>&3)
  201. # shellcheck disable=SC2181
  202. if [ $? -eq 0 ]; then
  203. SELECTED_APP="${name[$((selected_app_index-1))]}"
  204. fi
  205. }
  206. function view_or_change_passwords {
  207. passwords_select_user
  208. if [ ! "$SELECTED_USERNAME" ]; then
  209. return
  210. fi
  211. detect_installed_apps
  212. passwords_show_apps
  213. if [ ! "$SELECTED_APP" ]; then
  214. return
  215. fi
  216. CURR_PASSWORD=$("${PROJECT_NAME}-pass" -u "${SELECTED_USERNAME}" -a "${SELECTED_APP}")
  217. icann_address=$(get_app_icann_address "${SELECTED_APP}")
  218. onion_address=$(get_app_onion_address "${SELECTED_APP}")
  219. titlestr=$"View or Change Password"
  220. if [ ${#onion_address} -gt 0 ]; then
  221. viewstr=$"${SELECTED_APP} password for ${SELECTED_USERNAME} on $icann_address or $onion_address\\n\\nCopy or change it if you wish."
  222. else
  223. viewstr=$"${SELECTED_APP} password for ${SELECTED_USERNAME} on $icann_address\\n\\nCopy or change it if you wish."
  224. fi
  225. if [ -f /root/.nostore ]; then
  226. titlestr=$"Change Password"
  227. if [ ${#onion_address} -gt 0 ]; then
  228. viewstr=$"Change the ${SELECTED_APP} password for ${SELECTED_USERNAME} on $icann_address or $onion_address."
  229. else
  230. viewstr=$"Change the ${SELECTED_APP} password for ${SELECTED_USERNAME} on $icann_address."
  231. fi
  232. fi
  233. if [[ "${SELECTED_APP}" == 'mariadb' ]]; then
  234. CURR_PASSWORD=$("${PROJECT_NAME}-pass" -u root -a mariadb)
  235. dialog --title $"MariaDB database password" \
  236. --msgbox "\\n ${CURR_PASSWORD}" 7 40
  237. return
  238. fi
  239. data=$(mktemp 2>/dev/null)
  240. dialog --title "$titlestr" \
  241. --backtitle $"Freedombone Control Panel" \
  242. --inputbox "$viewstr" 12 75 "$CURR_PASSWORD" 2>"$data"
  243. sel=$?
  244. case $sel in
  245. 0)
  246. CURR_PASSWORD=$(<"$data")
  247. if [ ${#CURR_PASSWORD} -gt 8 ]; then
  248. "${PROJECT_NAME}-pass" -u "${SELECTED_USERNAME}" -a "${SELECTED_APP}" -p "${CURR_PASSWORD}"
  249. "change_password_${SELECTED_APP}" "${SELECTED_USERNAME}" "${CURR_PASSWORD}"
  250. dialog --title $"Change password" \
  251. --msgbox $"The password was changed" 6 40
  252. else
  253. dialog --title $"Change password" \
  254. --msgbox $"The password given must be at least 8 characters" 6 40
  255. fi
  256. ;;
  257. esac
  258. rm -f "$data"
  259. }
  260. function show_firewall {
  261. W=()
  262. while read -r line; do
  263. firewall_name=$(echo "$line" | awk -F '=' '{print $1}')
  264. firewall_port=$(echo "$line" | awk -F '=' '{print $2}')
  265. W+=("${firewall_name}" "${firewall_port}")
  266. done < "$FIREWALL_CONFIG"
  267. # shellcheck disable=SC2068
  268. dialog --backtitle $"Freedombone Administrator Control Panel" --title $"Firewall" --menu $"Press ESC to return to main menu" 28 50 28 "${W[@]}" 3>&2 2>&1 1>&3
  269. }
  270. function export_passwords {
  271. detect_usb_drive
  272. dialog --title $"Export passwords to USB drive $USB_DRIVE" \
  273. --backtitle $"Security Settings" \
  274. --defaultno \
  275. --yesno $"\\nPlease confirm that you wish to export passwords to a LUKS formatted USB drive. The drive should be plugged in." 10 60
  276. sel=$?
  277. case $sel in
  278. 1) return;;
  279. 255) return;;
  280. esac
  281. dialog --title $"Export passwords to USB drive $USB_DRIVE" \
  282. --backtitle $"Security Settings" \
  283. --defaultno \
  284. --yesno $"\\nDo you need to format the drive as LUKS encrypted?" 12 60
  285. sel=$?
  286. case $sel in
  287. 0) ${PROJECT_NAME}-format "$USB_DRIVE";;
  288. esac
  289. clear
  290. backup_mount_drive "${USB_DRIVE}"
  291. ${PROJECT_NAME}-pass --export "${USB_MOUNT}/${PROJECT_NAME}-passwords.xml"
  292. backup_unmount_drive "${USB_DRIVE}"
  293. }
  294. function get_protocols_from_website {
  295. if [ ! -f "$WEBSITES_DIRECTORY/$1" ]; then
  296. return
  297. fi
  298. SSL_PROTOCOLS=$(grep 'ssl_protocols ' "$WEBSITES_DIRECTORY/$1" | awk -F "ssl_protocols " '{print $2}' | awk -F ';' '{print $1}')
  299. }
  300. function get_ciphers_from_website {
  301. if [ ! -f "$WEBSITES_DIRECTORY/$1" ]; then
  302. return
  303. fi
  304. SSL_CIPHERS=$(grep 'ssl_ciphers ' "$WEBSITES_DIRECTORY/$1" | awk -F "ssl_ciphers " '{print $2}' | awk -F "'" '{print $2}')
  305. }
  306. function get_imap_settings {
  307. if [ ! -f $DOVECOT_CIPHERS ]; then
  308. return
  309. fi
  310. # clear commented out cipher list
  311. sed -i "s|#ssl_cipher_list.*||g" $DOVECOT_CIPHERS
  312. if [ "$SSL_CIPHERS" ]; then
  313. return
  314. fi
  315. if [ ${#SSL_CIPHERS} -gt $MINIMUM_LENGTH ]; then
  316. return
  317. fi
  318. SSL_CIPHERS=$(grep 'ssl_cipher_list' "$DOVECOT_CIPHERS" | awk -F '=' '{print $2}' | awk -F "'" '{print $2}')
  319. }
  320. function get_xmpp_settings {
  321. if [ ! -f $XMPP_CONFIG ]; then
  322. return
  323. fi
  324. XMPP_CIPHERS=$(grep 'ciphers ' "$XMPP_CONFIG" | awk -F '=' '{print $2}' | awk -F '"' '{print $2}')
  325. XMPP_ECC_CURVE=$(grep 'curve ' "$XMPP_CONFIG" | awk -F '=' '{print $2}' | awk -F '"' '{print $2}')
  326. }
  327. function get_ssh_settings {
  328. if [ -f $SSH_CONFIG ]; then
  329. SSH_PASSWORDS=$(grep 'PasswordAuthentication ' "$SSH_CONFIG" | awk -F 'PasswordAuthentication ' '{print $2}')
  330. fi
  331. if [ -f /etc/ssh/ssh_config ]; then
  332. SSH_HOST_KEY_ALGORITHMS=$(grep 'HostKeyAlgorithms ' "/etc/ssh/ssh_config" | awk -F 'HostKeyAlgorithms ' '{print $2}')
  333. fi
  334. }
  335. function change_website_settings {
  336. if [ ! "$SSL_PROTOCOLS" ]; then
  337. return
  338. fi
  339. if [ ! "$SSL_CIPHERS" ]; then
  340. return
  341. fi
  342. if [ ${#SSL_PROTOCOLS} -lt $MINIMUM_LENGTH ]; then
  343. return
  344. fi
  345. if [ ${#SSL_CIPHERS} -lt $MINIMUM_LENGTH ]; then
  346. return
  347. fi
  348. if [ ! -d $WEBSITES_DIRECTORY ]; then
  349. return
  350. fi
  351. cd $WEBSITES_DIRECTORY || exit 2468724628
  352. for file in $(dir -d "*") ; do
  353. sed -i "s|ssl_protocols .*|ssl_protocols $SSL_PROTOCOLS;|g" "$WEBSITES_DIRECTORY/$file"
  354. if ! grep -q "Mobile compatible ciphers" "$WEBSITES_DIRECTORY/$file"; then
  355. sed -i "s|ssl_ciphers .*|ssl_ciphers '$SSL_CIPHERS';|g" "$WEBSITES_DIRECTORY/$file"
  356. else
  357. sed -i "s|ssl_ciphers .*|ssl_ciphers '$SSL_CIPHERS_MOBILE';|g" "$WEBSITES_DIRECTORY/$file"
  358. fi
  359. done
  360. systemctl restart nginx
  361. echo $'Web security settings changed'
  362. }
  363. function change_imap_settings {
  364. if [ ! -f $DOVECOT_CIPHERS ]; then
  365. return
  366. fi
  367. if [ ! "$SSL_CIPHERS" ]; then
  368. return
  369. fi
  370. if [ ${#SSL_CIPHERS} -lt $MINIMUM_LENGTH ]; then
  371. return
  372. fi
  373. sed -i "s|ssl_cipher_list.*|ssl_cipher_list = '$SSL_CIPHERS'|g" $DOVECOT_CIPHERS
  374. sed -i "s|ssl_protocols.*|ssl_protocols = '$SSL_PROTOCOLS'|g" $DOVECOT_CIPHERS
  375. systemctl restart dovecot
  376. echo $'imap security settings changed'
  377. }
  378. function change_ssh_settings {
  379. if [ -f /etc/ssh/ssh_config ]; then
  380. if [ "$SSH_HOST_KEY_ALGORITHMS" ]; then
  381. sed -i "s|HostKeyAlgorithms .*|HostKeyAlgorithms $SSH_HOST_KEY_ALGORITHMS|g" /etc/ssh/ssh_config
  382. echo $'ssh client security settings changed'
  383. fi
  384. fi
  385. if [ -f $SSH_CONFIG ]; then
  386. if [ ! $SSH_CIPHERS ]; then
  387. return
  388. fi
  389. if [ ! $SSH_MACS ]; then
  390. return
  391. fi
  392. if [ ! $SSH_KEX ]; then
  393. return
  394. fi
  395. if [ ! "$SSH_PASSWORDS" ]; then
  396. SSH_PASSWORDS='yes'
  397. fi
  398. sed -i "s|Ciphers .*|Ciphers $SSH_CIPHERS|g" $SSH_CONFIG
  399. sed -i "s|MACs .*|MACs $SSH_MACS|g" $SSH_CONFIG
  400. sed -i "s|KexAlgorithms .*|KexAlgorithms $SSH_KEX|g" $SSH_CONFIG
  401. sed -i "s|#PasswordAuthentication .*|PasswordAuthentication $SSH_PASSWORDS|g" $SSH_CONFIG
  402. sed -i "s|PasswordAuthentication .*|PasswordAuthentication $SSH_PASSWORDS|g" $SSH_CONFIG
  403. systemctl restart ssh
  404. echo $'ssh server security settings changed'
  405. fi
  406. }
  407. function change_xmpp_settings {
  408. if [ ! -f $XMPP_CONFIG ]; then
  409. return
  410. fi
  411. if [ ! "$XMPP_CIPHERS" ]; then
  412. return
  413. fi
  414. if [ ! "$XMPP_ECC_CURVE" ]; then
  415. return
  416. fi
  417. sed -i "s|ciphers =.*|ciphers = \"$XMPP_CIPHERS\";|g" $XMPP_CONFIG
  418. sed -i "s|curve =.*|curve = \"$XMPP_ECC_CURVE\";|g" $XMPP_CONFIG
  419. systemctl restart prosody
  420. echo $'xmpp security settings changed'
  421. }
  422. function allow_ssh_passwords {
  423. dialog --title $"SSH Passwords" \
  424. --backtitle $"Freedombone Security Configuration" \
  425. --yesno $"\\nAllow SSH login using passwords?" 7 60
  426. sel=$?
  427. case $sel in
  428. 0) SSH_PASSWORDS="yes";;
  429. 1) SSH_PASSWORDS="no";;
  430. 255) exit 0;;
  431. esac
  432. }
  433. function interactive_setup {
  434. if [ "$SSL_CIPHERS" ]; then
  435. data=$(mktemp 2>/dev/null)
  436. dialog --backtitle $"Freedombone Security Configuration" \
  437. --form $"\\nWeb/IMAP Ciphers:" 10 95 2 \
  438. $"Protocols:" 1 1 "$SSL_PROTOCOLS" 1 15 90 90 \
  439. $"Ciphers:" 2 1 "$SSL_CIPHERS" 2 15 90 512 \
  440. 2> "$data"
  441. sel=$?
  442. case $sel in
  443. 1) SSL_PROTOCOLS=$(sed -n 1p < "$data")
  444. SSL_CIPHERS=$(sed -n 2p < "$data")
  445. ;;
  446. 255) rm -f "$data"
  447. exit 0;;
  448. esac
  449. rm -f "$data"
  450. fi
  451. data=$(mktemp 2>/dev/null)
  452. if [ "$SSH_HOST_KEY_ALGORITHMS" ]; then
  453. dialog --backtitle $"Freedombone Security Configuration" \
  454. --form $"\\nSecure Shell Ciphers:" 13 95 4 \
  455. $"Ciphers:" 1 1 "$SSH_CIPHERS" 1 15 90 512 \
  456. $"MACs:" 2 1 "$SSH_MACS" 2 15 90 512 \
  457. $"KEX:" 3 1 "$SSH_KEX" 3 15 90 512 \
  458. $"Host key algorithms:" 4 1 "$SSH_HOST_KEY_ALGORITHMS" 4 15 90 512 \
  459. 2> "$data"
  460. sel=$?
  461. case $sel in
  462. 1) SSH_CIPHERS=$(sed -n 1p < "$data")
  463. SSH_MACS=$(sed -n 2p < "$data")
  464. SSH_KEX=$(sed -n 3p < "$data")
  465. SSH_HOST_KEY_ALGORITHMS=$(sed -n 4p < "$data")
  466. ;;
  467. 255) rm -f "$data"
  468. exit 0;;
  469. esac
  470. else
  471. dialog --backtitle $"Freedombone Security Configuration" \
  472. --form $"\\nSecure Shell Ciphers:" 11 95 3 \
  473. $"Ciphers:" 1 1 "$SSH_CIPHERS" 1 15 90 512 \
  474. $"MACs:" 2 1 "$SSH_MACS" 2 15 90 512 \
  475. $"KEX:" 3 1 "$SSH_KEX" 3 15 90 512 \
  476. 2> "$data"
  477. sel=$?
  478. case $sel in
  479. 1) SSH_CIPHERS=$(sed -n 1p < "$data")
  480. SSH_MACS=$(sed -n 2p < "$data")
  481. SSH_KEX=$(sed -n 3p < "$data")
  482. ;;
  483. 255) rm -f "$data"
  484. exit 0;;
  485. esac
  486. fi
  487. rm -f "$data"
  488. if [ "$XMPP_CIPHERS" ]; then
  489. data=$(mktemp 2>/dev/null)
  490. dialog --backtitle $"Freedombone Security Configuration" \
  491. --form $"\\nXMPP Ciphers:" 10 95 2 \
  492. $"Ciphers:" 1 1 "$XMPP_CIPHERS" 1 15 90 512 \
  493. $"ECC Curve:" 2 1 "$XMPP_ECC_CURVE" 2 15 50 50 \
  494. 2> "$data"
  495. sel=$?
  496. case $sel in
  497. 1) XMPP_CIPHERS=$(sed -n 1p < "$data")
  498. XMPP_ECC_CURVE=$(sed -n 2p < "$data")
  499. ;;
  500. 255) rm -f "$data"
  501. exit 0;;
  502. esac
  503. rm -f "$data"
  504. fi
  505. dialog --title $"Final Confirmation" \
  506. --backtitle $"Freedombone Security Configuration" \
  507. --defaultno \
  508. --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
  509. sel=$?
  510. case $sel in
  511. 1) clear
  512. echo $'Exiting without changing security settings'
  513. exit 0;;
  514. 255) clear
  515. echo $'Exiting without changing security settings'
  516. exit 0;;
  517. esac
  518. clear
  519. }
  520. function send_monkeysphere_server_keys_to_users {
  521. monkeysphere_server_keys=$(monkeysphere-host show-key | grep $"OpenPGP fingerprint" | awk -F ' ' '{print $3}')
  522. for d in /home/*/ ; do
  523. USERNAME=$(echo "$d" | awk -F '/' '{print $3}')
  524. if [[ $(is_valid_user "$USERNAME") == "1" ]]; then
  525. if [ ! -d "/home/$USERNAME/.monkeysphere" ]; then
  526. mkdir "/home/$USERNAME/.monkeysphere"
  527. fi
  528. echo "$monkeysphere_server_keys" > "/home/$USERNAME/.monkeysphere/server_keys"
  529. chown -R "$USERNAME":"$USERNAME" "/home/$USERNAME/.monkeysphere"
  530. fi
  531. done
  532. }
  533. function regenerate_ssh_host_keys {
  534. rm -f /etc/ssh/ssh_host_*
  535. dpkg-reconfigure openssh-server
  536. echo $'ssh host keys regenerated'
  537. # remove small moduli
  538. awk '$5 > 2000' /etc/ssh/moduli > ~/moduli
  539. mv ~/moduli /etc/ssh/moduli
  540. echo $'ssh small moduli removed'
  541. # update monkeysphere
  542. DEFAULT_DOMAIN_NAME=
  543. read_config_param "DEFAULT_DOMAIN_NAME"
  544. monkeysphere-host import-key /etc/ssh/ssh_host_rsa_key "ssh://$DEFAULT_DOMAIN_NAME"
  545. SSH_ONION_HOSTNAME=$(grep 'ssh onion domain' "${COMPLETION_FILE}" | awk -F ':' '{print $2}')
  546. monkeysphere-host import-key /etc/ssh/ssh_host_rsa_key "ssh://$SSH_ONION_HOSTNAME"
  547. monkeysphere-host publish-key
  548. send_monkeysphere_server_keys_to_users
  549. echo $'updated monkeysphere ssh host key'
  550. systemctl restart ssh
  551. }
  552. function regenerate_dh_keys {
  553. if [ ! -d /etc/ssl/mycerts ]; then
  554. echo $'No dhparam certificates were found'
  555. return
  556. fi
  557. data=$(mktemp 2>/dev/null)
  558. dialog --backtitle "Freedombone Security Configuration" \
  559. --title "Diffie-Hellman key length" \
  560. --radiolist "The smaller length is better suited to low power embedded systems:" 12 40 3 \
  561. 1 "2048 bits" off \
  562. 2 "3072 bits" on \
  563. 3 "4096 bits" off 2> "$data"
  564. sel=$?
  565. case $sel in
  566. 1) rm -f "$data"
  567. exit 1;;
  568. 255) rm -f "$data"
  569. exit 1;;
  570. esac
  571. case $(cat "$data") in
  572. 1) DH_KEYLENGTH=2048;;
  573. 2) DH_KEYLENGTH=3072;;
  574. 3) DH_KEYLENGTH=4096;;
  575. esac
  576. rm -f "$data"
  577. ${PROJECT_NAME}-dhparam --recalc yes -l ${DH_KEYLENGTH}
  578. }
  579. function renew_startssl {
  580. renew_domain=
  581. data=$(mktemp 2>/dev/null)
  582. dialog --title $"Renew a StartSSL certificate" \
  583. --backtitle $"Freedombone Security Settings" \
  584. --inputbox $"Enter the domain name" 8 60 2>"$data"
  585. sel=$?
  586. case $sel in
  587. 0)
  588. renew_domain=$(<"$data")
  589. ;;
  590. esac
  591. rm -f "$data"
  592. if [ ! "$renew_domain" ]; then
  593. return
  594. fi
  595. if [[ $renew_domain == "http"* ]]; then
  596. dialog --title $"Renew a StartSSL certificate" \
  597. --msgbox $"Don't include the https://" 6 40
  598. return
  599. fi
  600. if [ ! -f "/etc/ssl/certs/${renew_domain}.dhparam" ]; then
  601. dialog --title $"Renew a StartSSL certificate" \
  602. --msgbox $"An existing certificate for $renew_domain was not found" 6 40
  603. return
  604. fi
  605. if [[ $renew_domain != *"."* ]]; then
  606. dialog --title $"Renew a StartSSL certificate" \
  607. --msgbox $"Invalid domain name: $renew_domain" 6 40
  608. return
  609. fi
  610. ${PROJECT_NAME}-renew-cert -h "$renew_domain" -p startssl
  611. exit 0
  612. }
  613. function renew_letsencrypt {
  614. renew_domain=
  615. data=$(mktemp 2>/dev/null)
  616. dialog --title $"Renew a Let's Encrypt certificate" \
  617. --backtitle $"Freedombone Security Settings" \
  618. --inputbox $"Enter the domain name" 8 60 2>"$data"
  619. sel=$?
  620. case $sel in
  621. 0)
  622. renew_domain=$(<"$data")
  623. ;;
  624. esac
  625. rm -f "$data"
  626. if [ ! "$renew_domain" ]; then
  627. return
  628. fi
  629. if [[ $renew_domain == "http"* ]]; then
  630. dialog --title $"Renew a Let's Encrypt certificate" \
  631. --msgbox $"Don't include the https://" 6 40
  632. return
  633. fi
  634. if [ ! -f "/etc/ssl/certs/${renew_domain}.dhparam" ]; then
  635. dialog --title $"Renew a Let's Encrypt certificate" \
  636. --msgbox $"An existing certificate for $renew_domain was not found" 6 40
  637. return
  638. fi
  639. if [[ $renew_domain != *"."* ]]; then
  640. dialog --title $"Renew a Let's Encrypt certificate" \
  641. --msgbox $"Invalid domain name: $renew_domain" 6 40
  642. return
  643. fi
  644. ${PROJECT_NAME}-renew-cert -h "$renew_domain" -p 'letsencrypt'
  645. exit 0
  646. }
  647. function delete_letsencrypt {
  648. delete_domain=
  649. data=$(mktemp 2>/dev/null)
  650. dialog --title $"Delete a Let's Encrypt certificate" \
  651. --backtitle $"Freedombone Security Settings" \
  652. --inputbox $"Enter the domain name" 8 60 2>"$data"
  653. sel=$?
  654. case $sel in
  655. 0)
  656. delete_domain=$(<"$data")
  657. ;;
  658. esac
  659. rm -f "$data"
  660. if [ ! "$delete_domain" ]; then
  661. return
  662. fi
  663. if [[ $delete_domain == "http"* ]]; then
  664. dialog --title $"Delete a Let's Encrypt certificate" \
  665. --msgbox $"Don't include the https://" 6 40
  666. return
  667. fi
  668. if [ ! -f "/etc/ssl/certs/${delete_domain}.dhparam" ]; then
  669. dialog --title $"Delete a Let's Encrypt certificate" \
  670. --msgbox $"An existing certificate for $renew_domain was not found" 6 40
  671. return
  672. fi
  673. if [[ $delete_domain != *"."* ]]; then
  674. dialog --title $"Delete a Let's Encrypt certificate" \
  675. --msgbox $"Invalid domain name: $delete_domain" 6 40
  676. return
  677. fi
  678. dialog --title $"Delete a Let's Encrypt certificate" \
  679. --backtitle $"Freedombone Security Settings" \
  680. --defaultno \
  681. --yesno $"\\nConfirm deletion of the TLS certificate for $delete_domain ?" 7 60
  682. sel=$?
  683. case $sel in
  684. 0) ${PROJECT_NAME}-addcert -r "$delete_domain";;
  685. 255) exit 0;;
  686. esac
  687. exit 0
  688. }
  689. function create_letsencrypt {
  690. new_domain=
  691. data=$(mktemp 2>/dev/null)
  692. dialog --title $"Create a new Let's Encrypt certificate" \
  693. --backtitle $"Freedombone Security Settings" \
  694. --inputbox $"Enter the domain name" 8 60 2>"$data"
  695. sel=$?
  696. case $sel in
  697. 0)
  698. new_domain=$(<"$data")
  699. ;;
  700. esac
  701. rm -f "$data"
  702. if [ ! "$new_domain" ]; then
  703. return
  704. fi
  705. if [[ $new_domain == "http"* ]]; then
  706. dialog --title $"Create a new Let's Encrypt certificate" \
  707. --msgbox $"Don't include the https://" 6 40
  708. return
  709. fi
  710. if [[ $new_domain != *"."* ]]; then
  711. dialog --title $"Create a new Let's Encrypt certificate" \
  712. --msgbox $"Invalid domain name: $new_domain" 6 40
  713. return
  714. fi
  715. if [ ! -d "/var/www/${new_domain}" ]; then
  716. domain_found=
  717. if [ -f /etc/nginx/sites-available/radicale ]; then
  718. if grep -q "${new_domain}" /etc/nginx/sites-available/radicale; then
  719. domain_found=1
  720. fi
  721. fi
  722. if [ -f "/etc/nginx/sites-available/${new_domain}" ]; then
  723. domain_found=1
  724. fi
  725. if [[ "${new_domain}" == "jitsi"* || "${new_domain}" == "meet"* ]]; then
  726. domain_found=1
  727. fi
  728. if [ ! $domain_found ]; then
  729. dialog --title $"Create a new Let's Encrypt certificate" \
  730. --msgbox $'Domain not found within /var/www' 6 40
  731. return
  732. fi
  733. fi
  734. ${PROJECT_NAME}-addcert -e "$new_domain" -s "$LETSENCRYPT_SERVER" --dhkey "$DH_KEYLENGTH"
  735. exit 0
  736. }
  737. function update_ciphersuite {
  738. RECOMMENDED_SSL_CIPHERS="$SSL_CIPHERS"
  739. if [ ${#RECOMMENDED_SSL_CIPHERS} -lt 5 ]; then
  740. return
  741. fi
  742. RECOMMENDED_SSL_PROTOCOLS="$SSL_PROTOCOLS"
  743. if [ ${#RECOMMENDED_SSL_PROTOCOLS} -lt 5 ]; then
  744. return
  745. fi
  746. RECOMMENDED_SSH_CIPHERS="$SSH_CIPHERS"
  747. if [ ${#RECOMMENDED_SSH_CIPHERS} -lt 5 ]; then
  748. return
  749. fi
  750. RECOMMENDED_SSH_MACS="$SSH_MACS"
  751. if [ ${#RECOMMENDED_SSH_MACS} -lt 5 ]; then
  752. return
  753. fi
  754. RECOMMENDED_SSH_KEX="$SSH_KEX"
  755. if [ ${#RECOMMENDED_SSH_KEX} -lt 5 ]; then
  756. return
  757. fi
  758. cd $WEBSITES_DIRECTORY || exit 728425476
  759. for file in $(dir -d "*") ; do
  760. sed -i "s|ssl_protocols .*|ssl_protocols $RECOMMENDED_SSL_PROTOCOLS;|g" "$WEBSITES_DIRECTORY/$file"
  761. if ! grep -q "Mobile compatible ciphers" "$WEBSITES_DIRECTORY/$file"; then
  762. sed -i "s|ssl_ciphers .*|ssl_ciphers '$RECOMMENDED_SSL_CIPHERS';|g" "$WEBSITES_DIRECTORY/$file"
  763. else
  764. sed -i "s|ssl_ciphers .*|ssl_ciphers '$SSL_CIPHERS_MOBILE';|g" "$WEBSITES_DIRECTORY/$file"
  765. fi
  766. done
  767. systemctl restart nginx
  768. write_config_param "SSL_PROTOCOLS" "$RECOMMENDED_SSL_PROTOCOLS"
  769. write_config_param "SSL_CIPHERS" "$RECOMMENDED_SSL_CIPHERS"
  770. sed -i "s|Ciphers .*|Ciphers $RECOMMENDED_SSH_CIPHERS|g" $SSH_CONFIG
  771. sed -i "s|MACs .*|MACs $RECOMMENDED_SSH_MACS|g" $SSH_CONFIG
  772. sed -i "s|KexAlgorithms .*|KexAlgorithms $RECOMMENDED_SSH_KEX|g" $SSH_CONFIG
  773. systemctl restart ssh
  774. write_config_param "SSH_CIPHERS" "$RECOMMENDED_SSH_CIPHERS"
  775. write_config_param "SSH_MACS" "$RECOMMENDED_SSH_MACS"
  776. write_config_param "SSH_KEX" "$RECOMMENDED_SSH_KEX"
  777. dialog --title $"Update ciphersuite" \
  778. --msgbox $"The ciphersuite has been updated to recommended versions" 6 40
  779. exit 0
  780. }
  781. function enable_monkeysphere {
  782. monkey=
  783. dialog --title $"GPG based authentication" \
  784. --backtitle $"Freedombone Security Configuration" \
  785. --defaultno \
  786. --yesno $"\\nEnable GPG based authentication with monkeysphere ?" 7 60
  787. sel=$?
  788. case $sel in
  789. 0) monkey='yes';;
  790. 255) exit 0;;
  791. esac
  792. if [ $monkey ]; then
  793. read_config_param "MY_USERNAME"
  794. if [ ! -f /home/$MY_USERNAME/.monkeysphere/authorized_user_ids ]; then
  795. dialog --title $"GPG based authentication" \
  796. --msgbox $"$MY_USERNAME does not currently have any ids within ~/.monkeysphere/authorized_user_ids" 6 40
  797. exit 0
  798. fi
  799. MY_GPG_PUBLIC_KEY_ID=$(gpg_pubkey_from_email "$MY_USERNAME" "$MY_USERNAME@$HOSTNAME")
  800. if [ ${#MY_GPG_PUBLIC_KEY_ID} -lt 4 ]; then
  801. echo $"monkeysphere unable to get GPG key ID for user $MY_USERNAME@$HOSTNAME"
  802. exit 52825
  803. fi
  804. sed -i 's|#AuthorizedKeysFile|AuthorizedKeysFile|g' /etc/ssh/sshd_config
  805. sed -i 's|AuthorizedKeysFile.*|AuthorizedKeysFile /var/lib/monkeysphere/authorized_keys/%u|g' /etc/ssh/sshd_config
  806. monkeysphere-authentication update-users
  807. # The admin user is the identity certifier
  808. fpr=$(gpg --with-colons --fingerprint "$MY_GPG_PUBLIC_KEY_ID" | grep fpr | head -n 1 | awk -F ':' '{print $10}')
  809. monkeysphere-authentication add-identity-certifier "$fpr"
  810. monkeysphere-host publish-key
  811. send_monkeysphere_server_keys_to_users
  812. else
  813. sed -i 's|#AuthorizedKeysFile|AuthorizedKeysFile|g' /etc/ssh/sshd_config
  814. sed -i 's|AuthorizedKeysFile.*|AuthorizedKeysFile %h/.ssh/authorized_keys|g' /etc/ssh/sshd_config
  815. fi
  816. systemctl restart ssh
  817. if [ $monkey ]; then
  818. dialog --title $"GPG based authentication" \
  819. --msgbox $"GPG based authentication was enabled" 6 40
  820. else
  821. dialog --title $"GPG based authentication" \
  822. --msgbox $"GPG based authentication was disabled" 6 40
  823. fi
  824. exit 0
  825. }
  826. function register_website {
  827. domain="$1"
  828. if [[ ${domain} == *".local" ]]; then
  829. echo $"Can't register local domains"
  830. return
  831. fi
  832. if [ ! -f "/etc/ssl/private/${domain}.key" ]; then
  833. echo $"No SSL/TLS private key found for ${domain}"
  834. return
  835. fi
  836. if [ ! -f "/etc/nginx/sites-available/${domain}" ]; then
  837. echo $"No virtual host found for ${domain}"
  838. return
  839. fi
  840. monkeysphere-host import-key "/etc/ssl/private/${domain}.key" "https://${domain}"
  841. monkeysphere-host publish-key
  842. echo "0"
  843. }
  844. function register_website_interactive {
  845. data=$(mktemp 2>/dev/null)
  846. dialog --title $"Register a website with monkeysphere" \
  847. --backtitle $"Freedombone Security Settings" \
  848. --inputbox $"Enter the website domain name (without https://)" 8 60 2>"$data"
  849. sel=$?
  850. case $sel in
  851. 0)
  852. domain=$(<"$data")
  853. if ! register_website "$domain"; then
  854. dialog --title $"Register a website with monkeysphere" \
  855. --msgbox "$?" 6 40
  856. else
  857. dialog --title $"Register a website with monkeysphere" \
  858. --msgbox $"$domain has been registered" 6 40
  859. fi
  860. ;;
  861. esac
  862. rm -f "$data"
  863. }
  864. function pin_all_tls_certs {
  865. ${PROJECT_NAME}-pin-cert all
  866. }
  867. function remove_pinning {
  868. data=$(mktemp 2>/dev/null)
  869. dialog --title $"Remove pinning for a domain" \
  870. --backtitle $"Freedombone Security Settings" \
  871. --inputbox $"Enter the website domain name (without https://)" 8 60 2>"$data"
  872. sel=$?
  873. case $sel in
  874. 0)
  875. domain=$(<"$data")
  876. if ! ${PROJECT_NAME}-pin-cert "$domain" remove; then
  877. dialog --title $"Removed pinning from $domain" \
  878. --msgbox "$?" 6 40
  879. fi
  880. ;;
  881. esac
  882. rm -f "$data"
  883. }
  884. function store_passwords {
  885. dialog --title $"Store Passwords" \
  886. --backtitle $"Freedombone Security Configuration" \
  887. --yesno $"\\nDo you wish to store passwords on the system? Stored passwords are convenient but carry some additional security risk." 10 60
  888. sel=$?
  889. case $sel in
  890. 0)
  891. if [ -f /root/.nostore ]; then
  892. read_config_param "MY_USERNAME"
  893. if [ ! -f /home/$MY_USERNAME/.ssh/authorized_keys ]; then
  894. dialog --title $"Store Passwords" \
  895. --msgbox $"\\nYou should first enable key based ssh login to improve security" 8 60
  896. return
  897. fi
  898. if [[ $SSH_PASSWORDS == 'yes' ]]; then
  899. dialog --title $"Store Passwords" \
  900. --msgbox $"\\nYou should disable ssh passwords to improve security" 8 60
  901. return
  902. fi
  903. ${PROJECT_NAME}-pass --enable yes
  904. dialog --title $"Store Passwords" \
  905. --msgbox $"\\nUser passwords will now be stored on the system" 8 60
  906. fi
  907. return
  908. ;;
  909. 1)
  910. ${PROJECT_NAME}-pass --clear yes
  911. dialog --title $"Passwords were removed and will not be stored" \
  912. --msgbox $"\\nFor the best security you should now manually change passwords via web interfaces so that there is no possibility of them being recovered from the disk" 9 60
  913. return
  914. ;;
  915. 255) return;;
  916. esac
  917. }
  918. function show_tor_bridges {
  919. clear
  920. bridges_list=$(grep "Bridge " /etc/tor/torrc | grep -v '##')
  921. if [ ${#bridges_list} -eq 0 ]; then
  922. echo $'No Tor bridges have been added'
  923. return
  924. fi
  925. echo "${bridges_list}"
  926. }
  927. function add_tor_bridge {
  928. data=$(mktemp 2>/dev/null)
  929. dialog --backtitle $"Freedombone Control Panel" \
  930. --title $"Add obfs4 Tor bridge" \
  931. --form "\\n" 9 60 4 \
  932. $"IP address: " 1 1 " . . . " 1 17 16 16 \
  933. $"Port: " 2 1 "" 2 17 8 8 \
  934. $"Key/Nickname: " 3 1 "" 3 17 250 250 \
  935. 2> "$data"
  936. sel=$?
  937. case $sel in
  938. 1) rm -f "$data"
  939. return;;
  940. 255) rm -f "$data"
  941. return;;
  942. esac
  943. bridge_ip_address=$(sed -n 1p < "$data")
  944. bridge_port=$(sed -n 2p < "$data")
  945. bridge_key=$(sed -n 3p < "$data")
  946. rm -f "$data"
  947. if [[ "${bridge_ip_address}" == *" "* ]]; then
  948. return
  949. fi
  950. if [[ "${bridge_ip_address}" != *"."* ]]; then
  951. return
  952. fi
  953. if [ ${#bridge_port} -eq 0 ]; then
  954. return
  955. fi
  956. if [ ${#bridge_key} -eq 0 ]; then
  957. return
  958. fi
  959. tor_add_bridge "${bridge_ip_address}" "${bridge_port}" "${bridge_key}"
  960. dialog --title $"Add obfs4 Tor bridge" \
  961. --msgbox $"Bridge added" 6 40
  962. }
  963. function remove_tor_bridge {
  964. bridge_removed=
  965. data=$(mktemp 2>/dev/null)
  966. dialog --title $"Remove obfs4 Tor bridge" \
  967. --backtitle $"Freedombone Control Panel" \
  968. --inputbox $"Enter the IP address, key or Nickname of the bridge" 8 65 2>"$data"
  969. sel=$?
  970. case $sel in
  971. 0)
  972. response=$(<"$data")
  973. if [ ${#response} -gt 2 ]; then
  974. if [[ "${response}" != *" "* ]]; then
  975. if [[ "${response}" == *"."* ]]; then
  976. if grep -q "Bridge ${response}" /etc/tor/torrc; then
  977. tor_remove_bridge "${response}"
  978. bridge_removed=1
  979. fi
  980. else
  981. if grep -q " $response" /etc/tor/torrc; then
  982. tor_remove_bridge "${response}"
  983. bridge_removed=1
  984. fi
  985. fi
  986. fi
  987. fi
  988. ;;
  989. esac
  990. rm -f "$data"
  991. if [ $bridge_removed ]; then
  992. dialog --title $"Remove obfs4 Tor bridge" \
  993. --msgbox $"Bridge removed" 6 40
  994. fi
  995. }
  996. function add_tor_bridge_relay {
  997. read_config_param 'TOR_BRIDGE_NICKNAME'
  998. read_config_param 'TOR_BRIDGE_PORT'
  999. # remove any previous bridge port from the firewall
  1000. if [ ${#TOR_BRIDGE_PORT} -gt 0 ]; then
  1001. firewall_remove "$TOR_BRIDGE_PORT" tcp
  1002. fi
  1003. data=$(mktemp 2>/dev/null)
  1004. dialog --backtitle $"Freedombone Control Panel" \
  1005. --title $"Become an obfs4 Tor bridge relay" \
  1006. --form "\\n" 8 60 2 \
  1007. $"Bridge Nickname: " 1 1 "$TOR_BRIDGE_NICKNAME" 1 20 250 250 \
  1008. 2> "$data"
  1009. sel=$?
  1010. case $sel in
  1011. 1) rm -f "$data"
  1012. return;;
  1013. 255) rm -f "$data"
  1014. return;;
  1015. esac
  1016. bridge_nickname=$(sed -n 1p < "$data")
  1017. rm -f "$data"
  1018. if [[ "${bridge_nickname}" == *" "* ]]; then
  1019. return
  1020. fi
  1021. if [ ${#bridge_nickname} -eq 0 ]; then
  1022. return
  1023. fi
  1024. TOR_BRIDGE_NICKNAME="$bridge_nickname"
  1025. TOR_BRIDGE_PORT=$((20000 + RANDOM % 40000))
  1026. write_config_param 'TOR_BRIDGE_NICKNAME' "$TOR_BRIDGE_NICKNAME"
  1027. write_config_param 'TOR_BRIDGE_PORT' "$TOR_BRIDGE_PORT"
  1028. tor_create_bridge_relay
  1029. dialog --title $"You are now an obfs4 Tor bridge relay" \
  1030. --msgbox $"\\nIP address: $(get_ipv4_address)\\n\\nPort: ${TOR_BRIDGE_PORT}\\n\\nNickname: ${TOR_BRIDGE_NICKNAME}" 10 65
  1031. }
  1032. function remove_tor_bridge_relay {
  1033. tor_remove_bridge_relay
  1034. dialog --title $"Remove Tor bridge relay" \
  1035. --msgbox $"Bridge relay removed" 10 60
  1036. }
  1037. function menu_tor_bridges {
  1038. W=(1 $"Show bridges"
  1039. 2 $"Add a bridge"
  1040. 3 $"Remove a bridge"
  1041. 4 $"Make this system into a bridge"
  1042. 5 $"Stop being a bridge")
  1043. # shellcheck disable=SC2068
  1044. selection=$(dialog --backtitle $"Freedombone Administrator Control Panel" --title $"Security Settings" --menu $"Choose an operation, or ESC to go back:" 14 50 6 "${W[@]}" 3>&2 2>&1 1>&3)
  1045. if [ ! "$selection" ]; then
  1046. exit 0
  1047. fi
  1048. case $selection in
  1049. 1)
  1050. show_tor_bridges
  1051. exit 0
  1052. ;;
  1053. 2)
  1054. add_tor_bridge
  1055. exit 0
  1056. ;;
  1057. 3)
  1058. remove_tor_bridge
  1059. exit 0
  1060. ;;
  1061. 4)
  1062. add_tor_bridge_relay
  1063. exit 0
  1064. ;;
  1065. 5)
  1066. remove_tor_bridge_relay
  1067. exit 0
  1068. ;;
  1069. esac
  1070. }
  1071. function menu_security_settings {
  1072. W=(1 $"Passwords"
  1073. 2 $"Run STIG tests"
  1074. 3 $"Fix STIG test failures"
  1075. 4 $"Show tripwire verification code"
  1076. 5 $"Reset tripwire"
  1077. 6 $"Enable or disable ping"
  1078. 7 $"Show ssh host public key"
  1079. 8 $"Tor bridges"
  1080. 9 $"Password storage"
  1081. 10 $"Export passwords"
  1082. 11 $"Regenerate ssh host keys"
  1083. 12 $"Regenerate Diffie-Hellman keys"
  1084. 13 $"Update cipersuite"
  1085. 14 $"Create a new Let's Encrypt certificate"
  1086. 15 $"Renew Let's Encrypt certificate"
  1087. 16 $"Delete a Let's Encrypt certificate"
  1088. 17 $"Allow ssh login with passwords"
  1089. 18 $"Show firewall")
  1090. # shellcheck disable=SC2068
  1091. selection=$(dialog --backtitle $"Freedombone Administrator Control Panel" --title $"Security Settings" --menu $"Choose an operation, or ESC to exit:" 25 76 25 "${W[@]}" 3>&2 2>&1 1>&3)
  1092. if [ ! "$selection" ]; then
  1093. exit 0
  1094. fi
  1095. clear
  1096. read_config_param SSL_CIPHERS
  1097. read_config_param SSL_PROTOCOLS
  1098. read_config_param SSH_CIPHERS
  1099. read_config_param SSH_MACS
  1100. read_config_param SSH_KEX
  1101. get_imap_settings
  1102. get_ssh_settings
  1103. get_xmpp_settings
  1104. import_settings
  1105. export_settings
  1106. case $selection in
  1107. 1)
  1108. view_or_change_passwords
  1109. exit 0;
  1110. ;;
  1111. 2)
  1112. clear
  1113. echo $'Running STIG tests...'
  1114. echo ''
  1115. ${PROJECT_NAME}-tests --stig showall
  1116. exit 0
  1117. ;;
  1118. 3)
  1119. clear
  1120. echo $'Fixing any STIG failures...'
  1121. echo ''
  1122. ${PROJECT_NAME}-tests --stig fix
  1123. echo $'Fixes applied. You will need to run the STIG tests again to be sure that they were all fixed.'
  1124. exit 0
  1125. ;;
  1126. 4)
  1127. show_tripwire_verification_code
  1128. any_key_verify
  1129. exit 0
  1130. ;;
  1131. 5)
  1132. reset_tripwire
  1133. exit 0
  1134. ;;
  1135. 6)
  1136. ping_enable_disable
  1137. exit 0
  1138. ;;
  1139. 7)
  1140. dialog --title $"SSH host public keys" \
  1141. --msgbox "\\n$(get_ssh_server_key)" 12 60
  1142. exit 0
  1143. ;;
  1144. 8)
  1145. menu_tor_bridges
  1146. exit 0
  1147. ;;
  1148. 9)
  1149. store_passwords
  1150. exit 0
  1151. ;;
  1152. 10)
  1153. export_passwords
  1154. exit 0
  1155. ;;
  1156. 11)
  1157. regenerate_ssh_host_keys
  1158. ;;
  1159. 12)
  1160. regenerate_dh_keys
  1161. ;;
  1162. 13)
  1163. interactive_setup
  1164. update_ciphersuite
  1165. ;;
  1166. 14)
  1167. create_letsencrypt
  1168. ;;
  1169. 15)
  1170. renew_letsencrypt
  1171. ;;
  1172. 16)
  1173. delete_letsencrypt
  1174. ;;
  1175. 17)
  1176. allow_ssh_passwords
  1177. change_ssh_settings
  1178. exit 0
  1179. ;;
  1180. 18)
  1181. show_firewall
  1182. exit 0
  1183. ;;
  1184. esac
  1185. change_website_settings
  1186. change_imap_settings
  1187. change_ssh_settings
  1188. change_xmpp_settings
  1189. }
  1190. function import_settings {
  1191. cd "$CURRENT_DIR" || exit 2468724684
  1192. if [ ! $IMPORT_FILE ]; then
  1193. return
  1194. fi
  1195. if [ ! -f $IMPORT_FILE ]; then
  1196. echo $"Import file $IMPORT_FILE not found"
  1197. exit 6393
  1198. fi
  1199. if grep -q "SSL_PROTOCOLS" $IMPORT_FILE; then
  1200. TEMP_VALUE=$(grep "SSL_PROTOCOLS" $IMPORT_FILE | awk -F '=' '{print $2}')
  1201. if [ ${#TEMP_VALUE} -gt $MINIMUM_LENGTH ]; then
  1202. SSL_PROTOCOLS=$TEMP_VALUE
  1203. fi
  1204. fi
  1205. if grep -q "SSL_CIPHERS" $IMPORT_FILE; then
  1206. TEMP_VALUE=$(grep "SSL_CIPHERS" $IMPORT_FILE | awk -F '=' '{print $2}')
  1207. if [ ${#TEMP_VALUE} -gt $MINIMUM_LENGTH ]; then
  1208. SSL_CIPHERS=$TEMP_VALUE
  1209. fi
  1210. fi
  1211. if grep -q "SSH_CIPHERS" $IMPORT_FILE; then
  1212. TEMP_VALUE=$(grep "SSH_CIPHERS" $IMPORT_FILE | awk -F '=' '{print $2}')
  1213. if [ ${#TEMP_VALUE} -gt $MINIMUM_LENGTH ]; then
  1214. SSH_CIPHERS=$TEMP_VALUE
  1215. fi
  1216. fi
  1217. if grep -q "SSH_MACS" $IMPORT_FILE; then
  1218. TEMP_VALUE=$(grep "SSH_MACS" $IMPORT_FILE | awk -F '=' '{print $2}')
  1219. if [ ${#TEMP_VALUE} -gt $MINIMUM_LENGTH ]; then
  1220. SSH_MACS=$TEMP_VALUE
  1221. fi
  1222. fi
  1223. if grep -q "SSH_KEX" $IMPORT_FILE; then
  1224. TEMP_VALUE=$(grep "SSH_KEX" $IMPORT_FILE | awk -F '=' '{print $2}')
  1225. if [ ${#TEMP_VALUE} -gt $MINIMUM_LENGTH ]; then
  1226. SSH_KEX=$TEMP_VALUE
  1227. fi
  1228. fi
  1229. if grep -q "SSH_HOST_KEY_ALGORITHMS" $IMPORT_FILE; then
  1230. TEMP_VALUE=$(grep "SSH_HOST_KEY_ALGORITHMS" $IMPORT_FILE | awk -F '=' '{print $2}')
  1231. if [ ${#TEMP_VALUE} -gt $MINIMUM_LENGTH ]; then
  1232. SSH_HOST_KEY_ALGORITHMS=$TEMP_VALUE
  1233. fi
  1234. fi
  1235. if grep -q "SSH_PASSWORDS" $IMPORT_FILE; then
  1236. TEMP_VALUE=$(grep "SSH_PASSWORDS" $IMPORT_FILE | awk -F '=' '{print $2}')
  1237. if [[ $TEMP_VALUE == "yes" || $TEMP_VALUE == "no" ]]; then
  1238. SSH_PASSWORDS=$TEMP_VALUE
  1239. fi
  1240. fi
  1241. if grep -q "XMPP_CIPHERS" $IMPORT_FILE; then
  1242. TEMP_VALUE=$(grep "XMPP_CIPHERS" $IMPORT_FILE | awk -F '=' '{print $2}')
  1243. if [ ${#TEMP_VALUE} -gt $MINIMUM_LENGTH ]; then
  1244. XMPP_CIPHERS=$TEMP_VALUE
  1245. fi
  1246. fi
  1247. if grep -q "XMPP_ECC_CURVE" $IMPORT_FILE; then
  1248. TEMP_VALUE=$(grep "XMPP_ECC_CURVE" $IMPORT_FILE | awk -F '=' '{print $2}')
  1249. if [ ${#TEMP_VALUE} -gt 3 ]; then
  1250. XMPP_ECC_CURVE=$TEMP_VALUE
  1251. fi
  1252. fi
  1253. }
  1254. function export_settings {
  1255. if [ ! $EXPORT_FILE ]; then
  1256. return
  1257. fi
  1258. cd "$CURRENT_DIR" || exit 92465274527
  1259. if [ ! -f $EXPORT_FILE ]; then
  1260. if [ "$SSL_PROTOCOLS" ]; then
  1261. echo "SSL_PROTOCOLS=$SSL_PROTOCOLS" >> $EXPORT_FILE
  1262. fi
  1263. if [ "$SSL_CIPHERS" ]; then
  1264. echo "SSL_CIPHERS=$SSL_CIPHERS" >> $EXPORT_FILE
  1265. fi
  1266. if [ "$SSH_CIPHERS" ]; then
  1267. echo "SSH_CIPHERS=$SSH_CIPHERS" >> $EXPORT_FILE
  1268. fi
  1269. if [ "$SSH_MACS" ]; then
  1270. echo "SSH_MACS=$SSH_MACS" >> $EXPORT_FILE
  1271. fi
  1272. if [ "$SSH_KEX" ]; then
  1273. echo "SSH_KEX=$SSH_KEX" >> $EXPORT_FILE
  1274. fi
  1275. if [ "$SSH_HOST_KEY_ALGORITHMS" ]; then
  1276. echo "SSH_HOST_KEY_ALGORITHMS=$SSH_HOST_KEY_ALGORITHMS" >> $EXPORT_FILE
  1277. fi
  1278. if [ "$SSH_PASSWORDS" ]; then
  1279. echo "SSH_PASSWORDS=$SSH_PASSWORDS" >> $EXPORT_FILE
  1280. fi
  1281. if [ "$XMPP_CIPHERS" ]; then
  1282. echo "XMPP_CIPHERS=$XMPP_CIPHERS" >> $EXPORT_FILE
  1283. fi
  1284. if [ "$XMPP_ECC_CURVE" ]; then
  1285. echo "XMPP_ECC_CURVE=$XMPP_ECC_CURVE" >> $EXPORT_FILE
  1286. fi
  1287. echo "Security settings exported to $EXPORT_FILE"
  1288. exit 0
  1289. fi
  1290. if [ "$SSL_PROTOCOLS" ]; then
  1291. if grep -q "SSL_PROTOCOLS" $EXPORT_FILE; then
  1292. sed -i "s|SSL_PROTOCOLS=.*|SSL_PROTOCOLS=$SSL_PROTOCOLS|g" $EXPORT_FILE
  1293. else
  1294. echo "SSL_PROTOCOLS=$SSL_PROTOCOLS" >> $EXPORT_FILE
  1295. fi
  1296. fi
  1297. if [ "$SSL_CIPHERS" ]; then
  1298. if grep -q "SSL_CIPHERS" $EXPORT_FILE; then
  1299. sed -i "s|SSL_CIPHERS=.*|SSL_CIPHERS=$SSL_CIPHERS|g" $EXPORT_FILE
  1300. else
  1301. echo "SSL_CIPHERS=$SSL_CIPHERS" >> $EXPORT_FILE
  1302. fi
  1303. fi
  1304. if [ "$SSH_CIPHERS" ]; then
  1305. if grep -q "SSH_CIPHERS" $EXPORT_FILE; then
  1306. sed -i "s|SSH_CIPHERS=.*|SSH_CIPHERS=$SSH_CIPHERS|g" $EXPORT_FILE
  1307. else
  1308. echo "SSH_CIPHERS=$SSH_CIPHERS" >> $EXPORT_FILE
  1309. fi
  1310. fi
  1311. if [ "$SSH_MACS" ]; then
  1312. if grep -q "SSH_MACS" $EXPORT_FILE; then
  1313. sed -i "s|SSH_MACS=.*|SSH_MACS=$SSH_MACS|g" $EXPORT_FILE
  1314. else
  1315. echo "SSH_MACS=$SSH_MACS" >> $EXPORT_FILE
  1316. fi
  1317. fi
  1318. if [ "$SSH_KEX" ]; then
  1319. if grep -q "SSH_KEX" $EXPORT_FILE; then
  1320. sed -i "s|SSH_KEX=.*|SSH_KEX=$SSH_KEX|g" $EXPORT_FILE
  1321. else
  1322. echo "SSH_KEX=$SSH_KEX" >> $EXPORT_FILE
  1323. fi
  1324. fi
  1325. if [ "$SSH_HOST_KEY_ALGORITHMS" ]; then
  1326. if grep -q "SSH_HOST_KEY_ALGORITHMS" $EXPORT_FILE; then
  1327. sed -i "s|SSH_HOST_KEY_ALGORITHMS=.*|SSH_HOST_KEY_ALGORITHMS=$SSH_HOST_KEY_ALGORITHMS|g" $EXPORT_FILE
  1328. else
  1329. echo "SSH_HOST_KEY_ALGORITHMS=$SSH_HOST_KEY_ALGORITHMS" >> $EXPORT_FILE
  1330. fi
  1331. fi
  1332. if [ "$SSH_PASSWORDS" ]; then
  1333. if grep -q "SSH_PASSWORDS" $EXPORT_FILE; then
  1334. sed -i "s|SSH_PASSWORDS=.*|SSH_PASSWORDS=$SSH_PASSWORDS|g" $EXPORT_FILE
  1335. else
  1336. echo "SSH_PASSWORDS=$SSH_PASSWORDS" >> $EXPORT_FILE
  1337. fi
  1338. fi
  1339. if [ "$XMPP_CIPHERS" ]; then
  1340. if grep -q "XMPP_CIPHERS" $EXPORT_FILE; then
  1341. sed -i "s|XMPP_CIPHERS=.*|XMPP_CIPHERS=$XMPP_CIPHERS|g" $EXPORT_FILE
  1342. else
  1343. echo "XMPP_CIPHERS=$XMPP_CIPHERS" >> $EXPORT_FILE
  1344. fi
  1345. fi
  1346. if [ "$XMPP_ECC_CURVE" ]; then
  1347. if grep -q "XMPP_ECC_CURVE" $EXPORT_FILE; then
  1348. sed -i "s|XMPP_ECC_CURVE=.*|XMPP_ECC_CURVE=$XMPP_ECC_CURVE|g" $EXPORT_FILE
  1349. else
  1350. echo "XMPP_ECC_CURVE=$XMPP_ECC_CURVE" >> $EXPORT_FILE
  1351. fi
  1352. fi
  1353. echo $"Security settings exported to $EXPORT_FILE"
  1354. exit 0
  1355. }
  1356. function refresh_gpg_keys {
  1357. for d in /home/*/ ; do
  1358. USERNAME=$(echo "$d" | awk -F '/' '{print $3}')
  1359. if [[ $(is_valid_user "$USERNAME") == "1" ]]; then
  1360. su -c 'gpg --refresh-keys' - "$USERNAME"
  1361. fi
  1362. done
  1363. exit 0
  1364. }
  1365. function monkeysphere_sign_server_keys {
  1366. server_keys_file=/home/$USER/.monkeysphere/server_keys
  1367. if [ ! -f "$server_keys_file" ]; then
  1368. exit 0
  1369. fi
  1370. keys_signed=
  1371. while read -r line; do
  1372. echo "$line"
  1373. if [ ${#line} -gt 2 ]; then
  1374. fpr=$(gpg --with-colons --fingerprint "$line" | grep fpr | head -n 1 | awk -F ':' '{print $10}')
  1375. if [ ${#fpr} -gt 2 ]; then
  1376. if gpg --sign-key "$fpr"; then
  1377. gpg --update-trustdb
  1378. keys_signed=1
  1379. fi
  1380. fi
  1381. fi
  1382. done <"$server_keys_file"
  1383. if [ $keys_signed ]; then
  1384. rm "$server_keys_file"
  1385. fi
  1386. exit 0
  1387. }
  1388. function htmly_hash {
  1389. # produces a hash corresponding to a htmly password
  1390. pass="$1"
  1391. HTMLYHASH_FILENAME=/usr/bin/htmlyhash
  1392. { echo '<?php';
  1393. echo "parse_str(implode(\"&\", array_slice(\$argv, 1)), \$_GET);";
  1394. echo "\$password = \$_GET[\"password\"];";
  1395. echo "\$hash = password_hash(\$password, PASSWORD_BCRYPT);";
  1396. echo "if (password_verify(\$password, \$hash)) {";
  1397. echo " echo \$hash;";
  1398. echo '}';
  1399. echo '?>'; } > "$HTMLYHASH_FILENAME"
  1400. php $HTMLYHASH_FILENAME password="$pass"
  1401. }
  1402. function show_help {
  1403. echo ''
  1404. echo "${PROJECT_NAME}-sec"
  1405. echo ''
  1406. echo $'Alters the security settings'
  1407. echo ''
  1408. echo ''
  1409. echo $' -h --help Show help'
  1410. echo $' -e --export Export security settings to a file'
  1411. echo $' -i --import Import security settings from a file'
  1412. echo $' -r --refresh Refresh GPG keys for all users'
  1413. echo $' -s --sign Sign monkeysphere server keys'
  1414. echo $' --register [domain] Register a https domain with monkeysphere'
  1415. echo $' -b --htmlyhash [password] Returns the hash of a password for a htmly blog'
  1416. echo ''
  1417. exit 0
  1418. }
  1419. # Get the commandline options
  1420. while [ $# -gt 1 ]
  1421. do
  1422. key="$1"
  1423. case $key in
  1424. -h|--help)
  1425. show_help
  1426. ;;
  1427. # Export settings
  1428. -e|--export)
  1429. shift
  1430. EXPORT_FILE="$1"
  1431. ;;
  1432. # Export settings
  1433. -i|--import)
  1434. shift
  1435. IMPORT_FILE="$1"
  1436. ;;
  1437. # Refresh GPG keys
  1438. -r|--refresh)
  1439. shift
  1440. refresh_gpg_keys
  1441. ;;
  1442. # register a website
  1443. --register|--reg|--site)
  1444. shift
  1445. register_website "$1"
  1446. ;;
  1447. # user signs monkeysphere server keys
  1448. -s|--sign)
  1449. shift
  1450. monkeysphere_sign_server_keys
  1451. ;;
  1452. # get a hash of the given htmly password
  1453. -b|--htmlyhash)
  1454. shift
  1455. htmly_hash "$1"
  1456. exit 0
  1457. ;;
  1458. *)
  1459. # unknown option
  1460. ;;
  1461. esac
  1462. shift
  1463. done
  1464. menu_security_settings
  1465. exit 0