freedombone-sec 50KB

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